{"page_id": "products-cctp-bridge-get-started", "page_title": "Get Started with CCTP", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 715, "end_char": 1484, "estimated_token_count": 224, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, make sure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n - Wallets funded with native tokens and USDC on two [supported CCTP chains](/docs/products/reference/supported-networks/#cctp){target=\\_blank}.\n\nThis example uses a Solana Devnet wallet with [USDC](https://faucet.circle.com/){target=\\_blank} and [SOL](https://faucet.solana.com/){target=\\_blank}, as well as a Base Sepolia wallet with testnet [ETH](https://www.alchemy.com/faucets/base-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."}
{"page_id": "products-cctp-bridge-get-started", "page_title": "Get Started with CCTP", "index": 1, "depth": 2, "title": "Configure Your Token Transfer Environment", "anchor": "configure-your-token-transfer-environment", "start_char": 1484, "end_char": 3405, "estimated_token_count": 511, "token_estimator": "heuristic-v1", "text": "## Configure Your Token Transfer Environment\n\n1. Create a new directory and initialize a Node.js project:\n\n    ```bash\n    mkdir cctp-bridge\n    cd cctp-bridge\n    npm init -y\n    ```\n\n2. Pin the SDK to specific dependency versions to ensure compatibility with the [CCTP executor routes](https://www.npmjs.com/package/@wormhole-labs/cctp-executor-route){target=\\_blank}:\n\n    ```bash\n    npm pkg set overrides.@wormhole-foundation/sdk-aptos=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-base=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-connect=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-definitions=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-evm=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-solana=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-solana-cctp=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-sui=4.0.2\n    npm pkg set overrides.@wormhole-foundation/sdk-sui-cctp=4.0.2\n    npm pkg set overrides.axios=1.11.0\n    npm pkg set overrides.ethers=6.15.0\n    ```\n\n3. Install the required dependencies. This example uses the SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1 @wormhole-labs/cctp-executor-route\n    npm install -D tsx typescript\n    ```\n\n4. Create a `transfer.ts` file to handle the multichain transfer logic and a `helper.ts` file to manage wallet signers:\n\n    ```bash\n    touch transfer.ts helper.ts\n    ```\n\n5. 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://getfoundry.sh/cast/reference/wallet/#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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."}
{"page_id": "products-cctp-bridge-get-started", "page_title": "Get Started with CCTP", "index": 2, "depth": 2, "title": "Perform a CCTP Transfer", "anchor": "perform-a-cctp-transfer", "start_char": 3405, "end_char": 15473, "estimated_token_count": 2503, "token_estimator": "heuristic-v1", "text": "## Perform a CCTP Transfer\n\nThis section walks you through a complete automatic USDC transfer using Wormhole's CCTP integration. You will initiate the transfer on Solana Devnet, and Wormhole's relayer will automatically handle the Circle attestation and finalize the redemption on Base Sepolia.\n\nStart by defining utility functions for signer and token setup:\n\n1. In `helper.ts`, define functions to load private keys and instantiate EVM signers:\n\n    ```ts title=\"helper.ts\"\n    import {\n      ChainAddress,\n      ChainContext,\n      Network,\n      Signer,\n      Wormhole,\n      Chain,\n    } from '@wormhole-foundation/sdk';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import evm from '@wormhole-foundation/sdk/evm';\n\n    /**\n     * Returns a signer for the given chain using locally scoped credentials.\n     * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must\n     * be loaded securely beforehand, for example via a keystore, secrets\n     * manager, or environment variables (not recommended).\n     */\n    export async function getSigner<N extends Network, C extends Chain>(\n      chain: ChainContext<N, C>\n    ): Promise<{\n      chain: ChainContext<N, C>;\n      signer: Signer<N, C>;\n      address: ChainAddress<C>;\n    }> {\n      let signer: Signer;\n      const platform = chain.platform.utils()._platform;\n\n      switch (platform) {\n        case 'Evm':\n          signer = await (\n            await evm()\n          ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!);\n          break;\n        case 'Solana':\n          signer = await (\n            await solana()\n          ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!);\n          break;\n        case 'Sui':\n          signer = await (\n            await sui()\n          ).getSigner(await chain.getRpc(), SUI_MNEMONIC!);\n          break;\n        default:\n          throw new Error(`Unsupported platform: ${platform}`);\n      }\n\n      return {\n        chain,\n        signer: signer as Signer<N, C>,\n        address: Wormhole.chainAddress(chain.chain, signer.address()),\n      };\n    }\n    ```\n\n2. In `transfer.ts`, add the script to perform the automatic transfer using CCTP. Wormhole supports both CCTP v1 and [CCTP v2](https://www.circle.com/blog/cctp-v2-the-future-of-cross-chain){target=\\_blank}, and the SDK provides executors for each version. See the [CCTP-supported executors](/docs/products/reference/executor-addresses/#cctp-with-executor){target=\\_blank} to determine which version applies to your case:\n\n    === \"CCTP v1\"\n\n        ```ts title=\"transfer.ts\"\n        import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/platforms/evm';\n        import solana from '@wormhole-foundation/sdk/platforms/solana';\n        import sui from '@wormhole-foundation/sdk/platforms/sui';\n        import '@wormhole-labs/cctp-executor-route';\n        import { cctpExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n        import type { CCTPExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV1';\n        import { getSigner } from './helper';\n\n        (async function () {\n          // Initialize Wormhole for the Testnet environment and add supported chains (evm, solana and sui)\n          const network = 'Testnet';\n          const wh = new Wormhole(network, [\n            evm.Platform,\n            solana.Platform,\n            sui.Platform,\n          ]);\n\n          // Grab chain contexts (cached RPC clients under the hood)\n          const src = wh.getChain('Solana');\n          const dst = wh.getChain('BaseSepolia');\n\n          // Get signers from local keys\n          const srcSigner = await getSigner(src);\n          const dstSigner = await getSigner(dst);\n\n          // Fetch the USDC contract addresses for these chains\n          const srcUsdc = circle.usdcContract.get(network, src.chain);\n          const dstUsdc = circle.usdcContract.get(network, dst.chain);\n\n          if (!srcUsdc || !dstUsdc) {\n            throw new Error(\n              'USDC is not configured on the selected source/destination'\n            );\n          }\n\n          // Build the transfer request for the CCTP v1 executor\n          const tr = await routes.RouteTransferRequest.create(wh, {\n            source: Wormhole.tokenId(src.chain, srcUsdc),\n            destination: Wormhole.tokenId(dst.chain, dstUsdc),\n            sourceDecimals: 6,\n            destinationDecimals: 6,\n            sender: srcSigner.address,\n            recipient: dstSigner.address,\n          });\n\n          // Configure the executor route (referrer fee off)\n          const ExecutorRoute = cctpExecutorRoute({ referrerFeeDbps: 0n });\n          const route = new ExecutorRoute(wh);\n\n          // Define the amount of USDC to transfer (in the smallest unit, so 1.000001 USDC = 1,000,001 units assuming 6 decimals)\n          const transferAmount = '1.000001';\n\n          // Set the native gas drop-off (0 <= nativeGas <= 1)\n          const nativeGasPercent = 0.1;\n\n          const validated = await route.validate(tr, {\n            amount: transferAmount,\n            options: { nativeGas: nativeGasPercent },\n          });\n\n          // Validate inputs and exit early on failure\n          if (!validated.valid) {\n            const { error } = validated as Extract<typeof validated, { valid: false }>;\n            throw new Error(`Validation failed: ${error.message}`);\n          }\n\n          // Quote expects the normalized params produced by validate(); cast to that shape\n          const validatedParams = validated.params as CCTPExecutorRoute.ValidatedParams;\n          const quote = await route.quote(tr, validatedParams);\n          if (!quote.success) {\n            const { error } = quote as Extract<typeof quote, { success: false }>;\n            throw new Error(`Quote failed: ${error.message}`);\n          }\n\n          // Start the transfer on the source chain via the executor\n          const receipt = await route.initiate(\n            tr,\n            srcSigner.signer,\n            quote,\n            dstSigner.address\n          );\n          if ('originTxs' in receipt && Array.isArray(receipt.originTxs)) {\n            console.log('Source transactions:', receipt.originTxs);\n\n            const lastTx = receipt.originTxs[receipt.originTxs.length - 1];\n            if (lastTx) {\n              const txid =\n                typeof lastTx === 'string' ? lastTx : lastTx.txid ?? String(lastTx);\n              const wormholeScanUrl = `https://wormholescan.io/#/tx/${txid}?network=${network}`;\n              console.log('WormholeScan URL:', wormholeScanUrl);\n            }\n          } else {\n            console.log('Receipt returned without origin transactions:', receipt);\n          }\n        })();\n        ```\n\n    === \"CCTP v2\"\n\n        ```ts title=\"transfer.ts\"\n        import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/platforms/evm';\n        import solana from '@wormhole-foundation/sdk/platforms/solana';\n        import sui from '@wormhole-foundation/sdk/platforms/sui';\n        import '@wormhole-labs/cctp-executor-route';\n        import { cctpV2StandardExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n        import type { CCTPv2ExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV2Base';\n        import { getSigner } from './helper';\n\n        (async function () {\n          // Initialize Wormhole for the Testnet environment and add supported chains (evm, solana and sui)\n          const network = 'Testnet';\n          const wh = new Wormhole(network, [\n            evm.Platform,\n            solana.Platform,\n            sui.Platform,\n          ]);\n\n          // Grab chain contexts (cached RPC clients under the hood)\n          const src = wh.getChain('Solana');\n          const dst = wh.getChain('BaseSepolia');\n\n          // Get signers from local keys\n          const srcSigner = await getSigner(src);\n          const dstSigner = await getSigner(dst);\n\n          // Fetch the USDC contract addresses for these chains\n          const srcUsdc = circle.usdcContract.get(network, src.chain);\n          const dstUsdc = circle.usdcContract.get(network, dst.chain);\n\n          if (!srcUsdc || !dstUsdc) {\n            throw new Error(\n              'USDC is not configured on the selected source/destination'\n            );\n          }\n\n          // Build the transfer request for the CCTP v2 executor\n          const tr = await routes.RouteTransferRequest.create(wh, {\n            source: Wormhole.tokenId(src.chain, srcUsdc),\n            destination: Wormhole.tokenId(dst.chain, dstUsdc),\n            sourceDecimals: 6,\n            destinationDecimals: 6,\n            sender: srcSigner.address,\n            recipient: dstSigner.address,\n          });\n\n          // Configure the executor route (referrer fee off)\n          const ExecutorRoute = cctpV2StandardExecutorRoute({ referrerFeeDbps: 0n });\n          const route = new ExecutorRoute(wh);\n\n          // Define the amount of USDC to transfer (in the smallest unit, so 1.000001 USDC = 1,000,001 units assuming 6 decimals)\n          const transferAmount = '1.000001';\n\n          // Set the native gas drop-off (0 <= nativeGas <= 1)\n          const nativeGasPercent = 0.1;\n\n          const validated = await route.validate(tr, {\n            amount: transferAmount,\n            options: { nativeGas: nativeGasPercent },\n          });\n\n          // Validate inputs and exit early on failure\n          if (!validated.valid) {\n            const { error } = validated as Extract<typeof validated, { valid: false }>;\n            throw new Error(`Validation failed: ${error.message}`);\n          }\n\n          // Quote expects the normalized params produced by validate(); cast to that shape\n          const validatedParams =\n            validated.params as CCTPv2ExecutorRoute.ValidatedParams;\n          const quote = await route.quote(tr, validatedParams);\n          if (!quote.success) {\n            const { error } = quote as Extract<typeof quote, { success: false }>;\n            throw new Error(`Quote failed: ${error.message}`);\n          }\n\n          // Start the transfer on the source chain via the executor\n          const receipt = await route.initiate(\n            tr,\n            srcSigner.signer,\n            quote,\n            dstSigner.address\n          );\n          if ('originTxs' in receipt && Array.isArray(receipt.originTxs)) {\n            console.log('Source transactions:', receipt.originTxs);\n\n            const lastTx = receipt.originTxs[receipt.originTxs.length - 1];\n            if (lastTx) {\n              const txid =\n                typeof lastTx === 'string' ? lastTx : lastTx.txid ?? String(lastTx);\n              const wormholeScanUrl = `https://wormholescan.io/#/tx/${txid}?network=${network}`;\n              console.log('WormholeScan URL:', wormholeScanUrl);\n            }\n          } else {\n            console.log('Receipt returned without origin transactions:', receipt);\n          }\n        })();\n        ```\n\n3. Run the script to execute the transfer:\n\n    ```bash\n    npx tsx transfer.ts\n    ```\n\n    You will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n    \t<span data-ty>Source transactions: [ </span>\n    \t<span data-ty\n    \t\t>{\n    \t\t\tchain: 'Solana',\n    \t\t\ttxid: 's1gCiQi1aCJVuGGyjMZZcad3bZS3h4mJKvaNBNctrWLq7ooEpdvs3ehjuGx6esK7wGR1y4sEjQJcBbUfqLp8h3H'\n    \t\t}]\n    \t</span>\n    \t<span data-ty> </span>\n    \t<span data-ty\n    \t\t>WormholeScan URL: https://wormholescan.io/#/tx/s1gCiQi1aCJVuGGyjMZZcad3bZS3h4mJKvaNBNctrWLq7ooEpdvs3ehjuGx6esK7wGR1y4sEjQJcBbUfqLp8h3H?network=Testnet</span\n    \t>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\nTo verify the transaction and view its details, paste the transaction hash into [Wormholescan](https://wormholescan.io/#/?network=Testnet){target=\\_blank}."}
{"page_id": "products-cctp-bridge-get-started", "page_title": "Get Started with CCTP", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 15473, "end_char": 16180, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow that you've completed a CCTP USDC transfer using the Wormhole SDK, you're ready to explore more advanced features and expand your integration.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Circle CCTP Documentation**\n\n    ---\n\n    Learn how USDC cross-chain transfers work and explore advanced CCTP features.\n\n    [:custom-arrow: See the Circle Docs](https://developers.circle.com/cctp){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1015, "end_char": 1379, "estimated_token_count": 95, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo interact with the Wormhole CCTP, you'll need the following:\n\n- [The address of the CCTP contract](/docs/products/reference/contract-addresses/#cctp){target=\\_blank} on the chains you're deploying your contract on.\n- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\\_blank} of the chains you're deploying your contract on."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 1, "depth": 2, "title": "Wormhole's CCTP Integration Contract", "anchor": "wormholes-cctp-integration-contract", "start_char": 1379, "end_char": 18179, "estimated_token_count": 2659, "token_estimator": "heuristic-v1", "text": "## Wormhole's CCTP Integration Contract\n\nWormhole's Circle Integration contract, `CircleIntegration.sol`, is the contract that applications interact with on the source chain. It initiates CCTP burns via [Circle's CCTP contracts](#circles-cctp-contracts) and emits Wormhole messages to coordinate completion on the destination chain.\n\nThis contract can be found in [Wormhole's `wormhole-circle-integration` repository](https://github.com/wormhole-foundation/wormhole-circle-integration/){target=\\_blank} on GitHub.\n\n!!! note\n    Wormhole supports all CCTP-supported chains, but Circle currently supports only a [handful of chains](https://developers.circle.com/cctp/cctp-supported-blockchains#cctp-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.\n\n??? code \"Circle Integration contract\"\n    ```solidity\n    // SPDX-License-Identifier: Apache 2\n    pragma solidity ^0.8.19;\n\n    import {ReentrancyGuard} from \"@openzeppelin/contracts/security/ReentrancyGuard.sol\";\n    import {IERC20} from \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n    import {SafeERC20} from \"@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol\";\n    import {IWormhole} from \"wormhole/interfaces/IWormhole.sol\";\n    import {BytesLib} from \"wormhole/libraries/external/BytesLib.sol\";\n\n    import {ICircleBridge} from \"../interfaces/circle/ICircleBridge.sol\";\n\n    import {CircleIntegrationGovernance} from \"./CircleIntegrationGovernance.sol\";\n    import {CircleIntegrationMessages} from \"./CircleIntegrationMessages.sol\";\n\n    /**\n     * @notice This contract burns and mints Circle-supported tokens by using Circle's Cross-Chain Transfer Protocol. It also emits\n     * Wormhole messages with arbitrary payloads to allow for additional composability when performing cross-chain\n     * transfers of Circle-suppored assets.\n     */\n    contract CircleIntegration is\n        CircleIntegrationMessages,\n        CircleIntegrationGovernance,\n        ReentrancyGuard\n    {\n        using BytesLib for bytes;\n\n        /**\n         * @notice Emitted when Circle-supported assets have been minted to the mintRecipient\n         * @param emitterChainId Wormhole chain ID of emitter contract on source chain\n         * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on source chain\n         * @param sequence Sequence of Wormhole message used to mint tokens\n         */\n        event Redeemed(\n            uint16 indexed emitterChainId,\n            bytes32 indexed emitterAddress,\n            uint64 indexed sequence\n        );\n\n        /**\n         * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits\n         * a Wormhole message containing a user-specified payload with instructions for what to do with\n         * the Circle-supported assets once they have been minted on the target chain.\n         * @dev reverts if:\n         * - user passes insufficient value to pay Wormhole message fee\n         * - `token` is not supported by Circle Bridge\n         * - `amount` is zero\n         * - `targetChain` is not supported\n         * - `mintRecipient` is bytes32(0)\n         * @param transferParams Struct containing the following attributes:\n         * - `token` Address of the token to be burned\n         * - `amount` Amount of `token` to be burned\n         * - `targetChain` Wormhole chain ID of the target blockchain\n         * - `mintRecipient` The recipient wallet or contract address on the target chain\n         * @param batchId ID for Wormhole message batching\n         * @param payload Arbitrary payload to be delivered to the target chain via Wormhole\n         * @return messageSequence Wormhole sequence number for this contract\n         */\n        function transferTokensWithPayload(\n            TransferParameters memory transferParams,\n            uint32 batchId,\n            bytes memory payload\n        ) public payable nonReentrant returns (uint64 messageSequence) {\n            // cache wormhole instance and fees to save on gas\n            IWormhole wormhole = wormhole();\n            uint256 wormholeFee = wormhole.messageFee();\n\n            // confirm that the caller has sent enough ether to pay for the wormhole message fee\n            require(msg.value == wormholeFee, \"insufficient value\");\n\n            // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient`\n            // should be the target contract (or wallet) composing on this contract.\n            (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}(\n                transferParams.token,\n                transferParams.amount,\n                transferParams.targetChain,\n                transferParams.mintRecipient\n            );\n\n            // encode DepositWithPayload message\n            bytes memory encodedMessage = encodeDepositWithPayload(\n                DepositWithPayload({\n                    token: addressToBytes32(transferParams.token),\n                    amount: amountReceived,\n                    sourceDomain: localDomain(),\n                    targetDomain: getDomainFromChainId(transferParams.targetChain),\n                    nonce: nonce,\n                    fromAddress: addressToBytes32(msg.sender),\n                    mintRecipient: transferParams.mintRecipient,\n                    payload: payload\n                })\n            );\n\n            // send the DepositWithPayload wormhole message\n            messageSequence = wormhole.publishMessage{value: wormholeFee}(\n                batchId,\n                encodedMessage,\n                wormholeFinality()\n            );\n        }\n\n        function _transferTokens(\n            address token,\n            uint256 amount,\n            uint16 targetChain,\n            bytes32 mintRecipient\n        ) internal returns (uint64 nonce, uint256 amountReceived) {\n            // sanity check user input\n            require(amount > 0, \"amount must be > 0\");\n            require(mintRecipient != bytes32(0), \"invalid mint recipient\");\n            require(isAcceptedToken(token), \"token not accepted\");\n            require(\n                getRegisteredEmitter(targetChain) != bytes32(0),\n                \"target contract not registered\"\n            );\n\n            // take custody of tokens\n            amountReceived = custodyTokens(token, amount);\n\n            // cache Circle Bridge instance\n            ICircleBridge circleBridge = circleBridge();\n\n            // approve the Circle Bridge to spend tokens\n            SafeERC20.safeApprove(\n                IERC20(token),\n                address(circleBridge),\n                amountReceived\n            );\n\n            // burn tokens on the bridge\n            nonce = circleBridge.depositForBurnWithCaller(\n                amountReceived,\n                getDomainFromChainId(targetChain),\n                mintRecipient,\n                token,\n                getRegisteredEmitter(targetChain)\n            );\n        }\n\n        function custodyTokens(\n            address token,\n            uint256 amount\n        ) internal returns (uint256) {\n            // query own token balance before transfer\n            (, bytes memory queriedBalanceBefore) = token.staticcall(\n                abi.encodeWithSelector(IERC20.balanceOf.selector, address(this))\n            );\n            uint256 balanceBefore = abi.decode(queriedBalanceBefore, (uint256));\n\n            // deposit tokens\n            SafeERC20.safeTransferFrom(\n                IERC20(token),\n                msg.sender,\n                address(this),\n                amount\n            );\n\n            // query own token balance after transfer\n            (, bytes memory queriedBalanceAfter) = token.staticcall(\n                abi.encodeWithSelector(IERC20.balanceOf.selector, address(this))\n            );\n            uint256 balanceAfter = abi.decode(queriedBalanceAfter, (uint256));\n\n            return balanceAfter - balanceBefore;\n        }\n\n        /**\n         * @notice `redeemTokensWithPayload` verifies the Wormhole message from the source chain and\n         * verifies that the passed Circle Bridge message is valid. It calls the Circle Bridge\n         * contract by passing the Circle message and attestation to mint tokens to the specified\n         * mint recipient. It also verifies that the caller is the specified mint recipient to ensure\n         * atomic execution of the additional instructions in the Wormhole message.\n         * @dev reverts if:\n         * - Wormhole message is not properly attested\n         * - Wormhole message was not emitted from a registered contrat\n         * - Wormhole message was already consumed by this contract\n         * - msg.sender is not the encoded mintRecipient\n         * - Circle Bridge message and Wormhole message are not associated\n         * - `receiveMessage` call to Circle Transmitter fails\n         * @param params Struct containing the following attributes:\n         * - `encodedWormholeMessage` Wormhole message emitted by a registered contract including\n         * information regarding the token burn on the source chain and an arbitrary message.\n         * - `circleBridgeMessage` Message emitted by Circle Bridge contract with information regarding\n         * the token burn on the source chain.\n         * - `circleAttestation` Serialized EC Signature attesting the cross-chain transfer\n         * @return depositInfo Struct containing the following attributes:\n         * - `token` Address (bytes32 left-zero-padded) of token to be minted\n         * - `amount` Amount of tokens to be minted\n         * - `sourceDomain` Circle domain for the source chain\n         * - `targetDomain` Circle domain for the target chain\n         * - `nonce` Circle sequence number for the transfer\n         * - `fromAddress` Source CircleIntegration contract caller's address\n         * - `mintRecipient` Recipient of minted tokens (must be caller of this contract)\n         * - `payload` Arbitrary Wormhole message payload\n         */\n        function redeemTokensWithPayload(\n            RedeemParameters calldata params\n        ) public returns (DepositWithPayload memory depositInfo) {\n            // verify the wormhole message\n            IWormhole.VM memory verifiedMessage = verifyWormholeRedeemMessage(\n                params.encodedWormholeMessage\n            );\n\n            // Decode the message payload into the DepositWithPayload struct. Call the Circle TokenMinter\n            // contract to determine the address of the encoded token on this chain.\n            depositInfo = decodeDepositWithPayload(verifiedMessage.payload);\n            depositInfo.token = fetchLocalTokenAddress(\n                depositInfo.sourceDomain,\n                depositInfo.token\n            );\n\n            // confirm that circle gave us a valid token address\n            require(depositInfo.token != bytes32(0), \"invalid local token address\");\n\n            // confirm that the caller is the `mintRecipient` to ensure atomic execution\n            require(\n                addressToBytes32(msg.sender) == depositInfo.mintRecipient,\n                \"caller must be mintRecipient\"\n            );\n\n            // confirm that the caller passed the correct message pair\n            require(\n                verifyCircleMessage(\n                    params.circleBridgeMessage,\n                    depositInfo.sourceDomain,\n                    depositInfo.targetDomain,\n                    depositInfo.nonce\n                ),\n                \"invalid message pair\"\n            );\n\n            // call the circle bridge to mint tokens to the recipient\n            bool success = circleTransmitter().receiveMessage(\n                params.circleBridgeMessage,\n                params.circleAttestation\n            );\n            require(success, \"CIRCLE_INTEGRATION: failed to mint tokens\");\n\n            // emit Redeemed event\n            emit Redeemed(\n                verifiedMessage.emitterChainId,\n                verifiedMessage.emitterAddress,\n                verifiedMessage.sequence\n            );\n        }\n\n        function verifyWormholeRedeemMessage(\n            bytes memory encodedMessage\n        ) internal returns (IWormhole.VM memory) {\n            require(evmChain() == block.chainid, \"invalid evm chain\");\n\n            // parse and verify the Wormhole core message\n            (\n                IWormhole.VM memory verifiedMessage,\n                bool valid,\n                string memory reason\n            ) = wormhole().parseAndVerifyVM(encodedMessage);\n\n            // confirm that the core layer verified the message\n            require(valid, reason);\n\n            // verify that this message was emitted by a trusted contract\n            require(verifyEmitter(verifiedMessage), \"unknown emitter\");\n\n            // revert if this message has been consumed already\n            require(\n                !isMessageConsumed(verifiedMessage.hash),\n                \"message already consumed\"\n            );\n            consumeMessage(verifiedMessage.hash);\n\n            return verifiedMessage;\n        }\n\n        function verifyEmitter(\n            IWormhole.VM memory vm\n        ) internal view returns (bool) {\n            // verify that the sender of the wormhole message is a trusted\n            return (getRegisteredEmitter(vm.emitterChainId) == vm.emitterAddress &&\n                vm.emitterAddress != bytes32(0));\n        }\n\n        function verifyCircleMessage(\n            bytes memory circleMessage,\n            uint32 sourceDomain,\n            uint32 targetDomain,\n            uint64 nonce\n        ) internal pure returns (bool) {\n            // parse the circle bridge message inline\n            uint32 circleSourceDomain = circleMessage.toUint32(4);\n            uint32 circleTargetDomain = circleMessage.toUint32(8);\n            uint64 circleNonce = circleMessage.toUint64(12);\n\n            // confirm that both the Wormhole message and Circle message share the same transfer info\n            return (sourceDomain == circleSourceDomain &&\n                targetDomain == circleTargetDomain &&\n                nonce == circleNonce);\n        }\n\n        /**\n         * @notice Fetches the local token address given an address and domain from\n         * a different chain.\n         * @param sourceDomain Circle domain for the sending chain.\n         * @param sourceToken Address of the token for the sending chain.\n         * @return Address bytes32 formatted address of the `sourceToken` on this chain.\n         */\n        function fetchLocalTokenAddress(\n            uint32 sourceDomain,\n            bytes32 sourceToken\n        ) public view returns (bytes32) {\n            return\n                addressToBytes32(\n                    circleTokenMinter().remoteTokensToLocalTokens(\n                        keccak256(abi.encodePacked(sourceDomain, sourceToken))\n                    )\n                );\n        }\n\n        /**\n         * @notice Converts type address to bytes32 (left-zero-padded)\n         * @param address_ Address to convert to bytes32\n         * @return Address bytes32\n         */\n        function addressToBytes32(address address_) public pure returns (bytes32) {\n            return bytes32(uint256(uint160(address_)));\n        }\n    }\n    ```\n\nThe Circle Integration contract is used for source-chain initiation. Calling `transferTokensWithPayload` initiates a CCTP transfer by burning USDC on the source chain and emitting a Wormhole message with an application-defined payload. When used with the [Executor framework](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank}, this Wormhole message serves as the input for the off-chain execution flow. Attestation retrieval, redemption, and destination execution are handled by a relay provider after an execution request is submitted.\n\n??? interface \"Parameters\"\n\n    `transferParams` ++\"TransferParameters\"++\n\n    A tuple containing the parameters for the transfer.\n\n    ??? child \"`TransferParameters` struct\"\n\n        `token` ++\"address\"++\n\n        Address of the token to be burned.\n\n        ---\n\n        `amount` ++\"uint256\"++\n\n        Amount of the token to be burned.\n\n        ---\n\n        `targetChain` ++\"uint16\"++\n\n        Wormhole chain ID of the target blockchain.\n\n        ---\n\n        `mintRecipient` ++\"bytes32\"++\n\n        The recipient wallet or contract address on the target chain.\n\n    ---\n\n    `batchId` ++\"uint32\"++\n\n    The ID for Wormhole message batching.\n\n    ---\n\n    `payload` ++\"bytes\"++\n\n    Arbitrary payload to be delivered to the target chain via Wormhole.\n\n??? interface \"Returns\"\n\n    `messageSequence` ++\"uint64\"++\n\n    Wormhole sequence number for this contract."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 2, "depth": 2, "title": "Circle's CCTP Contracts", "anchor": "circles-cctp-contracts", "start_char": 18179, "end_char": 19262, "estimated_token_count": 223, "token_estimator": "heuristic-v1", "text": "## Circle's CCTP Contracts\n\nThree key contracts power Circle's CCTP:\n\n- **`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.\n- **`MessageTransmitter`**: Handles generic message passing, sending messages from the source chain and receiving them on the destination chain.\n- **`TokenMinter`**: Responsible for the actual minting and burning of USDC, utilizing chain-specific settings for both the burners and minters across different networks.\n\nThe following sections will examine these contracts in-depth, focusing on the methods invoked indirectly through function calls in the Wormhole Circle Integration contract.\n\n!!! note\n    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.\n\nThese contracts can be found in [Circle's `evm-cctp-contracts` repository](https://github.com/circlefin/evm-cctp-contracts/){target=\\_blank} on GitHub."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 3, "depth": 3, "title": "Token Messenger Contract", "anchor": "token-messenger-contract", "start_char": 19262, "end_char": 53821, "estimated_token_count": 5452, "token_estimator": "heuristic-v1", "text": "### Token Messenger Contract\n\nThe 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.\n\nTo 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.\n\nAdditionally, 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.\n\n??? code \"Token Messenger contract\"\n    ```solidity\n    /*\n     * Copyright (c) 2022, Circle Internet Financial Limited.\n     *\n     * Licensed under the Apache License, Version 2.0 (the \"License\");\n     * you may not use this file except in compliance with the License.\n     * You may obtain a copy of the License at\n     *\n     * http://www.apache.org/licenses/LICENSE-2.0\n     *\n     * Unless required by applicable law or agreed to in writing, software\n     * distributed under the License is distributed on an \"AS IS\" BASIS,\n     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     * See the License for the specific language governing permissions and\n     * limitations under the License.\n     */\n    pragma solidity 0.7.6;\n\n    import \"./interfaces/IMessageHandler.sol\";\n    import \"./interfaces/ITokenMinter.sol\";\n    import \"./interfaces/IMintBurnToken.sol\";\n    import \"./interfaces/IMessageTransmitter.sol\";\n    import \"./messages/BurnMessage.sol\";\n    import \"./messages/Message.sol\";\n    import \"./roles/Rescuable.sol\";\n\n    /**\n     * @title TokenMessenger\n     * @notice Sends messages and receives messages to/from MessageTransmitters\n     * and to/from TokenMinters\n     */\n    contract TokenMessenger is IMessageHandler, Rescuable {\n        // ============ Events ============\n        /**\n         * @notice Emitted when a DepositForBurn message is sent\n         * @param nonce unique nonce reserved by message\n         * @param burnToken address of token burnt on source domain\n         * @param amount deposit amount\n         * @param depositor address where deposit is transferred from\n         * @param mintRecipient address receiving minted tokens on destination domain as bytes32\n         * @param destinationDomain destination domain\n         * @param destinationTokenMessenger address of TokenMessenger on destination domain as bytes32\n         * @param destinationCaller authorized caller as bytes32 of receiveMessage() on destination domain, if not equal to bytes32(0).\n         * If equal to bytes32(0), any address can call receiveMessage().\n         */\n        event DepositForBurn(\n            uint64 indexed nonce,\n            address indexed burnToken,\n            uint256 amount,\n            address indexed depositor,\n            bytes32 mintRecipient,\n            uint32 destinationDomain,\n            bytes32 destinationTokenMessenger,\n            bytes32 destinationCaller\n        );\n\n        /**\n         * @notice Emitted when tokens are minted\n         * @param mintRecipient recipient address of minted tokens\n         * @param amount amount of minted tokens\n         * @param mintToken contract address of minted token\n         */\n        event MintAndWithdraw(\n            address indexed mintRecipient,\n            uint256 amount,\n            address indexed mintToken\n        );\n\n        /**\n         * @notice Emitted when a remote TokenMessenger is added\n         * @param domain remote domain\n         * @param tokenMessenger TokenMessenger on remote domain\n         */\n        event RemoteTokenMessengerAdded(uint32 domain, bytes32 tokenMessenger);\n\n        /**\n         * @notice Emitted when a remote TokenMessenger is removed\n         * @param domain remote domain\n         * @param tokenMessenger TokenMessenger on remote domain\n         */\n        event RemoteTokenMessengerRemoved(uint32 domain, bytes32 tokenMessenger);\n\n        /**\n         * @notice Emitted when the local minter is added\n         * @param localMinter address of local minter\n         * @notice Emitted when the local minter is added\n         */\n        event LocalMinterAdded(address localMinter);\n\n        /**\n         * @notice Emitted when the local minter is removed\n         * @param localMinter address of local minter\n         * @notice Emitted when the local minter is removed\n         */\n        event LocalMinterRemoved(address localMinter);\n\n        // ============ Libraries ============\n        using TypedMemView for bytes;\n        using TypedMemView for bytes29;\n        using BurnMessage for bytes29;\n        using Message for bytes29;\n\n        // ============ State Variables ============\n        // Local Message Transmitter responsible for sending and receiving messages to/from remote domains\n        IMessageTransmitter public immutable localMessageTransmitter;\n\n        // Version of message body format\n        uint32 public immutable messageBodyVersion;\n\n        // Minter responsible for minting and burning tokens on the local domain\n        ITokenMinter public localMinter;\n\n        // Valid TokenMessengers on remote domains\n        mapping(uint32 => bytes32) public remoteTokenMessengers;\n\n        // ============ Modifiers ============\n        /**\n         * @notice Only accept messages from a registered TokenMessenger contract on given remote domain\n         * @param domain The remote domain\n         * @param tokenMessenger The address of the TokenMessenger contract for the given remote domain\n         */\n        modifier onlyRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger) {\n            require(\n                _isRemoteTokenMessenger(domain, tokenMessenger),\n                \"Remote TokenMessenger unsupported\"\n            );\n            _;\n        }\n\n        /**\n         * @notice Only accept messages from the registered message transmitter on local domain\n         */\n        modifier onlyLocalMessageTransmitter() {\n            // Caller must be the registered message transmitter for this domain\n            require(_isLocalMessageTransmitter(), \"Invalid message transmitter\");\n            _;\n        }\n\n        // ============ Constructor ============\n        /**\n         * @param _messageTransmitter Message transmitter address\n         * @param _messageBodyVersion Message body version\n         */\n        constructor(address _messageTransmitter, uint32 _messageBodyVersion) {\n            require(\n                _messageTransmitter != address(0),\n                \"MessageTransmitter not set\"\n            );\n            localMessageTransmitter = IMessageTransmitter(_messageTransmitter);\n            messageBodyVersion = _messageBodyVersion;\n        }\n\n        // ============ External Functions  ============\n        /**\n         * @notice Deposits and burns tokens from sender to be minted on destination domain.\n         * Emits a `DepositForBurn` event.\n         * @dev reverts if:\n         * - given burnToken is not supported\n         * - given destinationDomain has no TokenMessenger registered\n         * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n         * to this contract is less than `amount`.\n         * - burn() reverts. For example, if `amount` is 0.\n         * - MessageTransmitter returns false or reverts.\n         * @param amount amount of tokens to burn\n         * @param destinationDomain destination domain\n         * @param mintRecipient address of mint recipient on destination domain\n         * @param burnToken address of contract to burn deposited tokens, on local domain\n         * @return _nonce unique nonce reserved by message\n         */\n        function depositForBurn(\n            uint256 amount,\n            uint32 destinationDomain,\n            bytes32 mintRecipient,\n            address burnToken\n        ) external returns (uint64 _nonce) {\n            return\n                _depositForBurn(\n                    amount,\n                    destinationDomain,\n                    mintRecipient,\n                    burnToken,\n                    // (bytes32(0) here indicates that any address can call receiveMessage()\n                    // on the destination domain, triggering mint to specified `mintRecipient`)\n                    bytes32(0)\n                );\n        }\n\n        /**\n         * @notice Deposits and burns tokens from sender to be minted on destination domain. The mint\n         * on the destination domain must be called by `destinationCaller`.\n         * WARNING: if the `destinationCaller` does not represent a valid address as bytes32, then it will not be possible\n         * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n         * depositForBurn() should be preferred for use cases where a specific destination caller is not required.\n         * Emits a `DepositForBurn` event.\n         * @dev reverts if:\n         * - given destinationCaller is zero address\n         * - given burnToken is not supported\n         * - given destinationDomain has no TokenMessenger registered\n         * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n         * to this contract is less than `amount`.\n         * - burn() reverts. For example, if `amount` is 0.\n         * - MessageTransmitter returns false or reverts.\n         * @param amount amount of tokens to burn\n         * @param destinationDomain destination domain\n         * @param mintRecipient address of mint recipient on destination domain\n         * @param burnToken address of contract to burn deposited tokens, on local domain\n         * @param destinationCaller caller on the destination domain, as bytes32\n         * @return nonce unique nonce reserved by message\n         */\n        function depositForBurnWithCaller(\n            uint256 amount,\n            uint32 destinationDomain,\n            bytes32 mintRecipient,\n            address burnToken,\n            bytes32 destinationCaller\n        ) external returns (uint64 nonce) {\n            // Destination caller must be nonzero. To allow any destination caller, use depositForBurn().\n            require(destinationCaller != bytes32(0), \"Invalid destination caller\");\n\n            return\n                _depositForBurn(\n                    amount,\n                    destinationDomain,\n                    mintRecipient,\n                    burnToken,\n                    destinationCaller\n                );\n        }\n\n        /**\n         * @notice Replace a BurnMessage to change the mint recipient and/or\n         * destination caller. Allows the sender of a previous BurnMessage\n         * (created by depositForBurn or depositForBurnWithCaller)\n         * to send a new BurnMessage to replace the original.\n         * The new BurnMessage will reuse the amount and burn token of the original,\n         * without requiring a new deposit.\n         * @dev The new message will reuse the original message's nonce. For a\n         * given nonce, all replacement message(s) and the original message are\n         * valid to broadcast on the destination domain, until the first message\n         * at the nonce confirms, at which point all others are invalidated.\n         * Note: The msg.sender of the replaced message must be the same as the\n         * msg.sender of the original message.\n         * @param originalMessage original message bytes (to replace)\n         * @param originalAttestation original attestation bytes\n         * @param newDestinationCaller the new destination caller, which may be the\n         * same as the original destination caller, a new destination caller, or an empty\n         * destination caller (bytes32(0), indicating that any destination caller is valid.)\n         * @param newMintRecipient the new mint recipient, which may be the same as the\n         * original mint recipient, or different.\n         */\n        function replaceDepositForBurn(\n            bytes calldata originalMessage,\n            bytes calldata originalAttestation,\n            bytes32 newDestinationCaller,\n            bytes32 newMintRecipient\n        ) external {\n            bytes29 _originalMsg = originalMessage.ref(0);\n            _originalMsg._validateMessageFormat();\n            bytes29 _originalMsgBody = _originalMsg._messageBody();\n            _originalMsgBody._validateBurnMessageFormat();\n\n            bytes32 _originalMsgSender = _originalMsgBody._getMessageSender();\n            // _originalMsgSender must match msg.sender of original message\n            require(\n                msg.sender == Message.bytes32ToAddress(_originalMsgSender),\n                \"Invalid sender for message\"\n            );\n            require(\n                newMintRecipient != bytes32(0),\n                \"Mint recipient must be nonzero\"\n            );\n\n            bytes32 _burnToken = _originalMsgBody._getBurnToken();\n            uint256 _amount = _originalMsgBody._getAmount();\n\n            bytes memory _newMessageBody = BurnMessage._formatMessage(\n                messageBodyVersion,\n                _burnToken,\n                newMintRecipient,\n                _amount,\n                _originalMsgSender\n            );\n\n            localMessageTransmitter.replaceMessage(\n                originalMessage,\n                originalAttestation,\n                _newMessageBody,\n                newDestinationCaller\n            );\n\n            emit DepositForBurn(\n                _originalMsg._nonce(),\n                Message.bytes32ToAddress(_burnToken),\n                _amount,\n                msg.sender,\n                newMintRecipient,\n                _originalMsg._destinationDomain(),\n                _originalMsg._recipient(),\n                newDestinationCaller\n            );\n        }\n\n        /**\n         * @notice Handles an incoming message received by the local MessageTransmitter,\n         * and takes the appropriate action. For a burn message, mints the\n         * associated token to the requested recipient on the local domain.\n         * @dev Validates the local sender is the local MessageTransmitter, and the\n         * remote sender is a registered remote TokenMessenger for `remoteDomain`.\n         * @param remoteDomain The domain where the message originated from.\n         * @param sender The sender of the message (remote TokenMessenger).\n         * @param messageBody The message body bytes.\n         * @return success Bool, true if successful.\n         */\n        function handleReceiveMessage(\n            uint32 remoteDomain,\n            bytes32 sender,\n            bytes calldata messageBody\n        )\n            external\n            override\n            onlyLocalMessageTransmitter\n            onlyRemoteTokenMessenger(remoteDomain, sender)\n            returns (bool)\n        {\n            bytes29 _msg = messageBody.ref(0);\n            _msg._validateBurnMessageFormat();\n            require(\n                _msg._getVersion() == messageBodyVersion,\n                \"Invalid message body version\"\n            );\n\n            bytes32 _mintRecipient = _msg._getMintRecipient();\n            bytes32 _burnToken = _msg._getBurnToken();\n            uint256 _amount = _msg._getAmount();\n\n            ITokenMinter _localMinter = _getLocalMinter();\n\n            _mintAndWithdraw(\n                address(_localMinter),\n                remoteDomain,\n                _burnToken,\n                Message.bytes32ToAddress(_mintRecipient),\n                _amount\n            );\n\n            return true;\n        }\n\n        /**\n         * @notice Add the TokenMessenger for a remote domain.\n         * @dev Reverts if there is already a TokenMessenger set for domain.\n         * @param domain Domain of remote TokenMessenger.\n         * @param tokenMessenger Address of remote TokenMessenger as bytes32.\n         */\n        function addRemoteTokenMessenger(uint32 domain, bytes32 tokenMessenger)\n            external\n            onlyOwner\n        {\n            require(tokenMessenger != bytes32(0), \"bytes32(0) not allowed\");\n\n            require(\n                remoteTokenMessengers[domain] == bytes32(0),\n                \"TokenMessenger already set\"\n            );\n\n            remoteTokenMessengers[domain] = tokenMessenger;\n            emit RemoteTokenMessengerAdded(domain, tokenMessenger);\n        }\n\n        /**\n         * @notice Remove the TokenMessenger for a remote domain.\n         * @dev Reverts if there is no TokenMessenger set for `domain`.\n         * @param domain Domain of remote TokenMessenger\n         */\n        function removeRemoteTokenMessenger(uint32 domain) external onlyOwner {\n            // No TokenMessenger set for given remote domain.\n            require(\n                remoteTokenMessengers[domain] != bytes32(0),\n                \"No TokenMessenger set\"\n            );\n\n            bytes32 _removedTokenMessenger = remoteTokenMessengers[domain];\n            delete remoteTokenMessengers[domain];\n            emit RemoteTokenMessengerRemoved(domain, _removedTokenMessenger);\n        }\n\n        /**\n         * @notice Add minter for the local domain.\n         * @dev Reverts if a minter is already set for the local domain.\n         * @param newLocalMinter The address of the minter on the local domain.\n         */\n        function addLocalMinter(address newLocalMinter) external onlyOwner {\n            require(newLocalMinter != address(0), \"Zero address not allowed\");\n\n            require(\n                address(localMinter) == address(0),\n                \"Local minter is already set.\"\n            );\n\n            localMinter = ITokenMinter(newLocalMinter);\n\n            emit LocalMinterAdded(newLocalMinter);\n        }\n\n        /**\n         * @notice Remove the minter for the local domain.\n         * @dev Reverts if the minter of the local domain is not set.\n         */\n        function removeLocalMinter() external onlyOwner {\n            address _localMinterAddress = address(localMinter);\n            require(_localMinterAddress != address(0), \"No local minter is set.\");\n\n            delete localMinter;\n            emit LocalMinterRemoved(_localMinterAddress);\n        }\n\n        // ============ Internal Utils ============\n        /**\n         * @notice Deposits and burns tokens from sender to be minted on destination domain.\n         * Emits a `DepositForBurn` event.\n         * @param _amount amount of tokens to burn (must be non-zero)\n         * @param _destinationDomain destination domain\n         * @param _mintRecipient address of mint recipient on destination domain\n         * @param _burnToken address of contract to burn deposited tokens, on local domain\n         * @param _destinationCaller caller on the destination domain, as bytes32\n         * @return nonce unique nonce reserved by message\n         */\n        function _depositForBurn(\n            uint256 _amount,\n            uint32 _destinationDomain,\n            bytes32 _mintRecipient,\n            address _burnToken,\n            bytes32 _destinationCaller\n        ) internal returns (uint64 nonce) {\n            require(_amount > 0, \"Amount must be nonzero\");\n            require(_mintRecipient != bytes32(0), \"Mint recipient must be nonzero\");\n\n            bytes32 _destinationTokenMessenger = _getRemoteTokenMessenger(\n                _destinationDomain\n            );\n\n            ITokenMinter _localMinter = _getLocalMinter();\n            IMintBurnToken _mintBurnToken = IMintBurnToken(_burnToken);\n            require(\n                _mintBurnToken.transferFrom(\n                    msg.sender,\n                    address(_localMinter),\n                    _amount\n                ),\n                \"Transfer operation failed\"\n            );\n            _localMinter.burn(_burnToken, _amount);\n\n            // Format message body\n            bytes memory _burnMessage = BurnMessage._formatMessage(\n                messageBodyVersion,\n                Message.addressToBytes32(_burnToken),\n                _mintRecipient,\n                _amount,\n                Message.addressToBytes32(msg.sender)\n            );\n\n            uint64 _nonceReserved = _sendDepositForBurnMessage(\n                _destinationDomain,\n                _destinationTokenMessenger,\n                _destinationCaller,\n                _burnMessage\n            );\n\n            emit DepositForBurn(\n                _nonceReserved,\n                _burnToken,\n                _amount,\n                msg.sender,\n                _mintRecipient,\n                _destinationDomain,\n                _destinationTokenMessenger,\n                _destinationCaller\n            );\n\n            return _nonceReserved;\n        }\n\n        /**\n         * @notice Sends a BurnMessage through the local message transmitter\n         * @dev calls local message transmitter's sendMessage() function if `_destinationCaller` == bytes32(0),\n         * or else calls sendMessageWithCaller().\n         * @param _destinationDomain destination domain\n         * @param _destinationTokenMessenger address of registered TokenMessenger contract on destination domain, as bytes32\n         * @param _destinationCaller caller on the destination domain, as bytes32. If `_destinationCaller` == bytes32(0),\n         * any address can call receiveMessage() on destination domain.\n         * @param _burnMessage formatted BurnMessage bytes (message body)\n         * @return nonce unique nonce reserved by message\n         */\n        function _sendDepositForBurnMessage(\n            uint32 _destinationDomain,\n            bytes32 _destinationTokenMessenger,\n            bytes32 _destinationCaller,\n            bytes memory _burnMessage\n        ) internal returns (uint64 nonce) {\n            if (_destinationCaller == bytes32(0)) {\n                return\n                    localMessageTransmitter.sendMessage(\n                        _destinationDomain,\n                        _destinationTokenMessenger,\n                        _burnMessage\n                    );\n            } else {\n                return\n                    localMessageTransmitter.sendMessageWithCaller(\n                        _destinationDomain,\n                        _destinationTokenMessenger,\n                        _destinationCaller,\n                        _burnMessage\n                    );\n            }\n        }\n\n        /**\n         * @notice Mints tokens to a recipient\n         * @param _tokenMinter address of TokenMinter contract\n         * @param _remoteDomain domain where burned tokens originate from\n         * @param _burnToken address of token burned\n         * @param _mintRecipient recipient address of minted tokens\n         * @param _amount amount of minted tokens\n         */\n        function _mintAndWithdraw(\n            address _tokenMinter,\n            uint32 _remoteDomain,\n            bytes32 _burnToken,\n            address _mintRecipient,\n            uint256 _amount\n        ) internal {\n            ITokenMinter _minter = ITokenMinter(_tokenMinter);\n            address _mintToken = _minter.mint(\n                _remoteDomain,\n                _burnToken,\n                _mintRecipient,\n                _amount\n            );\n\n            emit MintAndWithdraw(_mintRecipient, _amount, _mintToken);\n        }\n\n        /**\n         * @notice return the remote TokenMessenger for the given `_domain` if one exists, else revert.\n         * @param _domain The domain for which to get the remote TokenMessenger\n         * @return _tokenMessenger The address of the TokenMessenger on `_domain` as bytes32\n         */\n        function _getRemoteTokenMessenger(uint32 _domain)\n            internal\n            view\n            returns (bytes32)\n        {\n            bytes32 _tokenMessenger = remoteTokenMessengers[_domain];\n            require(_tokenMessenger != bytes32(0), \"No TokenMessenger for domain\");\n            return _tokenMessenger;\n        }\n\n        /**\n         * @notice return the local minter address if it is set, else revert.\n         * @return local minter as ITokenMinter.\n         */\n        function _getLocalMinter() internal view returns (ITokenMinter) {\n            require(address(localMinter) != address(0), \"Local minter is not set\");\n            return localMinter;\n        }\n\n        /**\n         * @notice Return true if the given remote domain and TokenMessenger is registered\n         * on this TokenMessenger.\n         * @param _domain The remote domain of the message.\n         * @param _tokenMessenger The address of the TokenMessenger on remote domain.\n         * @return true if a remote TokenMessenger is registered for `_domain` and `_tokenMessenger`,\n         * on this TokenMessenger.\n         */\n        function _isRemoteTokenMessenger(uint32 _domain, bytes32 _tokenMessenger)\n            internal\n            view\n            returns (bool)\n        {\n            return\n                _tokenMessenger != bytes32(0) &&\n                remoteTokenMessengers[_domain] == _tokenMessenger;\n        }\n\n        /**\n         * @notice Returns true if the message sender is the local registered MessageTransmitter\n         * @return true if message sender is the registered local message transmitter\n         */\n        function _isLocalMessageTransmitter() internal view returns (bool) {\n            return\n                address(localMessageTransmitter) != address(0) &&\n                msg.sender == address(localMessageTransmitter);\n        }\n    }\n    ```\n\n    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.\n\nThe functions provided by the Token Messenger contract are as follows:\n\n- **`depositForBurn`**: Deposits and burns tokens from the sender to be minted on the destination domain. Minted tokens will be transferred to `mintRecipient`.\n\n    ??? interface \"Parameters\"\n\n        `amount` ++\"uint256\"++\n        \n        The amount of tokens to burn.\n\n        ---\n\n        `destinationDomain` ++\"uint32\"++\n        \n        The network where the token will be minted after burn.\n\n        ---\n\n        `mintRecipient` ++\"bytes32\"++\n        \n        Address of mint recipient on destination domain.\n\n        ---\n\n        `burnToken` ++\"address\"++\n        \n        Address of contract to burn deposited tokens, on local domain.\n\n    ??? interface \"Returns\"\n\n        `_nonce` ++\"uint64\"++\n        \n        Unique nonce reserved by message.\n\n    ??? interface \"Emits\"\n\n        `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\n\n        ??? child \"Event Arguments\"\n\n            `nonce` ++\"uint64\"++ \n            \n            Unique nonce reserved by message (indexed).\n\n            ---\n\n            `burnToken` ++\"address\"++ \n            \n            Address of token burnt on source domain.\n\n            ---\n\n            `amount` ++\"uint256\"++\n            \n            The deposit amount.\n\n            ---\n\n            `depositor` ++\"address\"++\n            \n            Address where deposit is transferred from.\n\n            ---\n\n            `mintRecipient` ++\"bytes32\"++\n            \n            Address receiving minted tokens on destination domain.\n\n            ---\n\n            `destinationDomain` ++\"uint32\"++ -\n            \n            Destination domain.\n\n            ---\n\n            `destinationTokenMessenger` ++\"bytes32\"++\n            \n            Address of `TokenMessenger` on destination domain.\n            \n            ---\n\n            `destinationCaller` ++\"bytes32\"++\n            \n            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`.\n- **`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.\n\n    ??? interface \"Parameters\"\n\n        `amount` ++\"uint256\"++\n        \n        The amount of tokens to burn.\n\n        ---\n\n        `destinationDomain` ++\"uint32\"++\n        \n        The network where the token will be minted after burn.\n\n        ---\n\n        `mintRecipient` ++\"bytes32\"++\n        \n        Address of mint recipient on destination domain.\n\n        ---\n\n        `burnToken` ++\"address\"++\n        \n        Address of contract to burn deposited tokens, on local domain.\n\n        ---\n\n        `destinationCaller` ++\"bytes32\"++\n        \n        Address of the caller on the destination domain who will trigger the mint.\n\n    ??? interface \"Returns\"\n\n        `_nonce` ++\"uint64\"++\n        \n        Unique nonce reserved by message.\n\n    ??? interface \"Emits\"\n\n        `DepositForBurn` - event emitted when `depositForBurnWithCaller` is called\n\n        ??? child \"Event Arguments\"\n\n            `nonce` ++\"uint64\"++ \n            \n            Unique nonce reserved by message (indexed).\n\n            ---\n\n            `burnToken` ++\"address\"++ \n            \n            Address of token burnt on source domain.\n\n            ---\n\n            `amount` ++\"uint256\"++\n            \n            The deposit amount.\n\n            ---\n\n            `depositor` ++\"address\"++\n            \n            Address where deposit is transferred from.\n\n            ---\n\n            `mintRecipient` ++\"bytes32\"++\n            \n            Address receiving minted tokens on destination domain.\n\n            ---\n\n            `destinationDomain` ++\"uint32\"++ -\n            \n            Destination domain.\n\n            ---\n\n            `destinationTokenMessenger` ++\"bytes32\"++\n            \n            Address of `TokenMessenger` on destination domain.\n            \n            ---\n\n            `destinationCaller` ++\"bytes32\"++\n            \n            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`.\n- **`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.\n\n    ??? interface \"Parameters\"\n\n        `originalMessage` ++\"bytes\"++\n        \n        The original burn message to be replaced.\n\n        ---\n\n        `originalAttestation` ++\"bytes\"++\n        \n        The attestation of the original message.\n\n        ---\n\n        `newDestinationCaller` ++\"bytes32\"++\n        \n        The new caller on the destination domain, can be the same or updated.\n\n        ---\n\n        `newMintRecipient` ++\"bytes32\"++\n        \n        The new recipient for the minted tokens, can be the same or updated.\n\n    ??? interface \"Returns\"\n\n        None.\n\n    ??? interface \"Emits\"\n\n        `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\n\n        ??? child \"Event Arguments\"\n\n            `nonce` ++\"uint64\"++ \n            \n            Unique nonce reserved by message (indexed).\n\n            ---\n\n            `burnToken` ++\"address\"++ \n            \n            Address of token burnt on source domain.\n\n            ---\n\n            `amount` ++\"uint256\"++\n            \n            The deposit amount.\n\n            ---\n\n            `depositor` ++\"address\"++\n            \n            Address where deposit is transferred from.\n\n            ---\n\n            `mintRecipient` ++\"bytes32\"++\n            \n            Address receiving minted tokens on destination domain.\n\n            ---\n\n            `destinationDomain` ++\"uint32\"++ -\n            \n            Destination domain.\n\n            ---\n\n            `destinationTokenMessenger` ++\"bytes32\"++\n            \n            Address of `TokenMessenger` on destination domain.\n            \n            ---\n\n            `destinationCaller` ++\"bytes32\"++\n            \n            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`.\n- **`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.\n\n    ???+ note\n\n        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.\n\n    ??? interface \"Parameters\"\n\n        `remoteDomain` ++\"uint32\"++\n        \n        The domain where the message originated.\n\n        ---\n\n        `sender` ++\"bytes32\"++\n        \n        The address of the sender of the message.\n\n        ---\n\n        `messageBody` ++\"bytes\"++\n        \n        The bytes making up the body of the message.\n\n    ??? interface \"Returns\"\n\n        `success` ++\"boolean\"++\n        \n        Returns `true` if successful, otherwise, it returns `false`.\n\n    ??? interface \"Emits\"\n\n        `MintAndWithdraw` - event emitted when tokens are minted\n\n        ??? child \"Event arguments\"\n\n            `localMinter` ++\"address\"++\n            \n            Minter responsible for minting and burning tokens on the local domain.\n\n            ---\n\n            `remoteDomain` ++\"uint32\"++\n            \n            The domain where the message originated from.\n\n            ---\n\n            `burnToken` ++\"address\"++\n            \n            Address of contract to burn deposited tokens, on local domain.\n\n            ---\n\n            `mintRecipient` ++\"address\"++\n            \n            Recipient address of minted tokens (indexed).\n\n            ---\n\n            `amount` ++\"uint256\"++\n            \n            Amount of minted tokens."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 4, "depth": 3, "title": "Message Transmitter Contract", "anchor": "message-transmitter-contract", "start_char": 53821, "end_char": 74843, "estimated_token_count": 3438, "token_estimator": "heuristic-v1", "text": "### Message Transmitter Contract\n\nThe 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.\n\nThe 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.\n\nAdditional 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.\n\n??? code \"Message Transmitter contract\"\n    ```solidity\n    /*\n     * Copyright (c) 2022, Circle Internet Financial Limited.\n     *\n     * Licensed under the Apache License, Version 2.0 (the \"License\");\n     * you may not use this file except in compliance with the License.\n     * You may obtain a copy of the License at\n     *\n     * http://www.apache.org/licenses/LICENSE-2.0\n     *\n     * Unless required by applicable law or agreed to in writing, software\n     * distributed under the License is distributed on an \"AS IS\" BASIS,\n     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     * See the License for the specific language governing permissions and\n     * limitations under the License.\n     */\n    pragma solidity 0.7.6;\n\n    import \"@memview-sol/contracts/TypedMemView.sol\";\n    import \"./interfaces/IMessageTransmitter.sol\";\n    import \"./interfaces/IMessageHandler.sol\";\n    import \"./messages/Message.sol\";\n    import \"./roles/Pausable.sol\";\n    import \"./roles/Rescuable.sol\";\n    import \"./roles/Attestable.sol\";\n\n    /**\n     * @title MessageTransmitter\n     * @notice Contract responsible for sending and receiving messages across chains.\n     */\n    contract MessageTransmitter is\n        IMessageTransmitter,\n        Pausable,\n        Rescuable,\n        Attestable\n    {\n        // ============ Events ============\n        /**\n         * @notice Emitted when a new message is dispatched\n         * @param message Raw bytes of message\n         */\n        event MessageSent(bytes message);\n\n        /**\n         * @notice Emitted when a new message is received\n         * @param caller Caller (msg.sender) on destination domain\n         * @param sourceDomain The source domain this message originated from\n         * @param nonce The nonce unique to this message\n         * @param sender The sender of this message\n         * @param messageBody message body bytes\n         */\n        event MessageReceived(\n            address indexed caller,\n            uint32 sourceDomain,\n            uint64 indexed nonce,\n            bytes32 sender,\n            bytes messageBody\n        );\n\n        /**\n         * @notice Emitted when max message body size is updated\n         * @param newMaxMessageBodySize new maximum message body size, in bytes\n         */\n        event MaxMessageBodySizeUpdated(uint256 newMaxMessageBodySize);\n\n        // ============ Libraries ============\n        using TypedMemView for bytes;\n        using TypedMemView for bytes29;\n        using Message for bytes29;\n\n        // ============ State Variables ============\n        // Domain of chain on which the contract is deployed\n        uint32 public immutable localDomain;\n\n        // Message Format version\n        uint32 public immutable version;\n\n        // Maximum size of message body, in bytes.\n        // This value is set by owner.\n        uint256 public maxMessageBodySize;\n\n        // Next available nonce from this source domain\n        uint64 public nextAvailableNonce;\n\n        // Maps a bytes32 hash of (sourceDomain, nonce) -> uint256 (0 if unused, 1 if used)\n        mapping(bytes32 => uint256) public usedNonces;\n\n        // ============ Constructor ============\n        constructor(\n            uint32 _localDomain,\n            address _attester,\n            uint32 _maxMessageBodySize,\n            uint32 _version\n        ) Attestable(_attester) {\n            localDomain = _localDomain;\n            maxMessageBodySize = _maxMessageBodySize;\n            version = _version;\n        }\n\n        // ============ External Functions  ============\n        /**\n         * @notice Send the message to the destination domain and recipient\n         * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n         * @param destinationDomain Domain of destination chain\n         * @param recipient Address of message recipient on destination chain as bytes32\n         * @param messageBody Raw bytes content of message\n         * @return nonce reserved by message\n         */\n        function sendMessage(\n            uint32 destinationDomain,\n            bytes32 recipient,\n            bytes calldata messageBody\n        ) external override whenNotPaused returns (uint64) {\n            bytes32 _emptyDestinationCaller = bytes32(0);\n            uint64 _nonce = _reserveAndIncrementNonce();\n            bytes32 _messageSender = Message.addressToBytes32(msg.sender);\n\n            _sendMessage(\n                destinationDomain,\n                recipient,\n                _emptyDestinationCaller,\n                _messageSender,\n                _nonce,\n                messageBody\n            );\n\n            return _nonce;\n        }\n\n        /**\n         * @notice Replace a message with a new message body and/or destination caller.\n         * @dev The `originalAttestation` must be a valid attestation of `originalMessage`.\n         * Reverts if msg.sender does not match sender of original message, or if the source domain of the original message\n         * does not match this MessageTransmitter's local domain.\n         * @param originalMessage original message to replace\n         * @param originalAttestation attestation of `originalMessage`\n         * @param newMessageBody new message body of replaced message\n         * @param newDestinationCaller the new destination caller, which may be the\n         * same as the original destination caller, a new destination caller, or an empty\n         * destination caller (bytes32(0), indicating that any destination caller is valid.)\n         */\n        function replaceMessage(\n            bytes calldata originalMessage,\n            bytes calldata originalAttestation,\n            bytes calldata newMessageBody,\n            bytes32 newDestinationCaller\n        ) external override whenNotPaused {\n            // Validate each signature in the attestation\n            _verifyAttestationSignatures(originalMessage, originalAttestation);\n\n            bytes29 _originalMsg = originalMessage.ref(0);\n\n            // Validate message format\n            _originalMsg._validateMessageFormat();\n\n            // Validate message sender\n            bytes32 _sender = _originalMsg._sender();\n            require(\n                msg.sender == Message.bytes32ToAddress(_sender),\n                \"Sender not permitted to use nonce\"\n            );\n\n            // Validate source domain\n            uint32 _sourceDomain = _originalMsg._sourceDomain();\n            require(\n                _sourceDomain == localDomain,\n                \"Message not originally sent from this domain\"\n            );\n\n            uint32 _destinationDomain = _originalMsg._destinationDomain();\n            bytes32 _recipient = _originalMsg._recipient();\n            uint64 _nonce = _originalMsg._nonce();\n\n            _sendMessage(\n                _destinationDomain,\n                _recipient,\n                newDestinationCaller,\n                _sender,\n                _nonce,\n                newMessageBody\n            );\n        }\n\n        /**\n         * @notice Send the message to the destination domain and recipient, for a specified `destinationCaller` on the\n         * destination domain.\n         * @dev Increment nonce, format the message, and emit `MessageSent` event with message information.\n         * WARNING: if the `destinationCaller` does not represent a valid address, then it will not be possible\n         * to broadcast the message on the destination domain. This is an advanced feature, and the standard\n         * sendMessage() should be preferred for use cases where a specific destination caller is not required.\n         * @param destinationDomain Domain of destination chain\n         * @param recipient Address of message recipient on destination domain as bytes32\n         * @param destinationCaller caller on the destination domain, as bytes32\n         * @param messageBody Raw bytes content of message\n         * @return nonce reserved by message\n         */\n        function sendMessageWithCaller(\n            uint32 destinationDomain,\n            bytes32 recipient,\n            bytes32 destinationCaller,\n            bytes calldata messageBody\n        ) external override whenNotPaused returns (uint64) {\n            require(\n                destinationCaller != bytes32(0),\n                \"Destination caller must be nonzero\"\n            );\n\n            uint64 _nonce = _reserveAndIncrementNonce();\n            bytes32 _messageSender = Message.addressToBytes32(msg.sender);\n\n            _sendMessage(\n                destinationDomain,\n                recipient,\n                destinationCaller,\n                _messageSender,\n                _nonce,\n                messageBody\n            );\n\n            return _nonce;\n        }\n\n        /**\n         * @notice Receive a message. Messages with a given nonce\n         * can only be broadcast once for a (sourceDomain, destinationDomain)\n         * pair. The message body of a valid message is passed to the\n         * specified recipient for further processing.\n         *\n         * @dev Attestation format:\n         * A valid attestation is the concatenated 65-byte signature(s) of exactly\n         * `thresholdSignature` signatures, in increasing order of attester address.\n         * ***If the attester addresses recovered from signatures are not in\n         * increasing order, signature verification will fail.***\n         * If incorrect number of signatures or duplicate signatures are supplied,\n         * signature verification will fail.\n         *\n         * Message format:\n         * Field                 Bytes      Type       Index\n         * version               4          uint32     0\n         * sourceDomain          4          uint32     4\n         * destinationDomain     4          uint32     8\n         * nonce                 8          uint64     12\n         * sender                32         bytes32    20\n         * recipient             32         bytes32    52\n         * messageBody           dynamic    bytes      84\n         * @param message Message bytes\n         * @param attestation Concatenated 65-byte signature(s) of `message`, in increasing order\n         * of the attester address recovered from signatures.\n         * @return success bool, true if successful\n         */\n        function receiveMessage(bytes calldata message, bytes calldata attestation)\n            external\n            override\n            whenNotPaused\n            returns (bool success)\n        {\n            // Validate each signature in the attestation\n            _verifyAttestationSignatures(message, attestation);\n\n            bytes29 _msg = message.ref(0);\n\n            // Validate message format\n            _msg._validateMessageFormat();\n\n            // Validate domain\n            require(\n                _msg._destinationDomain() == localDomain,\n                \"Invalid destination domain\"\n            );\n\n            // Validate destination caller\n            if (_msg._destinationCaller() != bytes32(0)) {\n                require(\n                    _msg._destinationCaller() ==\n                        Message.addressToBytes32(msg.sender),\n                    \"Invalid caller for message\"\n                );\n            }\n\n            // Validate version\n            require(_msg._version() == version, \"Invalid message version\");\n\n            // Validate nonce is available\n            uint32 _sourceDomain = _msg._sourceDomain();\n            uint64 _nonce = _msg._nonce();\n            bytes32 _sourceAndNonce = _hashSourceAndNonce(_sourceDomain, _nonce);\n            require(usedNonces[_sourceAndNonce] == 0, \"Nonce already used\");\n            // Mark nonce used\n            usedNonces[_sourceAndNonce] = 1;\n\n            // Handle receive message\n            bytes32 _sender = _msg._sender();\n            bytes memory _messageBody = _msg._messageBody().clone();\n            require(\n                IMessageHandler(Message.bytes32ToAddress(_msg._recipient()))\n                    .handleReceiveMessage(_sourceDomain, _sender, _messageBody),\n                \"handleReceiveMessage() failed\"\n            );\n\n            // Emit MessageReceived event\n            emit MessageReceived(\n                msg.sender,\n                _sourceDomain,\n                _nonce,\n                _sender,\n                _messageBody\n            );\n            return true;\n        }\n\n        /**\n         * @notice Sets the max message body size\n         * @dev This value should not be reduced without good reason,\n         * to avoid impacting users who rely on large messages.\n         * @param newMaxMessageBodySize new max message body size, in bytes\n         */\n        function setMaxMessageBodySize(uint256 newMaxMessageBodySize)\n            external\n            onlyOwner\n        {\n            maxMessageBodySize = newMaxMessageBodySize;\n            emit MaxMessageBodySizeUpdated(maxMessageBodySize);\n        }\n\n        // ============ Internal Utils ============\n        /**\n         * @notice Send the message to the destination domain and recipient. If `_destinationCaller` is not equal to bytes32(0),\n         * the message can only be received on the destination chain when called by `_destinationCaller`.\n         * @dev Format the message and emit `MessageSent` event with message information.\n         * @param _destinationDomain Domain of destination chain\n         * @param _recipient Address of message recipient on destination domain as bytes32\n         * @param _destinationCaller caller on the destination domain, as bytes32\n         * @param _sender message sender, as bytes32\n         * @param _nonce nonce reserved for message\n         * @param _messageBody Raw bytes content of message\n         */\n        function _sendMessage(\n            uint32 _destinationDomain,\n            bytes32 _recipient,\n            bytes32 _destinationCaller,\n            bytes32 _sender,\n            uint64 _nonce,\n            bytes calldata _messageBody\n        ) internal {\n            // Validate message body length\n            require(\n                _messageBody.length <= maxMessageBodySize,\n                \"Message body exceeds max size\"\n            );\n\n            require(_recipient != bytes32(0), \"Recipient must be nonzero\");\n\n            // serialize message\n            bytes memory _message = Message._formatMessage(\n                version,\n                localDomain,\n                _destinationDomain,\n                _nonce,\n                _sender,\n                _recipient,\n                _destinationCaller,\n                _messageBody\n            );\n\n            // Emit MessageSent event\n            emit MessageSent(_message);\n        }\n\n        /**\n         * @notice hashes `_source` and `_nonce`.\n         * @param _source Domain of chain where the transfer originated\n         * @param _nonce The unique identifier for the message from source to\n                  destination\n         * @return hash of source and nonce\n         */\n        function _hashSourceAndNonce(uint32 _source, uint64 _nonce)\n            internal\n            pure\n            returns (bytes32)\n        {\n            return keccak256(abi.encodePacked(_source, _nonce));\n        }\n\n        /**\n         * Reserve and increment next available nonce\n         * @return nonce reserved\n         */\n        function _reserveAndIncrementNonce() internal returns (uint64) {\n            uint64 _nonceReserved = nextAvailableNonce;\n            nextAvailableNonce = nextAvailableNonce + 1;\n            return _nonceReserved;\n        }\n    }\n    ```\n\n    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.\n\nThe functions provided by the Message Transmitter contract are as follows:\n\n- **`receiveMessage`**: Processes and validates an incoming message and its attestation. If valid, it triggers further action based on the message body.\n\n    ??? interface \"Parameters\"\n\n        `message` ++\"bytes\"++\n        \n        The message to be processed, including details such as sender, recipient, and message body.\n\n        --- \n\n        `attestation` ++\"bytes\"++\n        \n        Concatenated 65-byte signature(s) that attest to the validity of the `message`.\n\n    ??? interface \"Returns\"\n\n        `success` ++\"boolean\"++\n        \n        Returns `true` if successful, otherwise, returns `false`.\n\n    ??? interface \"Emits\"\n\n        `MessageReceived` - event emitted when a new message is received\n\n        ??? child \"Event arguments\"\n\n            `caller` ++\"address\"++\n            \n            Caller on destination domain.\n\n            ---\n\n            `sourceDomain` ++\"uint32\"++\n            \n            The source domain this message originated from.\n\n            ---\n\n            `nonce` ++\"uint64\"++\n            \n            Nonce unique to this message (indexed).\n\n            ---\n\n            `sender` ++\"bytes32\"++\n            \n            Sender of this message.\n\n            ---\n\n            `messageBody` ++\"bytes\"++\n            \n            The body of the message.\n\n- **`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.\n\n    ??? interface \"Parameters\"\n\n        `destinationDomain` ++\"uint32\"++\n        \n        The target blockchain network where the message is to be sent.\n\n        ---\n\n        `recipient` ++\"bytes32\"++\n        \n        The recipient's address on the destination domain.\n\n        ---\n\n        `messageBody` ++\"bytes\"++\n        \n        The raw bytes content of the message.\n\n    ??? interface \"Returns\"\n\n        `nonce` ++\"uint64\"++\n        \n        Nonce unique to this message.\n\n    ??? interface \"Emits\"\n\n        `MessageSent` - event emitted when a new message is dispatched\n\n        ??? child \"Event arguments\"\n\n            `message` ++\"bytes\"++\n            \n            The raw bytes of the message.\n- **`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.\n\n    ??? interface \"Parameters\"\n\n        `destinationDomain` ++\"uint32\"++\n        \n        The target blockchain network where the message is to be sent.\n\n        ---\n\n        `recipient` ++\"bytes32\"++\n        \n        The recipient's address on the destination domain.\n\n        ---\n\n        `destinationCaller` ++\"bytes32\"++ \n        \n        The caller on the destination domain.\n\n        ---\n\n        `messageBody` ++\"bytes\"++\n        \n        The raw bytes content of the message.\n\n    ??? interface \"Returns\"\n\n        `nonce` ++\"uint64\"++\n        \n        Nonce unique to this message.\n\n    ??? interface \"Emits\"\n\n        `MessageSent` - event emitted when a new message is dispatched\n\n        ??? child \"Event arguments\"\n\n            `message` ++\"bytes\"++\n            \n            The raw bytes of the message.\n- **`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.\n\n    ??? interface \"Parameters\"\n\n        `originalMessage` ++\"bytes\"++\n        \n        The original message to be replaced.\n\n        ---\n\n        `originalAttestation` ++\"bytes\"++\n        \n        Attestation verifying the original message.\n\n        ---\n\n        `newMessageBody` ++\"bytes\"++\n        \n        The new content for the replaced message.\n\n        ---\n\n        `newDestinationCaller` ++\"bytes32\"++\n        \n        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.\n\n    ??? interface \"Returns\"\n\n        None.\n\n    ??? interface \"Emits\"\n\n        `MessageSent` - event emitted when a new message is dispatched\n\n        ??? child \"Event arguments\"\n\n            `message` ++\"bytes\"++\n            \n            The raw bytes of the message."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 5, "depth": 3, "title": "Token Minter Contract", "anchor": "token-minter-contract", "start_char": 74843, "end_char": 84639, "estimated_token_count": 1713, "token_estimator": "heuristic-v1", "text": "### Token Minter Contract\n\nThe 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.\n\nThe 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.\n\nTo 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.\n\n??? code \"Token Minter contract\"\n    ```solidity\n    /*\n     * Copyright (c) 2022, Circle Internet Financial Limited.\n     *\n     * Licensed under the Apache License, Version 2.0 (the \"License\");\n     * you may not use this file except in compliance with the License.\n     * You may obtain a copy of the License at\n     *\n     * http://www.apache.org/licenses/LICENSE-2.0\n     *\n     * Unless required by applicable law or agreed to in writing, software\n     * distributed under the License is distributed on an \"AS IS\" BASIS,\n     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     * See the License for the specific language governing permissions and\n     * limitations under the License.\n     */\n    pragma solidity 0.7.6;\n\n    import \"./interfaces/ITokenMinter.sol\";\n    import \"./interfaces/IMintBurnToken.sol\";\n    import \"./roles/Pausable.sol\";\n    import \"./roles/Rescuable.sol\";\n    import \"./roles/TokenController.sol\";\n    import \"./TokenMessenger.sol\";\n\n    /**\n     * @title TokenMinter\n     * @notice Token Minter and Burner\n     * @dev Maintains registry of local mintable tokens and corresponding tokens on remote domains.\n     * This registry can be used by caller to determine which token on local domain to mint for a\n     * burned token on a remote domain, and vice versa.\n     * It is assumed that local and remote tokens are fungible at a constant 1:1 exchange rate.\n     */\n    contract TokenMinter is ITokenMinter, TokenController, Pausable, Rescuable {\n        // ============ Events ============\n        /**\n         * @notice Emitted when a local TokenMessenger is added\n         * @param localTokenMessenger address of local TokenMessenger\n         * @notice Emitted when a local TokenMessenger is added\n         */\n        event LocalTokenMessengerAdded(address localTokenMessenger);\n\n        /**\n         * @notice Emitted when a local TokenMessenger is removed\n         * @param localTokenMessenger address of local TokenMessenger\n         * @notice Emitted when a local TokenMessenger is removed\n         */\n        event LocalTokenMessengerRemoved(address localTokenMessenger);\n\n        // ============ State Variables ============\n        // Local TokenMessenger with permission to call mint and burn on this TokenMinter\n        address public localTokenMessenger;\n\n        // ============ Modifiers ============\n        /**\n         * @notice Only accept messages from the registered message transmitter on local domain\n         */\n        modifier onlyLocalTokenMessenger() {\n            require(_isLocalTokenMessenger(), \"Caller not local TokenMessenger\");\n            _;\n        }\n\n        // ============ Constructor ============\n        /**\n         * @param _tokenController Token controller address\n         */\n        constructor(address _tokenController) {\n            _setTokenController(_tokenController);\n        }\n\n        // ============ External Functions  ============\n        /**\n         * @notice Mints `amount` of local tokens corresponding to the\n         * given (`sourceDomain`, `burnToken`) pair, to `to` address.\n         * @dev reverts if the (`sourceDomain`, `burnToken`) pair does not\n         * map to a nonzero local token address. This mapping can be queried using\n         * getLocalToken().\n         * @param sourceDomain Source domain where `burnToken` was burned.\n         * @param burnToken Burned token address as bytes32.\n         * @param to Address to receive minted tokens, corresponding to `burnToken`,\n         * on this domain.\n         * @param amount Amount of tokens to mint. Must be less than or equal\n         * to the minterAllowance of this TokenMinter for given `_mintToken`.\n         * @return mintToken token minted.\n         */\n        function mint(\n            uint32 sourceDomain,\n            bytes32 burnToken,\n            address to,\n            uint256 amount\n        )\n            external\n            override\n            whenNotPaused\n            onlyLocalTokenMessenger\n            returns (address mintToken)\n        {\n            address _mintToken = _getLocalToken(sourceDomain, burnToken);\n            require(_mintToken != address(0), \"Mint token not supported\");\n            IMintBurnToken _token = IMintBurnToken(_mintToken);\n\n            require(_token.mint(to, amount), \"Mint operation failed\");\n            return _mintToken;\n        }\n\n        /**\n         * @notice Burn tokens owned by this TokenMinter.\n         * @param burnToken burnable token address.\n         * @param burnAmount amount of tokens to burn. Must be\n         * > 0, and <= maximum burn amount per message.\n         */\n        function burn(address burnToken, uint256 burnAmount)\n            external\n            override\n            whenNotPaused\n            onlyLocalTokenMessenger\n            onlyWithinBurnLimit(burnToken, burnAmount)\n        {\n            IMintBurnToken _token = IMintBurnToken(burnToken);\n            _token.burn(burnAmount);\n        }\n\n        /**\n         * @notice Add TokenMessenger for the local domain. Only this TokenMessenger\n         * has permission to call mint() and burn() on this TokenMinter.\n         * @dev Reverts if a TokenMessenger is already set for the local domain.\n         * @param newLocalTokenMessenger The address of the new TokenMessenger on the local domain.\n         */\n        function addLocalTokenMessenger(address newLocalTokenMessenger)\n            external\n            onlyOwner\n        {\n            require(\n                newLocalTokenMessenger != address(0),\n                \"Invalid TokenMessenger address\"\n            );\n\n            require(\n                localTokenMessenger == address(0),\n                \"Local TokenMessenger already set\"\n            );\n\n            localTokenMessenger = newLocalTokenMessenger;\n\n            emit LocalTokenMessengerAdded(localTokenMessenger);\n        }\n\n        /**\n         * @notice Remove the TokenMessenger for the local domain.\n         * @dev Reverts if the TokenMessenger of the local domain is not set.\n         */\n        function removeLocalTokenMessenger() external onlyOwner {\n            address _localTokenMessengerBeforeRemoval = localTokenMessenger;\n            require(\n                _localTokenMessengerBeforeRemoval != address(0),\n                \"No local TokenMessenger is set\"\n            );\n\n            delete localTokenMessenger;\n            emit LocalTokenMessengerRemoved(_localTokenMessengerBeforeRemoval);\n        }\n\n        /**\n         * @notice Set tokenController to `newTokenController`, and\n         * emit `SetTokenController` event.\n         * @dev newTokenController must be nonzero.\n         * @param newTokenController address of new token controller\n         */\n        function setTokenController(address newTokenController)\n            external\n            override\n            onlyOwner\n        {\n            _setTokenController(newTokenController);\n        }\n\n        /**\n         * @notice Get the local token address associated with the given\n         * remote domain and token.\n         * @param remoteDomain Remote domain\n         * @param remoteToken Remote token\n         * @return local token address\n         */\n        function getLocalToken(uint32 remoteDomain, bytes32 remoteToken)\n            external\n            view\n            override\n            returns (address)\n        {\n            return _getLocalToken(remoteDomain, remoteToken);\n        }\n\n        // ============ Internal Utils ============\n        /**\n         * @notice Returns true if the message sender is the registered local TokenMessenger\n         * @return True if the message sender is the registered local TokenMessenger\n         */\n        function _isLocalTokenMessenger() internal view returns (bool) {\n            return\n                address(localTokenMessenger) != address(0) &&\n                msg.sender == address(localTokenMessenger);\n        }\n    }\n    ```\n\n    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.\n\nMost 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.\n\n- **`getLocalToken`**: A read-only function that returns the local token address associated with a given remote domain and token.\n\n    ??? interface \"Parameters\"\n\n        `remoteDomain` ++\"uint32\"++\n        \n        The remote blockchain domain where the token resides.\n\n        ---\n\n        `remoteToken` ++\"bytes32\"++\n        \n        The address of the token on the remote domain.\n\n    ??? interface \"Returns\"\n\n        ++\"address\"++\n        \n        The local token address."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 6, "depth": 2, "title": "CCTP Transfers with Executor", "anchor": "cctp-transfers-with-executor", "start_char": 84639, "end_char": 85556, "estimated_token_count": 151, "token_estimator": "heuristic-v1", "text": "## CCTP Transfers with Executor\n\nThis section describes how the Circle Integration contract is used in practice when executing CCTP transfers through the Executor.\n\nTo initiate a cross-chain USDC transfer using Wormhole’s CCTP integration, applications interact directly with the Circle Integration contract on the source chain. \n\nThe primary entry point is `CircleIntegration.transferTokensWithPayload`. This function burns USDC on the source chain using Circle’s CCTP contracts and emits a Wormhole message containing an application-defined payload. This message serves as the input for Executor-based completion of the transfer.\n\nUnder the Executor framework, on-chain contracts are only responsible for initiating the transfer. A relay provider completes the transfer by retrieving the Circle attestation and submitting the destination transactions required to redeem USDC and execute any payload-defined logic."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 7, "depth": 3, "title": "On-Chain Transfer Initiation", "anchor": "on-chain-transfer-initiation", "start_char": 85556, "end_char": 89483, "estimated_token_count": 599, "token_estimator": "heuristic-v1", "text": "### On-Chain Transfer Initiation\n\nWhen initiating a transfer, a source-chain contract typically performs the following steps:\n\n- Approves the Circle Integration contract to spend USDC\n- Calls `transferTokensWithPayload`, specifying:\n    - The USDC amount to burn.\n    - The target Wormhole chain ID.\n    - The mint recipient on the destination chain.\n    - An application-defined payload.\n\n??? code \"transferTokensWithPayload\"\n\n    ```solidity\n        /**\n         * @notice `transferTokensWithPayload` calls the Circle Bridge contract to burn Circle-supported tokens. It emits\n         * a Wormhole message containing a user-specified payload with instructions for what to do with\n         * the Circle-supported assets once they have been minted on the target chain.\n         * @dev reverts if:\n         * - user passes insufficient value to pay Wormhole message fee\n         * - `token` is not supported by Circle Bridge\n         * - `amount` is zero\n         * - `targetChain` is not supported\n         * - `mintRecipient` is bytes32(0)\n         * @param transferParams Struct containing the following attributes:\n         * - `token` Address of the token to be burned\n         * - `amount` Amount of `token` to be burned\n         * - `targetChain` Wormhole chain ID of the target blockchain\n         * - `mintRecipient` The recipient wallet or contract address on the target chain\n         * @param batchId ID for Wormhole message batching\n         * @param payload Arbitrary payload to be delivered to the target chain via Wormhole\n         * @return messageSequence Wormhole sequence number for this contract\n         */\n        function transferTokensWithPayload(\n            TransferParameters memory transferParams,\n            uint32 batchId,\n            bytes memory payload\n        ) public payable nonReentrant returns (uint64 messageSequence) {\n            // cache wormhole instance and fees to save on gas\n            IWormhole wormhole = wormhole();\n            uint256 wormholeFee = wormhole.messageFee();\n\n            // confirm that the caller has sent enough ether to pay for the wormhole message fee\n            require(msg.value == wormholeFee, \"insufficient value\");\n\n            // Call the circle bridge and `depositForBurnWithCaller`. The `mintRecipient`\n            // should be the target contract (or wallet) composing on this contract.\n            (uint64 nonce, uint256 amountReceived) = _transferTokens{value: wormholeFee}(\n                transferParams.token,\n                transferParams.amount,\n                transferParams.targetChain,\n                transferParams.mintRecipient\n            );\n\n            // encode DepositWithPayload message\n            bytes memory encodedMessage = encodeDepositWithPayload(\n                DepositWithPayload({\n                    token: addressToBytes32(transferParams.token),\n                    amount: amountReceived,\n                    sourceDomain: localDomain(),\n                    targetDomain: getDomainFromChainId(transferParams.targetChain),\n                    nonce: nonce,\n                    fromAddress: addressToBytes32(msg.sender),\n                    mintRecipient: transferParams.mintRecipient,\n                    payload: payload\n                })\n            );\n\n            // send the DepositWithPayload wormhole message\n            messageSequence = wormhole.publishMessage{value: wormholeFee}(\n                batchId,\n                encodedMessage,\n                wormholeFinality()\n            );\n        }\n    ```\n\nCalling `transferTokensWithPayload` performs the following on-chain actions:\n\n- USDC is burned on the source chain via Circle’s Token Messenger and Token Minter contracts\n- A Wormhole message is emitted by the Circle Integration contract, encoding:\n    - Transfer metadata.\n    - The application payload.\n\nThe function returns a Wormhole sequence number that uniquely identifies the transfer."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 8, "depth": 3, "title": "Execution and Delivery via Executor", "anchor": "execution-and-delivery-via-executor", "start_char": 89483, "end_char": 90368, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "### Execution and Delivery via Executor\n\nOnce the transfer is initiated on-chain, completion is handled through the Executor:\n\n1. An off-chain client observes the emitted Wormhole message and requests execution through the CCTP Executor route (via the TypeScript SDK).\n2. A relay provider:\n    - Retrieves the Circle message and attestation.\n    - Submits the redemption transaction on the destination chain.\n    - Invokes any destination logic associated with the payload.\n\nThis flow applies to both CCTP v1 and CCTP v2. The version used depends on the source and destination chain configurations and the selected executor route, but the on-chain initiation via `transferTokensWithPayload` remains the same.\n\nFrom the perspective of a smart contract integrating with CCTP, initiating the transfer is sufficient. The Executor framework and relay providers handle the remaining steps."}
{"page_id": "products-cctp-bridge-guides-cctp-contracts", "page_title": "Interacting with CCTP Contracts", "index": 9, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 90368, "end_char": 91501, "estimated_token_count": 282, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow that you've learned how to interact directly with Circle's CCTP Bridge contracts, you're ready to explore more advanced features and expand your integration.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **CCTP Executor Guide**\n\n    ---\n\n    A walkthrough for executing CCTP transfers using the Executor, covering quoting, execution, and status tracking.\n\n    [:custom-arrow: Read the guide](/docs/protocol/infrastructure-guides/cctp-executor/){target=\\_blank}\n\n-   :octicons-repo-16:{ .lg .middle } **Demo CCTP Transfer Repository**\n\n    ---\n\n    A demo showcasing CCTP transfers using the Executor, intended as a practical reference for local testing and experimentation.\n\n    [:custom-arrow: View the repository](https://github.com/wormhole-foundation/demo-cctp-transfer){target=\\_blank}\n\n-   :octicons-repo-16:{ .lg .middle } **Hello USDC (Legacy Example)**\n\n    ---\n\n    A legacy, contract-based example demonstrating how to integrate with Wormhole’s CCTP contracts.\n\n    [:custom-arrow: Explore on GitHub](https://github.com/wormhole-foundation/hello-usdc){target=\\_blank}\n\n</div>"}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 509, "end_char": 1646, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **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.\n- **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.\n- **Automated relaying**: Eliminates the need for users to redeem USDC transfers themselves.\n- **Enhanced composability**: Developers can build more sophisticated cross-chain applications by sending additional data alongside the transfer.\n- **Gas drop off**: Enables users to convert a portion of USDC into the destination chain's gas token upon a successful transfer.\n- **Gas payment**: Covering destination gas in automated vs. manual transfers.\n    - **Automated**: Users often don't need destination gas tokens upfront, relayers cover these gas costs, reimbursed via gas drop-off or initial fees.\n    - **Manual**: Users pay destination gas directly, the protocol may offer post-claim USDC-to-gas conversion."}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 1646, "end_char": 3984, "estimated_token_count": 493, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nThis 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.\n\n1. **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.\n\n2. **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.\n\n3. **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}.\n\n4. **A relayer automatically processes the messages**: Once the VAA and Circle attestation are available, a relayer submits them to the Circle Bridge on Avalanche.\n\n5. **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.\n\n```mermaid\nsequenceDiagram\n    participant User as Alice\n    participant SourceChain as Circle Bridge<br>on Ethereum\n    participant Circle\n    participant Guardians as Wormhole Guardians\n    participant Relayer\n    participant DestinationChain as Circle Bridge<br>on Avalanche\n\n    User->>SourceChain: Submit transfer <br>(100 USDC to Avalanche)\n    SourceChain->>Circle: Initiate a burn\n    Circle->>Circle: Burn USDC and provide attestation\n    SourceChain->>Guardians: Emit Wormhole message (transfer metadata)\n    Guardians->>Guardians: Sign message and produce VAA\n    Relayer->>Guardians: Fetch signed VAA\n    Relayer->>Circle: Fetch Circle burn attestation\n    Relayer->>DestinationChain: Submit VAA and<br> attestation\n    DestinationChain->>Circle: Verify Circle attestation\n    Circle->>User: Mint USDC to Alice\n```\n\n!!! note \n    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/cctp/cctp-supported-blockchains#cctp-domains){target=\\_blank}."}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 2, "depth": 2, "title": "CCTP vs Wrapped Token Transfers (WTT)", "anchor": "cctp-vs-wrapped-token-transfers-wtt", "start_char": 3984, "end_char": 5400, "estimated_token_count": 352, "token_estimator": "heuristic-v1", "text": "## CCTP vs Wrapped Token Transfers (WTT)\n\n| Feature               | CCTP (native USDC)                                                | WTT (wrapped tokens)                                                        |\n|-----------------------|-------------------------------------------------------------------|-----------------------------------------------------------------------------|\n| Supported assets      | Circle-issued USDC                                                | Standards-compliant tokens (e.g., ERC-20, SPL)                              |\n| Mechanism             | Burn on source, mint on destination                               | Lock on source, mint wrapped on destination                                 |\n| Result on destination | Native USDC                                                       | Wormhole-wrapped token                                                      |\n| Payload               | Optional transfer with payload; executed on the destination when USDC is minted | Optional transfer with payload; executed by the recipient contract during redemption |\n| Use it for            | Native USDC between CCTP-enabled chains                           | Non-USDC assets, or USDC when CCTP isn't supported on the destination       |\n\nCheck the [CCTP Supported Networks](/docs/products/cctp-bridge/reference/supported-networks/){target=\\_blank} to see which routes are available."}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 3, "depth": 2, "title": "When to Use CCTP", "anchor": "when-to-use-cctp", "start_char": 5400, "end_char": 6175, "estimated_token_count": 190, "token_estimator": "heuristic-v1", "text": "## When to Use CCTP\n\nCCTP is the right choice in the following situations:\n\n- **Sending USDC between [CCTP-enabled chains](/docs/products/cctp-bridge/reference/supported-networks/){target=\\_blank}**: This route appears only if both chains support Circle CCTP and the asset is native USDC.\n- **Sending USDC with an attached payload**: The destination contract can execute logic as the tokens are minted on the target chain.\n\nFor other transfers, consider these options:\n\n- **Data-only transfers without moving USDC**: Use [Messaging](/docs/products/messaging/overview/){target=\\_blank}.\n- **Destinations without CCTP support**: The transfer routes via [WTT](/docs/products/token-bridge/overview/){target=\\_blank}, with the option to include a payload executed on redemption."}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 4, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 6175, "end_char": 6739, "estimated_token_count": 141, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\nIntegrating Wormhole's messaging with CCTP enables the secure transfer of native USDC across blockchains, unlocking key cross-chain use cases, which include:\n\n- **USDC Payments Across Chains**\n    - **[CCTP](/docs/products/cctp-bridge/get-started/)**: Transfer native USDC using Circle's burn-and-mint protocol.\n    - **[Wormhole TypeScript SDK](/docs/tools/typescript-sdk/sdk-reference/)**: Automate attestation delivery and gas handling.\n    - **[Connect](/docs/products/connect/overview/)**: Embed multichain USDC transfers directly in your app."}
{"page_id": "products-cctp-bridge-overview", "page_title": "CCTP Bridge with Wormhole", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 6739, "end_char": 7737, "estimated_token_count": 259, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow that you're familiar with CCTP, here is a list of resources for more hands-on practice.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with the CCTP Bridge**\n\n    ---\n\n    Perform a multichain USDC transfer from Avalanche to Sepolia using Wormhole's TypeScript SDK and Circle's CCTP.\n\n    [:custom-arrow: Get Started](/docs/products/cctp-bridge/get-started/)\n\n-   :octicons-tools-16:{ .lg .middle } **Complete USDC Transfer Flow**\n\n    ---\n\n    Execute a USDC cross-chain transfer using Wormhole SDK and Circle's CCTP, covering manual, automatic, and partial transfer recovery.\n\n    [:custom-arrow: Get Started](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/)\n\n-   :octicons-book-16:{ .lg .middle } **Circle CCTP Documentation**\n\n    ---\n\n    Learn how USDC cross-chain transfers work and explore advanced CCTP features.\n\n    [:custom-arrow: See the Circle Docs](https://developers.circle.com/cctp){target=\\_blank}\n\n</div>"}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 0, "depth": 2, "title": "Core Concepts", "anchor": "core-concepts", "start_char": 1480, "end_char": 2186, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "## Core Concepts\n\nWhen 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:\n\n - **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.\n\n - **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."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 2186, "end_char": 2709, "estimated_token_count": 141, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n - [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally.\n - [USDC tokens](https://faucet.circle.com/){target=\\_blank} on supported chains. This tutorial uses Avalanche and Sepolia as examples.\n - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 2, "depth": 2, "title": "Supported Chains", "anchor": "supported-chains", "start_char": 2709, "end_char": 3061, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "## Supported Chains\n\nThe 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 [supported networks page](/docs/products/reference/supported-networks/#cctp){target=\\_blank}, which covers both Testnet and Mainnet environments."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 3, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 3061, "end_char": 7507, "estimated_token_count": 956, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nIn 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.\n\n1. **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.\n\n    ```bash\n    mkdir cctp-circle\n    cd cctp-circle\n    npm init -y\n    ```\n\n2. **Install dependencies**: Install the Wormhole SDK. This tutorial uses the SDK version `4.14.1`.\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1\n    ```\n\n3. **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://getfoundry.sh/cast/reference/wallet/#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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.\n\n5. **Create a `helpers.ts` file**: To simplify the interaction between chains, create a file to store utility functions, setting up signers for different chains, and managing transaction relays.\n\n    1. Create the helpers file:\n\n        ```bash\n        mkdir helpers\n        touch helpers/helpers.ts\n        ```\n\n    2. Open the `helpers.ts` file and add the following code:\n\n        ```typescript\n        import {\n          ChainAddress,\n          ChainContext,\n          Network,\n          Signer,\n          Wormhole,\n          Chain,\n        } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import solana from '@wormhole-foundation/sdk/solana';\n\n        export interface SignerStuff<N extends Network, C extends Chain> {\n          chain: ChainContext<N, C>;\n          signer: Signer<N, C>;\n          address: ChainAddress<C>;\n        }\n\n        // Signer setup function for different blockchain platforms\n        export async function getSigner<N extends Network, C extends Chain>(\n          chain: ChainContext<N, C>\n        ): Promise<{\n          chain: ChainContext<N, C>;\n          signer: Signer<N, C>;\n          address: ChainAddress<C>;\n        }> {\n          let signer: Signer;\n          const platform = chain.platform.utils()._platform;\n\n          switch (platform) {\n            case 'Solana':\n              signer = await (\n                await solana()\n              ).getSigner(await chain.getRpc(), 'SOL_PRIVATE_KEY');\n              break;\n            case 'Evm':\n              signer = await (\n                await evm()\n              ).getSigner(await chain.getRpc(), 'ETH_PRIVATE_KEY');\n              break;\n            default:\n              throw new Error('Unsupported platform: ' + platform);\n          }\n\n          return {\n            chain,\n            signer: signer as Signer<N, C>,\n            address: Wormhole.chainAddress(chain.chain, signer.address()),\n          };\n        }\n        ```\n\n        - **`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 provided private key.\n\n6. **Create the main script**: Create a new file named `manual-transfer.ts` to hold your script for transferring USDC across chains.\n\n    1. Create the `manual-transfer.ts` file in the `src` directory:\n\n        ```bash\n        mkdir src\n        touch src/manual-transfer.ts\n        ```\n\n    2. Open the `manual-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files:\n\n        ```typescript\n        import { wormhole, amount } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import solana from '@wormhole-foundation/sdk/solana';\n        import { getSigner } from './helpers/helpers';\n        ```\n\n        - **`evm`**: This import is for working with EVM-compatible chains, like Avalanche, Ethereum, Base Sepolia, and more.\n        - **`solana`**: This adds support for Solana, a non-EVM chain.\n        - **`getSigner`**: Utility function from the helper file that retrieves the signer to sign transactions."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 4, "depth": 2, "title": "Manual Transfers", "anchor": "manual-transfers", "start_char": 7507, "end_char": 8026, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "## Manual Transfers\n\nIn 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.\n\nThis section will guide you through performing a manual USDC transfer across chains using the Wormhole SDK and Circle's CCTP."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 5, "depth": 3, "title": "Set Up the Transfer Environment", "anchor": "set-up-the-transfer-environment", "start_char": 8026, "end_char": 14814, "estimated_token_count": 1444, "token_estimator": "heuristic-v1", "text": "### Set Up the Transfer Environment\n\n#### Configure Transfer Details\n\nBefore initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains.\n\n1. **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.\n\n    ```typescript\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana]);\n    ```\n    \n    !!! note\n        You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on Mainnet.\n\n2. **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.\n\n    ```typescript\n      const sendChain = wh.getChain('Avalanche');\n      const rcvChain = wh.getChain('Sepolia');\n    ```\n\n3. **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.\n\n    ```typescript\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n    ```\n\n4. **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.\n\n    ```typescript\n      const amt = 100_000n;\n    ```\n\n5. **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.\n\n    ```typescript\n      const automatic = false;\n    ```\n\n#### Initiate the Transfer\n\nTo begin the manual transfer process, you first need to create the transfer object and then manually initiate the transfer on the source chain.\n\n1. **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.\n\n    ```typescript\n      const xfer = await wh.circleTransfer(\n        amt,\n        source.address,\n        destination.address,\n        automatic\n      );\n    ```\n\n2. **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.\n\n    ```typescript\n      const srcTxids = await xfer.initiateTransfer(source.signer);\n      console.log(`Started Transfer: `, srcTxids);\n    ```\n\n#### Fetch the Circle Attestation (VAA)\n\nOnce 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.\n\n\n1. **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.\n\n    ```typescript\n      const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds)\n    ```\n\n2. **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.\n\n    ```typescript\n      const attestIds = await xfer.fetchAttestation(timeout);\n      console.log(`Got Attestation: `, attestIds);\n    ```\n\n    The `attestIds` will contain the details of the fetched attestation, which Wormhole uses to complete the transfer on the destination chain.\n\n#### Complete the Transfer on the Destination Chain\n\nOnce 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.\n\nUse 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.\n\n```typescript\n  const dstTxids = await xfer.completeTransfer(destination.signer);\n  console.log(`Completed Transfer: `, dstTxids);\n\n  console.log('Circle Transfer status: ', xfer);\n\n  process.exit(0);\n```\n\nThe `dstTxIds` will hold the transaction IDs for the transfer on the destination chain, confirming that the transfer has been completed.\n\nYou can find the full code for the manual USDC transfer script below:\n\n???- code \"`manual-transfer.ts`\"\n    ```typescript\n    import { wormhole, amount } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner } from './helpers/helpers';\n\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Set up source and destination chains\n      const sendChain = wh.getChain('Avalanche');\n      const rcvChain = wh.getChain('Sepolia');\n\n      // Configure the signers\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n\n      // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals)\n      const amt = 100_000n;\n\n      const automatic = false;\n\n      // Create the Circle transfer object\n      const xfer = await wh.circleTransfer(\n        amt,\n        source.address,\n        destination.address,\n        automatic\n      );\n\n      console.log('Circle Transfer object created:', xfer);\n\n      // Initiate the transfer on the source chain (Avalanche)\n      console.log('Starting Transfer');\n      const srcTxids = await xfer.initiateTransfer(source.signer);\n      console.log(`Started Transfer: `, srcTxids);\n\n      // Wait for Circle Attestation (VAA)\n      const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds)\n      console.log('Waiting for Attestation');\n      const attestIds = await xfer.fetchAttestation(timeout);\n      console.log(`Got Attestation: `, attestIds);\n\n      // Complete the transfer on the destination chain (Sepolia)\n      console.log('Completing Transfer');\n      const dstTxids = await xfer.completeTransfer(destination.signer);\n      console.log(`Completed Transfer: `, dstTxids);\n\n      console.log('Circle Transfer status: ', xfer);\n\n      process.exit(0);\n    })();\n    ```"}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 6, "depth": 3, "title": "Run Manual Transfer", "anchor": "run-manual-transfer", "start_char": 14814, "end_char": 15226, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### Run Manual Transfer\n\nTo execute the manual transfer script, you can use `ts-node` to run the TypeScript file directly\n\n```bash\nnpx ts-node src/manual-transfer.ts\n```\n\nThis will initiate the USDC transfer from the source chain (Avalanche) and complete it on the destination chain (Sepolia).\n\nYou can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/){target=\\_blank}."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 7, "depth": 3, "title": "Complete Partial Transfer", "anchor": "complete-partial-transfer", "start_char": 15226, "end_char": 18021, "estimated_token_count": 559, "token_estimator": "heuristic-v1", "text": "### Complete Partial Transfer\n\nIn some cases, a manual transfer may start but not finish, possibly because the user terminates their session or an issue arises before the transfer can be completed. The Wormhole SDK allows you to reconstitute the transfer object from the transaction hash on the source chain.\n\nThis feature is handy for recovering an incomplete transfer or when debugging.\n\nHere's how you can complete a partial transfer using just the source chain and transaction hash:\n\n```typescript\n  const xfer = await CircleTransfer.from(\n    wh,\n    {\n      chain: 'Avalanche',\n      txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd',\n    },\n    timeout\n  );\n\n  const dstTxIds = await xfer.completeTransfer(destination.signer);\n  console.log('Completed transfer: ', dstTxIds);\n```\n\nYou will need to provide the below requirements to complete the partial transfer:\n - **Transaction ID (`txId`)**: The transaction hash from the source chain where the transfer was initiated.\n - **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.\n\nThis 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.\n\nYou can find the full code for the manual USDC transfer script below:\n\n??? code \"`partial-transfer.ts`\"\n    ```typescript\n    import { CircleTransfer, wormhole } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner } from '../helpers/helpers';\n\n    (async function () {\n      // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana)\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Grab chain Contexts -- these hold a reference to a cached rpc client\n      const rcvChain = wh.getChain('Sepolia');\n\n      // Get signer from local key\n      const destination = await getSigner(rcvChain);\n\n      const timeout = 60 * 1000; // Timeout in milliseconds (60 seconds)\n\n      // Rebuild the transfer from the source txid\n      const xfer = await CircleTransfer.from(\n        wh,\n        {\n          chain: 'Avalanche',\n          txid: '0x6b6d5f101a32aa6d2f7bf0bf14d72bfbf76a640e1b2fdbbeeac5b82069cda4dd',\n        },\n        timeout\n      );\n\n      const dstTxIds = await xfer.completeTransfer(destination.signer);\n      console.log('Completed transfer: ', dstTxIds);\n\n      console.log('Circle Transfer status: ', xfer);\n\n      process.exit(0);\n    })();\n    ```"}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 8, "depth": 2, "title": "Automatic Transfers", "anchor": "automatic-transfers", "start_char": 18021, "end_char": 18801, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Automatic Transfers\n\nIn an automatic CCTP transfer, you submit one transaction on the source chain, and Wormhole's relayer does the rest: it observes the Wormhole message and Circle burn, obtains the required attestations, and submits them on the destination chain to mint native USDC. You don't fetch a VAA or Circle attestation or call redeem, the relayer finalizes (and can handle destination gas). \n\nThis section will guide you through performing an automatic USDC transfer across chains using the Wormhole SDK and Circle's CCTP.\n\n![Automatic CCTP transfer flow and architecture](/docs/images/products/cctp/tutorials/automatic-cctp.webp#only-dark)\n![Automatic CCTP transfer flow and architecture](/docs/images/products/cctp/tutorials/automatic-cctp-light.webp#only-light)"}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 9, "depth": 3, "title": "Set Up the Transfer Environment", "anchor": "set-up-the-transfer-environment-2", "start_char": 18801, "end_char": 21802, "estimated_token_count": 658, "token_estimator": "heuristic-v1", "text": "### Set Up the Transfer Environment\n\n#### Configure Transfer Details\n\nThe 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.\n\n```typescript\n  const automatic = true;\n```\n\n#### Set Native Gas Amount\n\nOptionally include a native gas drop for the destination, allowing your receiver to execute without pre-funding. Specify the amount in the destination chain's native token (wei); use 0 to skip.\n\n```typescript\n  const nativeGas = amount.units(amount.parse('0.1', 6));\n```\n\n#### Initiate the Transfer\n\nThe transfer process is the same as that for manual transfers. You create the transfer object and then start the transfer on the source chain.\n\n```typescript\n  const xfer = await wh.circleTransfer(\n    amt,\n    source.address,\n    destination.address,\n    automatic,\n    undefined,\n    nativeGas\n  );\n```\n\n#### Log Transfer Details\n\nAfter 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.\n\n```typescript\n  const srcTxids = await xfer.initiateTransfer(source.signer);\n  console.log(`Started Transfer: `, srcTxids);\n\n  process.exit(0);\n```\n\nYou can find the full code for the automatic USDC transfer script below:\n\n??? code \"`automatic-transfer.ts`\"\n    ```typescript\n    import { wormhole, amount } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner } from '../helpers/helpers';\n\n    (async function () {\n      // Initialize the Wormhole object for the Testnet environment and add supported chains (evm and solana)\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Set up source and destination chains\n      const sendChain = wh.getChain('Avalanche');\n      const rcvChain = wh.getChain('Sepolia');\n\n      // Configure the signers\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n\n      // Define the transfer amount (in the smallest unit, so 0.1 USDC = 100,000 units assuming 6 decimals)\n      const amt = 100_000_001n;\n\n      // Set the automatic transfer\n      const automatic = true;\n\n      // Set the native gas amount\n      const nativeGas = amount.units(amount.parse('0.1', 6));\n\n      // Create the Circle transfer object (USDC-only)\n      const xfer = await wh.circleTransfer(\n        amt,\n        source.address,\n        destination.address,\n        automatic,\n        undefined,\n        nativeGas\n      );\n\n      console.log('Circle Transfer object created:', xfer);\n\n      // Initiate the transfer on the source chain (Avalanche)\n      console.log('Starting Transfer');\n      const srcTxids = await xfer.initiateTransfer(source.signer);\n      console.log(`Started Transfer: `, srcTxids);\n\n      process.exit(0);\n    })();\n    ```"}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 10, "depth": 3, "title": "Run Automatic Transfer", "anchor": "run-automatic-transfer", "start_char": 21802, "end_char": 22149, "estimated_token_count": 79, "token_estimator": "heuristic-v1", "text": "### Run Automatic Transfer\n\nAssuming 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`:\n\n```bash\nnpx ts-node src/automatic-transfer.ts\n```\n\nThe automatic relayer will take care of fetching the attestation and completing the transfer for you."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 11, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 22149, "end_char": 22617, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Resources\n\nIf 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."}
{"page_id": "products-cctp-bridge-tutorials-complete-usdc-transfer", "page_title": "Complete USDC Transfer Flow", "index": 12, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 22617, "end_char": 23307, "estimated_token_count": 140, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nIn 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.\n\nBy following these steps, you've learned how to:\n\n- Set up cross-chain transfers for native USDC between supported chains.\n- Handle both manual and automatic relaying of transactions.\n- Recover and complete incomplete transfers using the transaction hash and the destination chain's signer.\n\nLooking for more? Check out the [Wormhole Tutorial Demo repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank} for additional examples."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 0, "depth": 2, "title": "Routes Overview {: #routes-overview}", "anchor": "routes-overview-routes-overview", "start_char": 0, "end_char": 1099, "estimated_token_count": 222, "token_estimator": "heuristic-v1", "text": "## Routes Overview {: #routes-overview}\n\nThis 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}.\n\nRoutes are methods by which the widget will transfer the assets. Wormhole Connect supports Wrapped Token Transfers (WTT) for transferring any arbitrary token, and for specific tokens, it also supports more advanced transfer methods that provide superior UX.\n\nWhen 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 WTT 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.\n\n!!! note \"Terminology\" \n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 1, "depth": 2, "title": "WTT Routes {: #wtt-routes}", "anchor": "wtt-routes-wtt-routes", "start_char": 1099, "end_char": 2129, "estimated_token_count": 212, "token_estimator": "heuristic-v1", "text": "## WTT Routes {: #wtt-routes}\n\nWTT 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.\n\n#### Manual Route {: #manual-route}\n\nThe 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.\n\n#### Automatic Route {: #automatic-route}\n\nTrustless 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."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 2, "depth": 2, "title": "CCTP Routes (USDC) {: #cctp-routes-usdc}", "anchor": "cctp-routes-usdc-cctp-routes-usdc", "start_char": 2129, "end_char": 3386, "estimated_token_count": 286, "token_estimator": "heuristic-v1", "text": "## CCTP Routes (USDC) {: #cctp-routes-usdc}\n \n[Circle](https://www.circle.com/){target=\\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/cross-chain-transfer-protocol){target=\\_blank} chains. Wormhole Connect can facilitate such transfers.\n\nNote that if native USDC is transferred from the CCTP-enabled chains to any other outside of this list, the transfer will be routed through WTT, and the resulting asset will be a Wormhole-wrapped token instead of native USDC.\n\n#### Manual Route {: #manual-route-cctp}\n\nThis 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.\n\n#### Automatic Route {: #automatic-route-cctp}\n\nTrustless 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."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 3, "depth": 2, "title": "Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes}", "anchor": "native-token-transfers-ntt-routes-native-token-transfers-ntt-routes", "start_char": 3386, "end_char": 4876, "estimated_token_count": 331, "token_estimator": "heuristic-v1", "text": "## Native Token Transfers (NTT) Routes {: #native-token-transfers-ntt-routes}\n\n[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 WTT. 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.\n\n#### Manual Route {: #manual-route-ntt}\n\nThis 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.\n\n#### Automatic Route  {: #automatic-route-ntt}\n\nTrustless 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."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 4, "depth": 2, "title": "ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth}", "anchor": "eth-bridge-route-for-native-eth-and-wsteth-eth-bridge-route-for-native-eth-and-wsteth", "start_char": 4876, "end_char": 5720, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "## ETH Bridge Route for Native ETH and wstETH {: #eth-bridge-route-for-native-eth-and-wsteth}\n\n[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).\n\n#### Automatic Route {: #automatic-route-eth}\n\nOnly 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."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 5, "depth": 2, "title": "USDT Bridge Route {: #usdt-bridge-route}", "anchor": "usdt-bridge-route-usdt-bridge-route", "start_char": 5720, "end_char": 6354, "estimated_token_count": 128, "token_estimator": "heuristic-v1", "text": "## USDT Bridge Route {: #usdt-bridge-route}\n\nOperating 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.\n\n#### Automatic Route {: #automatic-route-usdt}\n\nOnly 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."}
{"page_id": "products-connect-concepts-routes", "page_title": "Routes", "index": 6, "depth": 2, "title": "tBTC Route {: #tbtc-route}", "anchor": "tbtc-route-tbtc-route", "start_char": 6354, "end_char": 7385, "estimated_token_count": 230, "token_estimator": "heuristic-v1", "text": "## tBTC Route {: #tbtc-route}\n\nYou can bridge [Threshold's Bitcoin](https://www.threshold.network/){target=\\_blank} via this hybrid solution that combines WTT and Threshold's contracts. Native tBTC is first locked in the Wormhole WTT, 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).\n\nNote that if native tBTC is transferred out of these chains to any other outside of this list, the transfer will be routed through WTT, and the resulting asset will be a Wormhole-wrapped token instead of native tBTC.\n\n#### Manual Route {: #manual-route-tbtc}\n\nThis 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."}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 0, "depth": 2, "title": "Get Started", "anchor": "get-started", "start_char": 1032, "end_char": 1937, "estimated_token_count": 244, "token_estimator": "heuristic-v1", "text": "## Get Started\n\nConfigure 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.\n\n=== \"React\"\n\n    ```ts\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n      \n    const config: WormholeConnectConfig = {\n      networks: ['ethereum', 'polygon', 'solana'],\n      tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'],\n      rpcs: {\n        ethereum: 'https://rpc.ankr.com/eth',\n        solana: 'https://rpc.ankr.com/solana',\n      }\n    }\n      \n    <WormholeConnect config={config} />\n    ```\n\n=== \"HTML Tags\"\n\n    ```html\n    <div\n      id=\"wormhole-connect\"\n      data-config='{\"tokens\":[\"ETH\",\"WETH\",\"WBTC\",\"USDCeth\"]}'\n      data-theme='{\"background\":{\"default\": \"#81c784\"}}'\n    />\n    ```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 1, "depth": 2, "title": "Examples {: #examples }", "anchor": "examples-examples", "start_char": 1937, "end_char": 12137, "estimated_token_count": 1883, "token_estimator": "heuristic-v1", "text": "## Examples {: #examples }\n\nBelow 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.\n\n??? code \"View `WormholeConnectConfig`\"\n    ```ts\n    import {\n      ChainName,\n      WormholeContext,\n      WormholeConfig,\n      ChainResourceMap,\n    } from 'sdklegacy';\n    import MAINNET from './mainnet';\n    import TESTNET from './testnet';\n    import DEVNET from './devnet';\n    import type { WormholeConnectConfig } from './types';\n    import {\n      Network,\n      InternalConfig,\n      Route,\n      WrappedTokenAddressCache,\n    } from './types';\n    import {\n      mergeCustomTokensConfig,\n      mergeNttGroups,\n      validateDefaults,\n    } from './utils';\n    import { wrapEventHandler } from './events';\n\n    import { SDKConverter } from './converter';\n\n    import {\n      wormhole as getWormholeV2,\n      Wormhole as WormholeV2,\n      Network as NetworkV2,\n      Token as TokenV2,\n      Chain as ChainV2,\n      ChainTokens as ChainTokensV2,\n      WormholeConfigOverrides as WormholeConfigOverridesV2,\n    } from '@wormhole-foundation/sdk';\n\n    import '@wormhole-foundation/sdk/addresses';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import aptos from '@wormhole-foundation/sdk/aptos';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import cosmwasm from '@wormhole-foundation/sdk/cosmwasm';\n    import algorand from '@wormhole-foundation/sdk/algorand';\n\n    export function buildConfig(\n      customConfig?: WormholeConnectConfig\n    ): InternalConfig<NetworkV2> {\n      const network = (\n        customConfig?.network ||\n        customConfig?.env || // TODO remove; deprecated\n        import.meta.env.REACT_APP_CONNECT_ENV?.toLowerCase() ||\n        'mainnet'\n      ).toLowerCase() as Network;\n\n      if (!['mainnet', 'testnet', 'devnet'].includes(network))\n        throw new Error(`Invalid env \"${network}\"`);\n\n      const networkData = { MAINNET, DEVNET, TESTNET }[network.toUpperCase()]!;\n\n      const tokens = mergeCustomTokensConfig(\n        networkData.tokens,\n        customConfig?.tokensConfig\n      );\n\n      const sdkConfig = WormholeContext.getConfig(network);\n\n      const rpcs = Object.assign(\n        {},\n        sdkConfig.rpcs,\n        networkData.rpcs,\n        customConfig?.rpcs\n      );\n\n      const wh = getWormholeContext(network, sdkConfig, rpcs);\n\n      if (customConfig?.bridgeDefaults) {\n        validateDefaults(customConfig.bridgeDefaults, networkData.chains, tokens);\n      }\n\n      const sdkConverter = new SDKConverter(wh);\n\n      return {\n        wh,\n        sdkConfig,\n        sdkConverter,\n\n        v2Network: sdkConverter.toNetworkV2(network),\n\n        network,\n        isMainnet: network === 'mainnet',\n        // External resources\n        rpcs,\n        rest: Object.assign(\n          {},\n          sdkConfig.rest,\n          networkData.rest,\n          customConfig?.rest\n        ),\n        graphql: Object.assign({}, networkData.graphql, customConfig?.graphql),\n        wormholeApi: {\n          mainnet: 'https://api.wormholescan.io/',\n          testnet: 'https://api.testnet.wormholescan.io/',\n          devnet: '',\n        }[network],\n        wormholeRpcHosts: {\n          mainnet: [\n            'https://wormhole-v2-mainnet-api.mcf.rocks',\n            'https://wormhole-v2-mainnet-api.chainlayer.network',\n            'https://wormhole-v2-mainnet-api.staking.fund',\n          ],\n          testnet: [\n            'https://guardian.testnet.xlabs.xyz',\n            'https://guardian-01.testnet.xlabs.xyz',\n            'https://guardian-02.testnet.xlabs.xyz',\n          ],\n          devnet: ['http://localhost:7071'],\n        }[network],\n        coinGeckoApiKey: customConfig?.coinGeckoApiKey,\n\n        // Callbacks\n        triggerEvent: wrapEventHandler(customConfig?.eventHandler),\n        validateTransfer: customConfig?.validateTransferHandler,\n\n        // White lists\n        chains: networkData.chains,\n        chainsArr: Object.values(networkData.chains).filter((chain) => {\n          return customConfig?.networks\n            ? customConfig.networks!.includes(chain.key)\n            : true;\n        }),\n        tokens,\n        tokensArr: Object.values(tokens).filter((token) => {\n          return customConfig?.tokens\n            ? customConfig.tokens!.includes(token.key)\n            : true;\n        }),\n\n        // For token bridge ^_^\n        wrappedTokenAddressCache: new WrappedTokenAddressCache(\n          tokens,\n          sdkConverter\n        ),\n\n        gasEstimates: networkData.gasEstimates,\n        // TODO: routes that aren't supported yet are disabled\n        routes: (customConfig?.routes ?? Object.values(Route)).filter((r) =>\n          [\n            Route.Bridge,\n            Route.Relay,\n            Route.NttManual,\n            Route.NttRelay,\n            Route.CCTPManual,\n            Route.CCTPRelay,\n          ].includes(r as Route)\n        ),\n\n        // UI details\n        cta: customConfig?.cta,\n        explorer: customConfig?.explorer,\n        attestUrl: {\n          mainnet: 'https://portalbridge.com/legacy-tools/#/register',\n          devnet: '',\n          testnet:\n            'https://wormhole-foundation.github.io/example-token-bridge-ui/#/register',\n        }[network],\n        bridgeDefaults: customConfig?.bridgeDefaults,\n        cctpWarning: customConfig?.cctpWarning?.href || '',\n        pageHeader: customConfig?.pageHeader,\n        pageSubHeader: customConfig?.pageSubHeader,\n        menu: customConfig?.menu ?? [],\n        searchTx: customConfig?.searchTx,\n        moreTokens: customConfig?.moreTokens,\n        moreNetworks: customConfig?.moreNetworks,\n        partnerLogo: customConfig?.partnerLogo,\n        walletConnectProjectId:\n          customConfig?.walletConnectProjectId ??\n          import.meta.env.REACT_APP_WALLET_CONNECT_PROJECT_ID,\n        showHamburgerMenu: customConfig?.showHamburgerMenu ?? false,\n        previewMode: !!customConfig?.previewMode,\n\n        // Route options\n        ethBridgeMaxAmount: customConfig?.ethBridgeMaxAmount ?? 5,\n        wstETHBridgeMaxAmount: customConfig?.wstETHBridgeMaxAmount ?? 5,\n\n        // NTT config\n        nttGroups: mergeNttGroups(\n          tokens,\n          networkData.nttGroups,\n          customConfig?.nttGroups\n        ),\n\n        // Guardian set\n        guardianSet: networkData.guardianSet,\n\n        // Render redesign views\n        useRedesign: customConfig?.useRedesign,\n      };\n    }\n\n    // Running buildConfig with no argument generates the default configuration\n    const config = buildConfig();\n    export default config;\n\n    // TODO SDKV2: REMOVE\n    export function getWormholeContext(\n      network: Network,\n      sdkConfig: WormholeConfig,\n      rpcs: ChainResourceMap\n    ): WormholeContext {\n      const wh: WormholeContext = new WormholeContext(network, {\n        ...sdkConfig,\n        ...{ rpcs },\n      });\n\n      return wh;\n    }\n\n    export function getDefaultWormholeContext(network: Network): WormholeContext {\n      const sdkConfig = WormholeContext.getConfig(network);\n      const networkData = { mainnet: MAINNET, devnet: DEVNET, testnet: TESTNET }[\n        network\n      ]!;\n\n      const rpcs = Object.assign({}, sdkConfig.rpcs, networkData.rpcs);\n\n      return getWormholeContext(network, sdkConfig, rpcs);\n    }\n\n    export async function getWormholeContextV2(): Promise<WormholeV2<NetworkV2>> {\n      if (config.v2Wormhole) return config.v2Wormhole;\n      config.v2Wormhole = await newWormholeContextV2();\n      return config.v2Wormhole;\n    }\n\n    export async function newWormholeContextV2(): Promise<WormholeV2<NetworkV2>> {\n      const v2Config: WormholeConfigOverridesV2<NetworkV2> = { chains: {} };\n\n      for (const key in config.chains) {\n        const chainV1 = key as ChainName;\n        const chainConfigV1 = config.chains[chainV1]!;\n\n        const chainContextV1 = chainConfigV1.context;\n\n        const chainV2 = config.sdkConverter.toChainV2(\n          chainV1 as ChainName\n        ) as ChainV2;\n\n        const rpc = config.rpcs[chainV1];\n        const tokenMap: ChainTokensV2 = {};\n\n        for (const token of config.tokensArr) {\n          const nativeChainV2 = config.sdkConverter.toChainV2(token.nativeChain);\n\n          const tokenV2: Partial<TokenV2> = {\n            key: token.key,\n            chain: chainV2,\n            symbol: token.symbol,\n          };\n\n          if (nativeChainV2 == chainV2) {\n            const decimals =\n              token.decimals[chainContextV1] ?? token.decimals.default;\n            if (!decimals) {\n              continue;\n            } else {\n              tokenV2.decimals = decimals;\n            }\n            const address = config.sdkConverter.getNativeTokenAddressV2(token);\n            if (!address) throw new Error('Token must have address');\n            tokenV2.address = address;\n          } else {\n            tokenV2.original = nativeChainV2;\n            if (token.foreignAssets) {\n              const fa = token.foreignAssets[chainV1]!;\n\n              if (!fa) {\n                continue;\n              } else {\n                tokenV2.address = fa.address;\n                tokenV2.decimals = fa.decimals;\n              }\n            } else {\n              continue;\n            }\n          }\n\n          tokenMap[token.key] = tokenV2 as TokenV2;\n        }\n\n        v2Config.chains![chainV2] = { rpc, tokenMap };\n      }\n\n      return await getWormholeV2(\n        config.v2Network,\n        [evm, solana, aptos, cosmwasm, sui, algorand],\n        v2Config\n      );\n    }\n\n    // setConfig can be called afterwards to override the default config with integrator-provided config\n    export function setConfig(customConfig?: WormholeConnectConfig) {\n      const newConfig: InternalConfig<NetworkV2> = buildConfig(customConfig);\n\n      // We overwrite keys in the existing object so the references to the config\n      // imported elsewhere point to the new values\n      for (const key in newConfig) {\n        /* @ts-ignore */\n        config[key] = newConfig[key];\n      }\n    }\n\n    // TODO: add config validation step to buildConfig\n    //validateConfigs();\n    ```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 2, "depth": 3, "title": "Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints }", "anchor": "custom-networks-and-rpc-endpoints-custom-networks-and-rpc-endpoints", "start_char": 12137, "end_char": 13685, "estimated_token_count": 378, "token_estimator": "heuristic-v1", "text": "### Custom Networks and RPC Endpoints {: #custom-networks-and-rpc-endpoints }\n\nSpecify supported networks, tokens, and custom RPC endpoints. Your users may encounter rate limits using public RPC endpoints if you don't provide your own.\n\n=== \"Mainnet\"\n\n    ```js\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      env: 'mainnet',\n      networks: ['ethereum', 'polygon', 'solana'],\n      tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'],\n      rpcs: {\n        ethereum: 'https://rpc.ankr.com/eth',\n        solana: 'https://rpc.ankr.com/solana',\n      },\n    };\n\n    function App() {\n      return <WormholeConnect config={config} />;\n    }\n    ```\n\n=== \"Testnet\"\n\n    ```js\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      env: 'testnet',\n      networks: ['sepolia', 'arbitrum_sepolia', 'base_sepolia', 'fuji'],\n\n      rpcs: {\n        fuji: 'https://rpc.ankr.com/avalanche_fuji',\n        base_sepolia: 'https://base-sepolia-rpc.publicnode.com',\n      },\n    };\n\n    function App() {\n      return <WormholeConnect config={config} />;\n    }\n    ```\n\n!!! note\n    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}."}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 3, "depth": 3, "title": "Fully Customized Theme {: #fully-customized-theme }", "anchor": "fully-customized-theme-fully-customized-theme", "start_char": 13685, "end_char": 15567, "estimated_token_count": 509, "token_estimator": "heuristic-v1", "text": "### Fully Customized Theme {: #fully-customized-theme }\n\nWormhole 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}.\n\n```jsx\nimport WormholeConnect, {\n  WormholeConnectTheme,\n} from '@wormhole-foundation/wormhole-connect';\nimport red from '@mui/material/colors/red';\nimport lightblue from '@mui/material/colors/lightBlue';\nimport grey from '@mui/material/colors/grey';\nimport green from '@mui/material/colors/green';\nimport orange from '@mui/material/colors/orange';\n\nconst customTheme: WormholeConnectTheme = {\n  mode: 'dark',\n  primary: grey,\n  secondary: grey,\n  divider: 'rgba(255, 255, 255, 0.2)',\n  background: {\n    default: '#232323',\n  },\n  text: {\n    primary: '#ffffff',\n    secondary: grey[500],\n  },\n  error: red,\n  info: lightblue,\n  success: green,\n  warning: orange,\n  button: {\n    primary: 'rgba(255, 255, 255, 0.2)',\n    primaryText: '#ffffff',\n    disabled: 'rgba(255, 255, 255, 0.1)',\n    disabledText: 'rgba(255, 255, 255, 0.4)',\n    action: orange[300],\n    actionText: '#000000',\n    hover: 'rgba(255, 255, 255, 0.7)',\n  },\n  options: {\n    hover: '#474747',\n    select: '#5b5b5b',\n  },\n  card: {\n    background: '#333333',\n    secondary: '#474747',\n    elevation: 'none',\n  },\n  popover: {\n    background: '#1b2033',\n    secondary: 'rgba(255, 255, 255, 0.5)',\n    elevation: 'none',\n  },\n  modal: {\n    background: '#474747',\n  },\n  font: {\n    primary: 'Impact',\n    header: 'Impact',\n  },\n};\n\nexport default function App() {\n  return <WormholeConnect theme={customTheme} />;\n}\n```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 4, "depth": 3, "title": "Environment {: #environment }", "anchor": "environment-environment", "start_char": 15567, "end_char": 15991, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "### Environment {: #environment }\n\nYou can configure Connect to be used in Testnet environments, too. You can toggle between Mainnet and Testnet environments by defining the `WormholeConnectConfig` as follows:\n\n=== \"Mainnet\"\n\n    ```ts\n    const config: WormholeConnectConfig = {\n      env: 'mainnet',\n    };\n    ```\n\n=== \"Testnet\"\n\n    ```ts\n    const config: WormholeConnectConfig = {\n      env: 'testnet',\n    };\n    ```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 5, "depth": 3, "title": "Custom RPC Endpoint {: #custom-rpc-endpoint }", "anchor": "custom-rpc-endpoint-custom-rpc-endpoint", "start_char": 15991, "end_char": 16399, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "### Custom RPC Endpoint {: #custom-rpc-endpoint }\n\nYou 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.\n\n```ts\nconst config: WormholeConnectConfig = {\n  rpcs: {\n    solana: 'https://rpc.ankr.com/solana/ee827255553bb0fa9e0aaeab27e988707e60ea06ae36be0658b778072e94979e',\n  },\n};\n```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 6, "depth": 3, "title": "Arbitrary Token {: #arbitrary-token }", "anchor": "arbitrary-token-arbitrary-token", "start_char": 16399, "end_char": 17730, "estimated_token_count": 335, "token_estimator": "heuristic-v1", "text": "### Arbitrary Token {: #arbitrary-token }\n\nThe following section shows how to add an arbitrary token to your deployment of Connect.\n\n!!! note\n    You will need to [register](https://portalbridge.com/legacy-tools/#/register){target=\\_blank} your token with Wrapped Token Transfers (WTT) to get the contract addresses necessary for it to work with Connect.\n\nThis 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.\n\nSee [`src/config/types.ts`](https://github.com/wormhole-foundation/wormhole-connect/blob/production%400.3.21/wormhole-connect/src/config/types.ts){target=\\_blank} for the type definition of `TokensConfig`.\n\n```json\nconst config: WormholeConnectConfig = {\n  networks: ['solana', 'ethereum'],\n  tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC', 'BSKT'],\n  tokensConfig: {\n    BSKT: {\n      key: 'BSKT',\n      symbol: 'BSKT',\n      nativeChain: 'solana',\n      tokenId: {\n        chain: 'solana',\n        address: '6gnCPhXtLnUD76HjQuSYPENLSZdG8RvDB1pTLM5aLSJA',\n      },\n      coinGeckoId: 'basket',\n      icon: 'https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891',\n      color: '#2894EE',\n      decimals: {\n        default: 5,\n      },\n    },\n  },\n};\n```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 7, "depth": 2, "title": "More Configuration Options {: #more-configuration-options }", "anchor": "more-configuration-options-more-configuration-options", "start_char": 17730, "end_char": 17794, "estimated_token_count": 14, "token_estimator": "heuristic-v1", "text": "## More Configuration Options {: #more-configuration-options }"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 8, "depth": 3, "title": "Whitelisting Tokens {: #whitelisting-tokens }", "anchor": "whitelisting-tokens-whitelisting-tokens", "start_char": 17794, "end_char": 20786, "estimated_token_count": 364, "token_estimator": "heuristic-v1", "text": "### Whitelisting Tokens {: #whitelisting-tokens }\n\nBy 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:\n\n|    Mainnet     |              Testnet               |\n|:--------------:|:----------------------------------:|\n|      ETH       |          ETH, ETHsepolia           |\n|      WETH      |         WETH, WETHsepolia          |\n|    USDCeth     |              USDCeth               |\n|      WBTC      |                 -                  |\n|      USDT      |                 -                  |\n|      DAI       |                 -                  |\n|      BUSD      |                 -                  |\n|     MATIC      |               MATIC                |\n|     WMATIC     |               WMATIC               |\n|  USDCpolygon   |                 -                  |\n|      BNB       |                BNB                 |\n|      WBNB      |                WBNB                |\n|    USDCbnb     |                 -                  |\n|      AVAX      |                AVAX                |\n|     WAVAX      |               WAVAX                |\n|    USDCavax    |              USDCavax              |\n|      FTM       |                FTM                 |\n|      WFTM      |                WFTM                |\n|      CELO      |                CELO                |\n|      GLMR      |                GLMR                |\n|     WGLMR      |               WGLMR                |\n|      SOL       |                WSOL                |\n|      PYTH      |                 -                  |\n|      SUI       |                SUI                 |\n|    USDCsol     |                 -                  |\n|      APT       |                APT                 |\n|  ETHarbitrum   |  ETHarbitrum, ETHarbitrum_sepolia  |\n|  WETHarbitrum  | WETHarbitrum, WETHarbitrum_sepolia |\n|  USDCarbitrum  |            USDCarbitrum            |\n|  ETHoptimism   |  ETHoptimism, ETHoptimism_sepolia  |\n|  WETHoptimism  | WETHoptimism, WETHoptimism_sepolia |\n|  USDCoptimism  |            USDCoptimism            |\n|    ETHbase     |      ETHbase, ETHbase_sepolia      |\n|    WETHbase    |     WETHbase, WETHbase_sepolia     |\n|      tBTC      |                tBTC                |\n|  tBTCpolygon   |            tBTCpolygon             |\n|  tBTCoptimism  |            tBTCoptimism            |\n|  tBTCarbitrum  |            tBTCarbitrum            |\n|    tBTCbase    |              tBTCbase              |\n|    tBTCsol     |              tBTCsol               |\n|  WETHpolygon   |                 -                  |\n|    WETHbsc     |                 -                  |\n|     wstETH     |               wstETH               |\n| wstETHarbitrum |                 -                  |\n| wstETHoptimism |                 -                  |\n| wstETHpolygon  |                 -                  |\n|   wstETHbase   |                 -                  |"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 9, "depth": 3, "title": "Routes {: #routes }", "anchor": "routes-routes", "start_char": 20786, "end_char": 21385, "estimated_token_count": 138, "token_estimator": "heuristic-v1", "text": "### Routes {: #routes }\n\nBy 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:\n\n|   Mainnet    |  Testnet   |\n|:------------:|:----------:|\n|    bridge    |   bridge   |\n|    relay     |   relay    |\n|  cctpManual  | cctpManual |\n|  cctpRelay   | cctpRelay  |\n|  nttManual   | nttManual  |\n|   nttRelay   |  nttRelay  |\n|  ethBridge   |     -      |\n| wstETHBridge |     -      |\n|  usdtBridge  |     -      |\n|     tBTC     |    tBTC    |"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 10, "depth": 3, "title": "Wallet Set Up  {: #wallet-connect-project-id }", "anchor": "wallet-set-up-wallet-connect-project-id", "start_char": 21385, "end_char": 22024, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "### Wallet Set Up  {: #wallet-connect-project-id }\n\nWhen using Wormhole Connect, your selected blockchain network determines the available wallet options.\n\n - For EVM chains, wallets like MetaMask and WalletConnect are supported.\n - For Solana, you'll see options such as Phantom, Torus, and Coin98.\n\nThe wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration.\n\nIf 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}."}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 11, "depth": 3, "title": "Toggle Hamburger Menu {: #toggle-hamburger-menu }", "anchor": "toggle-hamburger-menu-toggle-hamburger-menu", "start_char": 22024, "end_char": 23089, "estimated_token_count": 296, "token_estimator": "heuristic-v1", "text": "### Toggle Hamburger Menu {: #toggle-hamburger-menu }\n\nBy setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, causing the links to be positioned at the bottom.\n\n#### Add Extra Menu Entry {: #add-extra-menu-entry }\n\nBy setting the `showHamburgerMenu` option to `false`, you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`):\n\n| Property |                 Description                 |\n|:--------:|:-------------------------------------------:|\n| `label`  |            Link name to show up             |\n|  `href`  |              Target URL or URN              |\n| `target` | Anchor standard target, by default `_blank` |\n| `order`  | Order where the new item should be injected |\n\n#### Sample Configuration {: #sample-configuration }\n\n```json\n{\n    \"showHamburgerMenu\": false,\n    \"menu\": [\n        {\n            \"label\": \"Advance Tools\",\n            \"href\": \"https://portalbridge.com\",\n            \"target\": \"_self\",\n            \"order\": 1\n        }\n    ]\n}\n```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 12, "depth": 3, "title": "CoinGecko API Key {: #coingecko-api-key }", "anchor": "coingecko-api-key-coingecko-api-key", "start_char": 23089, "end_char": 23511, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### CoinGecko API Key {: #coingecko-api-key }\n\nThe 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`."}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 13, "depth": 3, "title": "More Networks {: #more-networks }", "anchor": "more-networks-more-networks", "start_char": 23511, "end_char": 26903, "estimated_token_count": 691, "token_estimator": "heuristic-v1", "text": "### More Networks {: #more-networks }\n\nSpecify 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`):\n\n| <div style=\"width:15em\">Property</div> |                                                                       Description                                                                       |\n|:--------------------------------------:|:-------------------------------------------------------------------------------------------------------------------------------------------------------:|\n|                 `href`                 |                                                  **Required**. Default value for missing network hrefs                                                  |\n|                `target`                |                                           Default value for missing network link targets. Defaults to `_self`                                           |\n|             `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 |\n|           `networks[].icon`            |                                                     **Required**. URL data encoded icon to display                                                      |\n|           `networks[].href`            | Network href to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting  |\n|           `networks[].label`           |                                                               **Required**. Display text                                                                |\n|           `networks[].name`            |                                            Unique network key. Defaults to a snake_case version of the label                                            |\n|        `networks[].description`        |                                                Description value. Defaults to `moreNetworks.description`                                                |\n|          `networks[].target`           |                                                  href target value. Defaults to `moreNetworks.target`                                                   |\n|     `networks[].showOpenInNewIcon`     |                    Disable top right open in new icon. Defaults to **true** if target is `_blank` or **false** if target is `_self`                     |\n\n??? code \"View full configuration\"\n    ```json\n    {\n        ...\n        \"moreNetworks\": {\n            \"href\": \"https://example.com\",\n            \"target\": \"_blank\",\n            \"description\": \"brief description that should be displayed as tooltip when the user hovers over a more network icon\",\n            \"networks\": [\n                {\n                    \"icon\": \"https://assets.coingecko.com/coins/images/34661/standard/BSKT_Logo.png?1705636891\",\n                    \"name\": \"more\",\n                    \"label\": \"More networks\",\n                    \"href\": \"https://portalbridge.com/#/transfer\",\n                    \"showOpenInNewIcon\": false\n                }\n            ]\n        }\n        ...\n    }\n    ```"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 14, "depth": 3, "title": "More Tokens {: #more-tokens }", "anchor": "more-tokens-more-tokens", "start_char": 26903, "end_char": 28010, "estimated_token_count": 301, "token_estimator": "heuristic-v1", "text": "### More Tokens {: #more-tokens }\n\nShow 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`):\n\n| Property |                                                                         Description                                                                         |\n|:--------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:|\n| `label`  |                                                                 **Required**. Display text                                                                  |\n|  `href`  | **Required**. URL to redirect to. If present, the values `sourceChain` and `targetChain` are replaced with the currently selected chains before redirecting |\n| `target` |                                                              href target. Defaults to `_self`                                                               |"}
{"page_id": "products-connect-configuration-configuration-v0", "page_title": "Configure Your Connect Widget v0", "index": 15, "depth": 3, "title": "Explorer {: #explorer }", "anchor": "explorer-explorer", "start_char": 28010, "end_char": 29321, "estimated_token_count": 362, "token_estimator": "heuristic-v1", "text": "### Explorer {: #explorer }\n\nEnable 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`):\n\n| Property |                                                                                             Description                                                                                             |\n|:--------:|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------:|\n| `label`  |                                                                              Display text. Defaults to `Transactions`                                                                               |\n|  `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 |\n| `target` |                                                                                 `href` target. Defaults to `_blank`                                                                                 |"}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 0, "depth": 2, "title": "Data Configuration", "anchor": "data-configuration", "start_char": 0, "end_char": 350, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "## Data Configuration\n\nThis 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."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 1, "depth": 2, "title": "Get Started", "anchor": "get-started", "start_char": 350, "end_char": 1739, "estimated_token_count": 356, "token_estimator": "heuristic-v1", "text": "## Get Started\n\nConfigure Wormhole Connect by passing a `WormholeConnectConfig` object as the `config` prop.\n\n=== \"React integration\"\n\n    ```ts\n    import WormholeConnect, {\n      type config,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      chains: ['Ethereum', 'Polygon', 'Solana'],\n      tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'],\n      rpcs: {\n        Ethereum: 'https://rpc.ankr.com/eth',\n        Solana: 'https://rpc.ankr.com/solana',\n      }\n    }\n\n    <WormholeConnect config={config} />\n    ```\n\n=== \"Hosted integration\"\n\n    ```ts\n    import WormholeConnect, { wormholeConnectHosted, type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      chains: ['Ethereum', 'Polygon', 'Solana'],\n      tokens: ['ETH', 'WETH', 'MATIC', 'WMATIC'],\n      rpcs: {\n        Ethereum: 'https://rpc.ankr.com/eth',\n        Solana: 'https://rpc.ankr.com/solana',\n      },\n    };\n\n    const container = document.getElementById('bridge-container');\n\n    wormholeConnectHosted(container, {\n      config,\n    });\n    ```\n\n!!! note\n    The complete type definition of `WormholeConnectConfig` is available in the [Wormhole Connect repository](https://github.com/wormhole-foundation/wormhole-connect/blob/production%403.0.0/wormhole-connect/src/config/types.ts#L96){target=\\_blank}."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 2, "depth": 2, "title": "Examples {: #examples }", "anchor": "examples-examples", "start_char": 1739, "end_char": 1767, "estimated_token_count": 8, "token_estimator": "heuristic-v1", "text": "## Examples {: #examples }"}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 3, "depth": 3, "title": "Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints }", "anchor": "configuring-chains-and-rpc-endpoints-chains-and-rpc-endpoints", "start_char": 1767, "end_char": 3266, "estimated_token_count": 369, "token_estimator": "heuristic-v1", "text": "### Configuring Chains and RPC Endpoints {: #chains-and-rpc-endpoints }\n\nConnect 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.\n\n=== \"Mainnet\"\n\n    ```js\n    import WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      chains: ['Ethereum', 'Polygon', 'Solana'],\n      rpcs: {\n        Ethereum: 'https://rpc.ankr.com/eth',\n        Solana: 'https://rpc.ankr.com/solana',\n      },\n    };\n\n    function App() {\n      return <WormholeConnect config={config} />;\n    }\n    ```\n\n=== \"Testnet\"\n\n    ```js\n    import WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      // You can use Connect with testnet chains by specifying \"network\":\n      network: 'Testnet',\n      chains: ['Sepolia', 'ArbitrumSepolia', 'BaseSepolia', 'Avalanche'],\n      rpcs: {\n        Avalanche: 'https://rpc.ankr.com/avalanche_fuji',\n        BaseSepolia: 'https://base-sepolia-rpc.publicnode.com',\n      },\n    };\n\n    function App() {\n      return <WormholeConnect config={config} />;\n    }\n    ```\n\n!!! note\n    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}."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 4, "depth": 3, "title": "Configuring Routes", "anchor": "configuring-routes", "start_char": 3266, "end_char": 7965, "estimated_token_count": 1222, "token_estimator": "heuristic-v1", "text": "### Configuring Routes\n\nBy default, Connect offers two bridging protocols: Wrapped Token Transfers (WTT) 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.\n\n!!! note \"Terminology\"\n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol.\n\n#### Available Route Plugins\n\nThe `@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:\n\n- **[`TokenBridgeRoute`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/manual.ts){target=\\_blank}**: Manually redeemed Wormhole WTT route.\n- **[`ExecutorTokenBridgeRoute`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/tokenBridge/executor.ts){target=\\_blank}**: Executor.\n- **[`CCTPRoute`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/manual.ts){target=\\_blank}**: Manually redeemed CCTP route.\n- **[`AutomaticCCTPRoute`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/connect/src/routes/cctp/automatic.ts){target=\\_blank}**: Automatically redeemed (relayed) CCTP route.\n- **`DEFAULT_ROUTES`**: Array containing the four preceding routes (`TokenBridgeRoute`, `AutomaticTokenBridgeRoute`, `CCTPRoute`, `AutomaticCCTPRoute`).\n- **[`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.\n- **`nttExecutorRoute(nttConfig)`**: Function that returns the Executor-powered NTT route for one-click transfers.\n- **[`MayanRoute`](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L57){target=\\_blank}**: Route that offers multiple Mayan protocols.\n- **[`MayanRouteSWIFT`](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L528){target=\\_blank}**: Route for Mayan's Swift protocol only.\n- **[`MayanRouteMCTP`](https://github.com/mayan-finance/wormhole-sdk-route/blob/main/src/index.ts#L539){target=\\_blank}**: Route for Mayan's MCTP protocol only.\n- **[`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.\n\nIn 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.\n\nFor 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}.\n\n#### Example: Offer Only CCTP Transfers\n\nTo configure Wormhole Connect to offer only USDC transfers via the CCTP route, use the following configuration:\n\n```typescript\nimport WormholeConnect, {\n  AutomaticCCTPRoute,\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  routes: [AutomaticCCTPRoute],\n};\n\n<WormholeConnect config={config} />;\n```\n\n#### Example: Offer All Default Routes and Third-Party Plugins\n\nIn this example, Wormhole Connect is configured with routes for both default protocols (WTT and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\\_blank}.\n\n```typescript\nimport WormholeConnect, {\n  DEFAULT_ROUTES,\n  MayanRouteSWIFT,\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\nimport { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\nimport { myNttConfig } from './consts'; // Custom NTT configuration\n\nconst config: config.WormholeConnectConfig = {\n  routes: [...DEFAULT_ROUTES, nttExecutorRoute({ ntt: myNttConfig }), MayanRouteSWIFT],\n};\n\n<WormholeConnect config={config} />;\n```\n\nThis flexible plugin allows you to combine default routes (such as WTT and CCTP) with third-party protocols, offering complete control over which routes are available in your application."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 5, "depth": 3, "title": "Adding Custom Tokens {: #custom-tokens }", "anchor": "adding-custom-tokens-custom-tokens", "start_char": 7965, "end_char": 9208, "estimated_token_count": 282, "token_estimator": "heuristic-v1", "text": "### Adding Custom Tokens {: #custom-tokens }\n\nThe following section shows how to add an arbitrary token to your deployment of Connect.\n\n!!! note\n    You will need to [register](https://portalbridge.com/legacy-tools/#/register){target=\\_blank} your token with WTT to get the contract addresses necessary for it to work with that protocol.\n\nThis example configuration adds the BONK token to Connect. Note the `wrappedTokens` property, which is required for use with WTT.\n\nSee the [Connect source code](https://github.com/wormhole-foundation/wormhole-connect/blob/production%403.0.0/wormhole-connect/src/config/types.ts#L182){target=\\_blank} for the type definition of `TokensConfig`.\n\n```typescript\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  tokensConfig: {\n    BONK: {\n      key: 'BONK',\n      symbol: 'BONK',\n      nativeChain: 'Ethereum',\n      icon: Icon.ETH,\n      tokenId: {\n        chain: 'Ethereum',\n        address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6',\n      },\n      coinGeckoId: 'bonk',\n      decimals: 18,\n    },\n  },\n  wrappedTokens: {\n    BONK: {\n      Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',\n    },\n  },\n};\n```"}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 6, "depth": 3, "title": "Configuring Native Token Transfers (NTT)", "anchor": "configuring-native-token-transfers-ntt", "start_char": 9208, "end_char": 11943, "estimated_token_count": 529, "token_estimator": "heuristic-v1", "text": "### Configuring Native Token Transfers (NTT)\n\nConnect supports [NTT](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}, which allows native tokens to move between supported chains using NTT-deployed contracts, such as managers and transceivers.\n\nTo enable NTT in your app, follow these steps:\n\n 1. Add the NTT route to the `routes` array by calling `nttExecutorRoute(...)` with your token deployment config. This sets up the Executor-powered route logic for native token transfers.\n 2. Provide token metadata for each of the tokens listed in `nttExecutorRoute` in the [`tokensConfig`](#custom-tokens) object. These entries must include `symbol`, `decimals`, and the `tokenId`.\n\n```typescript\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\nimport { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\nconst wormholeConfig: config.WormholeConnectConfig = {\n  network: 'Testnet',\n  chains: ['Solana', 'BaseSepolia'],\n  tokens: ['WSV'],\n  ui: {\n    title: 'Wormhole NTT UI',\n    defaultInputs: {\n      fromChain: 'Solana',\n      toChain: 'BaseSepolia',\n    },\n  },\n  routes: [\n    nttExecutorRoute({\n      ntt: {\n        tokens: {\n          WSV_NTT: [\n            {\n              chain: 'Solana',\n              manager: 'nMxHx1o8GUg2pv99y8JAQb5RyWNqDWixbxWCaBcurQx',\n              token: '2vLDzr7hUpLFHQotmR8EPcMTWczZUwCK31aefAzumkmv',\n              transceiver: [\n                {\n                  address: 'AjL3f9FMHJ8VkNUHZqLYxa5aFy3aTN6LUWMv4qmdf5PN',\n                  type: 'wormhole',\n                },\n              ],\n            },\n            {\n              chain: 'BaseSepolia',\n              manager: '0xaE02Ff9C3781C5BA295c522fB469B87Dc5EE9205',\n              token: '0xb8dccDA8C166172159F029eb003d5479687452bD',\n              transceiver: [\n                {\n                  address: '0xF4Af1Eac8995766b54210b179A837E3D59a9F146',\n                  type: 'wormhole',\n                },\n              ],\n            },\n          ],\n        },\n      },\n    }),\n  ],\n  tokensConfig: {\n    WSVsol: {\n      symbol: 'WSV',\n      tokenId: {\n        chain: 'Solana',\n        address: '2vLDzr7hUpLFHQotmR8EPcMTWczZUwCK31aefAzumkmv',\n      },\n      icon: 'https://wormhole.com/token.png',\n      decimals: 9,\n    },\n    WSVbase: {\n      symbol: 'WSV',\n      tokenId: {\n        chain: 'BaseSepolia',\n        address: '0xb8dccDA8C166172159F029eb003d5479687452bD',\n      },\n      icon: 'https://wormhole.com/token.png',\n      decimals: 9,\n    },\n  },\n};\n```\n\nFor a complete working example of NTT configuration in Wormhole Connect, see the [ntt-connect demo repository](https://github.com/wormhole-foundation/demo-ntt-connect){target=\\_blank}."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 7, "depth": 3, "title": "Whitelisting Tokens {: #whitelisting-tokens }", "anchor": "whitelisting-tokens-whitelisting-tokens", "start_char": 11943, "end_char": 14154, "estimated_token_count": 558, "token_estimator": "heuristic-v1", "text": "### Whitelisting Tokens {: #whitelisting-tokens }\n\nConnect offers a list of built-in tokens by default. You can see it below:\n\n- [Mainnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/production%403.0.0/wormhole-connect/src/config/mainnet/tokens.ts){target=\\_blank}\n- [Testnet tokens](https://github.com/wormhole-foundation/wormhole-connect/blob/production%403.0.0/wormhole-connect/src/config/testnet/tokens.ts){target=\\_blank}\n\nYou 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.\n\n```jsx\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  chains: ['Ethereum', 'Solana'],\n  tokens: ['ETH', 'SOL', 'BONK'],\n  rpcs: {\n    Ethereum: 'https://rpc.ankr.com/eth',\n    Solana: 'https://rpc.ankr.com/solana',\n  },\n  tokensConfig: {\n    BONK: {\n      key: 'BONK',\n      symbol: 'BONK',\n      icon: 'https://assets.coingecko.com/coins/images/28600/large/bonk.jpg?1696527587',\n      tokenId: {\n        chain: 'Ethereum',\n        address: '0x1151CB3d861920e07a38e03eEAd12C32178567F6',\n      },\n      decimals: 18,\n    },\n  },\n  wrappedTokens: {\n    BONK: {\n      Solana: 'DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263',\n    },\n  },\n};\n\nfunction App() {\n  return <WormholeConnect config={config} />;\n}\n```\n\nYou 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.\n\n```jsx\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  chains: ['Ethereum', 'Solana'],\n  tokens: [\n    // Whitelist BONK on every whitelisted chain\n    'BONK',\n    // Also whitelist USDC, specifically on Solana\n    ['Solana', 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v']\n  ],\n  ...\n};\n\nfunction App() {\n  return <WormholeConnect config={config} />;\n}\n```"}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 8, "depth": 3, "title": "User-Inputted Tokens {: #user-inputted-tokens }", "anchor": "user-inputted-tokens-user-inputted-tokens", "start_char": 14154, "end_char": 14932, "estimated_token_count": 174, "token_estimator": "heuristic-v1", "text": "### User-Inputted Tokens {: #user-inputted-tokens }\n\nAs 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).\n\nIf you provide a token whitelist (see above), this is turned off automatically. However, you can also disable it explicitly like this:\n\n```jsx\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  ui: {\n    disableUserInputtedTokens: true,\n  },\n};\n\nfunction App() {\n  return <WormholeConnect config={config} />;\n}\n```\n\nSetting `ui.disableUserInputtedTokens` to `true` will disable the ability to paste in token addresses."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 9, "depth": 3, "title": "Transaction Settings {: #transaction-settings }", "anchor": "transaction-settings-transaction-settings", "start_char": 14932, "end_char": 16577, "estimated_token_count": 341, "token_estimator": "heuristic-v1", "text": "### Transaction Settings {: #transaction-settings }\n\nLanding 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.\n\n```jsx\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  transactionSettings: {\n    Solana: {\n      priorityFee: {\n        // Number between 0-1, defaults to 0.9. Higher percentile yields higher fees.\n        // For example, you can set percentile to 0.95 to make Connect compute the\n        // 95th percentile priority fee amount based on recent transactions\n        percentile: 0.95,\n\n        // Any number, defaults to 1.0. The fee amount is multiplied by this number.\n        // This can be used to further raise or lower the fees Connect is using.\n        // For example, percentile=0.95 and percentileMultiple=1.1 would use\n        // the 95th percentile fee, with a 10% increase\n        percentileMultiple: 1.1,\n\n        // Minimum fee you want to use in microlamports, regardless of recent transactions\n        // Defaults to 1\n        min: 200_000,\n\n        // Maximum fee you want to use in microlamports, regardless of recent transactions\n        // Defaults to 100,000,000\n        max: 5_000_000,\n      },\n    },\n  },\n};\n\nfunction App() {\n  return <WormholeConnect config={config} />;\n}\n```\n\n!!! note\n    Connect can calculate fees more accurately if you are using a [Triton](https://triton.one){target=\\_blank} RPC endpoint."}
{"page_id": "products-connect-configuration-data", "page_title": "Connect Data Configuration", "index": 10, "depth": 3, "title": "Wallet Set Up  {: #reown-cloud-project-id }", "anchor": "wallet-set-up-reown-cloud-project-id", "start_char": 16577, "end_char": 17928, "estimated_token_count": 326, "token_estimator": "heuristic-v1", "text": "### Wallet Set Up  {: #reown-cloud-project-id }\n\nYour selected blockchain network determines the available wallet options when using Wormhole Connect.\n\n - For EVM chains, wallets like [MetaMask](https://metamask.io/){target=\\_blank} and [Reown Cloud](https://reown.com/home){target=\\_blank} (formerly WalletConnect) are supported.\n - For Solana, you'll see options such as [Phantom](https://phantom.com/){target=\\_blank}, [Web3Auth](https://wallet.web3auth.io/){target=\\_blank}, and [Coin98](https://coin98.com/){target=\\_blank}.\n\nThe wallet options automatically adjust based on the selected chain, providing a seamless user experience without additional configuration.\n\nTo add Reown Cloud (formerly known as WalletConnect) as a supported wallet option, you need to obtain a project ID from the [Reown Cloud dashboard](https://dashboard.reown.com/){target=\\_blank}. Once you have the project ID, set it in your `WormholeConnectConfig` under the `walletConnectProjectId` property.\n\n```typescript\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst wormholeConfig: config.WormholeConnectConfig = {\n  ...\n  walletConnectProjectId: 'INSERT_PROJECT_ID',\n};\n```\n\n!!! note\n    If the `walletConnectProjectId` is not set, Reown Cloud (WalletConnect) will be disabled from the available wallet list in the Connect UI."}
{"page_id": "products-connect-configuration-theme", "page_title": "Connect Theme & UI Customization", "index": 0, "depth": 2, "title": "Theme & UI Customization", "anchor": "theme-ui-customization", "start_char": 0, "end_char": 289, "estimated_token_count": 60, "token_estimator": "heuristic-v1", "text": "## Theme & UI Customization\n\nThis 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."}
{"page_id": "products-connect-configuration-theme", "page_title": "Connect Theme & UI Customization", "index": 1, "depth": 3, "title": "Changing the Color Scheme", "anchor": "changing-the-color-scheme", "start_char": 289, "end_char": 3000, "estimated_token_count": 611, "token_estimator": "heuristic-v1", "text": "### Changing the Color Scheme\n\nYou can customize Connect's color scheme by providing a `theme` prop.\n\n=== \"React integration\"\n\n    ```ts\n    import WormholeConnect, { type config, WormholeConnectTheme } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      /* Your config... */\n    };\n\n    const theme: WormholeConnectTheme = {\n      mode: 'dark',\n      primary: '#78c4b6',\n      font: 'Comic Sans; sans-serif',\n    };\n\n    function App() {\n      return <WormholeConnect config={config} theme={theme} />;\n    }\n    ```\n\n=== \"Hosted integration\"\n\n    ```ts\n    import WormholeConnect, { type config, WormholeConnectTheme, wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      /* Your config... */\n    };\n\n    const theme: WormholeConnectTheme = {\n      mode: 'dark',\n      primary: '#78c4b6',\n      font: 'Comic Sans; sans-serif',\n    };\n\n    const container = document.getElementById('bridge-container');\n\n    wormholeConnectHosted(container, {\n      config,\n      theme,\n    });\n    ```\n\nThe `WormholeConnectTheme` type supports the following properties:\n\n| <div style=\"width:10em\">Property</div> |                              Description                              |        Example        |\n|:--------------------------------------:|:---------------------------------------------------------------------:|:---------------------:|\n|                 `mode`                 |                 Dark mode or light mode. **Required**                 | `\"dark\"` or `\"light\"` |\n|                `input`                 |                Color used for input fields, dropdowns                 |      `\"#AABBCC\"`      |\n|               `primary`                |                    Primary color used for buttons                     |      `\"#AABBCC\"`      |\n|              `secondary`               |               Secondary color used for some UI elements               |      `\"#AABBCC\"`      |\n|                 `text`                 |                      Primary color used for text                      |      `\"#AABBCC\"`      |\n|            `textSecondary`             |                 Secondary color used for dimmer text                  |      `\"#AABBCC\"`      |\n|                `error`                 |         Color to display errors in, usually some shade of red         |      `\"#AABBCC\"`      |\n|               `success`                |                 Color to display success messages in                  |      `\"#AABBCC\"`      |\n|                 `font`                 | Font used in the UI, can be custom font available in your application | `\"Arial; sans-serif\"` |"}
{"page_id": "products-connect-configuration-theme", "page_title": "Connect Theme & UI Customization", "index": 2, "depth": 3, "title": "Toggle Hamburger Menu {: #toggle-hamburger-menu }", "anchor": "toggle-hamburger-menu-toggle-hamburger-menu", "start_char": 3000, "end_char": 4187, "estimated_token_count": 322, "token_estimator": "heuristic-v1", "text": "### Toggle Hamburger Menu {: #toggle-hamburger-menu }\n\nBy setting the `showHamburgerMenu` option to **false**, you can deactivate the hamburger menu, which will position the links at the bottom.\n\n#### Add Extra Menu Entry {: #add-extra-menu-entry }\n\nBy setting the `showHamburgerMenu` option to `false`, you can add extra links. The following properties are accessed through the `menu[]` property (e.g., `menu[].label`):\n\n| Property |                 Description                 |\n|:--------:|:-------------------------------------------:|\n| `label`  |            Link name to show up             |\n|  `href`  |              Target URL or URN              |\n| `target` | Anchor standard target, by default `_blank` |\n| `order`  | Order where the new item should be injected |\n\n```jsx\nimport WormholeConnect, { type config } from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  ui: {\n    showHamburgerMenu: false,\n    menu: [\n      {\n        label: 'Advance Tools',\n        href: 'https://portalbridge.com',\n        target: '_self',\n        order: 1,\n      },\n    ],\n  },\n};\n\nfunction App() {\n  return <WormholeConnect config={config} />;\n}\n```"}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 0, "depth": 2, "title": "What types of assets does Connect support?", "anchor": "what-types-of-assets-does-connect-support", "start_char": 16, "end_char": 493, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "## What types of assets does Connect support? \n\nConnect supports both native and wrapped assets across all Wormhole-supported blockchains. This includes:\n\n - Major stablecoins like USDT and USDC (via CCTP).\n - Native gas tokens such as ETH, SOL, etc.\n - Cross-chain asset swaps through integrators like Mayan.\n\nWhen bridging assets through Wrapped Token Transfers (WTT), depending on the chain and token, assets may arrive as Wormhole-wrapped tokens on the destination chain."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 1, "depth": 2, "title": "What chains does Connect support?", "anchor": "what-chains-does-connect-support", "start_char": 493, "end_char": 858, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## What chains does Connect support? \n\nConnect supports around 30 chains, spanning various blockchain runtimes:\n\n - EVM-based chains (Ethereum, Base, Arbitrum, BSC, etc.)\n - Solana\n - Move-based chains (Sui, Aptos)\n\nFor a complete list of supported chains, see the [Connect-supported chains list](/docs/products/connect/reference/support-matrix/){target=\\_blank}."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 2, "depth": 2, "title": "What is gas dropoff?", "anchor": "what-is-gas-dropoff", "start_char": 858, "end_char": 1189, "estimated_token_count": 58, "token_estimator": "heuristic-v1", "text": "## What is gas dropoff? \n\nGas 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."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 3, "depth": 2, "title": "Can I customize Connect inside my application?", "anchor": "can-i-customize-connect-inside-my-application", "start_char": 1189, "end_char": 1597, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Can I customize Connect inside my application?\n\nConnect 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}."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 4, "depth": 2, "title": "How can I disable specific routes?", "anchor": "how-can-i-disable-specific-routes", "start_char": 1597, "end_char": 3713, "estimated_token_count": 460, "token_estimator": "heuristic-v1", "text": "## How can I disable specific routes?\n\nUse `isRouteSupportedHandler` in your `WormholeConnectConfig`. The callback runs when Connect evaluates a route for the current selection. If it returns `false`, that exact route is hidden in the widget, so the user cannot select it.\n\nCommon patterns you can implement include:\n\n - Disabling all routes of a given type (`AutomaticTokenBridge` or `ManualTokenBridge`).\n - Disabling routes by token using `fromToken` or `toToken`.\n - Disabling routes by direction using `fromChain` or `toChain`.\n\n**Example: Disable all `AutomaticTokenBridge` routes**\n\n```typescript\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  // ...\n  isRouteSupportedHandler: async ({ route }) => {\n    if (route === 'AutomaticTokenBridge') {\n      return false;\n    }\n    return true; // keep other routes visible\n  },\n};\n```\n\n**Example: Disable a specific route for a particular token**\n\n```typescript\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst BLOCKED_ADDRESSES = new Set<string>(['INSERT_TOKEN_ADDRESS']);\n\nconst config: config.WormholeConnectConfig = {\n  // ...\n  isRouteSupportedHandler: async ({ route, fromToken }) => {\n    const tokenAddress =\n      fromToken.tokenId !== 'native' ? fromToken.tokenId.address : 'native';\n\n    if (\n      BLOCKED_ADDRESSES.has(tokenAddress) &&\n      route === 'AutomaticTokenBridge'\n    ) {\n      return false;\n    }\n    return true; // keep other routes visible\n  },\n};\n```\n\n**Example: Disable `AutomaticTokenBridge` from a specific chain**\n\n```typescript\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst BLOCKED_SOURCE_CHAINS = new Set<Chain>(['INSERT_CHAIN_NAME']);\n\nconst config: config.WormholeConnectConfig = {\n  // ...\n  isRouteSupportedHandler: async ({ route, fromChain }) => {\n    if (\n      BLOCKED_SOURCE_CHAINS.has(fromChain) &&\n      route === 'AutomaticTokenBridge'\n    ) {\n      return false;\n    }\n    return true; // keep other routes visible\n  },\n};\n```"}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 5, "depth": 2, "title": "How can I hide specific tokens from the picker?", "anchor": "how-can-i-hide-specific-tokens-from-the-picker", "start_char": 3713, "end_char": 4468, "estimated_token_count": 170, "token_estimator": "heuristic-v1", "text": "## How can I hide specific tokens from the picker?\n\nUse `isTokenSupportedHandler` in your `WormholeConnectConfig`. The callback runs for each token candidate; if it returns `false`, that token is not shown in the picker and can't be selected.\n\n**Example: Hide a token by address**\n\n```typescript\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst BLOCKED_ADDRESSES = new Set<string>(['INSERT_TOKEN_ADDRESS']);\n\nconst config: config.WormholeConnectConfig = {\n  // ...\n  isTokenSupportedHandler: (token) => {\n    // Address string provided by Connect\n    const addr = token.addressString;\n\n    if (addr && BLOCKED_ADDRESSES.has(addr)) {\n      return false;\n    }\n    return true; // show all others\n  },\n};\n```"}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 6, "depth": 2, "title": "Which functions or events does Connect rely on for NTT integration?", "anchor": "which-functions-or-events-does-connect-rely-on-for-ntt-integration", "start_char": 4468, "end_char": 4831, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "## Which functions or events does Connect rely on for NTT integration? \n\nConnect 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."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 7, "depth": 2, "title": "Do integrators need to enable wallets like Phantom or Backpack in Connect?", "anchor": "do-integrators-need-to-enable-wallets-like-phantom-or-backpack-in-connect", "start_char": 4831, "end_char": 5113, "estimated_token_count": 55, "token_estimator": "heuristic-v1", "text": "## Do integrators need to enable wallets like Phantom or Backpack in Connect?\n\nIntegrators 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."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 8, "depth": 2, "title": "Which function should be modified to set priority fees for Solana transactions?", "anchor": "which-function-should-be-modified-to-set-priority-fees-for-solana-transactions", "start_char": 5113, "end_char": 5968, "estimated_token_count": 181, "token_estimator": "heuristic-v1", "text": "## Which function should be modified to set priority fees for Solana transactions?\n\nIn [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.\n\nTo control the priority fee applied to your transactions, you can modify the `feePercentile` and `minPriorityFee` parameters in the `addComputeBudget` and `determineComputeBudget` functions.\n\nThe 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}."}
{"page_id": "products-connect-faqs", "page_title": "Connect FAQs", "index": 9, "depth": 2, "title": "Is there a minimum amount for bridging with CCTP or the Connect SDK?", "anchor": "is-there-a-minimum-amount-for-bridging-with-cctp-or-the-connect-sdk", "start_char": 5968, "end_char": 7369, "estimated_token_count": 338, "token_estimator": "heuristic-v1", "text": "## Is there a minimum amount for bridging with CCTP or the Connect SDK?\n\nThere 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.\n\nCurrent relay fees:\n\n- **Ethereum L1**: ~4.2 USDC\n- **Base, Optimism, Arbitrum, Avalanche**: 0.3 USDC\n\nAdditional notes:\n\n- **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.\n- **Frontend integrations**:\n    - **Connect**: A pre-built UI available via [@wormhole-foundation/wormhole-connect](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\\_blank}.\n    - **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.\n\n        !!!note\n            The TypeScript SDK was previously referred to as the \"Connect SDK,\" but this naming has since been discontinued."}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 0, "depth": 2, "title": "Install Connect", "anchor": "install-connect", "start_char": 358, "end_char": 595, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "## Install Connect\n\nTo install the [Wormhole Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\\_blank}, run the following command:\n\n```bash\nnpm i @wormhole-foundation/wormhole-connect\n```"}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 595, "end_char": 1013, "estimated_token_count": 120, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, make sure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n\n- (Optional) To test a transfer from your demo app, you'll need:\n\n    - A wallet with [Sui testnet tokens](https://faucet.sui.io/){target=\\_blank}.\n    - A wallet with an Avalanche Fuji address (to use as the recipient; no tokens required)."}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 2, "depth": 2, "title": "Install and Set Up Project", "anchor": "install-and-set-up-project", "start_char": 1013, "end_char": 1618, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Install and Set Up Project\n\n1. Clone the demo repository and navigate to the project directory:\n\n    ```bash\n    git clone https://github.com/wormhole-foundation/demo-basic-connect.git\n    cd demo-basic-connect\n    ```\n\n2. Install the dependencies. This example uses the Connect version `5.1.1`:\n\n    ```bash\n    npm install\n    ```\n\n3. Start the application:\n\n    ```bash\n    npm start\n    ```\n\n4. Open your browser to `http://localhost:3000` to view the application locally.\n\n    ![Deployed Connect Widget](/docs/images/products/connect/tutorials/react-dapp/get-started/connect-get-started-01.webp)"}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 3, "depth": 2, "title": "Configure Connect", "anchor": "configure-connect", "start_char": 1618, "end_char": 3008, "estimated_token_count": 354, "token_estimator": "heuristic-v1", "text": "## Configure Connect\n\nOpen the `App.tsx` file in your code editor of choice. You will see code similar to the following:\n\n```typescript title=\"App.tsx\"\nimport './App.css';\nimport WormholeConnect, { type config, WormholeConnectTheme } from '@wormhole-foundation/wormhole-connect';\n\nfunction App() {\n  const config: config.WormholeConnectConfig = {\n    // Define the network\n    network: 'Testnet',\n\n    // Define the chains\n    chains: ['Sui', 'Avalanche'],\n\n    // UI configuration\n    ui: {\n      title: 'SUI Connect TS Demo',\n    },\n  };\n\n  const theme: WormholeConnectTheme = {\n    // Define the theme\n    mode: 'dark',\n    primary: '#78c4b6',\n  };\n\n  return <WormholeConnect config={config} theme={theme} />;\n}\n\nexport default App;\n```\n\nThe preceding sample code configures Connect by setting values inside `config` and `theme` as follows:\n\n- **Defines the network**: Options include `Mainnet`, `Testnet`, or `Devnet`.\n- **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.\n- **Adds a title to UI**: (Optional) If defined, it will render above the widget in the UI.\n- **Defines the theme**: This example sets the mode to `dark` and adds a primary color."}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 4, "depth": 2, "title": "Interact with Connect", "anchor": "interact-with-connect", "start_char": 3008, "end_char": 3244, "estimated_token_count": 42, "token_estimator": "heuristic-v1", "text": "## Interact with Connect\n\nCongratulations! 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."}
{"page_id": "products-connect-get-started", "page_title": "Get Started with Connect", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3244, "end_char": 4469, "estimated_token_count": 303, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nUse the following guides to configure your Connect instance and integrate it into your application.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Data Configuration**\n\n    ---\n\n    Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more.\n\n    [:custom-arrow: View Data Configs](/docs/products/connect/configuration/data/)\n\n-   :octicons-tools-16:{ .lg .middle } **Theme Configuration**\n\n    ---\n\n    Learn how to customize Connect's look and feel to match your application's branding.\n\n    [:custom-arrow: View Theme Configs](/docs/products/connect/configuration/theme/)\n\n-   :octicons-book-16:{ .lg .middle } **Integrate Connect into a React DApp**\n\n    ---\n\n    Learn how to integrate Connect into a React application, including setting up the widget and handling transfers.\n\n    [:custom-arrow: Get Started](/docs/products/connect/tutorials/react-dapp/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-connect-guides-hosted-version", "page_title": "Integrate Connect via CDN", "index": 0, "depth": 2, "title": "Install Connect", "anchor": "install-connect", "start_char": 624, "end_char": 852, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "## Install Connect\n\nTo install the [Connect npm package](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\\_blank}, run the following command:\n\n```bash\nnpm i @wormhole-foundation/wormhole-connect\n```"}
{"page_id": "products-connect-guides-hosted-version", "page_title": "Integrate Connect via CDN", "index": 1, "depth": 2, "title": "Add Connect to Your Project Using the Hosted Version", "anchor": "add-connect-to-your-project-using-the-hosted-version", "start_char": 852, "end_char": 1945, "estimated_token_count": 247, "token_estimator": "heuristic-v1", "text": "## Add Connect to Your Project Using the Hosted Version\n\nThe 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:\n\n```js\nimport { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect';\n\n// Existing DOM element where you want to mount Connect\nconst container = document.getElementById('bridge-container');\nif (!container) {\n  throw new Error(\"Element with id 'bridge-container' not found\");\n}\n\nwormholeConnectHosted(container);\n```\n\nYou can provide config and theme parameters in a second function argument:\n\n```js\nimport { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect';\n\n// Existing DOM element where you want to mount Connect\nconst container = document.getElementById('bridge-container');\nif (!container) {\n  throw new Error(\"Element with id 'connect' not found\");\n}\n\nwormholeConnectHosted(container, {\n  config: {\n    rpcs: {\n      // ...\n    },\n  },\n  theme: {\n    background: {\n      default: '#004547',\n    },\n  },\n});\n```"}
{"page_id": "products-connect-guides-hosted-version", "page_title": "Integrate Connect via CDN", "index": 2, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 1945, "end_char": 2596, "estimated_token_count": 160, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nUse the following guides to configure your Connect instance.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Data Configuration**\n\n    ---\n\n    Learn how to specify custom networks and RPC endpoints, integrate different bridging protocols, add new tokens, and more.\n\n    [:custom-arrow: View Data Configs](/docs/products/connect/configuration/data/)\n\n-   :octicons-tools-16:{ .lg .middle } **Theme Configuration**\n\n    ---\n\n    Learn how to customize Connect's look and feel to match your application's branding.\n\n    [:custom-arrow: View Theme Configs](/docs/products/connect/configuration/theme/)\n\n</div>"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 0, "depth": 2, "title": "V5 to V6 {: #v5-to-v6 }", "anchor": "v5-to-v6-v5-to-v6", "start_char": 492, "end_char": 1061, "estimated_token_count": 148, "token_estimator": "heuristic-v1", "text": "## V5 to V6 {: #v5-to-v6 }\n\nWormhole Connect v6 removes the legacy \"automatic\" routes in favor of [Executor](/docs/products/messaging/guides/executor/)-powered replacements. **Most integrators need no code changes** - default usage and `DEFAULT_ROUTES` are wired to the new routes automatically.\n\nThe breaking change was introduced in [PR #4025](https://github.com/wormhole-foundation/wormhole-connect/pull/4025){target=\\_blank}. See the full [v6 release notes](https://github.com/wormhole-foundation/wormhole-connect/releases){target=\\_blank} for additional context."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 1, "depth": 3, "title": "Route Replacements", "anchor": "route-replacements", "start_char": 1061, "end_char": 1719, "estimated_token_count": 151, "token_estimator": "heuristic-v1", "text": "### Route Replacements\n\n| Removed | Replacement |\n|---|---|\n| `AutomaticCCTPRoute` | `cctpV2FastExecutorRoute()`, `cctpV2StandardExecutorRoute()` |\n| `AutomaticTokenBridgeRoute`, `TokenBridgeRoute` | `executorTokenBridgeRoute()` |\n| `nttAutomaticRoute` | `nttExecutorRoute` |\n\nRoute name strings (used in `filterRoutes`, telemetry):\n\n| Old | New |\n|---|---|\n| `AutomaticCCTP` | `CCTPV2FastExecutorRoute`, `CCTPV2StandardExecutorRoute` |\n| `AutomaticTokenBridge` | `TokenBridgeExecutorRoute` |\n| `AutomaticNtt` | `NttExecutorRoute` |\n\n**Unchanged**: `CCTPRoute`, `TBTCRoute`, `nttManualRoute`, `nttExecutorRoute`, `nttRoutes`, and all Mayan and LiFi routes."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 2, "depth": 3, "title": "When You Need to Change Code", "anchor": "when-you-need-to-change-code", "start_char": 1719, "end_char": 2294, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### When You Need to Change Code\n\nYou only need changes if you:\n\n- Import any removed route by name.\n- Build a custom `routes: [...]` array using a removed route.\n- Compare against old route name strings (in `filterRoutes`, telemetry handlers, etc.).\n\nDefault usage (`<WormholeConnect />` with no `routes` config) and `DEFAULT_ROUTES` are wired to the new routes automatically.\n\n!!! tip \"Note\"\n    The new Executor routes are **factory functions** - invoke them with `()` when adding to a `routes` array. The legacy automatic routes were class constructors passed directly."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 3, "depth": 3, "title": "Update the Connect Package", "anchor": "update-the-connect-package", "start_char": 2294, "end_char": 2419, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "### Update the Connect Package\n\nInstall the v6 release:\n\n```bash\nnpm install @wormhole-foundation/wormhole-connect@^6.0\n```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 4, "depth": 3, "title": "`DEFAULT_ROUTES` Has Been Updated", "anchor": "default_routes-has-been-updated", "start_char": 2419, "end_char": 3045, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "### `DEFAULT_ROUTES` Has Been Updated\n\nThe default route set used when integrators don't specify a `routes` array now uses Executor-based routes:\n\n=== \"v5.x\"\n\n    ```typescript\n    DEFAULT_ROUTES = [\n      AutomaticCCTPRoute,\n      CCTPRoute,\n      AutomaticTokenBridgeRoute,\n      TokenBridgeRoute,\n      TBTCRoute,\n    ];\n    ```\n\n=== \"v6.x\"\n\n    ```typescript\n    DEFAULT_ROUTES = [\n      cctpV2FastExecutorRoute(),\n      cctpV2StandardExecutorRoute(),\n      CCTPRoute,\n      executorTokenBridgeRoute(),\n      TBTCRoute,\n    ];\n    ```\n\nIf you rely on `DEFAULT_ROUTES` without overriding it, no code changes are required."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 5, "depth": 3, "title": "Update Custom `routes` Arrays", "anchor": "update-custom-routes-arrays", "start_char": 3045, "end_char": 3918, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "### Update Custom `routes` Arrays\n\nIf you pass a custom `routes` array, replace removed routes with their Executor equivalents and remember to invoke the new factory functions with `()`:\n\n=== \"v5.x\"\n\n    ```typescript\n    import {\n      AutomaticCCTPRoute,\n      CCTPRoute,\n      AutomaticTokenBridgeRoute,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config = {\n      routes: [AutomaticCCTPRoute, CCTPRoute, AutomaticTokenBridgeRoute],\n    };\n    ```\n\n=== \"v6.x\"\n\n    ```typescript\n    import {\n      cctpV2FastExecutorRoute,\n      cctpV2StandardExecutorRoute,\n      CCTPRoute,\n      executorTokenBridgeRoute,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config = {\n      routes: [\n        cctpV2FastExecutorRoute(),\n        cctpV2StandardExecutorRoute(),\n        CCTPRoute,\n        executorTokenBridgeRoute(),\n      ],\n    };\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 6, "depth": 3, "title": "Update NTT Routes", "anchor": "update-ntt-routes", "start_char": 3918, "end_char": 4470, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### Update NTT Routes\n\nIf you use the `nttRoutes(...)` helper, no changes are needed. Otherwise, swap `nttAutomaticRoute` for `nttExecutorRoute`:\n\n=== \"v5.x\"\n\n    ```typescript\n    import { nttAutomaticRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\n    const config = {\n      routes: [nttAutomaticRoute(myNttConfig)],\n    };\n    ```\n\n=== \"v6.x\"\n\n    ```typescript\n    import { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\n    const config = {\n      routes: [nttExecutorRoute({ ntt: myNttConfig })],\n    };\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 7, "depth": 2, "title": "V0/V1/V2 to V3 {: #v0-v1-v2-to-v3 }", "anchor": "v0v1v2-to-v3-v0-v1-v2-to-v3", "start_char": 4470, "end_char": 5403, "estimated_token_count": 201, "token_estimator": "heuristic-v1", "text": "## V0/V1/V2 to V3 {: #v0-v1-v2-to-v3 }\n\nThe Wormhole Connect feature has been updated to **version 3.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.\n\nThis 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:\n\n - Update to the latest Connect package.\n - Apply configuration changes to the `WormholeConnectConfig` object.\n - Understand new routing capabilities and plugin options.\n\nThese updates ensure better performance and a smoother integration experience.\n\n!!! tip \"Note\"\n    Connect versions v1.x and v2.x share the same configuration structure. This guide outlines a unified upgrade process to v3.x, regardless of whether you're using v0.x, v1.x, or v2.x."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 8, "depth": 2, "title": "Update the Connect Package", "anchor": "update-the-connect-package-2", "start_char": 5403, "end_char": 6018, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "## Update the Connect Package\n\nTo begin the migration process, update the Connect [**npm package**](https://www.npmjs.com/package/@wormhole-foundation/wormhole-connect){target=\\_blank} to the latest version 3.0. Updating to the latest version provides access to the newest features and improvements, including the modernized design and enhanced routing capabilities.\n\nRun the following command in your terminal:\n\n```bash\nnpm install @wormhole-foundation/wormhole-connect@^3.0\n```\n\nThis command installs the latest stable version of Wormhole Connect and prepares your environment for the new configuration changes."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 9, "depth": 2, "title": "Update the `WormholeConnectConfig` Object", "anchor": "update-the-wormholeconnectconfig-object", "start_char": 6018, "end_char": 6289, "estimated_token_count": 52, "token_estimator": "heuristic-v1", "text": "## Update the `WormholeConnectConfig` Object\n\nIn version 3.0, the `config.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."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 10, "depth": 3, "title": "Summary of Breaking Changes", "anchor": "summary-of-breaking-changes", "start_char": 6289, "end_char": 6943, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "### Summary of Breaking Changes\n\n- Chain names are now capitalized. For example:`solana` → `Solana`.\n- `env` renamed to `network` and is now capitalized. For example: `mainnet` → `Mainnet`.\n- `networks` renamed to `chains`, with capitalized names.\n- `routes` updated to use route plugins.\n- `nttGroups` removed in favor of route plugin configuration.\n- `tokensConfig` updated, with a new key `wrappedTokens` added.\n- Many UI-related properties consolidated under a top-level `ui` key.\n- `customTheme` and `mode` were removed, replaced by a top-level `theme` property.\n\nThese changes are explained in more detail below, with examples for easy reference."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 11, "depth": 3, "title": "Capitalize Chain Names", "anchor": "capitalize-chain-names", "start_char": 6943, "end_char": 8334, "estimated_token_count": 324, "token_estimator": "heuristic-v1", "text": "### Capitalize Chain Names\n\nIn version 3.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`.\n\n=== \"v0.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      rpcs: {\n        ethereum: 'INSERT_ETH_RPC_URL',\n        solana: 'INSERT_SOLANA_RPC_URL',\n      },\n    };\n    ```\n\n=== \"v1.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      rpcs: {\n        Ethereum: 'INSERT_ETH_RPC_URL',\n        Solana: 'INSERT_SOLANA_RPC_URL',\n      },\n    };\n    ```\n\n=== \"v3.x\"\n\n    ```typescript\n    import { type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      rpcs: {\n        Ethereum: 'INSERT_ETH_RPC_URL',\n        Solana: 'INSERT_SOLANA_RPC_URL',\n      },\n    };\n    ```\n\nYou can find the complete list of supported chain names in the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/base/src/constants/chains.ts#L6-L71){target=\\_blank}."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 12, "depth": 3, "title": "Rename `env` to `network`", "anchor": "rename-env-to-network", "start_char": 8334, "end_char": 9462, "estimated_token_count": 274, "token_estimator": "heuristic-v1", "text": "### Rename `env` to `network`\n\nThe `env` property has been renamed to `network`, with capitalized values. This change affects how you configure Testnet and Mainnet environments.\n\n=== \"v0.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      env: 'testnet',\n    };\n    ```\n\n=== \"v1.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      network: 'Testnet',\n    };\n    ```\n\n=== \"v3.x\"\n\n    ```typescript\n    import { type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      network: 'Testnet',\n    };\n    ```\n\nIf you don’t explicitly set the `network` value, Connect will default to `Mainnet`.\n\n```typescript\n// Defaults to Mainnet\nconst config: config.WormholeConnectConfig = {};\n```\n\nFor 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}."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 13, "depth": 3, "title": "Rename `networks` to `chains`", "anchor": "rename-networks-to-chains", "start_char": 9462, "end_char": 10253, "estimated_token_count": 192, "token_estimator": "heuristic-v1", "text": "### Rename `networks` to `chains`\n\nThe `networks` property, which allowed whitelisting chains, is now renamed `chains`, and the chain names are capitalized.\n\n=== \"v0.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      networks: ['solana', 'ethereum'],\n    };\n    ```\n=== \"v1.x\"\n\n    ```typescript\n    import { WormholeConnectConfig } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      chains: ['Solana', 'Ethereum'],\n    };\n    ```\n=== \"v3.x\"\n\n    ```typescript\n    import { type config } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      chains: ['Solana', 'Ethereum'],\n    };\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 14, "depth": 3, "title": "Update `routes` to Use Route Plugins", "anchor": "update-routes-to-use-route-plugins", "start_char": 10253, "end_char": 14505, "estimated_token_count": 979, "token_estimator": "heuristic-v1", "text": "### Update `routes` to Use Route Plugins\n\nThe `routes` property in Connect version 3.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.\n\nBy default, if no `routes` property is set, Connect will provide routes for two core protocols:\n\n - [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}\n - [CCTP](/docs/products/cctp-bridge/overview/){target=\\_blank}\n\nFor 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.\n\n#### Available `route` Plugins\n\nThe `@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:\n\n???- tip \"`route` Plugins\"\n    - **`TokenBridgeRoute`**: Manually redeemed WTT route.\n    - **`AutomaticTokenBridgeRoute`**: Automatically redeemed (relayed) WTT route.\n    - **`CCTPRoute`**: Manually redeemed CCTP route.\n    - **`AutomaticCCTPRoute`**: Automatically redeemed (relayed) CCTP route.\n    - **`DEFAULT_ROUTES`**: Array containing the four preceding routes (TokenBridgeRoute, AutomaticTokenBridgeRoute, CCTPRoute, AutomaticCCTPRoute).\n    - **`nttAutomaticRoute(nttConfig)`**: Function that returns the automatically-redeemed (relayed) Native Token Transfer (NTT) route.\n    - **`nttManualRoute(nttConfig)`**: Function that returns the manually-redeemed NTT route.\n    - **`nttExecutorRoute(nttConfig)`**: Function that returns the Executor-powered NTT route for one-click transfers.\n    - **`MayanRoute`**: Route that offers multiple Mayan protocols.\n    - **`MayanRouteSWIFT`**: Route for Mayan’s Swift protocol only.\n    - **`MayanRouteMCTP`**: Route for Mayan’s MCTP protocol only.\n    - **`MayanRouteWH`**: Route for Mayan’s original Wormhole transfer protocol.\n\nIn 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.\n\nFor 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}.\n\nNow that you know the available `route` plugins, let's explore some examples of configuring them.\n\n#### Example: Offer Only CCTP Transfers\n\nTo configure Connect to offer only USDC transfers via the CCTP route, use the following configuration:\n\n```typescript\nimport WormholeConnect, {\n  AutomaticCCTPRoute,\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  routes: [AutomaticCCTPRoute],\n};\n\n<WormholeConnect config={config} />;\n```\n\n#### Example: Offer All Default Routes and Third-Party Plugins\n\nIn this example, Connect is configured with routes for both default protocols (WTT and CCTP), as well as third-party protocols like [Native Token Transfers (NTT)](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank} and [Mayan Swap](https://swap.mayan.finance/){target=\\_blank}.\n\n```typescript\nimport WormholeConnect, {\n  DEFAULT_ROUTES,\n  MayanRouteSWIFT,\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\nimport { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\nimport { myNttConfig } from './consts'; // Custom NTT configuration\n\nconst config: config.WormholeConnectConfig = {\n  routes: [...DEFAULT_ROUTES, nttExecutorRoute({ ntt: myNttConfig }), MayanRouteSWIFT],\n};\n\n<WormholeConnect config={config} />;\n```\n\nThis flexible plugin allows you to combine default routes (such as WTT and CCTP) with third-party protocols, offering complete control over which routes are available in your application."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 15, "depth": 3, "title": "Update the `tokensConfig` Structure", "anchor": "update-the-tokensconfig-structure", "start_char": 14505, "end_char": 18631, "estimated_token_count": 769, "token_estimator": "heuristic-v1", "text": "### Update the `tokensConfig` Structure\n\nIn Connect version 3.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.\n\nKey Changes to `tokensConfig`:\n\n - **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.\n - **`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 WTT routes.\n - **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.\n\n=== \"v0.x\"\n\n    In the old structure, the `foreignAssets` field defined the token’s presence on other chains, and `decimals` were mapped across multiple chains.\n\n    ```typescript\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      tokensConfig: {\n        WETH: {\n          key: 'WETH',\n          symbol: 'WETH',\n          nativeChain: 'ethereum',\n          icon: Icon.ETH,\n          tokenId: {\n            chain: 'ethereum',\n            address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n          },\n          coinGeckoId: 'ethereum',\n          color: '#62688F',\n          decimals: { Ethereum: 18, default: 8 },\n          foreignAssets: {\n            Solana: {\n              address: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',\n              decimals: 8,\n            },\n          },\n        },\n      },\n    };\n    ```\n\n=== \"v1.x\"\n\n    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.\n\n    ```typescript\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      tokensConfig: {\n        WETH: {\n          key: 'WETH',\n          symbol: 'WETH',\n          nativeChain: 'Ethereum', // Chain name now capitalized\n          icon: Icon.ETH,\n          tokenId: {\n            chain: 'Ethereum',\n            address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n          },\n          coinGeckoId: 'ethereum',\n          color: '#62688F',\n          decimals: 18, // Simplified decimals field\n        },\n      },\n      wrappedTokens: {\n        WETH: {\n          Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',\n          /* additional chains */\n        },\n      },\n    };\n    ```\n\n=== \"v3.x\"\n\n    In v3.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.\n\n    ```typescript\n    import WormholeConnect, {\n      type config,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: config.WormholeConnectConfig = {\n      tokensConfig: {\n        WETH: {\n          key: 'WETH',\n          symbol: 'WETH',\n          nativeChain: 'Ethereum', // Chain name now capitalized\n          icon: Icon.ETH,\n          tokenId: {\n            chain: 'Ethereum',\n            address: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',\n          },\n          coinGeckoId: 'ethereum',\n          color: '#62688F',\n          decimals: 18, // Simplified decimals field\n        },\n      },\n      wrappedTokens: {\n        WETH: {\n          Solana: '7vfCXTUXx5WJV5JADk17DUJ4ksgau7utNKj4b963voxs',\n          /* additional chains */\n        },\n      },\n    };\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 16, "depth": 3, "title": "Update NTT Configuration", "anchor": "update-ntt-configuration", "start_char": 18631, "end_char": 23809, "estimated_token_count": 776, "token_estimator": "heuristic-v1", "text": "### Update NTT Configuration\n\nIn Connect version 3.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.\n\nKey changes:\n\n - **Removed `nttGroups`**: The `nttGroups` property has been removed from the configuration and is now passed as an argument to the `nttExecutorRoute` function.\n - **Direct NTT route configuration**: NTT routes are now defined more explicitly, allowing for a more organized structure when specifying tokens, chains, and managers.\n\nThis change simplifies the configuration process by providing a cleaner, more flexible way to handle NTT routes across different chains.\n\n=== \"v0.x\"\n\n    In the previous version, `nttGroups` defined the NTT managers and transceivers for different tokens across multiple chains.\n\n    ```typescript\n    import WormholeConnect, {\n      nttRoutes,\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      nttGroups: {\n        Lido_wstETH: {\n          nttManagers: [\n            {\n              chainName: 'ethereum',\n              address: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9',\n              tokenKey: 'wstETH',\n              transceivers: [\n                {\n                  address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0',\n                  type: 'wormhole',\n                },\n              ],\n            },\n            {\n              chainName: 'bsc',\n              address: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278',\n              tokenKey: 'wstETH',\n              transceivers: [\n                {\n                  address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986',\n                  type: 'wormhole',\n                },\n              ],\n            },\n          ],\n        },\n      },\n    };\n    ```\n\n=== \"v1.x\"\n\n    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.\n\n    ```typescript\n    import WormholeConnect, {\n      nttRoutes,\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      routes: [\n        ...nttRoutes({\n          tokens: {\n            Lido_wstETH: [\n              {\n                chain: 'Ethereum',\n                manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9',\n                token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',\n                transceiver: [\n                  {\n                    address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0',\n                    type: 'wormhole',\n                  },\n                ],\n              },\n              {\n                chain: 'Bsc',\n                manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278',\n                token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C',\n                transceiver: [\n                  {\n                    address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986',\n                    type: 'wormhole',\n                  },\n                ],\n              },\n            ],\n          },\n        }),\n        /* other routes */\n      ],\n    };\n    ```\n\n=== \"v3.x\"\n\n    In v3.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 `nttExecutorRoute` configuration.\n\n    ```typescript\n    import WormholeConnect, {\n      type config,\n    } from '@wormhole-foundation/wormhole-connect';\n    import { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\n    const config: config.WormholeConnectConfig = {\n      routes: [\n        nttExecutorRoute({\n          ntt: {\n            tokens: {\n              Lido_wstETH: [\n                {\n                  chain: 'Ethereum',\n                  manager: '0xb948a93827d68a82F6513Ad178964Da487fe2BD9',\n                  token: '0x7f39C581F595B53c5cb19bD0b3f8dA6c935E2Ca0',\n                  transceiver: [\n                    {\n                      address: '0xA1ACC1e6edaB281Febd91E3515093F1DE81F25c0',\n                      type: 'wormhole',\n                    },\n                  ],\n                },\n                {\n                  chain: 'Bsc',\n                  manager: '0x6981F5621691CBfE3DdD524dE71076b79F0A0278',\n                  token: '0x26c5e01524d2E6280A48F2c50fF6De7e52E9611C',\n                  transceiver: [\n                    {\n                      address: '0xbe3F7e06872E0dF6CD7FF35B7aa4Bb1446DC9986',\n                      type: 'wormhole',\n                    },\n                  ],\n                },\n              ],\n            },\n          },\n        }),\n        /* other routes */\n      ],\n    };\n    ```\n\n    In this new structure, NTT routes are passed directly through the `nttExecutorRoute` function, with the `token`, `chain`, `manager` and `transceiver` clearly defined for each supported asset."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 17, "depth": 3, "title": "Update UI Configuration", "anchor": "update-ui-configuration", "start_char": 23809, "end_char": 28873, "estimated_token_count": 1128, "token_estimator": "heuristic-v1", "text": "### Update UI Configuration\n\nIn Connect version 3.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.\n\nKey UI changes:\n\n - **Consolidated UI properties**: Many UI-related properties moved under a new top-level ui key for better organization.\n - **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.\n\n#### UI Properties\n\nThe following properties that were previously defined at the root level of the configuration are now part of the `ui` key:\n\n - **`explorer` → `ui.explorer`**: Specifies the explorer to use for viewing transactions.\n - **`bridgeDefaults` → `ui.defaultInputs`**: Sets default input values for the bridge, such as the source and destination chains and token.\n - **`pageHeader` → `ui.pageHeader`**: Sets the title and header for the page.\n - **`menu` → `ui.menu`**: Defines the menu items displayed in the interface.\n - **`searchTx` → `ui.searchTx`**: Configures the transaction search functionality.\n - **`partnerLogo` → `ui.partnerLogo`**: Displays a partner's logo on the interface.\n - **`walletConnectProjectId` → `ui.walletConnectProjectId`**: Integrates WalletConnect into the UI.\n - **`showHamburgerMenu` → `ui.showHamburgerMenu`**: Enables or disables the hamburger menu for navigation.\n\nAdditionally, there are two new properties under `ui`:\n\n - **`ui.title`**: Sets the title rendered in the top left corner of the UI. The default is \"Wormhole Connect\".\n - **`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.\n\n```typescript\nimport WormholeConnect, {\n  type config,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst config: config.WormholeConnectConfig = {\n  ui: {\n    title: 'My Custom Bridge Example',\n    getHelpUrl: 'https://examplehelp.com/',\n    menu: [\n      {\n        label: 'Support',\n        href: 'https://examplehelp.com/support',\n        target: '_blank',\n        order: 1, // Order of appearance in the menu\n      },\n      {\n        label: 'About',\n        href: 'https://examplehelp.com/about',\n        target: '_blank',\n        order: 2,\n      },\n    ],\n    showHamburgerMenu: false,\n  },\n};\n```\n\n#### UI Configuration\n\nIn the old structure, UI-related settings like `explorer` and `bridgeDefaults` were defined at the root level of the configuration. In version 3.0, these properties are now organized under the `ui` key, improving the configuration's readability and manageability.\n\n=== \"v0.x\"\n\n    ```typescript\n    \n    const config: WormholeConnectConfig = {\n      bridgeDefaults: {\n        fromNetwork: 'solana',\n        toNetwork: 'ethereum',\n        tokenKey: 'USDC',\n        requiredNetwork: 'solana',\n      },\n      showHamburgerMenu: true,\n    };\n    ```\n\n=== \"v1.x\"\n\n    ```typescript\n    const config: WormholeConnectConfig = {\n      ui: {\n        defaultInputs: {\n          fromChain: 'Solana', // Chain names now capitalized\n          toChain: 'Ethereum',\n          tokenKey: 'USDC',\n          requiredChain: 'Solana',\n        },\n        showHamburgerMenu: true,\n      },\n    };\n    ```\n\n=== \"v3.x\"\n\n    ```typescript\n    const config: config.WormholeConnectConfig = {\n      ui: {\n        defaultInputs: {\n          fromChain: 'Solana', // Chain names now capitalized\n          toChain: 'Ethereum',\n          tokenKey: 'USDC',\n          requiredChain: 'Solana',\n        },\n        showHamburgerMenu: true,\n      },\n    };\n    ```\n\n#### Remove `customTheme` and `mode` Properties\n\nIn version 3.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.\n\nImportant details:\n\n - The `theme` prop is not part of the `config` object and is passed separately to Connect.\n - `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.\n\n=== \"v0.x\"\n\n    ```typescript\n    import WormholeConnect, {\n      WormholeConnectConfig,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const config: WormholeConnectConfig = {\n      customTheme: {\n        primaryColor: '#4266f5',\n        secondaryColor: '#ff5733',\n      },\n      mode: 'dark',\n    };\n\n    <WormholeConnect config={config} />;\n    ```\n\n=== \"^v1.x\" \n\n    ```typescript\n    import WormholeConnect, {\n      WormholeConnectTheme,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    const theme: WormholeConnectTheme = {\n      mode: 'dark', // Can be dynamically changed\n      font: 'Arial',\n      button: {\n        primary: '#4266f5',\n      },\n    };\n\n    <WormholeConnect config={config} theme={theme} />;\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 18, "depth": 3, "title": "Removed Configuration Properties", "anchor": "removed-configuration-properties", "start_char": 28873, "end_char": 29412, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "### Removed Configuration Properties\n\nSeveral configuration properties have been removed in Connect version 3.0. These keys no longer have any effect, and providing values for them in the configuration will not result in any changes.\n\nRemoved config keys:\n\n - `cta`\n - `cctpWarning`\n - `pageSubHeader`\n - `moreTokens`\n - `moreChains`\n - `ethBridgeMaxAmount`\n - `wstETHBridgeMaxAmount`\n - `customTheme`\n - `mode`\n\nIf your current setup includes any of these properties, you can safely remove them, as they are no longer supported in v3.0."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 19, "depth": 2, "title": "Use the CDN-Hosted Version of Wormhole Connect", "anchor": "use-the-cdn-hosted-version-of-wormhole-connect", "start_char": 29412, "end_char": 29690, "estimated_token_count": 52, "token_estimator": "heuristic-v1", "text": "## Use the CDN-Hosted Version of Wormhole Connect\n\nFor 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."}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 20, "depth": 3, "title": "Install and Integrate the Hosted Version", "anchor": "install-and-integrate-the-hosted-version", "start_char": 29690, "end_char": 30167, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### Install and Integrate the Hosted Version\n\n1. Install the Connect package via npm:\n\n    ```bash\n    npm install @wormhole-foundation/wormhole-connect@^3.0\n    ```\n\n2. After installing the package, you can embed Connect into your page by adding the following code:\n\n    ```typescript\n    import { wormholeConnectHosted } from '@wormhole-foundation/wormhole-connect';\n\n    const container = document.getElementById('connect')!;\n\n    wormholeConnectHosted(container);\n    ```"}
{"page_id": "products-connect-guides-upgrade", "page_title": "Wormhole Connect Migration Guides", "index": 21, "depth": 3, "title": "Example: Custom Configuration for Hosted Version", "anchor": "example-custom-configuration-for-hosted-version", "start_char": 30167, "end_char": 31046, "estimated_token_count": 200, "token_estimator": "heuristic-v1", "text": "### Example: Custom Configuration for Hosted Version\n\nThe `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:\n\n```typescript\nimport {\n  wormholeConnectHosted,\n  MayanRoute,\n} from '@wormhole-foundation/wormhole-connect';\n\nconst container = document.getElementById('connect')!;\n\nwormholeConnectHosted(container, {\n  config: {\n    routes: [MayanRoute],\n    eventHandler: (e) => {\n      console.log('Connect event', e);\n    },\n  },\n  theme: {\n    background: {\n      default: '#004547',\n    },\n  },\n});\n```\n\nIn 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)."}
{"page_id": "products-connect-overview", "page_title": "Wormhole Connect", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 389, "end_char": 1186, "estimated_token_count": 188, "token_estimator": "heuristic-v1", "text": "## Key Features\n\nConnect's notable features include:\n\n- **In-app multichain transfers**: Bridge assets without leaving your app.\n- **Customizable features**: Specify chains and custom RPCs, manage tokens, and select bridging [routes](/docs/products/connect/concepts/routes/){target=\\_blank} such as WTT, CCTP, or NTT.\n- **Customizable UI**: Style the bridge interface to match your brand.\n- **Optional destination gas**: Provide gas for initial transactions on the target chain.\n- **Wrapped and native assets support**: Supports both wrapped and native tokens and integrates with Settlement.\n\nBe 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."}
{"page_id": "products-connect-overview", "page_title": "Wormhole Connect", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 1186, "end_char": 2569, "estimated_token_count": 303, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nWhen a user initiates a multichain transfer, Connect walks them through key steps and automates the transfer process behind the scenes, including:\n\n1. **Initiating the transfer**: Connect your chosen wallet to the source chain, select asset and source chain for the transfer.\n2. **Finalize transfer setup**: Connect the destination wallet, select the target chain and select a bridging route (manual or automatic).\n3. **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.\n4. **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}.\n5. **Relaying to destination**: The VAA or attestation is automatically relayed to the destination chain.\n6. **Verification on destination**: Contracts on the target chain receive and verify the incoming VAA.\n7. **Asset release/minting**: Upon successful verification, the equivalent assets are either released or minted on the target chain and delivered to your wallet.\n\n!!! tip\n    If you want more hands on experience with Connect, checkout [Portal Bridge](https://portalbridge.com/){target=\\_blank}."}
{"page_id": "products-connect-overview", "page_title": "Wormhole Connect", "index": 2, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 2569, "end_char": 3653, "estimated_token_count": 287, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\nHere are some key use cases that highlight the power and versatility of Connect:\n\n- **Cross-Chain Swaps and Liquidity Aggregation**\n\n    - **[Connect](/docs/products/connect/get-started/)**: Handles user-friendly asset transfers.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/)**: Moves native assets across chains.\n    - **[Queries](/docs/products/queries/overview/)**: Fetches real-time prices for optimal trade execution.\n\n- **Cross-Chain Payment Widgets**\n\n    - **[Connect](/docs/products/connect/get-started/)**: Facilitates seamless payments in various tokens.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/)**: Ensures direct, native asset transfers.\n\n- **Web3 Game Asset Transfers**\n\n    - **[Connect](/docs/products/connect/get-started/)**: Provide a user-friendly way to move game tokens across chains.\n    - **[Wrapped Token Transfers](/docs/products/token-transfers/wrapped-token-transfers/overview/)**: Handle the underlying lock-and-mint logic securely."}
{"page_id": "products-connect-overview", "page_title": "Wormhole Connect", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3653, "end_char": 3802, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Next Steps \n\nAdd Connect to your app with these key setup steps:\n\n[timeline(docs/.snippets/text/products/connect/overview/connect-timeline.json)]"}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 0, "depth": 2, "title": "Feature Support Matrix {: #feature-support-matrix}", "anchor": "feature-support-matrix-feature-support-matrix", "start_char": 0, "end_char": 2741, "estimated_token_count": 470, "token_estimator": "heuristic-v1", "text": "## Feature Support Matrix {: #feature-support-matrix}\n\n*Scroll down for details about each column.*\n\n| **Network** | **WTT**          | **WTT Relayer**          | **Circle CCTP** | **ETH Bridge** | **Gas Drop Off** |\n|:-----------:|:----------------:|:------------------------:|:---------------:|:--------------:|:----------------:|\n|   Solana    |        ✅         |            ✅             |        ✅        |       ❌        |        ✅         |\n|  Ethereum   |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|     BSC     |        ✅         |            ✅             |        ❌        |       ✅        |        ✅         |\n|   Polygon   |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|  Avalanche  |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|   Fantom    |        ✅         |            ✅             |        ❌        |       ❌        |        ✅         |\n|    Kaia     |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n|    Celo     |        ✅         |            ✅             |        ❌        |       ❌        |        ✅         |\n|  Moonbeam   |        ✅         |            ✅             |        ❌        |       ❌        |        ✅         |\n|  Injective  |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n|     Sui     |        ✅         |            ✅             |        ✅        |       ❌        |        ✅         |\n|    Aptos    |        ✅         |            ❌             |        ✅        |       ❌        |        ❌         |\n|  Arbitrum   |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|  Optimism   |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|    Base     |        ✅         |            ✅             |        ✅        |       ✅        |        ✅         |\n|     Sei     |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n|   Scroll    |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n|    Blast    |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n|   X Layer   |        ✅         |            ❌             |        ❌        |       ❌        |        ❌         |\n\n!!! note \"Terminology\" \n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol."}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 1, "depth": 2, "title": "Feature Explanation {: #feature-explanation}", "anchor": "feature-explanation-feature-explanation", "start_char": 2741, "end_char": 2790, "estimated_token_count": 11, "token_estimator": "heuristic-v1", "text": "## Feature Explanation {: #feature-explanation}"}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 2, "depth": 3, "title": "Wrapped Token Transfers (WTT) {: #wrapped-token-transfers}", "anchor": "wrapped-token-transfers-wtt-wrapped-token-transfers", "start_char": 2790, "end_char": 3310, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "### Wrapped Token Transfers (WTT) {: #wrapped-token-transfers}\n\nWormhole is best known for its WTT 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.\n\nThis route appears if both of the following conditions are satisfied:\n\n - Both the origin and destination chains support WTT.\n - No non-WTT routes are available for the selected token."}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 3, "depth": 3, "title": "WTT Relayer {: #wtt-relayer}", "anchor": "wtt-relayer-wtt-relayer", "start_char": 3310, "end_char": 4022, "estimated_token_count": 150, "token_estimator": "heuristic-v1", "text": "### WTT Relayer {: #wtt-relayer}\n\nOn the [routes](/docs/products/connect/concepts/routes/){target=\\_blank} page, this is referred to as the automatic route in the WTT section.\n\nTrustless 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.\n\nThis route appears if all of the following conditions are satisfied:\n\n- Both the origin and destination chains support WTT.\n- Both the origin and destination chains support WTT relayer.\n- No non-WTT routes are available for the selected token.\n- The relayer supports the selected token on the origin chain."}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 4, "depth": 3, "title": "Circle CCTP {: #circle-cctp}", "anchor": "circle-cctp-circle-cctp", "start_char": 4022, "end_char": 4469, "estimated_token_count": 116, "token_estimator": "heuristic-v1", "text": "### Circle CCTP {: #circle-cctp}\n\n[Circle](https://www.circle.com/){target=\\_blank}, the issuer of USDC, provides a native way for native USDC to be transferred between [CCTP-enabled](https://www.circle.com/cross-chain-transfer-protocol){target=\\_blank} chains.\n\nThis route appears if all of the following conditions are satisfied:\n\n- Both the origin and destination chains support Circle CCTP.\n- The selected token is native Circle-issued USDC."}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 5, "depth": 3, "title": "ETH Bridge {: #eth-bridge}", "anchor": "eth-bridge-eth-bridge", "start_char": 4469, "end_char": 4935, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### ETH Bridge {: #eth-bridge}\n\n[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.\n\nThis route appears if all of the following conditions are satisfied:\n\n- Both the origin and destination chains support the ETH Bridge.\n- The selected token is native ETH, wstETH, or canonical wETH."}
{"page_id": "products-connect-reference-support-matrix", "page_title": "Features", "index": 6, "depth": 3, "title": "Gas Drop Off {: #gas-drop-off}", "anchor": "gas-drop-off-gas-drop-off", "start_char": 4935, "end_char": 5523, "estimated_token_count": 125, "token_estimator": "heuristic-v1", "text": "### Gas Drop Off {: #gas-drop-off}\n\nA 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.\n\nThis route appears if all of the following conditions are satisfied:\n\n- Both the origin and destination chains support gas drop off.\n- An automatic route is selected.\n- The relayer accepts the selected token to swap into the gas token."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 960, "end_char": 1795, "estimated_token_count": 255, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo get started with Connect, we'll first need to set up a basic environment that allows for cross-chain token transfers.\nBefore starting this tutorial, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- A [Sui wallet](https://suiwallet.com/){target=\\_blank} set up and ready for use.\n- 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}.\n- 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."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 1, "depth": 2, "title": "Set Up Connect for Sui Transfers", "anchor": "set-up-connect-for-sui-transfers", "start_char": 1795, "end_char": 1832, "estimated_token_count": 8, "token_estimator": "heuristic-v1", "text": "## Set Up Connect for Sui Transfers"}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 2, "depth": 3, "title": "Create a React Project", "anchor": "create-a-react-project", "start_char": 1832, "end_char": 2402, "estimated_token_count": 138, "token_estimator": "heuristic-v1", "text": "### Create a React Project\n\nIn this tutorial, we'll use [Next.js](https://nextjs.org/docs/app/getting-started){target=\\_blank}, a popular framework built on top of React, to set up your app:\n\n1. Open your terminal and run the following command to create a new React app:\n\n    ```bash\n    npx create-next-app@latest connect-tutorial\n    ```\n\n    We recommend enabling TypeScript and creating a `src/` directory during setup. Other options can be configured based on your preferences.\n\n2. Navigate into the project directory:\n\n    ```bash\n    cd connect-tutorial\n    ```"}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 3, "depth": 3, "title": "Install Connect", "anchor": "install-connect", "start_char": 2402, "end_char": 2655, "estimated_token_count": 61, "token_estimator": "heuristic-v1", "text": "### Install Connect\n\nNext, install the Connect package as a dependency by running the following command inside your project directory. This tutorial uses the Connect version `5.1.1`:\n\n```bash\nnpm install @wormhole-foundation/wormhole-connect@5.1.1\n```"}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 4, "depth": 3, "title": "Integrate Connect into the Application", "anchor": "integrate-connect-into-the-application", "start_char": 2655, "end_char": 4237, "estimated_token_count": 380, "token_estimator": "heuristic-v1", "text": "### Integrate Connect into the Application\n\nNow, we need to modify the default `page.tsx` file to integrate Connect. We are going to use [version V1.0](/docs/products/connect/guides/upgrade/){target=\\_blank} or later, make sure to check which version of Connect you are using. Open `src/app/page.tsx` and replace the content with the following code:\n\n=== \"JavaScript\"\n\n    ```js\n    'use client';\n\n    import WormholeConnect from '@wormhole-foundation/wormhole-connect';\n\n    const config = {\n      network: 'Testnet',\n      chains: ['Sui', 'Avalanche'],\n    };\n\n    const theme = {\n      mode: 'light',\n      primary: '#78c4b6',\n    };\n\n    export default function Home() {\n      return <WormholeConnect config={config} theme={theme} />;\n    }\n    ```\n\n=== \"TypeScript\"\n\n    ```ts\n    'use client';\n\n    import WormholeConnect, {\n      type config,\n      WormholeConnectTheme,\n    } from '@wormhole-foundation/wormhole-connect';\n\n    export default function Home() {\n      const config: config.WormholeConnectConfig = {\n        network: 'Testnet',\n        chains: ['Sui', 'Avalanche'],\n\n        ui: {\n          title: 'SUI Connect TS Demo',\n        },\n      };\n\n      const theme: WormholeConnectTheme = {\n        mode: 'light',\n        primary: '#78c4b6',\n      };\n      return <WormholeConnect config={config} theme={theme} />;\n    }\n    ```\n\n- **Set `network` to `'Testnet'`**: This ensures that Connect uses the testnet environment.\n- **Set `chains` to `['Sui', 'Avalanche']`**: Configures the app to allow transfers between Sui and Avalanche Fuji, the testnet for Avalanche."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 5, "depth": 3, "title": "Customize Connect", "anchor": "customize-connect", "start_char": 4237, "end_char": 4562, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### Customize Connect\n\nTo further customize Connect for your application, such as adjusting the UI, adding custom tokens, enabling Reown (formerly known as WalletConnect), or configuring specific chain settings, you can refer to the [Connect Configuration guide](/docs/products/connect/configuration/data/){target=\\_blank}."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 6, "depth": 3, "title": "Run the Application", "anchor": "run-the-application", "start_char": 4562, "end_char": 4955, "estimated_token_count": 90, "token_estimator": "heuristic-v1", "text": "### Run the Application\n\nMake sure you're in the root directory of your React app, and run the following command to start the application:\n\n```bash\nnpm run dev\n```\n\nNow your React app should be up and running, and Connect should be visible on `http://localhost:3000/`. You should see the Connect component, which will include a UI for selecting networks and tokens for cross-chain transfers."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 7, "depth": 2, "title": "Transfer Tokens from Sui to Fuji", "anchor": "transfer-tokens-from-sui-to-fuji", "start_char": 4955, "end_char": 6771, "estimated_token_count": 439, "token_estimator": "heuristic-v1", "text": "## Transfer Tokens from Sui to Fuji\n\nBefore transferring token ensure you have enough testnet SUI and Fuji tokens to cover the gas fees for the transfer. \n\nTo transfer tokens from Sui to Fuji in the Connect interface:\n\n1. Select **Sui** as the source network, connect your Sui wallet, and choose **SUI** as the asset you wish to transfer.\n2. Choose **Fuji** as the destination network and connect your wallet with the Fuji network.\n3. Enter the amount of SUI tokens you wish to transfer.\n\n    ![](/docs/images/products/connect/tutorials/react-dapp/connect-1.webp){.half}\n\n4. Choose to view other routes.\n    \n    ![](/docs/images/products/connect/tutorials/react-dapp/connect-2.webp){.half}\n\n5. Select the manual bridge option, which will require two transactions: one on the source chain (Sui) and one on the destination chain (Fuji).\n\n    !!! note\n        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.\n\n    ![](/docs/images/products/connect/tutorials/react-dapp/connect-3.webp){.half}\n\n6. Review and confirm the transfer on Sui. This will lock your tokens on the Sui chain.\n\n    ![](/docs/images/products/connect/tutorials/react-dapp/connect-4.webp){.half}\n\n7. Follow the on-screen prompts to approve the transaction. You will be asked to sign with your Sui wallet.\n\n    ![](/docs/images/products/connect/tutorials/react-dapp/connect-5.webp){.half}\n\nOnce the transaction has been submitted, 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}."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 8, "depth": 2, "title": "Claim Tokens on Fuji", "anchor": "claim-tokens-on-fuji", "start_char": 6771, "end_char": 7243, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "## Claim Tokens on Fuji\n\nAfter 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.\n\n![](/docs/images/products/connect/tutorials/react-dapp/connect-6.webp){.half}\n\nOnce confirmed, check your Fuji wallet to verify that the wrapped SUI tokens have been successfully received.\n\n![](/docs/images/products/connect/tutorials/react-dapp/connect-7.webp){.half}"}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 9, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 7243, "end_char": 7643, "estimated_token_count": 88, "token_estimator": "heuristic-v1", "text": "## Resources\n\nIf 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 Connect in a React app for bridging tokens between the Sui and Fuji (Avalanche Testnet) networks."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 10, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 7643, "end_char": 8575, "estimated_token_count": 168, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nIn this tutorial, you've gained hands-on experience with integrating 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.\n\nBy following these steps, you've learned how to:\n\n- Set up a React project tailored for cross-chain transfers.\n- Install and configure Connect to support multiple blockchains.\n- Implement a streamlined UI for selecting source and destination chains, connecting wallets, and initiating transfers.\n- Execute a token transfer from Sui to Avalanche Fuji, monitoring each step and confirming the transaction on both networks.\n\nWith these tools and knowledge, you're now equipped to build powerful cross-chain applications using Connect, opening up possibilities for users to move assets across ecosystems securely and efficiently."}
{"page_id": "products-connect-tutorials-react-dapp", "page_title": "Integrate Connect into a React DApp Tutorial", "index": 11, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 8575, "end_char": 9383, "estimated_token_count": 198, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Build a Reimbursement App with Connect**\n\n    ---\n\n    Master the core features of Connect by building a real-world reimbursement application on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/1bee7446-5ed5-814a-8177-e087a5d7a6bc){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Demo Tutorials Repository**\n\n    ---\n\n    Looking for more hands-on tutorials? Check out the Wormhole Tutorial Demo repository on GitHub for additional examples.\n\n    [:custom-arrow: Explore the Demo Repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank}\n\n</div>"}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 0, "depth": 2, "title": "The Core Bridge Account Problem", "anchor": "the-core-bridge-account-problem", "start_char": 330, "end_char": 2324, "estimated_token_count": 396, "token_estimator": "heuristic-v1", "text": "## The Core Bridge Account Problem\n\nWhen you emit a message on Solana using the legacy [Wormhole core bridge](/docs/protocol/infrastructure/core-contracts/){target=\\_blank}, it creates a new on-chain account, a Program Derived Address (PDA), for every message. Each of these accounts must hold enough SOL to be rent-exempt, locking up lamports that cannot be reclaimed since the core bridge does not allow these accounts to be closed. Over time, this results in two big problems:\n\n- **Permanent On-Chain State**: Every message leaves behind a permanent account, increasing long-term storage needs on Solana.\n- **Lost Lamports to Rent**: Integrators lose SOL for every message, as the lamports needed for rent exemption remain locked in the message accounts indefinitely.\n\nSolana’s rent-exemption model isn't the fundamental limitation; the constraint lies in the legacy `post_message` function of the core bridge, which always creates a new, non-reclaimable account every time it’s called. Even after a message is consumed, these accounts can’t be closed or reused, resulting in unrecoverable rent costs.\n\nAlthough the `post_message_unreliable` function allows account reuse, it comes with significant tradeoffs. Once a message is overwritten, it can no longer be recovered, making it no longer observable by Guardians. It also locks you into the original account size, as the feature predates Solana’s account resizing.\n\nVerification has similar costs. The `post_vaa` instruction creates additional temporary accounts for signatures and VAA data, which, like the original accounts, require rent and aren’t automatically cleaned up. Over time, these add to both storage bloat and unrecoverable SOL.\n\nThis design ensures reliability, as message data is always available on-chain for Guardians to observe. However, it comes at a cost in both storage and lost SOL. To address these issues, Wormhole introduces Solana shims that fundamentally change the cost model for emissions and verification."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 1, "depth": 2, "title": "What Are the Solana Shims?", "anchor": "what-are-the-solana-shims", "start_char": 2324, "end_char": 3153, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "## What Are the Solana Shims?\n\nTo address the limitations of the core bridge, Wormhole deploys two specialized Solana programs called shims:\n\n- **[Post Message Shim (`EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX`)](https://explorer.solana.com/address/EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX){target=\\_blank}**: Emits Wormhole messages efficiently, without creating new message accounts for each emission, reducing rent costs.\n- **[Verify VAA Shim (`EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at`)](https://explorer.solana.com/address/EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at){target=\\_blank}**: Verifies VAAs on-chain without leaving permanent accounts.\n\nBoth act as lightweight wrappers around the existing core bridge. There are two different options, depending on whether you are emitting messages or verifying VAAs:"}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 2, "depth": 3, "title": "Emission Shim", "anchor": "emission-shim", "start_char": 3153, "end_char": 5890, "estimated_token_count": 583, "token_estimator": "heuristic-v1", "text": "### Emission Shim\n\nThe [Emission Shim](/docs/products/messaging/guides/solana-shims/sol-emission/){target=\\_blank} is a Solana program deployed at [`EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX`](https://explorer.solana.com/address/EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX){target=\\_blank} which wraps the core bridge’s `post_message_unreliable` instruction. The Emission Shim emits message data as a log event rather than storing it in a rent-exempt message account, eliminating rent costs and preventing long-term state bloat. Guardians are configured to observe this canonical shim, allowing integrators to send messages through it without additional setup.\n\nThis shim works by calling the [`post_message`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/idls/wormhole_post_message_shim.json){target=\\_blank} instruction on the Post Message Shim program. This instruction emits the Wormhole message as a log event instead of creating a rent-exempt message account.\n\nThe shim differs from the standard `post_message` approach in two key ways. First, it utilizes a Program Derived Address (PDA) per emitter for message accounts, eliminating the need to generate a new key pair for each emission. Second, instead of writing the message to a persistent, rent-exempt account, it emits the data via an Anchor CPI event that Guardians can observe directly. This design reduces rent costs and prevents unused accounts from being left behind.\n\nThe shim works through a few main components:\n\n- **Shim Program**: Provides a `post_message` instruction modeled on the core bridge’s `post_message_unreliable`.\n- **Sequence Handling**: The core bridge continues to manage sequence numbers. It reads the sequence number from the core bridge and emits it in a [CPI event](https://www.anchor-lang.com/docs/basics/cpi){target=\\_blank}, along with the timestamp.\n- **Message Account**: Calls `post_message_unreliable` on the core bridge, writing an empty payload, so no unique message is stored on-chain.\n- **Guardian Role**: Guardians reconstruct the message from instruction data and the emitted event, not from a persistent account.\n\n```mermaid\ngraph LR\n    A[Integrator Program]\n    B[Emission Shim]\n    C[Core Bridge]\n    D[Guardians]\n\n    A -- call post_message --> B\n    B -- emits event & calls core --> C\n    C -- instruction data & event --> D\n```\n\nThe emission fee is still paid, and the core bridge continues to manage sequence numbers as before. The difference is that instead of creating a new message account for each emission, the shim emits a CPI event with the message data. All the information Guardians need is captured in the transaction logs, without leaving behind permanent accounts."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 3, "depth": 3, "title": "Verification Shim", "anchor": "verification-shim", "start_char": 5890, "end_char": 8797, "estimated_token_count": 648, "token_estimator": "heuristic-v1", "text": "### Verification Shim \n\nThe [Verification Shim](/docs/products/messaging/guides/solana-shims/sol-verification/){target=\\_blank} is a Solana program deployed at [`EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at`](https://explorer.solana.com/address/EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at){target=\\_blank}. It provides a [`verify_hash`](https://github.com/wormhole-foundation/wormhole/blob/4656bd4a72cb99f4e94a771a802856c9451af844/svm/wormhole-core-shims/programs/verify-vaa/src/lib.rs#L195){target=\\_blank} instruction that checks Guardian signatures against the active Guardian set for a VAA's digest. It ensures quorum, validates each signature in order, recovers the public keys, and matches them against the Guardian set. If all checks pass, the VAA is verified without creating persistent rent-exempt accounts. This verification method replaces the use of the core bridge’s `post_vaa`. Integrators can call the canonical shim, but existing programs may need to be modified to adopt this approach.\n\nIt works by first calling the [`post_signatures`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/idls/wormhole_verify_vaa_shim.json#L43){target=\\_blank} on the Verification Shim to store Guardian signatures in a temporary account. Then, from within your program, call [`verify_hash`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/programs/verify-vaa/README.md#verify-hash-technical-details){target=\\_blank} to check the VAA’s digest against Guardian signatures. In the same transaction, close the signatures account with [`close_signatures`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/idls/wormhole_verify_vaa_shim.json#L11){target=\\_blank} to reclaim rent. \n\nInstead of the core bridge instructions, such as `verify_signatures` and `post_vaa`, the verification shim provides its own flow using `post_signatures`, `verify_hash`, and `close_signatures`. The flow is a simpler sequence that avoids leaving permanent accounts on-chain:\n\n\n1. **Call `post_signatures`**: Creates (or appends to) a temporary `GuardianSignatures` account that stores the collected Guardian signatures. This account is owned and managed by the verification shim.\n2. **Call `verify_hash`**: Verifies the digest of the VAA against the active Guardian set and checks quorum by recovering and validating each Guardian signature. If verification succeeds, your program can continue its logic.\n3. **Call `close_signatures`**: Immediately closes the `GuardianSignatures` account to reclaim the lamports paid for its creation.\n\n\n```mermaid\ngraph LR\n    A[post_signatures] --> B[verify_hash]\n    B --> C[Process Logic]\n    C --> D[close_signatures]\n```\n\nThis flow ensures verification is both rent-efficient and secure, no permanent accounts remain, and Guardians still enforce quorum and integrity guarantees."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 4, "depth": 2, "title": "Guardian Observation Methods: Legacy vs. Shims", "anchor": "guardian-observation-methods-legacy-vs-shims", "start_char": 8797, "end_char": 9805, "estimated_token_count": 233, "token_estimator": "heuristic-v1", "text": "## Guardian Observation Methods: Legacy vs. Shims\n\nThe following table compares how Guardians observe and verify messages on Solana before and after the introduction of the shims program.\n\n| Observation Methods  | Legacy Model           | Shim Model               |\n|----------------------|------------------------|--------------------------|\n| Message Storage      | On-chain account       | Transaction logs (CPI)   |\n| Data Permanence      | Permanent              | Until RPC history pruned |\n| Guardian Observation | Reads account data     | Reads transaction logs   |\n| Cost                 | High (rent + compute)  | Low (compute only)       |\n| Closing Accounts     | Not possible           | Not needed               |\n\nWith shims, the message’s existence depends on the transaction log, so cost drops, but indefinite on-chain visibility is no longer guaranteed. Sequence tracking remains the same as the legacy model, so integrators can switch between the two without disrupting sequence numbers."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 5, "depth": 2, "title": "Transaction Costs", "anchor": "transaction-costs", "start_char": 9805, "end_char": 10552, "estimated_token_count": 163, "token_estimator": "heuristic-v1", "text": "## Transaction Costs\n\nSolana charges for two primary resources when processing transactions: \n\n- Compute units for execution.\n- Rent for storing data on-chain. \n\nUnderstanding how each contributes to the overall cost is key to seeing why shims are cheaper.\n\n- **Compute Units (CU)**: Solana measures CPU resource usage per transaction as “compute units”. Each transaction has a CU limit (usually ~200,000 — which can be increased for a fee).\n- **Rent**: One-time cost in SOL to keep an account on-chain. Most of the core bridge’s cost comes from rent, not CUs.\n\nEven though the shim uses slightly more compute (extra logic for logging), it avoids account creation entirely. Since rent is the most significant cost, the total emission cost drops."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 6, "depth": 2, "title": "Safety, Tradeoffs & Limitations", "anchor": "safety-tradeoffs-limitations", "start_char": 10552, "end_char": 11931, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "## Safety, Tradeoffs & Limitations\n\nShims preserve the same security guarantees as the core bridge, so that integrators can adopt them without weakening protocol safety. The only difference is where data lives: instead of being stored permanently in message accounts, it is emitted in transaction logs or held temporarily until verification completes. Guardians are explicitly configured to observe shim output, ensuring messages and VAAs remain verifiable across the network.\n\nThe main tradeoff is durability. In the legacy model, messages and VAAs were always available on-chain for re-observation. With shims, message data persists only as long as RPC providers retain transaction history. This timeframe is sufficient for Guardian observation, but doesn’t provide indefinite public access to raw message data. Applications that rely on long-term on-chain storage may still prefer the legacy path, while most integrators benefit from the reduced cost and state bloat.\n\nFinally, adopting shims may require some integration changes. For emission, developers should route messages through the Post Message Shim rather than directly through the core bridge. For verification, programs must update their logic to call `verify_hash` and manage temporary accounts in the same transaction. These are lightweight adjustments, but they are necessary to realize the cost savings fully."}
{"page_id": "products-messaging-concepts-solana-shim", "page_title": "Solana Shims", "index": 7, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 11931, "end_char": 12712, "estimated_token_count": 184, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nTo put these concepts into practice, explore the dedicated guides for emission and verification on Solana.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Emit Messages**\n\n    ---\n\n    Learn how to reduce rent costs when emitting Wormhole messages on Solana by using the emission shim.\n\n    [:custom-arrow: Use the Emission Shim](/docs/products/messaging/guides/solana-shims/sol-emission/)\n\n-   :octicons-tools-16:{ .lg .middle } **Verify VAAs**\n\n    ---\n\n    Efficiently verify Wormhole VAAs on Solana using the verification shim, which avoids persistent rent-exempt accounts while keeping full security guarantees.\n\n    [:custom-arrow: Use the Verification Shim](/docs/products/messaging/guides/solana-shims/sol-verification/)\n\n</div>"}
{"page_id": "products-messaging-get-started", "page_title": "Get Started with Messaging", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 317, "end_char": 930, "estimated_token_count": 175, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed.\n- [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed.\n- [Ethers.js](https://docs.ethers.org/v6/getting-started/){target=\\_blank} installed (this example uses version 6).\n- 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.\n- A private key for signing blockchain transactions."}
{"page_id": "products-messaging-get-started", "page_title": "Get Started with Messaging", "index": 1, "depth": 2, "title": "Configure Your Messaging Environment", "anchor": "configure-your-messaging-environment", "start_char": 930, "end_char": 2213, "estimated_token_count": 302, "token_estimator": "heuristic-v1", "text": "## Configure Your Messaging Environment\n\n1. Create a directory and initialize a Node.js project:\n\n    ```bash\n    mkdir core-message\n    cd core-message\n    npm init -y\n    ```\n\n2. Install TypeScript, tsx, Node.js type definitions, and Ethers.js:\n\n    ```bash\n    npm install --save-dev tsx typescript @types/node ethers\n    ```\n\n3. Create a `tsconfig.json` file if you don't have one. You can generate a basic one using the following command:\n\n    ```bash\n    npx tsc --init\n    ```\n\n    Make sure your `tsconfig.json` includes the following settings:\n\n    ```json \n    {\n        \"compilerOptions\": {\n            // es2020 or newer\n            \"target\": \"es2020\",\n            // Use esnext if you configured your package.json with type: \"module\"\n            \"module\": \"commonjs\",\n            \"esModuleInterop\": true,\n            \"forceConsistentCasingInFileNames\": true,\n            \"strict\": true,\n            \"skipLibCheck\": true,\n            \"resolveJsonModule\": true\n            }\n    }\n    ```\n\n4. Install the [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\\_blank}. This example uses the SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1\n    ```\n\n5. Create a new file named `main.ts`:\n\n    ```bash\n    touch main.ts\n    ```"}
{"page_id": "products-messaging-get-started", "page_title": "Get Started with Messaging", "index": 2, "depth": 2, "title": "Construct and Publish Your Message", "anchor": "construct-and-publish-your-message", "start_char": 2213, "end_char": 11341, "estimated_token_count": 1877, "token_estimator": "heuristic-v1", "text": "## Construct and Publish Your Message\n\n1. Open `main.ts` and update the code there as follows:\n\n    ```ts title=\"main.ts\"\n    import {\n      wormhole,\n      signSendWait,\n      toNative,\n      encoding,\n      type Chain,\n      type Network,\n      type NativeAddress,\n      type WormholeMessageId,\n      type UnsignedTransaction,\n      type TransactionId,\n      type WormholeCore,\n      type Signer as WormholeSdkSigner,\n      type ChainContext,\n    } from '@wormhole-foundation/sdk';\n    // Platform-specific modules\n    import EvmPlatformLoader from '@wormhole-foundation/sdk/evm';\n    import { getEvmSigner } from '@wormhole-foundation/sdk-evm';\n    import { Wallet, JsonRpcProvider, Signer as EthersSigner } from 'ethers';\n\n    /**\n     * The required value (SEPOLIA_PRIVATE_KEY) must\n     * be loaded securely beforehand, for example via a keystore, secrets\n     * manager, or environment variables (not recommended).\n     */\n\n    const SEPOLIA_PRIVATE_KEY = SEPOLIA_PRIVATE_KEY!;\n    // Provide a private endpoint RPC URL for Sepolia, defaults to a public node\n    // if not set\n    const RPC_URL =\n      process.env.SEPOLIA_RPC_URL || 'https://ethereum-sepolia-rpc.publicnode.com';\n\n    async function main() {\n      // Initialize Wormhole SDK\n      const network = 'Testnet';\n      const wh = await wormhole(network, [EvmPlatformLoader]);\n      console.log('Wormhole SDK Initialized.');\n\n      // Get the EVM signer and provider\n      let ethersJsSigner: EthersSigner;\n      let ethersJsProvider: JsonRpcProvider;\n\n      try {\n        if (!SEPOLIA_PRIVATE_KEY) {\n          console.error('Please set the SEPOLIA_PRIVATE_KEY environment variable.');\n          process.exit(1);\n        }\n\n        ethersJsProvider = new JsonRpcProvider(RPC_URL);\n        const wallet = new Wallet(SEPOLIA_PRIVATE_KEY);\n        ethersJsSigner = wallet.connect(ethersJsProvider);\n        console.log(\n          `Ethers.js Signer obtained for address: ${await ethersJsSigner.getAddress()}`\n        );\n      } catch (error) {\n        console.error('Failed to get Ethers.js signer and provider:', error);\n        process.exit(1);\n      }\n\n      // Define the source chain context\n      const sourceChainName: Chain = 'Sepolia';\n      const sourceChainContext = wh.getChain(sourceChainName) as ChainContext<\n        'Testnet',\n        'Sepolia',\n        'Evm'\n      >;\n      console.log(`Source chain context obtained for: ${sourceChainContext.chain}`);\n\n      // Get the Wormhole SDK signer, which is a wrapper around the Ethers.js\n      // signer using the Wormhole SDK's signing and transaction handling\n      // capabilities\n      let sdkSigner: WormholeSdkSigner<Network, Chain>;\n      try {\n        sdkSigner = await getEvmSigner(ethersJsProvider, ethersJsSigner);\n        console.log(\n          `Wormhole SDK Signer obtained for address: ${sdkSigner.address()}`\n        );\n      } catch (error) {\n        console.error('Failed to get Wormhole SDK Signer:', error);\n        process.exit(1);\n      }\n\n      // Construct your message payload\n      const messageText = `HelloWormholeSDK-${Date.now()}`;\n      const payload: Uint8Array = encoding.bytes.encode(messageText);\n      console.log(`Message to send: \"${messageText}\"`);\n\n      // Define message parameters\n      const messageNonce = Math.floor(Math.random() * 1_000_000_000);\n      const consistencyLevel = 1;\n\n      try {\n        // Get the core protocol client\n        const coreProtocolClient: WormholeCore<Network> =\n          await sourceChainContext.getWormholeCore();\n\n        // Generate the unsigned transactions\n        const whSignerAddress: NativeAddress<Chain> = toNative(\n          sdkSigner.chain(),\n          sdkSigner.address()\n        );\n        console.log(\n          `Preparing to publish message from ${whSignerAddress.toString()} on ${\n            sourceChainContext.chain\n          }...`\n        );\n\n        const unsignedTxs: AsyncGenerator<UnsignedTransaction<Network, Chain>> =\n          coreProtocolClient.publishMessage(\n            whSignerAddress,\n            payload,\n            messageNonce,\n            consistencyLevel\n          );\n\n        // Sign and send the transactions\n        console.log(\n          'Signing and sending the message publication transaction(s)...'\n        );\n        const txIds: TransactionId[] = await signSendWait(\n          sourceChainContext,\n          unsignedTxs,\n          sdkSigner\n        );\n\n        if (!txIds || txIds.length === 0) {\n          throw new Error('No transaction IDs were returned from signSendWait.');\n        }\n        const primaryTxIdObject = txIds[txIds.length - 1];\n        const primaryTxid = primaryTxIdObject.txid;\n\n        console.log(`Primary transaction ID for parsing: ${primaryTxid}`);\n        console.log(\n          `View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/${primaryTxid}`\n        );\n\n        console.log(\n          '\\nWaiting a few seconds for transaction to propagate before parsing...'\n        );\n        await new Promise((resolve) => setTimeout(resolve, 8000));\n\n        // Retrieve VAA identifiers\n        console.log(\n          `Attempting to parse VAA identifiers from transaction: ${primaryTxid}...`\n        );\n        const messageIds: WormholeMessageId[] =\n          await sourceChainContext.parseTransaction(primaryTxid);\n\n        if (messageIds && messageIds.length > 0) {\n          const wormholeMessageId = messageIds[0];\n          console.log('--- VAA Identifiers (WormholeMessageId) ---');\n          console.log('  Emitter Chain:', wormholeMessageId.chain);\n          console.log('  Emitter Address:', wormholeMessageId.emitter.toString());\n          console.log('  Sequence:', wormholeMessageId.sequence.toString());\n          console.log('-----------------------------------------');\n        } else {\n          console.error(\n            `Could not parse Wormhole message IDs from transaction ${primaryTxid}.`\n          );\n        }\n      } catch (error) {\n        console.error(\n          'Error during message publishing or VAA identifier retrieval:',\n          error\n        );\n        if (error instanceof Error && error.stack) {\n          console.error('Stack Trace:', error.stack);\n        }\n      }\n    }\n\n    main().catch((e) => {\n      console.error('Critical error in main function (outer catch):', e);\n      if (e instanceof Error && e.stack) {\n        console.error('Stack Trace:', e.stack);\n      }\n      process.exit(1);\n    });\n    ```\n\n    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.\n\n2. Run the script using the following command:\n\n    ```bash\n    npx tsx main.ts\n    ```\n\n    You will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n      <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx main.ts</span>\n      <span data-ty>Wormhole SDK Initialized.</span>\n      <span data-ty>Ethers.js Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12</span>\n      <span data-ty>Source chain context obtained for: Sepolia</span>\n      <span data-ty>Wormhole SDK Signer obtained for address: 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12</span>\n      <span data-ty>Message to send: \"HelloWormholeSDK-1748362375390\"</span>\n      <span data-ty>Preparing to publish message from 0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12 on Sepolia...</span>\n      <span data-ty>Signing and sending the message publication transaction(s)...</span>\n      <span data-ty>Primary Transaction ID for parsing: 0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508</span>\n      <span data-ty>View on Sepolia Etherscan: https://sepolia.etherscan.io/tx/0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508</span>\n      <span data-ty>Waiting a few seconds for transaction to propagate before parsing...</span>\n      <span data-ty>Attempting to parse VAA identifiers from transaction:\n        0xeb34f35f91c72e4e5198509071d24fd25d8a979aa93e2f168de075e3568e1508...</span>\n      <span data-ty>--- VAA Identifiers (WormholeMessageId) ---</span>\n      <span data-ty> Emitter Chain: Sepolia</span>\n      <span data-ty> Emitter Address: 0x000000000000000000000000cd8bcd9a793a7381b3c66c763c3f463f70de4e12</span>\n      <span data-ty> Sequence: 1</span>\n      <span data-ty>-----------------------------------------</span>\n      <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n3. 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.\n\nCongratulations! 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."}
{"page_id": "products-messaging-get-started", "page_title": "Get Started with Messaging", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 11341, "end_char": 11989, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with WTT**\n\n    ---\n\n    Follow this guide to start working with multichain token transfers using Wormhole Wrapped Token Transfers' lock and mint mechanism to send tokens across chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/get-started/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-messaging-guides-core-contracts", "page_title": "Get Started with Core Contracts", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 855, "end_char": 1417, "estimated_token_count": 142, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo interact with the Wormhole Core Contract, you'll need the following:\n\n- The [address of the Core Contract](/docs/products/reference/contract-addresses/#core-contracts){target=\\_blank} on the chains you're deploying your contract on.\n- The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\\_blank} of the chains you're deploying your contract on.\n- The [Wormhole Finality](/docs/products/reference/consistency-levels/){target=\\_blank} (consistency) levels (required finality) for the chains you're deploying your contract on."}
{"page_id": "products-messaging-guides-core-contracts", "page_title": "Get Started with Core Contracts", "index": 1, "depth": 2, "title": "How to Interact with Core Contracts", "anchor": "how-to-interact-with-core-contracts", "start_char": 1417, "end_char": 1969, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "## How to Interact with Core Contracts\n\nBefore writing your own contracts, it's essential to understand the key functions and events of the Wormhole Core Contracts. The primary functionality revolves around:\n\n- **Sending messages**: Submitting messages to the Wormhole network for cross-chain communication.\n- **Receiving and verifying messages**: Validating messages received from other chains via the Wormhole network.\n\nWhile the implementation details of the Core Contracts vary by network, the core functionality remains consistent across chains."}
{"page_id": "products-messaging-guides-core-contracts", "page_title": "Get Started with Core Contracts", "index": 2, "depth": 3, "title": "Sending Messages", "anchor": "sending-messages", "start_char": 1969, "end_char": 9832, "estimated_token_count": 1646, "token_estimator": "heuristic-v1", "text": "### Sending Messages\n\nTo 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 [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}.\n\n=== \"EVM\"\n\n    The `IWormhole.sol` interface provides the `publishMessage` function, which can be used to publish a message directly to the Core Contract:\n\n    ```solidity\n    function publishMessage(\n        uint32 nonce,\n        bytes memory payload,\n        uint8 consistencyLevel\n    ) external payable returns (uint64 sequence);\n    ```\n\n    ??? interface \"Parameters\"\n\n        `nonce` ++\"uint32\"++\n        \n        A free integer field that can be used however you like. Note that changing the `nonce` will result in a different digest.\n\n        ---\n\n        `payload` ++\"bytes memory\"++\n        \n        The content of the emitted message. Due to the constraints of individual blockchains, it may be capped to a certain maximum length.\n\n        ---\n\n        `consistencyLevel` ++\"uint8\"++\n        \n        A value that defines the required level of finality that must be reached before the Guardians will observe and attest to emitted events.\n\n    ??? interface \"Returns\"\n\n        `sequence` ++\"uint64\"++\n        \n        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}.\n    \n    ??? interface \"Example\"\n\n        ```solidity\n        IWormhole wormhole = IWormhole(wormholeAddr);\n\n        // Get the fee for publishing a message\n        uint256 wormholeFee = wormhole.messageFee();\n\n        // Check fee and send parameters\n\n        // Create the HelloWorldMessage struct\n        HelloWorldMessage memory parsedMessage = HelloWorldMessage({\n            payloadID: uint8(1),\n            message: helloWorldMessage\n        });\n\n        // Encode the HelloWorldMessage struct into bytes\n        bytes memory encodedMessage = encodeMessage(parsedMessage);\n\n        // Send the HelloWorld message by calling publishMessage on the\n        // wormhole core contract and paying the Wormhole protocol fee.\n        messageSequence = wormhole.publishMessage{value: wormholeFee}(\n            0, // batchID\n            encodedMessage,\n            wormholeFinality()\n        );\n        ```\n\n        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.\n\n=== \"Solana\"\n\n    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:\n\n    ```rs\n    pub fn post_message<'info>(\n        ctx: CpiContext<'_, '_, '_, 'info, PostMessage<'info>>,\n        batch_id: u32,\n        payload: Vec<u8>,\n        finality: Finality\n    ) -> Result<()>\n    ```\n\n    ??? interface \"Parameters\"\n\n        `ctx` ++\"CpiContext<'_, '_, '_, 'info, PostMessage<'info>>\"++ \n        \n        Provides the necessary context for executing the function, including the accounts and program information required for the Cross-Program Invocation (CPI).\n\n        ??? child \"Type `pub struct CpiContext<'a, 'b, 'c, 'info, T>`\"\n\n            ```rs\n            pub struct CpiContext<'a, 'b, 'c, 'info, T>\n            where\n                T: ToAccountMetas + ToAccountInfos<'info>,\n            {\n                pub accounts: T,\n                pub remaining_accounts: Vec<AccountInfo<'info>>,\n                pub program: AccountInfo<'info>,\n                pub signer_seeds: &'a [&'b [&'c [u8]]],\n            }\n            ```\n\n            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}.\n\n        ??? child \"Type `PostMessage<'info>`\"\n\n            ```rs\n            pub struct PostMessage<'info> {\n                pub config: AccountInfo<'info>,\n                pub message: AccountInfo<'info>,\n                pub emitter: AccountInfo<'info>,\n                pub sequence: AccountInfo<'info>,\n                pub payer: AccountInfo<'info>,\n                pub fee_collector: AccountInfo<'info>,\n                pub clock: AccountInfo<'info>,\n                pub rent: AccountInfo<'info>,\n                pub system_program: AccountInfo<'info>,\n            }\n            ```\n\n            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}.\n\n        ---\n\n        `batch_id` ++\"u32\"++\n        \n        An identifier for the message batch.\n\n        ---\n\n        `payload` ++\"Vec<u8>\"++\n        \n        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.\n\n        ---\n\n        `finality` ++\"Finality\"++\n        \n        Specifies the level of finality or confirmation required for the message.\n        \n        ??? child \"Type `Finality`\"\n\n            ```rs\n            pub enum Finality {\n                Confirmed,\n                Finalized,\n            }\n            ```\n    \n    ??? interface \"Returns\"\n\n        ++\"Result<()>\"++\n        \n        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\n    \n    ??? interface \"Example\"\n\n        ```rust\n        let fee = ctx.accounts.wormhole_bridge.fee();\n        // ... Check fee and send parameters\n\n        let config = &ctx.accounts.config;\n        let payload: Vec<u8> = HelloWorldMessage::Hello { message }.try_to_vec()?;\n\n        // Invoke `wormhole::post_message`.\n        wormhole::post_message(\n            CpiContext::new_with_signer(\n                ctx.accounts.wormhole_program.to_account_info(),\n                wormhole::PostMessage {\n                    // ... Set fields\n                },\n                &[\n                    // ... Set seeds\n                ],\n            ),\n            config.batch_id,\n            payload,\n            config.finality.into(),\n        )?;\n        ```\n\n        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.\n\nOnce 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://solana.com/docs/core/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.\n\nVAAs 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."}
{"page_id": "products-messaging-guides-core-contracts", "page_title": "Get Started with Core Contracts", "index": 3, "depth": 3, "title": "Receiving Messages", "anchor": "receiving-messages", "start_char": 9832, "end_char": 15490, "estimated_token_count": 1080, "token_estimator": "heuristic-v1", "text": "### Receiving Messages\n\nThe way a message is received and handled depends on the environment.\n\n=== \"EVM\"\n\n    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.\n\n    ```solidity\n    function parseAndVerifyVM(\n        bytes calldata encodedVM\n    ) external view returns (VM memory vm, bool valid, string memory reason);\n    ```\n\n    ??? interface \"Parameters\"\n\n        `encodedVM` ++\"bytes calldata\"++\n        \n        The encoded message as a Verified Action Approval (VAA), which contains all necessary information for verification and processing.\n\n    ??? interface \"Returns\"\n\n        `vm` ++\"VM memory\"++\n        \n        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.\n\n        ??? child \"Struct `VM`\"\n\n            ```solidity\n            struct VM {\n                uint8 version;\n                uint32 timestamp;\n                uint32 nonce;\n                uint16 emitterChainId;\n                bytes32 emitterAddress;\n                uint64 sequence;\n                uint8 consistencyLevel;\n                bytes payload;\n                uint32 guardianSetIndex;\n                Signature[] signatures;\n                bytes32 hash;\n            }\n            ```\n\n            For more information, refer to the [`IWormhole.sol` interface](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/interfaces/IWormhole.sol){target=\\_blank}.\n\n        ---\n        \n        `valid` ++\"bool\"++\n        \n        A boolean indicating whether the VAA is valid or not.\n        \n        ---\n\n        `reason` ++\"string\"++\n        \n        If the VAA is not valid, a reason will be provided\n\n    ??? interface \"Example\"\n\n        ```solidity\n        function receiveMessage(bytes memory encodedMessage) public {\n            // Call the Wormhole core contract to parse and verify the encodedMessage\n            (\n                IWormhole.VM memory wormholeMessage,\n                bool valid,\n                string memory reason\n            ) = wormhole().parseAndVerifyVM(encodedMessage);\n\n            // Perform safety checks here\n\n            // Decode the message payload into the HelloWorldMessage struct\n            HelloWorldMessage memory parsedMessage = decodeMessage(\n                wormholeMessage.payload\n            );\n\n            // Your custom application logic here\n        }\n        ```\n\n        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.\n\n=== \"Solana\"\n\n    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.\n\n    Retrieve the raw message data:\n\n    ```rs\n    let posted_message = &ctx.accounts.posted;\n    posted_message.data()\n    ```\n\n    ??? interface \"Example\"\n\n        ```rust\n        pub fn receive_message(ctx: Context<ReceiveMessage>, vaa_hash: [u8; 32]) -> Result<()> {\n            let posted_message = &ctx.accounts.posted;\n\n            if let HelloWorldMessage::Hello { message } = posted_message.data() {\n                // Check message\n                // Your custom application logic here\n                Ok(())\n            } else {\n                Err(HelloWorldError::InvalidMessage.into())\n            }\n        }\n        ```\n\n        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.\n\n#### Validating the Emitter\n\nWhen 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.\n\nTypically, 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:\n\n```solidity\nrequire(isRegisteredSender(emitterChainId, emitterAddress), \"Invalid emitter\");\n```\n\nThis 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.\n\n```typescript\nconst tx = await receiverContract.setRegisteredSender(\n  sourceChain.chainId,\n  ethers.zeroPadValue(senderAddress as BytesLike, 32)\n);\n\nawait tx.wait();\n```\n\n#### Additional Checks\n\nIn 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:\n\n- **Sequence**: Is this the expected sequence number? How should out-of-order deliveries be handled?\n- **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?\n\nThe 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."}
{"page_id": "products-messaging-guides-core-contracts", "page_title": "Get Started with Core Contracts", "index": 4, "depth": 2, "title": "Source Code References", "anchor": "source-code-references", "start_char": 15490, "end_char": 16627, "estimated_token_count": 307, "token_estimator": "heuristic-v1", "text": "## Source Code References\n\nFor 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:\n\n- [Algorand Core Contract source code](https://github.com/wormhole-foundation/wormhole/blob/main/algorand/wormhole_core.py){target=\\_blank}\n- [Aptos Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/aptos/wormhole){target=\\_blank}\n- [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})\n- [NEAR Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/near/contracts/wormhole){target=\\_blank}\n- [Solana Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/solana/bridge/program){target=\\_blank}\n- [Sui Core Contract source code](https://github.com/wormhole-foundation/wormhole/tree/main/sui/wormhole){target=\\_blank}"}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1383, "end_char": 2114, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo interact with the emission shim, you'll need the following:\n\n- [Rust and Solana CLI](https://solana.com/docs/intro/installation){target=\\_blank} installed.  \n- [Anchor installed](https://www.anchor-lang.com/docs/installation){target=\\_blank}.\n- The canonical emission shim program already deployed at [`EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX`](https://explorer.solana.com/address/EtZMZM22ViKMo4r5y4Anovs3wKQ2owUmDpjygnMMcdEX){target=\\_blank}.\n- The shim’s [IDL](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/idls/wormhole_post_message_shim.json){target=\\_blank} for wiring accounts.\n- A payer (signer) funded with enough SOL to cover compute and message fees."}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 1, "depth": 2, "title": "Setup", "anchor": "setup", "start_char": 2114, "end_char": 2559, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "## Setup\n\nTo start, import the shim crate to call `wormhole_post_message_shim::cpi::post_message`. Then, pull the core bridge addresses needed to be passed along.\n\n```rs\ndeclare_program!(wormhole_post_message_shim);\n\nuse anchor_lang::prelude::*;\n\nuse wormhole_post_message_shim::{program::WormholePostMessageShim, types::Finality};\nuse wormhole_solana_consts::{\n    CORE_BRIDGE_CONFIG, CORE_BRIDGE_FEE_COLLECTOR, CORE_BRIDGE_PROGRAM_ID,\n};\n```"}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 2, "depth": 2, "title": "Accounts", "anchor": "accounts", "start_char": 2559, "end_char": 6653, "estimated_token_count": 931, "token_estimator": "heuristic-v1", "text": "## Accounts\n\nWhen calling the shim’s `post_message` instruction, you need to pass:\n\n- **`bridge`**: Holds the Wormhole core bridge config.\n- **`message`**: Represents the PDA derived from the emitter and is reused by the shim instead of generating new accounts.\n- **`emitter`**: Serves as the emitter address (signer).\n- **`sequence`**: Tracks the emitter's sequence account.\n- **`payer`**: Pays compute and any rent needed on first use (signer).\n- **`fee_collector`**: Collects the Wormhole message fee.\n- **`clock`**: Provides the current Solana time from the sysvar.\n- **`system_program`**: Supplies the standard Solana system program for account creation on first use.\n- **`wormhole_program`**: Points to the Wormhole core bridge program.\n- **`event_authority`**: Acts as the PDA used by the shim to emit log events (Anchor CPI events).\n- **`program`**: Specifies the shim program itself.\n\nThe struct below defines the accounts required by your instruction and wires the shim to the core bridge, ensuring the emitter PDA can sign the CPI via seeds.\n\n```rs\n#[derive(Accounts)]\npub struct PostMessage<'info> {\n    #[account(mut)]\n    payer: Signer<'info>,\n\n    wormhole_post_message_shim: Program<'info, WormholePostMessageShim>,\n\n    #[account(mut, address = CORE_BRIDGE_CONFIG)]\n    /// CHECK: Wormhole bridge config. [`wormhole::post_message`] requires this account be mutable.\n    /// Address constraint added for IDL generation / convenience, it will be enforced by the core bridge.\n    pub bridge: UncheckedAccount<'info>,\n\n    #[account(mut, seeds = [&emitter.key.to_bytes()], bump, seeds::program = wormhole_post_message_shim::ID)]\n    /// CHECK: Wormhole Message. [`wormhole::post_message`] requires this account be signer and mutable.\n    /// Seeds constraint added for IDL generation / convenience, it will be enforced by the shim.\n    pub message: UncheckedAccount<'info>,\n\n    #[account(seeds = [b\"emitter\"], bump)]\n    /// CHECK: Our emitter\n    /// Seeds constraint added for IDL generation / convenience, it will be enforced to match the signer used in the CPI call.\n    pub emitter: UncheckedAccount<'info>,\n\n    #[account(mut)]\n    /// CHECK: Emitter's sequence account. [`wormhole::post_message`] requires this account be mutable.\n    /// Explicitly do not re-derive this account. The core bridge verifies the derivation anyway and\n    /// as of Anchor 0.30.1, auto-derivation for other programs' accounts via IDL doesn't work.\n    pub sequence: UncheckedAccount<'info>,\n\n    #[account(mut, address = CORE_BRIDGE_FEE_COLLECTOR)]\n    /// CHECK: Wormhole fee collector. [`wormhole::post_message`] requires this account be mutable.\n    /// Address constraint added for IDL generation / convenience, it will be enforced by the core bridge.\n    pub fee_collector: UncheckedAccount<'info>,\n\n    /// Clock sysvar.\n    /// Type added for IDL generation / convenience, it will be enforced by the core bridge.\n    pub clock: Sysvar<'info, Clock>,\n\n    /// System program.\n    /// Type for IDL generation / convenience, it will be enforced by the core bridge.\n    pub system_program: Program<'info, System>,\n\n    #[account(address = CORE_BRIDGE_PROGRAM_ID)]\n    /// CHECK: Wormhole program.\n    /// Address constraint added for IDL generation / convenience, it will be enforced by the shim.\n    pub wormhole_program: UncheckedAccount<'info>,\n\n    /// CHECK: Shim event authority\n    /// TODO: An address constraint could be included if this address was published to wormhole_solana_consts\n    /// Address will be enforced by the shim.\n    pub wormhole_post_message_shim_ea: UncheckedAccount<'info>,\n}\n```\n\nThis instruction reuses a single per-emitter message PDA (no per-message rent). When invoked, the shim emits your payload as an Anchor CPI event and, in the same transaction, calls the core bridge with an empty payload, allowing the core bridge to still assign the sequence and enforce fees/finality. Guardians read the Core call (sequence/finality) and the shim event (payload) from the transaction logs, producing a standard VAA without leaving a persistent message account."}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 3, "depth": 2, "title": "Call post_message", "anchor": "call-post_message", "start_char": 6653, "end_char": 8930, "estimated_token_count": 458, "token_estimator": "heuristic-v1", "text": "## Call post_message\n\nThe `post_message` function builds a `CpiContext` and invokes the shim’s `post_message` instruction, forwarding the nonce, finality, and your payload. The Core Bridge enforces fee requirements and assigns the sequence, while the shim emits the payload as an event in the same transaction.\n\n```rs\npub fn post_message(ctx: Context<PostMessage>) -> Result<()> {\n    // wormhole::post_message may require that a fee be sent to the fee_collector account of the core bridge.\n    // The following code could be used to handle this via CPI call.\n    // However, this example handles this complexity on the client side using a `preInstruction`\n    //\n    // let fee = ctx.accounts.wormhole_bridge.fee();\n    // if fee > 0 {\n    //     solana_program::program::invoke(\n    //         &solana_program::system_instruction::transfer(\n    //             &ctx.accounts.payer.key(),\n    //             &ctx.accounts.fee_collector.key(),\n    //             fee,\n    //         ),\n    //         &ctx.accounts.to_account_infos(),\n    //     )?;\n    // }\n\n    wormhole_post_message_shim::cpi::post_message(\n        CpiContext::new_with_signer(\n            ctx.accounts.wormhole_post_message_shim.to_account_info(),\n            wormhole_post_message_shim::cpi::accounts::PostMessage {\n                payer: ctx.accounts.payer.to_account_info(),\n                bridge: ctx.accounts.bridge.to_account_info(),\n                message: ctx.accounts.message.to_account_info(),\n                emitter: ctx.accounts.emitter.to_account_info(),\n                sequence: ctx.accounts.sequence.to_account_info(),\n                fee_collector: ctx.accounts.fee_collector.to_account_info(),\n                clock: ctx.accounts.clock.to_account_info(),\n                system_program: ctx.accounts.system_program.to_account_info(),\n                wormhole_program: ctx.accounts.wormhole_program.to_account_info(),\n                program: ctx.accounts.wormhole_post_message_shim.to_account_info(),\n                event_authority: ctx.accounts.wormhole_post_message_shim_ea.to_account_info(),\n            },\n            &[&[b\"emitter\", &[ctx.bumps.emitter]]],\n        ),\n        0,\n        Finality::Finalized,\n        b\"your message goes here!\".to_vec(),\n    )?;\n\n    Ok(())\n}\n```"}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 4, "depth": 2, "title": "Limitations and Considerations", "anchor": "limitations-and-considerations", "start_char": 8930, "end_char": 9449, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "## Limitations and Considerations \n\n- **Rent**: No persistent account rent is paid for every emission; the cost is now dominated by compute and the emission fee.\n- **Logs**: Since all observability is log-based, re-observation is only possible while Solana transaction history is available.\n- **Parallelization**: Still limited by the `fee_collector` account being mutable.\n- **CPI Depth**: The first shim call for an emitter adds one extra stack depth. This is only relevant if you are near the Solana CPI limit (4)."}
{"page_id": "products-messaging-guides-solana-shims-sol-emission", "page_title": "Solana Message Emission via Shim", "index": 5, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 9449, "end_char": 9949, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nBy using the emission shim, you can dramatically reduce rent costs when emitting Wormhole messages from Solana, while ensuring compatibility with Guardian observation and core bridge sequencing.\n\nFor a complete, working reference, see the full example implementation in the Wormhole repo: [`post_message.rs`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/programs/wormhole-integrator-example/src/instructions/post_message.rs){target=\\_blank}."}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1130, "end_char": 1883, "estimated_token_count": 187, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo interact with the verification shim, you'll need the following:\n\n- [Rust and Solana CLI installed](https://solana.com/docs/intro/installation){target=\\_blank}.  \n- [Anchor installed](https://www.anchor-lang.com/docs/installation){target=\\_blank}.\n- The canonical verification shim program already deployed at [`EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at`](https://explorer.solana.com/address/EFaNWErqAtVWufdNb7yofSHHfWFos843DFpu4JBw24at){target=\\_blank}.\n- The shim’s [IDL](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/idls/wormhole_verify_vaa_shim.json){target=\\_blank} for wiring accounts.\n- A payer (signer) funded for compute and temporary account rent (you’ll close and reclaim)."}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 1, "depth": 2, "title": "Setup", "anchor": "setup", "start_char": 1883, "end_char": 2378, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Setup\n\nTo start, add the verification shim CPI and declare the external program so your instruction can CPI into it. This lets your program verify a VAA digest against the active Guardian set without creating persistent core bridge accounts.\n\n```rs\ndeclare_program!(wormhole_verify_vaa_shim);\n\nuse anchor_lang::{\n    prelude::*,\n    solana_program::{self, keccak},\n};\nuse wormhole_verify_vaa_shim::cpi::accounts::VerifyHash;\nuse wormhole_verify_vaa_shim::program::WormholeVerifyVaaShim;\n```"}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 2, "depth": 2, "title": "Accounts", "anchor": "accounts", "start_char": 2378, "end_char": 3520, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "## Accounts\n\nYou’ll wire three accounts for verification:\n\n- `guardian_set`: Core bridge `GuardianSet` PDA for the VAA’s `guardianSetIndex` (shim checks derivation).\n- `guardian_signatures`: Temporary account created by `post_signatures` (shim checks ownership & discriminator).\n- `wormhole_verify_vaa_shim`: The verification shim program.\n\n```rs\n#[derive(Accounts)]\npub struct ConsumeVaa<'info> {\n    /// CHECK: Guardian set used for signature verification by shim.\n    /// Derivation is checked by the shim.\n    guardian_set: UncheckedAccount<'info>,\n\n    /// CHECK: Stored guardian signatures to be verified by shim.\n    /// Ownership ownership and discriminator is checked by the shim.\n    guardian_signatures: UncheckedAccount<'info>,\n\n    wormhole_verify_vaa_shim: Program<'info, WormholeVerifyVaaShim>,\n}\n```\n\nHere, `guardian_set` is a core bridge PDA, and `guardian_signatures` is created and owned by the verification shim. Derive `guardian_set = PDA([\"GuardianSet\", index_be_bytes], CORE_BRIDGE_PROGRAM_ID)` using the `guardianSetIndex` from the VAA header (big-endian), compute its bump, and pass that bump into your instruction."}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 3, "depth": 2, "title": "Verify the VAA", "anchor": "verify-the-vaa", "start_char": 3520, "end_char": 4683, "estimated_token_count": 239, "token_estimator": "heuristic-v1", "text": "## Verify the VAA\n\nThe `consume_vaa` function computes the digest, calls the shim’s `verify_hash`, and then proceeds with your logic. This step validates Guardian signatures and quorum against the active Guardian set for the VAA’s `guardianSetIndex`, then lets your program proceed without persisting a `PostedVAA`. \n\n```rs\npub fn consume_vaa(\n    ctx: Context<ConsumeVaa>,\n    guardian_set_bump: u8,\n    vaa_body: Vec<u8>,\n) -> Result<()> {\n    // Compute the message hash.\n    let message_hash = &solana_program::keccak::hashv(&[&vaa_body]).to_bytes();\n    let digest = keccak::hash(message_hash.as_slice()).to_bytes();\n    // Verify the hash against the signatures.\n    wormhole_verify_vaa_shim::cpi::verify_hash(\n        CpiContext::new(\n            ctx.accounts.wormhole_verify_vaa_shim.to_account_info(),\n            VerifyHash {\n                guardian_set: ctx.accounts.guardian_set.to_account_info(),\n                guardian_signatures: ctx.accounts.guardian_signatures.to_account_info(),\n            },\n        ),\n        guardian_set_bump,\n        digest,\n    )?;\n    // Decode vaa_body, perform security checks, and do your thing.\n    Ok(())\n}\n```"}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 4, "depth": 2, "title": "Limitations and Security Considerations", "anchor": "limitations-and-security-considerations", "start_char": 4683, "end_char": 5298, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "## Limitations and Security Considerations\n\n- You must be the payer and/or account owner to reclaim lamports from the `GuardianSignatures` account.\n- The verification proof is not a permanent on-chain record unless you keep the account.\n- Compute usage (CU) is higher for the rent-efficient pattern, but the total cost is dramatically lower than keeping permanent accounts.\n- All validation guarantees remain as strong as with the legacy method.\n- If you do not close accounts you create, rent will be lost as before.\n- This approach assumes you do not need to later re-validate the VAA from an on-chain artifact."}
{"page_id": "products-messaging-guides-solana-shims-sol-verification", "page_title": "Solana VAA Verification via Shim", "index": 5, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 5298, "end_char": 5740, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nBy following this flow, you can efficiently verify VAAs on Solana with minimal rent overhead, leaving no unnecessary state behind on-chain. For a complete, working reference, see the full example implementation in the Wormhole repo: [`consume_vaa.rs`](https://github.com/wormhole-foundation/wormhole/blob/main/svm/wormhole-core-shims/anchor/programs/wormhole-integrator-example/src/instructions/consume_vaa.rs){target=\\_blank}."}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 967, "end_char": 1261, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n - [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally."}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 1, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 1261, "end_char": 3385, "estimated_token_count": 507, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nIn this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript.\n\n1. **Create the project**: set up the directory and navigate into it.\n\n    ```bash\n    mkdir wormholescan-api-demo\n    cd wormholescan-api-demo\n    ```\n\n2. **Initialize a Node.js project**: generate a `package.json` file.\n\n    ```bash\n    npm init -y\n    ```\n\n3. **Set up TypeScript**: create a `tsconfig.json` file.\n\n    ```bash\n    touch tsconfig.json\n    ```\n\n    Then, add the following configuration:\n\n    ```json title=\"tsconfig.json\"\n    {\n        \"compilerOptions\": {\n            \"target\": \"ES2022\",\n            \"module\": \"ESNext\",\n            \"moduleResolution\": \"node\",\n            \"strict\": true,\n            \"esModuleInterop\": true,\n            \"allowSyntheticDefaultImports\": true,\n            \"skipLibCheck\": true,\n            \"outDir\": \"./dist\",\n            \"declaration\": true,\n            \"declarationMap\": true,\n            \"sourceMap\": true\n        },\n        \"include\": [\"src/**/*\"],\n        \"exclude\": [\"node_modules\", \"dist\"]\n    }\n    ```\n\n4. **Install dependencies**: add the required packages. This guide uses the SDK version `3.x`.\n\n    ```bash\n    npm install @wormhole-foundation/sdk axios\n    npm install -D tsx typescript @types/node\n    ```\n\n     - `@wormhole-foundation/sdk`: utility methods (e.g., chain ID helpers).\n     - `axios`: HTTP client for calling the Wormholescan API.\n     - `tsx`: runs TypeScript files without compiling them.\n     - `typescript`: adds TypeScript support.\n     - `@types/node`: provides Node.js type definitions.\n\n5. **Create the project structure**: set up the required directories and files.\n\n    ```bash\n    mkdir -p src/helpers src/scripts\n\n    touch \\\n        src/helpers/api-client.ts \\\n        src/helpers/utils.ts \\\n        src/helpers/types.ts \\\n        src/scripts/fetch-ntt-tokens.ts \\\n        src/scripts/fetch-operations.ts\n    ```\n\n     - `src/helpers/`: contains shared API logic, utilities, and type definitions.\n     - `src/scripts/`: contains runnable scripts for fetching token and transfer data."}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 2, "depth": 2, "title": "Create Helper Functions", "anchor": "create-helper-functions", "start_char": 3385, "end_char": 3735, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "## Create Helper Functions\n\nBefore writing scripts that interact with Wormholescan, we will define a few reusable helper modules. These will handle API calls, extract token and chain data, and provide consistent TypeScript types for working with NTT tokens and transfers.\n\nThese helpers will make it easier to write clean, focused scripts later on."}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 3, "depth": 3, "title": "Create a Wormholescan API Client", "anchor": "create-a-wormholescan-api-client", "start_char": 3735, "end_char": 6048, "estimated_token_count": 532, "token_estimator": "heuristic-v1", "text": "### Create a Wormholescan API Client\n\nIn this step, you will create a lightweight API client to interact with Wormholescan. This helper will enable you to easily fetch NTT tokens and perform token transfer operations using a reusable `get()` method with built-in error handling. The client supports both mainnet and testnet endpoints.\n\nIt exposes two core methods:\n\n - `getNTTTokens()`: fetches the complete list of NTT-enabled tokens.\n - `getTokenTransfers()`: fetches token transfer operations with optional filters (chain, address, pagination, etc.).\n\nUnder the hood, both methods use a generic `get(endpoint, params)` wrapper that handles URL construction and error reporting.\n\nAdd the following code to `src/helpers/api-client.ts`:\n\n```typescript title=\"src/helpers/api-client.ts\"\nimport axios, { AxiosResponse } from 'axios';\n\n// WormholeScan API Client -  simple wrapper for making requests to the WormholeScan API\nexport class WormholeScanAPI {\n  private baseURL: string;\n\n  constructor(isTestnet: boolean = false) {\n    this.baseURL = isTestnet\n      ? 'https://api.testnet.wormholescan.io/api/v1'\n      : 'https://api.wormholescan.io/api/v1';\n  }\n\n  async get<T>(endpoint: string, params?: Record<string, any>): Promise<T> {\n    try {\n      const response: AxiosResponse<T> = await axios.get(\n        `${this.baseURL}${endpoint}`,\n        {\n          params,\n          headers: {\n            'Content-Type': 'application/json',\n          },\n        }\n      );\n\n      return response.data;\n    } catch (error) {\n      if (axios.isAxiosError(error)) {\n        throw new Error(\n          `API request failed: ${error.response?.status} - ${error.response?.statusText}`\n        );\n      }\n      throw new Error(`Unexpected error: ${error}`);\n    }\n  }\n\n  async getNTTTokens(withLinks: boolean = false) {\n    return this.get('/native-token-transfer/token-list', { withLinks });\n  }\n\n  async getTokenTransfers(\n    params: {\n      tokenAddress?: string;\n      fromChain?: number;\n      toChain?: number;\n      page?: number;\n      pageSize?: number;\n      sortBy?: string;\n      sortOrder?: 'asc' | 'desc';\n    } = {}\n  ) {\n    return this.get('/native-token-transfer', params);\n  }\n}\n\nexport const wormholeScanAPI = new WormholeScanAPI();\nexport const wormholeScanTestnetAPI = new WormholeScanAPI(true);\n```"}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 4, "depth": 3, "title": "Add Utility Functions", "anchor": "add-utility-functions", "start_char": 6048, "end_char": 8333, "estimated_token_count": 510, "token_estimator": "heuristic-v1", "text": "### Add Utility Functions\n\nNext, you will define two utility functions that help interpret NTT tokens and operations from Wormholescan:\n\n - `getRandomPlatform(token)`: selects a random platform for a given NTT token and returns its address and chain ID.\n - `getOperationStatus(operation)`: interprets the status of a token transfer operation (e.g., In Progress, Emitted, Completed).\n\nThese utilities will be used in later scripts to randomly select a chain/token combo and display the transfer status more clearly.\n\nAdd the following code to `src/helpers/utils.ts`:\n\n```typescript title=\"src/helpers/utils.ts\"\nimport { toChainId } from '@wormhole-foundation/sdk';\nimport { NTTToken, Operation } from './types';\n\nexport function getRandomPlatform(\n  token: NTTToken\n): { platform: string; address: string; chainId: number } | null {\n  const platforms = Object.entries(token.platforms);\n\n  if (platforms.length === 0) {\n    return null;\n  }\n\n  const randomIndex = Math.floor(Math.random() * platforms.length);\n  const [platform, address] = platforms[randomIndex];\n\n  try {\n    // SDK expects \"Ethereum\" not \"ethereum\"\n    const capitalizedPlatform =\n      platform.charAt(0).toUpperCase() + platform.slice(1);\n    const chainId = toChainId(capitalizedPlatform);\n    return { platform, address, chainId };\n  } catch (error) {\n    const platformMapping: Record<string, string> = {\n      'arbitrum-one': 'Arbitrum',\n      'binance-smart-chain': 'Bsc',\n      'polygon-pos': 'Polygon',\n      'optimistic-ethereum': 'Optimism',\n    };\n\n    const mappedPlatform = platformMapping[platform.toLowerCase()];\n    if (mappedPlatform) {\n      try {\n        const chainId = toChainId(mappedPlatform);\n        return { platform, address, chainId };\n      } catch (mappedError) {\n        console.warn(\n          `Could not convert mapped platform ${mappedPlatform} to chain ID`\n        );\n        return null;\n      }\n    }\n\n    console.warn(`Could not convert platform ${platform} to chain ID`);\n    return null;\n  }\n}\n\nexport function getOperationStatus(operation: Operation): string {\n  if (operation.targetChain) {\n    return 'Completed';\n  } else if (operation.vaa) {\n    return 'Emitted';\n  } else if (operation.sourceChain) {\n    return 'In Progress';\n  } else {\n    return 'Unknown';\n  }\n}\n```"}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 5, "depth": 3, "title": "Define Types for NTT Tokens and Transfers", "anchor": "define-types-for-ntt-tokens-and-transfers", "start_char": 8333, "end_char": 11613, "estimated_token_count": 594, "token_estimator": "heuristic-v1", "text": "### Define Types for NTT Tokens and Transfers\n\nBefore proceeding, let's define the TypeScript interfaces required for type-safe API responses from Wormholescan. These types will be used throughout the project to validate and work with token metadata and transfer operations.\n\nAdd the following content inside `src/helpers/types.ts`:\n\n```typescript title=\"src/helpers/types.ts\"\nexport interface NTTToken {\n  symbol: string;\n  coingecko_id: string;\n  fully_diluted_valuation: string;\n  price: string;\n  price_change_percentage_24h: string;\n  volume_24h: string;\n  total_value_transferred: string;\n  total_value_locked: string | null;\n  market_cap: string;\n  circulating_supply: string;\n  image: {\n    thumb: string;\n    small: string;\n    large: string;\n  };\n  platforms: Record<string, string>;\n}\n\nexport interface NTTTokenDetail {\n  home: {\n    blockchain: string;\n    externalSalt: string | null;\n    isCanonical: boolean;\n    lastIndexed: number;\n    manager: {\n      address: string;\n      limits: Array<{\n        amount: string;\n        baseAmount: string;\n        blockchain: string;\n        type: string;\n        wormholeChainId: number;\n      }>;\n      owner: {\n        address: string | null;\n        nttOwner: string | null;\n      };\n      transceivers: Array<{\n        address: string;\n        index: number;\n        type: string;\n      }>;\n      version: string;\n    };\n    mode: string;\n    token: {\n      address: string;\n      decimals: number;\n      maxSupply: string;\n      minter: string;\n      name: string;\n      owner: string;\n      symbol: string;\n      totalSupply: string;\n    };\n    wormholeChainId: number;\n  };\n  peers: any[];\n}\n\nexport interface Operation {\n  id: string;\n  emitterChain: number;\n  emitterAddress: {\n    hex: string;\n    native: string;\n  };\n  sequence: string;\n  vaa?: {\n    raw: string;\n    guardianSetIndex: number;\n    isDuplicated: boolean;\n  };\n  content: {\n    payload: {\n      nttManagerMessage: {\n        id: string;\n        sender: string;\n      };\n      nttMessage: {\n        additionalPayload: string;\n        sourceToken: string;\n        to: string;\n        toChain: number;\n        trimmedAmount: {\n          amount: string;\n          decimals: number;\n        };\n      };\n      transceiverMessage: {\n        prefix: string;\n        recipientNttManager: string;\n        sourceNttManager: string;\n        transceiverPayload: string;\n      };\n    };\n    standarizedProperties: {\n      appIds: string[];\n      fromChain: number;\n      fromAddress: string;\n      toChain: number;\n      toAddress: string;\n      tokenChain: number;\n      tokenAddress: string;\n      amount: string;\n      feeAddress: string;\n      feeChain: number;\n      fee: string;\n      normalizedDecimals: number;\n    };\n  };\n  sourceChain?: {\n    chainId: number;\n    timestamp: string;\n    transaction: {\n      txHash: string;\n    };\n    from: string;\n    status: string;\n    fee: string;\n    gasTokenNotional: string;\n    feeUSD: string;\n  };\n  targetChain?: {\n    chainId: number;\n    timestamp: string;\n    transaction: {\n      txHash: string;\n    };\n    status: string;\n    from: string;\n    to: string;\n    fee: string;\n    gasTokenNotional: string;\n    feeUSD: string;\n  };\n}\n\nexport interface OperationsResponse {\n  operations: Operation[];\n}\n```"}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 6, "depth": 2, "title": "Fetch and Inspect NTT Tokens", "anchor": "fetch-and-inspect-ntt-tokens", "start_char": 11613, "end_char": 15861, "estimated_token_count": 1159, "token_estimator": "heuristic-v1", "text": "## Fetch and Inspect NTT Tokens\n\nIn this step, you will create a script that fetches a list of NTT tokens from Wormholescan and inspects their detailed metadata.\n\nThe script does the following:\n\n - Retrieves all available NTT tokens via the API client.\n - Picks the first 5 with platform data.\n - Selects a random platform for each token (e.g., Ethereum, Arbitrum).\n - Fetches and logs metadata for that token on that platform.\n\nYou can control how many tokens are processed by modifying the `TOKENS_TO_PROCESS` constant near the top of the script.\n\nAdd the following code to `src/scripts/fetch-ntt-tokens.ts`:\n\n```typescript title=\"src/scripts/fetch-ntt-tokens.ts\"\n#!/usr/bin/env tsx\n\nimport { wormholeScanAPI } from '../helpers/api-client';\nimport { NTTToken, NTTTokenDetail } from '../helpers/types';\nimport { getRandomPlatform } from '../helpers/utils';\n\n// Configurable variable - easily adjust the number of tokens to process\nconst TOKENS_TO_PROCESS = INSERT_NUMBER_OF_TOKENS;\n\nasync function fetchNTTTokens() {\n  console.log('🔍 Fetching NTT tokens from WormholeScan API...\\n');\n\n  try {\n    const tokens = (await wormholeScanAPI.getNTTTokens(false)) as NTTToken[];\n\n    // Get detailed information for tokens\n    const tokensWithPlatforms = tokens.filter(\n      (token) => Object.keys(token.platforms).length > 0\n    );\n    const tokensToProcess = tokensWithPlatforms.slice(0, TOKENS_TO_PROCESS);\n\n    console.log(\n      `🔍 Fetching detailed NTT information for first ${TOKENS_TO_PROCESS} tokens...\\n`\n    );\n\n    for (const token of tokensToProcess) {\n      console.log(`📋 ${token.symbol} (${token.coingecko_id})`);\n\n      // Get a random platform from the token's available platforms\n      const platformInfo = getRandomPlatform(token);\n\n      if (!platformInfo) {\n        console.error(\n          `❌ Could not determine platform info for ${token.symbol}`\n        );\n        continue;\n      }\n\n      const { platform, address, chainId } = platformInfo;\n\n      console.log(`Selected Platform: ${platform} (Chain ID: ${chainId})`);\n\n      try {\n        // Fetch detailed NTT information using the correct chain ID\n        const detail = (await wormholeScanAPI.get(\n          `/ntt/token/${chainId}/${address}`\n        )) as NTTTokenDetail;\n\n        console.log(`Token Name: ${detail.home.token.name}`);\n        console.log(`Token Symbol: ${detail.home.token.symbol}`);\n        console.log(`Mode: ${detail.home.mode}`);\n        console.log(`Manager Address: ${detail.home.manager.address}`);\n        console.log(`Version: ${detail.home.manager.version}`);\n        console.log(\n          `Transceiver Address: ${\n            detail.home.manager.transceivers[0]?.address || 'N/A'\n          }`\n        );\n      } catch (error) {\n        console.log(\n          `❌ No NTT configuration found for ${token.symbol} on ${platform}`\n        );\n      }\n\n      console.log('\\n' + '='.repeat(50) + '\\n');\n    }\n  } catch (error) {\n    console.error('❌ Error fetching NTT tokens:', error);\n    process.exit(1);\n  }\n}\n\nfetchNTTTokens();\n```\n\nRun it with:\n\n```bash\nnpx tsx src/scripts/fetch-ntt-tokens.ts\n```\n\nIf successful, the output will be:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>npm run ntt-tokens</span>\n\t<span data-ty> </span>\n\t<span data-ty>> demo-wormholescan-api@1.0.0 ntt-tokens</span>\n\t<span data-ty>> npx tsx src/scripts/fetch-ntt-tokens.ts</span>\n\t<span data-ty> </span>\n\t<span data-ty>🔍 Fetching NTT tokens from WormholeScan API...</span>\n\t<span data-ty> </span>\n\t<span data-ty>🔍 Fetching detailed NTT information for first 5 tokens... </span>\n\t<span data-ty> </span>\n\t<span data-ty>📋 LINGO (lingo) </span>\n\t<span data-ty>Selected Platform: solana (Chain ID: 1) </span>\n\t<span data-ty>Token Name: Lingo </span>\n    <span data-ty>Token Symbol: Lingo </span>\n    <span data-ty>Mode: burning </span>\n    <span data-ty>Manager Address: nTTQspEC1JoEUJVFTcgZSatgcv4PNT8UYtCtyaUSKcX </span>\n    <span data-ty>Version: 3.0.0 </span>\n    <span data-ty>Transceiver Address: CnDQ53A3j2EcniJAm7UtuYKmQtovFAmumcuzC648moSE </span>\n    <span data-ty>================================================== </span>\n    <span data-ty>... </span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 7, "depth": 2, "title": "Fetch Transfer Operations", "anchor": "fetch-transfer-operations", "start_char": 15861, "end_char": 19712, "estimated_token_count": 917, "token_estimator": "heuristic-v1", "text": "## Fetch Transfer Operations\n\nNow, you will create a script to fetch NTT transfer operations using the Wormholescan API. These operations contain key details such as:\n\n - Source and target chains.\n - Wallet addresses.\n - Token amount and metadata.\n - VAA and execution status.\n\nYou will log the first few operations in a readable format to better understand how transfers are structured.\n\nThe script will use a specific emitter address to query transfers. You can easily change which token or manager you are tracking by modifying the `EMITTER_ADDRESS` constant near the top of the file.\n\nAdd the following code to `src/scripts/fetch-operations.ts`:\n\n```typescript title=\"src/scripts/fetch-operations.ts\"\n#!/usr/bin/env tsx\n\nimport { wormholeScanTestnetAPI } from '../helpers/api-client';\nimport { OperationsResponse } from '../helpers/types';\nimport { getOperationStatus } from '../helpers/utils';\n\nconst EMITTER_ADDRESS = 'INSERT_EMITTER_ADDRESS';\nconst PAGE_SIZE = 'INSERT_NUMBER_OF_TRANSFERS_TO_FETCH'; // e.g., 10, 20, etc.\n\nasync function fetchTokenTransfers() {\n  console.log(\n    '🔍 Fetching token transfer operations from WormholeScan API...\\n'\n  );\n\n  try {\n    const response = (await wormholeScanTestnetAPI.get(\n      `/operations?address=${EMITTER_ADDRESS}&pageSize=${PAGE_SIZE}`\n    )) as OperationsResponse;\n\n    console.log(\n      `✅ Found ${response.operations.length} operations for emitter ${EMITTER_ADDRESS}\\n`\n    );\n\n    for (const operation of response.operations) {\n      const overallStatus = getOperationStatus(operation);\n      const { standarizedProperties } = operation.content;\n\n      console.log(`📋 Status: ${overallStatus}`);\n      console.log(\n        `🔗 Transfer: Chain ${standarizedProperties.fromChain} → Chain ${standarizedProperties.toChain}`\n      );\n      console.log(`📍 From: ${standarizedProperties.fromAddress}`);\n      console.log(`📍 To: ${standarizedProperties.toAddress}`);\n\n      if (operation.sourceChain) {\n        console.log(\n          `🟢 Source: ${operation.sourceChain.transaction.txHash} (${operation.sourceChain.status})`\n        );\n      }\n\n      if (operation.targetChain) {\n        console.log(\n          `🟢 Target: ${operation.targetChain.transaction.txHash} (${operation.targetChain.status})`\n        );\n      }\n\n      if (operation.vaa && !operation.targetChain) {\n        console.log(`⏳ VAA emitted, awaiting completion`);\n      }\n\n      console.log(''); // Empty line between operations\n    }\n  } catch (error) {\n    console.error('❌ Error fetching token transfers:', error);\n    process.exit(1);\n  }\n}\n\nfetchTokenTransfers();\n```\n\nRun it with:\n\n```bash\nnpx tsx src/scripts/fetch-operations.ts\n```\n\nIf successful, the output will look like this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>npm run operations</span>\n\t<span data-ty> </span>\n\t<span data-ty>> demo-wormholescan-api@1.0.0 operations</span>\n\t<span data-ty>> npx tsx src/scripts/fetch-operations.ts</span>\n\t<span data-ty> </span>\n\t<span data-ty>🔍 Fetching token transfer operations from WormholeScan API...</span>\n\t<span data-ty> </span>\n\t<span data-ty>✅ Found 5 operations for emitter 0xdF77F921a560F6882e4EC4bbDc2fF37a7A26D4Db</span>\n\t<span data-ty> </span>\n\t<span data-ty>📋 Status: Completed</span>\n\t<span data-ty>🔗 Transfer: Chain 1 → Chain 10002</span>\n\t<span data-ty>📍 From: wA8eCo4AR7pAgFsAPpU64wYouBY6CUVPLGuMMBu2eaB</span>\n    <span data-ty>📍 To: 0xdF77F921a560F6882e4EC4bbDc2fF37a7A26D4Db</span>\n    <span data-ty>🟢 Source: 5axKXqHHq8C4vWqKnrZ3vnmDRTu4D9XPMaJBDrMrxuEawhRS7xnwcAJ5UZ1k9eYgakzz4LXopJdJjyCEZDbH9CEH (confirmed)</span>\n    <span data-ty>🟢 Target: 0x619da24b77289c20fbbd2564833b49522f2624db5e92194ddea65f18ebb116fc (completed)</span>\n    <span data-ty> </span>\n    <span data-ty>... </span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-messaging-guides-wormholescan-api", "page_title": "Query NTT Data and Transfers with Wormholescan", "index": 8, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 19712, "end_char": 20078, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "## Resources\n\nYou can explore the complete project and find all necessary scripts and configurations in Wormhole's [demo GitHub repository](https://github.com/wormhole-foundation/demo-wormholescan-api){target=\\_blank}.\n\nThe repository includes everything covered in this guide, which is helpful for dashboards, bots, or alerting systems built on top of Wormholescan."}
{"page_id": "products-messaging-overview", "page_title": "Messaging Overview", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 371, "end_char": 983, "estimated_token_count": 126, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **Multichain messaging**: Send arbitrary data between blockchains, enabling xDapps, governance actions, or coordination across ecosystems.\n- **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.\n- **Composable architecture**: Works with smart contracts, token bridges, or decentralized applications, providing a flexible foundation for multichain use cases."}
{"page_id": "products-messaging-overview", "page_title": "Messaging Overview", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 983, "end_char": 2157, "estimated_token_count": 288, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nThe messaging flow consists of several core components:\n\n1. **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.\n2. **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}.\n3. **Relayers (Executor)**: Off-chain or on-chain relayers transport the VAA to the destination chain. In Wormhole’s architecture, this role is fulfilled by the [**Executor**](/docs/products/messaging/concepts/executor-overview/){target=\\_blank}, a permissionless, shared framework that standardizes message delivery across all supported chains.\n4. **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.\n\n![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp)"}
{"page_id": "products-messaging-overview", "page_title": "Messaging Overview", "index": 2, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 2157, "end_char": 3804, "estimated_token_count": 480, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\nWormhole Messaging enables a wide range of multichain applications. Below are common use cases and the Wormhole stack components you can use to build them.\n\n- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\\_blank})**\n\n    - **[Messaging](/docs/products/messaging/get-started/){target=\\_blank}**: Coordinate actions across chains.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}**: Transfer collateral as native assets.\n\n- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\\_blank})**\n\n    - **[Messaging](/docs/products/messaging/get-started/){target=\\_blank}**: Relay verified data.\n\n- **Gas Abstraction**\n\n    - **[Messaging](/docs/products/messaging/get-started/){target=\\_blank}**: Coordinate gas logic.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}**: Handle native token swaps.\n\n- **Bridging Intent Library**\n\n    - **[Messaging](/docs/products/messaging/get-started/){target=\\_blank}**: Dispatch and execute intents.\n    - **[Settlement](/docs/products/settlement/overview/){target=\\_blank}**: Execute user-defined bridging intents.\n\n- **Decentralized Social Platforms (e.g., [Chingari](https://chingari.io/){target=\\_blank})**\n\n    - **[Messaging](/docs/products/messaging/get-started/){target=\\_blank}**: Facilitate decentralized interactions.\n    - **[Wrapped Token Transfers](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}**: Enable tokenized rewards."}
{"page_id": "products-messaging-overview", "page_title": "Messaging Overview", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3804, "end_char": 4962, "estimated_token_count": 286, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nFollow these steps to work with Wormhole Messaging:\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with Messaging**\n\n    ---\n\n    Use the core protocol to publish a multichain message and return transaction info with VAA identifiers.\n\n    [:custom-arrow: Get Started](/docs/products/messaging/get-started/)\n\n-   :octicons-book-16:{ .lg .middle } **Executor Overview**\n\n    ---\n\n    Learn how to use Executors to automate message handling and application logic across chains.\n\n    [:custom-arrow: Learn about Executors](/docs/protocol/infrastructure/relayers/executor-framework/)\n\n-   :octicons-tools-16:{ .lg .middle } **Solana Shim Programs**\n\n    ---\n\n    For lower-cost, efficient integration with Core Bridge on Solana, consider using shim programs:\n\n    [:custom-arrow: Learn about Solana Shims](/docs/products/messaging/concepts/solana-shim/)\n\n    [:custom-arrow: Emit Messages with the Emission Shim](/docs/products/messaging/guides/solana-shims/sol-emission/)\n\n    [:custom-arrow: Verify VAAs with the Verification Shim](/docs/products/messaging/guides/solana-shims/sol-verification/)\n\n</div>"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 371, "end_char": 1685, "estimated_token_count": 279, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe Wormhole Core system consists of a proxy contract and a modular implementation constructed through layered inheritance.\n\n```text\nWormhole.sol (Proxy)\n└── Implementation.sol\n    └── Governance.sol\n        ├── Getters.sol\n        ├── GovernanceStructs.sol\n        ├── Messages.sol\n        ├── Setters.sol\n        └── Structs.sol\n```\n\n**Key Components:**\n\n - **Wormhole.sol**: The upgradeable proxy contract that delegates all logic to `Implementation.sol`.\n - **Implementation.sol**: The main logic contract, which handles message publication and initialization. Inherits from Governance.sol.\n - **Governance.sol**: Core governance logic for processing upgrades, setting fees, and updating the Guardian set. Also responsible for verifying governance VAAs and performing privileged actions.\n - **Getters.sol**: Exposes view functions to access internal contract state, such as current Guardian sets, fees, and contract configuration.\n - **GovernanceStructs.sol**: Provides structures and helpers for processing governance-related VAAs.\n - **Messages.sol**: Handles VAA parsing and verification.\n - **Setters.sol**: Contains internal functions for mutating contract state.\n - **Structs.sol**: Defines core data structures like GuardianSet and VM (VAA Message) used across multiple modules."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 1, "depth": 2, "title": "State Variables", "anchor": "state-variables", "start_char": 1685, "end_char": 2800, "estimated_token_count": 311, "token_estimator": "heuristic-v1", "text": "## State Variables\n\n - **`provider` ++\"Structs.Provider\"++**: Holds metadata like `chainId`, `governanceChainId`, and `governanceContract`. This is a nested struct.\n - **`guardianSets` ++\"mapping(uint32 => GuardianSet)\"++**: Mapping of all Guardian sets by index.\n - **`guardianSetIndex` ++\"uint32\"++**: Index of the currently active Guardian set.\n - **`guardianSetExpiry` ++\"uint32\"++**: How long a Guardian set remains valid after it's replaced (in seconds).\n - **`sequences` ++\"mapping(address => uint64)\"++**: Tracks message sequences per emitter (used to enforce message ordering).\n - **`consumedGovernanceActions` ++\"mapping(bytes32 => bool)\"++**: Used to prevent governance VAAs from being reused (replay protection).\n - **`initializedImplementations` ++\"mapping(address => bool)\"++**: Tracks which implementation addresses have been initialized (for upgrade safety).\n - **`messageFee` ++\"uint256\"++**: The amount (in native gas token) required to post a message. Set via governance.\n - **`evmChainId` ++\"uint256\"++**: The actual EVM chain ID (e.g., 1 for Ethereum, 10 for Optimism). Used in fork recovery."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 2, "depth": 2, "title": "Events", "anchor": "events", "start_char": 2800, "end_char": 2811, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Events"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 3, "depth": 3, "title": "LogMessagePublished", "anchor": "logmessagepublished", "start_char": 2811, "end_char": 3592, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "### LogMessagePublished\n\nEmitted when a message is published via `publishMessage`. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*\n\n```solidity\nevent LogMessagePublished(\n    address indexed sender,\n    uint64 sequence,\n    uint32 nonce,\n    bytes payload,\n    uint8 consistencyLevel\n)\n```\n\n??? interface \"Parameters\"\n\n    `sender` ++\"address\"++  \n\n    Address that called `publishMessage`.\n\n    ---\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the message.\n\n    ---\n\n    `nonce` ++\"uint32\"++\n\n    The provided nonce.\n\n    ---\n\n    `payload` ++\"bytes\"++\n\n    The payload that was published.\n\n    ---\n\n    `consistencyLevel` ++\"uint8\"++\n\n    Finality level requested."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 4, "depth": 3, "title": "ContractUpgraded", "anchor": "contractupgraded", "start_char": 3592, "end_char": 4143, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "### ContractUpgraded\n\nEmitted when the Core Contract is upgraded to a new implementation via governance. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*\n\n```solidity\nevent ContractUpgraded(\n    address indexed oldContract,\n    address indexed newContract\n)\n```\n\n??? interface \"Parameters\"\n\n    `oldContract` ++\"address\"++\n\n    The address of the previous implementation.\n\n    ---\n\n    `newContract` ++\"address\"++\n\n    The address of the new implementation."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 5, "depth": 3, "title": "GuardianSetAdded", "anchor": "guardiansetadded", "start_char": 4143, "end_char": 4535, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "### GuardianSetAdded\n\nEmitted when a new Guardian set is registered via governance. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*\n\n```solidity\nevent GuardianSetAdded(\n    uint32 indexed index\n)\n```\n\n??? interface \"Parameters\"\n\n    `index` ++\"uint32\"++\n\n    Index of the newly added Guardian set."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 6, "depth": 3, "title": "LogGuardianSetChanged", "anchor": "logguardiansetchanged", "start_char": 4535, "end_char": 5044, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "### LogGuardianSetChanged\n\nEmitted when the active Guardian set is changed. *(Defined in [State.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/State.sol){target=\\_blank})*\n\n```solidity\nevent LogGuardianSetChanged(\n    uint32 oldGuardianIndex,\n    uint32 newGuardianIndex\n)\n```\n\n??? interface \"Parameters\"\n\n    `oldGuardianIndex` ++\"uint32\"++\n\n    The previous active Guardian set index.\n\n    ---\n\n    `newGuardianIndex` ++\"uint32\"++\n\n    The new active Guardian set index."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 7, "depth": 2, "title": "Functions", "anchor": "functions", "start_char": 5044, "end_char": 5058, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Functions"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 8, "depth": 3, "title": "publishMessage", "anchor": "publishmessage", "start_char": 5058, "end_char": 5862, "estimated_token_count": 186, "token_estimator": "heuristic-v1", "text": "### publishMessage\n\nPublishes a message to Wormhole's Guardian Network. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*\n\n```solidity\nfunction publishMessage(\n    uint32 nonce,\n    bytes memory payload,\n    uint8 consistencyLevel\n) public payable returns (uint64 sequence)\n```\n\n??? interface \"Parameters\"\n\n    `nonce` ++\"uint32\"++\n\n    Custom sequence identifier for the emitter.\n\n    ---\n\n    `payload` ++\"bytes\"++\n\n    Arbitrary user data to be included in the message.\n\n    ---\n\n    `consistencyLevel` ++\"uint8\"++\n\n    Finality requirement for Guardian attestation (e.g., safe or finalized).\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    Unique sequence number assigned to this message."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 9, "depth": 3, "title": "getCurrentGuardianSetIndex", "anchor": "getcurrentguardiansetindex", "start_char": 5862, "end_char": 6473, "estimated_token_count": 137, "token_estimator": "heuristic-v1", "text": "### getCurrentGuardianSetIndex\n\nReturns the index of the currently active Guardian set. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\nEach VAA includes the index of the Guardian set that signed it. This function allows contracts to retrieve the current index, ensuring the VAA is verified against the correct set.\n\n```solidity\nfunction getCurrentGuardianSetIndex() external view returns (uint32)\n```\n\n??? interface \"Returns\"\n\n    `index` ++\"uint32\"++\n\n    The index of the active Guardian set used to verify signatures."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 10, "depth": 3, "title": "getGuardianSet", "anchor": "getguardianset", "start_char": 6473, "end_char": 7103, "estimated_token_count": 157, "token_estimator": "heuristic-v1", "text": "### getGuardianSet\n\nRetrieves metadata for a given Guardian set index. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction getGuardianSet(uint32 index) external view returns (address[] memory keys, uint32 expirationTime)\n```\n\n??? interface \"Parameters\"\n\n    `index` ++\"uint32\"++\n\n    Guardian set index to query.\n\n??? interface \"Returns\"\n\n    `keys` ++\"address[]\"++\n\n    Public keys of the guardians in this set.\n\n    ---\n\n    `expirationTime` ++\"uint32\"++\n\n    Timestamp after which the Guardian set is considered expired."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 11, "depth": 3, "title": "getGuardianSetExpiry", "anchor": "getguardiansetexpiry", "start_char": 7103, "end_char": 7630, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "### getGuardianSetExpiry\n\nReturns the expiration time of a specific Guardian set index. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction getGuardianSetExpiry(uint32 index) external view returns (uint32)\n```\n\n??? interface \"Parameters\"\n\n    `index` ++\"uint32\"++\n\n    The index of the Guardian set to query.\n\n??? interface \"Returns\"\n\n    `expiry` ++\"uint32\"++\n\n    UNIX timestamp after which the set is no longer valid."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 12, "depth": 3, "title": "messageFee", "anchor": "messagefee", "start_char": 7630, "end_char": 8064, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "### messageFee\n\nReturns the current fee (in native tokens) required to publish a message. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction messageFee() public view returns (uint256)\n```\n\n??? interface \"Returns\"\n\n    `fee` ++\"uint256\"++\n\n    Fee in Wei required to publish a message successfully. Must be sent as `msg.value`."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 13, "depth": 3, "title": "nextSequence", "anchor": "nextsequence", "start_char": 8064, "end_char": 8598, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "### nextSequence\n\nRetrieves the next sequence number for a given emitter address. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction nextSequence(address emitter) external view returns (uint64)\n```\n\n??? interface \"Parameters\"\n\n    `emitter` ++\"address\"++\n\n    The address for which the next sequence will be issued.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    The next sequence number for the specified emitter."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 14, "depth": 3, "title": "parseAndVerifyVM", "anchor": "parseandverifyvm", "start_char": 8598, "end_char": 9360, "estimated_token_count": 181, "token_estimator": "heuristic-v1", "text": "### parseAndVerifyVM\n\nVerifies signatures and parses a signed VAA. *(Defined in [Messages.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Messages.sol){target=\\_blank})*\n\n```solidity\nfunction parseAndVerifyVM(bytes memory encodedVM)\n    external\n    view\n    returns (\n        VM memory vm,\n        bool valid,\n        string memory reason\n    )\n```\n\n??? interface \"Parameters\"\n\n    `encodedVM` ++\"bytes\"++\n\n    Serialized signed VAA from Guardians.\n\n??? interface \"Returns\"\n\n    `vm` ++\"VM memory\"++\n\n    Full parsed VAA contents\n\n    ---\n\n    `valid` ++\"bool\"++\n\n    Whether the VAA is valid according to the current Guardian set.\n\n    ---\n\n    `reason` ++\"string\"++\n\n    Reason for invalidity if `valid` is false (invalid)."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 15, "depth": 3, "title": "verifyVM", "anchor": "verifyvm", "start_char": 9360, "end_char": 9976, "estimated_token_count": 159, "token_estimator": "heuristic-v1", "text": "### verifyVM\n\nPerforms low-level VAA signature verification. *(Defined in [Messages.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Messages.sol){target=\\_blank})*\n\n```solidity\nfunction verifyVM(bytes memory encodedVM)\n    public view returns (bool isValid, string memory reason)\n```\n\n??? interface \"Parameters\"\n\n    `encodedVM` ++\"bytes\"++\n\n    Serialized signed VAA to verify.\n\n??? interface \"Returns\"\n\n    `isValid` ++\"bool\"++\n\n    `true` if the signatures are valid and meet the quorum.\n\n    ---\n\n    `reason` ++\"string\"++\n\n    Explanation for failure if `isValid` is `false`."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 16, "depth": 3, "title": "verifySignatures", "anchor": "verifysignatures", "start_char": 9976, "end_char": 10763, "estimated_token_count": 186, "token_estimator": "heuristic-v1", "text": "### verifySignatures\n\nUsed to verify individual Guardian signatures against a VAA digest. *(Defined in [Messages.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Messages.sol){target=\\_blank})*\n\n```solidity\nfunction verifySignatures(\n    bytes32 hash,\n    Structs.Signature[] memory signatures,\n    GuardianSet memory guardianSet\n) public view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `hash` ++\"bytes32\"++\n\n    The message digest to verify.\n\n    ---\n\n    `signatures` ++\"Structs.Signature[]\"++\n\n    An array of Guardian signatures.\n\n    ---\n\n    `guardianSet` ++\"GuardianSet memory\"++\n\n    Guardian set to validate against.\n\n??? interface \"Returns\"\n\n    `isValid` ++\"bool\"++\n\n    `true` if the required number of valid signatures is present."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 17, "depth": 3, "title": "quorum", "anchor": "quorum", "start_char": 10763, "end_char": 11190, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "### quorum\n\nReturns the number of Guardian signatures required to reach quorum. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*\n\n```solidity\nfunction quorum() public view returns (uint8)\n```\n\n??? interface \"Returns\"\n\n    `quorum` ++\"uint8\"++\n\n    Number of valid Guardian signatures required to reach consensus for VAA verification."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 18, "depth": 3, "title": "chainId", "anchor": "chainid", "start_char": 11190, "end_char": 11553, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "### chainId\n\nReturns Wormhole chain ID used internally by the protocol. *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction chainId() public view returns (uint16)\n```\n\n??? interface \"Returns\"\n\n    `id` ++\"uint16\"++\n\n    Wormhole-specific chain identifier."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 19, "depth": 3, "title": "evmChainId", "anchor": "evmchainid", "start_char": 11553, "end_char": 11934, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "### evmChainId\n\nReturns the EVM chain ID (i.e., value from `block.chainid`). *(Defined in [Getters.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Getters.sol){target=\\_blank})*\n\n```solidity\nfunction evmChainId() public view returns (uint256)\n```\n\n??? interface \"Returns\"\n\n    `id` ++\"uint256\"++\n\n    Native EVM chain ID for the current network."}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 20, "depth": 2, "title": "Errors", "anchor": "errors", "start_char": 11934, "end_char": 11945, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Errors"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 21, "depth": 3, "title": "Invalid Fee", "anchor": "invalid-fee", "start_char": 11945, "end_char": 12221, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "### Invalid Fee\n\nReverts when the message fee (`msg.value`) sent is not equal to the required fee returned by `messageFee()`. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 22, "depth": 3, "title": "Unsupported", "anchor": "unsupported", "start_char": 12221, "end_char": 12481, "estimated_token_count": 65, "token_estimator": "heuristic-v1", "text": "### Unsupported\n\nReverts on any call to the fallback function. The contract does not support arbitrary calls. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 23, "depth": 3, "title": "The Wormhole Contract Does Not Accept Assets", "anchor": "the-wormhole-contract-does-not-accept-assets", "start_char": 12481, "end_char": 12778, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "### The Wormhole Contract Does Not Accept Assets\n\nReverts when native tokens (ETH) are sent directly to the contract via the `receive()` function. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 24, "depth": 3, "title": "Already Initialized", "anchor": "already-initialized", "start_char": 12778, "end_char": 13080, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### Already Initialized\n\nReverts when trying to call `initialize()` on an implementation that has already been initialized. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank}, via `initializer` modifier)*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 25, "depth": 3, "title": "Unknown Chain ID", "anchor": "unknown-chain-id", "start_char": 13080, "end_char": 13375, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### Unknown Chain ID\n\nReverts inside the `initialize()` function if the chain ID stored by the contract does not match any known Wormhole chain. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Implementation.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 26, "depth": 3, "title": "Invalid Fork", "anchor": "invalid-fork", "start_char": 13375, "end_char": 13645, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "### Invalid Fork\n\nReverts when attempting to perform a governance action intended only for forked chains on a non-forked chain. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 27, "depth": 3, "title": "Invalid Module", "anchor": "invalid-module", "start_char": 13645, "end_char": 13883, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### Invalid Module\n\nReverts if the VAA’s module field doesn’t match the expected \"Core\" module. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 28, "depth": 3, "title": "Invalid Chain", "anchor": "invalid-chain", "start_char": 13883, "end_char": 14138, "estimated_token_count": 70, "token_estimator": "heuristic-v1", "text": "### Invalid Chain\n\nReverts if the VAA’s target chain doesn’t match the chain on which this contract is deployed. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 29, "depth": 3, "title": "New Guardian Set is Empty", "anchor": "new-guardian-set-is-empty", "start_char": 14138, "end_char": 14380, "estimated_token_count": 66, "token_estimator": "heuristic-v1", "text": "### New Guardian Set is Empty\n\nReverts when trying to register a new Guardian set that has no keys. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 30, "depth": 3, "title": "Index Must Increase in Steps of 1", "anchor": "index-must-increase-in-steps-of-1", "start_char": 14380, "end_char": 14646, "estimated_token_count": 70, "token_estimator": "heuristic-v1", "text": "### Index Must Increase in Steps of 1\n\nReverts when the new Guardian set index is not exactly one greater than the current. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 31, "depth": 3, "title": "Not a Fork", "anchor": "not-a-fork", "start_char": 14646, "end_char": 14867, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "### Not a Fork\n\nReverts when trying to recover chain ID on a non-forked chain. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 32, "depth": 3, "title": "Invalid EVM Chain", "anchor": "invalid-evm-chain", "start_char": 14867, "end_char": 15109, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### Invalid EVM Chain\n\nReverts if the recovered chain ID doesn't match the current `block.chainid`. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 33, "depth": 3, "title": "Governance Action Already Consumed", "anchor": "governance-action-already-consumed", "start_char": 15109, "end_char": 15357, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "### Governance Action Already Consumed\n\nReverts when the same governance VAA is submitted more than once. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 34, "depth": 3, "title": "Wrong Governance Contract", "anchor": "wrong-governance-contract", "start_char": 15357, "end_char": 15636, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "### Wrong Governance Contract\n\nReverts when the governance VAA’s emitter address doesn't match the expected governance contract address. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 35, "depth": 3, "title": "Wrong Governance Chain", "anchor": "wrong-governance-chain", "start_char": 15636, "end_char": 15908, "estimated_token_count": 71, "token_estimator": "heuristic-v1", "text": "### Wrong Governance Chain\n\nReverts when the governance VAA’s emitter chain doesn't match the expected governance chain (Solana). *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-evm", "page_title": "Core Contract (EVM)", "index": 36, "depth": 3, "title": "Not Signed by Current Guardian Set", "anchor": "not-signed-by-current-guardian-set", "start_char": 15908, "end_char": 16173, "estimated_token_count": 71, "token_estimator": "heuristic-v1", "text": "### Not Signed by Current Guardian Set\n\nReverts if the Guardian set index in the VAA doesn’t match the current Guardian set. *(Defined in [Governance.sol](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/Governance.sol){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 361, "end_char": 1751, "estimated_token_count": 315, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe Wormhole Core program on Solana is implemented using modular Rust files. Logic is separated across instruction dispatch, account definitions, core types, and signature verification.\n\n```text\nlib.rs\n├── instructions.rs\n├── accounts.rs\n├── api.rs\n│   ├── post_message\n│   ├── verify_signatures\n│   ├── post_vaa\n│   ├── upgrade_contract\n│   └── upgrade_guardian_set\n├── types.rs\n└── vaa.rs\n```\n\n**Key Components:**\n\n - **lib.rs**: Program entry point and instruction dispatcher. Registers all handlers and exposes the on-chain processor.\n - **instructions.rs**: Defines the `WormholeInstruction` enum and maps it to individual instruction handlers.\n - **accounts.rs**: Specifies the account constraints and validation logic for each instruction.\n - **api.rs**: Contains the main logic for processing instructions such as message posting, VAA verification, upgrades, and governance actions.\n - **types.rs**: Defines shared structs and enums used throughout the program, including configuration and `GuardianSet` formats.\n - **vaa.rs**: Implements VAA parsing, hashing, and signature-related logic used to verify Wormhole messages.\n - **error.rs** (not listed above): Defines custom error types used across the program for precise failure handling.\n - **wasm.rs** (not listed above): Provides WebAssembly bindings for testing and external tooling; not used on-chain."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 1, "depth": 2, "title": "State Accounts", "anchor": "state-accounts", "start_char": 1751, "end_char": 2915, "estimated_token_count": 301, "token_estimator": "heuristic-v1", "text": "## State Accounts\n\nBelow are on-chain PDAs used to store persistent state for the core contract. All are derived using deterministic seeds with the program ID.\n\n - **`bridge` ++\"BridgeData\"++**: Stores global config like the active Guardian set index, message fee, and Guardian set expiration time. (Derived at PDA seed `[\"Bridge\"]`)\n - **`guardianSets` ++\"GuardianSetData\"++**: Mapping of Guardian sets by index. Each Guardian set includes public key hashes and creation/expiration times. (Derived at PDA seed `[\"GuardianSet\", index]`)\n - **`sequences` ++\"SequenceTracker\"++**: Tracks the last sequence number used by each emitter, enforcing strict message ordering. (Derived at PDA seed `[\"Sequence\", emitter]`)\n - **`postedVAAs` ++\"PostedVAAData\"++**: Stores verified and finalized VAAs, preventing replay. (Derived at PDA seed `[\"PostedVAA\", hash]`)\n - **`claims` ++\"ClaimData\"++**: Tracks consumed governance VAAs to ensure replay protection. (Derived at PDA seed `[\"Claim\", emitter, sequence]`)\n - **`feeCollector` ++\"FeeCollector\"++**: Holds lamports collected via message fees, and can be drained via governance. (Derived at PDA seed `[\"fee_collector\"]`)"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 2, "depth": 2, "title": "Instructions", "anchor": "instructions", "start_char": 2915, "end_char": 2932, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Instructions"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 3, "depth": 3, "title": "initialize", "anchor": "initialize", "start_char": 2932, "end_char": 4025, "estimated_token_count": 282, "token_estimator": "heuristic-v1", "text": "### initialize\n\nInitializes the Wormhole Core contract on Solana with a Guardian set and fee configuration. This should be called only once at deployment time. *(Defined in [api/initialize.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/initialize.rs){target=\\_blank})*\n\n```rust\ninitialize(\n    payer: Pubkey,\n    fee: u64,\n    guardian_set_expiration_time: u32,\n    initial_guardians: &[[u8; 20]]\n)\n```\n\n??? interface \"Accounts\"\n\n    - **`Bridge`**: PDA to store global configuration.\n    - **`GuardianSet`**: PDA for Guardian set at index 0.\n    - **`FeeCollector`**: PDA to collect message posting fees.\n    - **`Payer`**: Funds account creation.\n    - **`Clock`, `Rent`, `SystemProgram`**: Solana system accounts.\n\n??? interface \"Parameters\"\n\n    `fee` ++\"u64\"++\n\n    Fee in lamports required to post messages.\n\n    ---\n\n    `guardian_set_expiration_time` ++\"u32\"++\n\n    Time in seconds after which the Guardian set expires.\n\n    ---\n\n    `initial_guardians` ++\"[[u8; 20]]\"++\n\n    List of Guardian public key hashes (Ethereum-style addresses)."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 4, "depth": 3, "title": "post_message", "anchor": "post_message", "start_char": 4025, "end_char": 5140, "estimated_token_count": 302, "token_estimator": "heuristic-v1", "text": "### post_message\n\nPosts a Wormhole message to the Solana Core contract. *(Defined in [api/post_message.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/post_message.rs){target=\\_blank})*\n\n```rust\nPostMessage {\n    nonce: u32,\n    payload: Vec<u8>,\n    consistency_level: u8\n}\n```\n\n??? interface \"Accounts\"\n\n    - **`Bridge`**: PDA for global config.\n    - **`Message`**: PDA where the posted message will be stored.\n    - **`Emitter`**: The emitting account (must sign).\n    - **`Sequence`**: PDA tracking the emitter’s message sequence.\n    - **`Payer`**: Pays for account creation and fees.\n    - **`FeeCollector`**: PDA that collects message fees.\n    - **`Clock`, `Rent`, `SystemProgram`**: Solana system accounts.\n\n??? interface \"Parameters\"\n\n    `nonce` ++\"u32\"++\n\n    Unique nonce to disambiguate messages with the same payload.\n\n    ---\n\n    `payload` ++\"Vec<u8>\"++\n\n    The arbitrary message payload to be posted.\n\n    ---\n\n    `consistency_level` ++\"u8\"++\n\n    Level of finality required before the message is processed.\n\n    `1` = Confirmed, `32` = Finalized."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 5, "depth": 3, "title": "post_message_unreliable", "anchor": "post_message_unreliable", "start_char": 5140, "end_char": 6341, "estimated_token_count": 312, "token_estimator": "heuristic-v1", "text": "### post_message_unreliable\n\nPosts a Wormhole message without requiring reliable delivery. Used for lightweight publishing when finality isn't critical. *(Defined in [api/post_message.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/post_message.rs){target=\\_blank})*\n\n```rust\nPostMessageUnreliable {\n    nonce: u32,\n    payload: Vec<u8>,\n    consistency_level: u8\n}\n```\n\n??? interface \"Accounts\"\n\n    - **`Bridge`**: PDA for global config.\n    - **`Message`**: PDA where the posted message will be stored.\n    - **`Emitter`**: The emitting account (must sign).\n    - **`Sequence`**: PDA tracking the emitter’s message sequence.\n    - **`Payer`**: Pays for account creation and fees.\n    - **`FeeCollector`**: PDA that collects message fees.\n    - **`Clock`, `Rent`, `SystemProgram`**: Solana system accounts.\n\n??? interface \"Parameters\"\n\n    `nonce` ++\"u32\"++\n\n    Unique nonce to disambiguate messages with the same payload.\n\n    ---\n\n    `payload` ++\"Vec<u8>\"++\n\n    The arbitrary message payload to be posted.\n\n    ---\n\n    `consistency_level` ++\"u8\"++\n\n    Level of finality required before the message is processed. `1` = Confirmed, `32` = Finalized."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 6, "depth": 3, "title": "verify_signatures", "anchor": "verify_signatures", "start_char": 6341, "end_char": 7337, "estimated_token_count": 249, "token_estimator": "heuristic-v1", "text": "### verify_signatures\n\nVerifies Guardian signatures over a VAA body hash. This is the first step in VAA processing and is required before posting the VAA. *(Defined in [api/verify_signature.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/verify_signature.rs){target=\\_blank})*\n\n```rust\nVerifySignatures {\n    signers: [i8; 19]\n}\n```\n\n??? interface \"Accounts\"\n\n    - **`Payer`**: Pays for account creation and fees.\n    - **`GuardianSet`**: PDA holding the current Guardian set.\n    - **`SignatureSet`**: PDA that will store the verified signature data.\n    - **`InstructionsSysvar`**: Required to access prior instructions (e.g., secp256k1 sigverify).\n    - **`Rent`, `SystemProgram`**: Solana system accounts.\n\n??? interface \"Parameters\"\n\n    `signers` ++\"[i8; 19]\"++\n\n    A mapping from Guardian index to its position in the instruction payload (or -1 if not present).\n\n    Used to correlate secp256k1 verify instructions with Guardian set entries."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 7, "depth": 3, "title": "post_vaa", "anchor": "post_vaa", "start_char": 7337, "end_char": 9106, "estimated_token_count": 450, "token_estimator": "heuristic-v1", "text": "### post_vaa\n\nFinalizes a VAA after signature verification. This stores the message on-chain and marks it as consumed. *(Defined in [api/post_vaa.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/post_vaa.rs){target=\\_blank})*\n\n```rust\nPostVAA {\n    version: u8,\n    guardian_set_index: u32,\n    timestamp: u32,\n    nonce: u32,\n    emitter_chain: u16,\n    emitter_address: [u8; 32],\n    sequence: u64,\n    consistency_level: u8,\n    payload: Vec<u8>\n}\n```\n\n??? interface \"Accounts\"\n\n    - **`GuardianSet`**: PDA of the Guardian set used to verify the VAA.\n    - **`Bridge`**: Global Wormhole state.\n    - **`SignatureSet`**: Verified signature PDA (from verify_signatures).\n    - **`PostedVAA`**: PDA where the VAA will be stored.\n    - **`Payer`**: Funds the account creation.\n    - **`Clock`, `Rent`, `SystemProgram`**: Solana system accounts.\n\n??? interface \"Parameters\"\n\n    `version` ++\"u8\"++\n\n    VAA protocol version.\n\n    ---\n\n    `guardian_set_index` ++\"u32\"++\n\n    Index of the Guardian Set that signed this VAA.\n\n    ---\n\n    `timestamp` ++\"u32\"++\n\n    The time the emitter submitted the message.\n\n    ---\n\n    `nonce` ++\"u32\"++\n\n    Unique identifier for the message.\n\n    ---\n\n    `emitter_chain` ++\"u16\"++\n\n    ID of the chain where the message originated.\n\n    ---\n\n    `emitter_address` ++\"[u8; 32]\"++\n\n    Address of the contract or account that emitted the message.\n\n    ---\n\n    `sequence` ++\"u64\"++\n\n    Monotonically increasing sequence number for the emitter.\n\n    ---\n\n    `consistency_level` ++\"u8\"++\n\n    Required confirmation level before the message is accepted.\n    \n    `1` = Confirmed, `32` = Finalized.\n\n    ---\n\n    `payload` ++\"Vec<u8>\"++\n\n    Arbitrary data being transferred in the message."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 8, "depth": 3, "title": "set_fees", "anchor": "set_fees", "start_char": 9106, "end_char": 9867, "estimated_token_count": 192, "token_estimator": "heuristic-v1", "text": "### set_fees\n\nUpdates the message posting fee for the core bridge contract. *(Defined in [api/governance.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/governance.rs){target=\\_blank})*\n\n```rust\nSetFees {}\n```\n\nThis function is called via governance and requires a valid governance VAA. The VAA payload must contain the new fee value.\n\n??? interface \"Accounts\"\n\n    - **`Payer`**: Funds transaction execution.\n    - **`Bridge`**: PDA storing global Wormhole state.\n    - **`Message`**: The PostedVAA account containing the governance message.\n    - **`Claim`**: PDA that ensures this governance message hasn't been processed already.\n    - **`SystemProgram`**: Required by Solana for creating/initializing accounts."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 9, "depth": 3, "title": "transfer_fees", "anchor": "transfer_fees", "start_char": 9867, "end_char": 10805, "estimated_token_count": 231, "token_estimator": "heuristic-v1", "text": "### transfer_fees\n\nTransfers the accumulated message posting fees from the contract to a specified recipient. *(Defined in [api/governance.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/governance.rs){target=\\_blank})*\n\n```rust\nTransferFees {}\n```\n\nThis function is triggered via a governance VAA and transfers the fee balance from the `FeeCollector` to the recipient address specified in the VAA payload.\n\n??? interface \"Accounts\"\n\n    - **`Payer`**: Funds transaction execution.\n    - **`Bridge`**: PDA storing global Wormhole state.\n    - **`Message`**: PostedVAA account containing the governance message.\n    - **`FeeCollector`**: PDA holding the accumulated fees.\n    - **`Recipient`**: The account that will receive the fees.\n    - **`Claim`**: PDA that ensures this governance message hasn't been processed already.\n    - **`Rent`, `SystemProgram`**: Standard Solana system accounts."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 10, "depth": 3, "title": "upgrade_contract", "anchor": "upgrade_contract", "start_char": 10805, "end_char": 12100, "estimated_token_count": 316, "token_estimator": "heuristic-v1", "text": "### upgrade_contract\n\nUpgrades the deployed Wormhole program using a governance VAA. *(Defined in [api/governance.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/governance.rs){target=\\_blank})*\n\n```rust\nUpgradeContract {}\n```\n\nThis instruction allows authorized governance messages to trigger an upgrade of the on-chain Wormhole program logic to a new address.\n\n??? interface \"Accounts\"\n\n    - **`Payer`**: Funds transaction execution.\n    - **`Bridge`**: PDA storing global Wormhole state.\n    - **`Message`**: PostedVAA account containing the governance message.\n    - **`Claim`**: PDA that ensures this governance message hasn't been processed already.\n    - **`UpgradeAuthority`**: PDA with authority to perform the upgrade (seeded with \"upgrade\").\n    - **`Spill`**: Account that receives remaining funds from the upgrade buffer.\n    - **`NewContract`**: Account holding the new program data.\n    - **`ProgramData`**: Metadata account for the upgradable program.\n    - **`Program`**: Current program to be upgraded.\n    - **`Rent`, `Clock`**: System accounts used during the upgrade process.\n    - **`BPFLoaderUpgradeable`**: Solana system program for upgrades.\n    - **`SystemProgram`**: Required by Solana for creating/initializing accounts."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 11, "depth": 3, "title": "upgrade_guardian_set", "anchor": "upgrade_guardian_set", "start_char": 12100, "end_char": 13016, "estimated_token_count": 222, "token_estimator": "heuristic-v1", "text": "### upgrade_guardian_set\n\nUpgrades the current Guardian set using a governance VAA. *(Defined in [api/governance.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/api/governance.rs){target=\\_blank})*\n\n```rust\nUpgradeGuardianSet {}\n```\n\nThis instruction replaces the active Guardian set with a new one, allowing the Wormhole network to rotate its validator keys securely through governance.\n\n??? interface \"Accounts\"\n\n    - **`Payer`**: Funds transaction execution.\n    - **`Bridge`**: PDA storing global Wormhole state.\n    - **`Message`**: PostedVAA account containing the governance message.\n    - **`Claim`**: PDA that ensures this governance message hasn't been processed already.\n    - **`GuardianSetOld`**: Current (active) Guardian set PDA.\n    - **`GuardianSetNew`**: PDA for the newly proposed Guardian set.\n    - **`SystemProgram`**: Standard Solana system accounts."}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 12, "depth": 2, "title": "Errors", "anchor": "errors", "start_char": 13016, "end_char": 13027, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Errors"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 13, "depth": 3, "title": "GuardianSetMismatch", "anchor": "guardiansetmismatch", "start_char": 13027, "end_char": 13247, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "### GuardianSetMismatch\n\nThe Guardian set index does not match the expected value. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 14, "depth": 3, "title": "InstructionAtWrongIndex", "anchor": "instructionatwrongindex", "start_char": 13247, "end_char": 13459, "estimated_token_count": 61, "token_estimator": "heuristic-v1", "text": "### InstructionAtWrongIndex\n\nThe instruction was found at the wrong index. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 15, "depth": 3, "title": "InsufficientFees", "anchor": "insufficientfees", "start_char": 13459, "end_char": 13671, "estimated_token_count": 61, "token_estimator": "heuristic-v1", "text": "### InsufficientFees\n\nInsufficient fees were provided to post the message. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 16, "depth": 3, "title": "InvalidFeeRecipient", "anchor": "invalidfeerecipient", "start_char": 13671, "end_char": 13911, "estimated_token_count": 66, "token_estimator": "heuristic-v1", "text": "### InvalidFeeRecipient\n\nThe recipient address does not match the one specified in the governance VAA. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 17, "depth": 3, "title": "InvalidGovernanceAction", "anchor": "invalidgovernanceaction", "start_char": 13911, "end_char": 14136, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "### InvalidGovernanceAction\n\nThe action specified in the governance payload is invalid. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 18, "depth": 3, "title": "InvalidGovernanceChain", "anchor": "invalidgovernancechain", "start_char": 14136, "end_char": 14365, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "### InvalidGovernanceChain\n\nThe governance VAA was not emitted by a valid governance chain. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 19, "depth": 3, "title": "InvalidGovernanceKey", "anchor": "invalidgovernancekey", "start_char": 14365, "end_char": 14606, "estimated_token_count": 66, "token_estimator": "heuristic-v1", "text": "### InvalidGovernanceKey\n\nThe emitter address in the governance VAA is not the expected governance key. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 20, "depth": 3, "title": "InvalidGovernanceModule", "anchor": "invalidgovernancemodule", "start_char": 14606, "end_char": 14831, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "### InvalidGovernanceModule\n\nThe module string in the governance VAA header is invalid. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 21, "depth": 3, "title": "InvalidGovernanceWithdrawal", "anchor": "invalidgovernancewithdrawal", "start_char": 14831, "end_char": 15089, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "### InvalidGovernanceWithdrawal\n\nFee withdrawal would cause the fee collector account to drop below rent-exempt balance. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 22, "depth": 3, "title": "InvalidGuardianSetUpgrade", "anchor": "invalidguardiansetupgrade", "start_char": 15089, "end_char": 15348, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### InvalidGuardianSetUpgrade\n\nThe Guardian set upgrade VAA is invalid (e.g., skipped index or mismatched current index). *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 23, "depth": 3, "title": "InvalidHash", "anchor": "invalidhash", "start_char": 15348, "end_char": 15569, "estimated_token_count": 65, "token_estimator": "heuristic-v1", "text": "### InvalidHash\n\nThe hash computed from the VAA does not match the expected result. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 24, "depth": 3, "title": "InvalidSecpInstruction", "anchor": "invalidsecpinstruction", "start_char": 15569, "end_char": 15806, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "### InvalidSecpInstruction\n\nThe SECP256k1 instruction used for signature verification is malformed. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 25, "depth": 3, "title": "MathOverflow", "anchor": "mathoverflow", "start_char": 15806, "end_char": 16013, "estimated_token_count": 59, "token_estimator": "heuristic-v1", "text": "### MathOverflow\n\nAn arithmetic overflow occurred during computation. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 26, "depth": 3, "title": "PostVAAConsensusFailed", "anchor": "postvaaconsensusfailed", "start_char": 16013, "end_char": 16240, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "### PostVAAConsensusFailed\n\nNot enough valid signatures were collected to achieve quorum. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 27, "depth": 3, "title": "PostVAAGuardianSetExpired", "anchor": "postvaaguardiansetexpired", "start_char": 16240, "end_char": 16469, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "### PostVAAGuardianSetExpired\n\nThe Guardian set used to verify the VAA has already expired. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 28, "depth": 3, "title": "TooManyGuardians", "anchor": "toomanyguardians", "start_char": 16469, "end_char": 16694, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "### TooManyGuardians\n\nThe Guardian set exceeds the maximum allowed number of guardians. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 29, "depth": 3, "title": "VAAAlreadyExecuted", "anchor": "vaaalreadyexecuted", "start_char": 16694, "end_char": 16920, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "### VAAAlreadyExecuted\n\nThe VAA has already been executed and cannot be processed again. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 30, "depth": 3, "title": "VAAInvalid", "anchor": "vaainvalid", "start_char": 16920, "end_char": 17125, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "### VAAInvalid\n\nThe VAA is structurally invalid or fails to decode. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 31, "depth": 3, "title": "InvalidPayloadLength", "anchor": "invalidpayloadlength", "start_char": 17125, "end_char": 17334, "estimated_token_count": 60, "token_estimator": "heuristic-v1", "text": "### InvalidPayloadLength\n\nThe payload length is incorrect or malformed. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-core-contract-solana", "page_title": "Core Contract (Solana)", "index": 32, "depth": 3, "title": "EmitterChanged", "anchor": "emitterchanged", "start_char": 17334, "end_char": 17532, "estimated_token_count": 58, "token_estimator": "heuristic-v1", "text": "### EmitterChanged\n\nThe emitter address changed unexpectedly. *(Defined in [error.rs](https://github.com/wormhole-foundation/wormhole/blob/main/solana/bridge/program/src/error.rs){target=\\_blank})*"}
{"page_id": "products-messaging-reference-executor-addresses", "page_title": "Executor Addresses", "index": 0, "depth": 2, "title": "Executor", "anchor": "executor", "start_char": 22, "end_char": 5081, "estimated_token_count": 1672, "token_estimator": "heuristic-v1", "text": "## Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x84EEe8dBa37C36947397E1E11251cA9A06Fc6F8a</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0xcD2BffD0C0289e8C0cb89c458dB1B74f1892Fa6c</code></td></tr><tr><td>Aptos</td><td><code>0x11aa75c059e1a7855be66b931bf340a2e0973274ac16b5f519c02ceafaf08a18</code></td></tr><tr><td>Arbitrum</td><td><code>0x3980f8318fc03d79033Bbb421A622CDF8d2Eeab4</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base</td><td><code>0x9E1936E91A4a5AE5A5F75fFc472D6cb8e93597ea</code></td></tr><tr><td>Berachain</td><td><code>0x0Dd7a5a32311b8D87A615Cc7f079B632D3d5e2D3</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Celo</td><td><code>0xe6Ea5087c6860B94Cf098a403506262D8F28cF05</code></td></tr><tr><td>CreditCoin</td><td><code>0xd2e420188f17607Aa6344ee19c3e76Cf86CA7BDe</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0xd7717899cc4381033Bc200431286D0AC14265F78</code></td></tr><tr><td>Ink</td><td><code>0x3e44a5F45cbD400acBEF534F51e616043B211Ddd</code></td></tr><tr><td>Linea</td><td><code>0x23aF2B5296122544A9A7861da43405D5B15a9bD3</code></td></tr><tr><td>MegaETH</td><td><code>0xD405E0A1f3f9edc25Ea32d0B079d6118328b2EcB</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0x7b8097af5459846c5A72fCc960D94F31C05915aD</code></td></tr><tr><td>Monad</td><td><code>0xC04dE634982cAdF2A677310b73630B7Ac56A3f65</code></td></tr><tr><td>Moonbeam</td><td><code>0x85D06449C78064c2E02d787e9DC71716786F8D19</code></td></tr><tr><td>Optimism</td><td><code>0x85B704501f6AE718205C0636260768C4e72ac3e7</code></td></tr><tr><td>Polygon</td><td><code>0x0B23efA164aB3eD08e9a39AC7aD930Ff4F5A5e81</code></td></tr><tr><td>Scroll</td><td><code>0xcFAdDE24640e395F5A71456A825D0D7C3741F075</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923fb7a5aefa5f0a2b419fc70f2368e66e5</code></td></tr><tr><td>Sonic</td><td><code>0x3Fdc36b4260Da38fBDba1125cCBD33DD0AC74812</code></td></tr><tr><td>Sui</td><td><code>0xdb0fe8bb1e2b5be628adbea0636063325073e1070ee11e4281457dfd7f158235</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>World Chain</td><td><code>0x8689b4E6226AdC8fa8FF80aCc3a60AcE31e8804B</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x8345E90Dcd92f5Cf2FAb0C8E2A56A5bc2c30d896</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xD0fb39f5a3361F21457653cB70F9D0C9bD86B66B</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x7C43825EeB76DF7aAf3e1D2e8f684d4876F0CC05</code></td></tr><tr><td>Aptos</td><td><code>0x139717c339f08af674be77143507a905aa28cbc67a0e53e7095c07b630d73815</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xBF161de6B819c8af8f2230Bcd99a9B3592f6F87b</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base Sepolia</td><td><code>0x51B47D493CBA7aB97e3F8F163D6Ce07592CE4482</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Converge</td><td><code>0xAab9935349B9c08e0e970720F6D640d5B91C293E</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>Linea</td><td><code>0x4f6c3a93a80DdC691312974DAAbf9B6e4Bb44111</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0xc4a03f2c47caA4b961101bAD6338DEf37376F052</code></td></tr><tr><td>Monad Testnet</td><td><code>0xe37D3E162B4B1F17131E4e0e6122DbA31243382f</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x5856651eB82aeb6979B4954317194d48e1891b3c</code></td></tr><tr><td>Plume</td><td><code>0x8fc2FbA8F962fbE89a9B02f03557a011c335A455</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x7056721C33De437f0997F67BC87521cA86b721d3</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923Fb7A5aEFA5F0A2b419fC70f2368e66e5</code></td></tr><tr><td>Sui</td><td><code>0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x4d9525D94D275dEB495b7C8840b154Ae04cfaC2A</code></td></tr></tbody></table>"}
{"page_id": "products-messaging-reference-executor-addresses", "page_title": "Executor Addresses", "index": 1, "depth": 2, "title": "CCTP with Executor", "anchor": "cctp-with-executor", "start_char": 5081, "end_char": 10193, "estimated_token_count": 1754, "token_estimator": "heuristic-v1", "text": "## CCTP with Executor\n\n\n\n=== \"Mainnet v1\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x6DDE92942DbB24F7c9B75765b74a33446980C1e3</code></td></tr><tr><td>Solana</td><td><code>CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs</code></td></tr><tr><td>Aptos</td><td><code>0xc89bf3746dfc70bb3f2de7c35a98f327a40b9d55a443743a5935c5e3de90b7ac</code></td></tr><tr><td>Arbitrum</td><td><code>0x772373214238F09a494828A5323574E3d7e27558</code></td></tr><tr><td>Avalanche</td><td><code>0x58aC806cd205083E7E048E196f36Ff6C4Ae17bE5</code></td></tr><tr><td>Base</td><td><code>0x4D1Cc8921e297155044C01761f581fa52a24C33d</code></td></tr><tr><td>Optimism</td><td><code>0x6826c075973a4393CEf0e131c4B16869426563a7</code></td></tr><tr><td>Polygon</td><td><code>0x7e6Ae241101B355447A4B471D0C6968b132eC4Ab</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0xa997Ef229E4D2a1fEca249eB41fBf5D4b2217d6E</code></td></tr></tbody></table>\n\n=== \"Testnet v1\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x2fcc7b2332d924764f17f1cf5eda1cd4b36751a2</code></td></tr><tr><td>Solana</td><td><code>CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs</code></td></tr><tr><td>Aptos</td><td><code>0x14a12d1fd6ef371b70c2113155534ec152ec7f779e281b54866c796c9a4a58d3</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x8158305d331594f3e8d18c33ca4e6d3cdc109b75</code></td></tr><tr><td>Avalanche</td><td><code>0x62819ab61cc7fcc864af7bcfc92e6c1965eb69a6</code></td></tr><tr><td>Base Sepolia</td><td><code>0x96846c31e4f87c0f186a322926c61d4183439f0a</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xe17de8e29f1f0941b541b053829af74ac81c89a6</code></td></tr><tr><td>Polygon</td><td><code>0xdce63172e9ad15243c97acafd01cc4fdda98bead</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0x2c1354296a11029056e0d7d7abbdd58743dbaf59</code></td></tr></tbody></table>\n\n=== \"Mainnet v2\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xDD68aBa3E04CB1a05082402B9325753314803005</code></td></tr><tr><td>Solana</td><td><code>Supported</code></td></tr><tr><td>Arbitrum</td><td><code>0x760feC4425B46E3D8FEf8E2CE49786e5a6f74446</code></td></tr><tr><td>Avalanche</td><td><code>0xE42aE9e352157fcEf74E971F2C5c74A5963a71D7</code></td></tr><tr><td>Base</td><td><code>0x52892976559fB2fc8b7f850440eD9AA5Dc26f7D9</code></td></tr><tr><td>Codex</td><td><code>0x0684286448140F75d4C3D2F2c02BF66f98CdEA51</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x001319beBA062d918d7007E4D2D76a0A9cc439Db</code></td></tr><tr><td>Ink</td><td><code>0xef0B43b49315A4aDF11bA2617Be81a304c5D6ecc</code></td></tr><tr><td>Linea</td><td><code>0x257dBB6AD7C7AC19360bEe1A107ebE631D568776</code></td></tr><tr><td>Monad</td><td><code>0x1FdCCf65318b34CFd3F5903fFb747C17e76330ac</code></td></tr><tr><td>Optimism</td><td><code>0x9b51579e67D4ab18D79609105509ad37B2a0D342</code></td></tr><tr><td>Plume</td><td><code>0x9be9C6B420eAfaaC1162D680fd7E61446b38Cf29</code></td></tr><tr><td>Polygon</td><td><code>0x5116F1358ae2445f571AA702dA1feB5e13094E59</code></td></tr><tr><td>SeiEVM</td><td><code>0xe067C0D378C50CDc34bCd973F202736D5A19e5D2</code></td></tr><tr><td>Sonic</td><td><code>0x8A850b2077F1eFccA89eAa9c35b45C4dC9227cdb</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0xaf7f4FbB6C220baf57ABC7babF81D47Fd628bdb4</code></td></tr><tr><td>World Chain</td><td><code>0xAA4841e5d9652593852403E3ce9e8003f8D579D0</code></td></tr></tbody></table>\n\n=== \"Testnet v2\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xc58475c97ebde9cf4fefa0d4fb2774df81905d43</code></td></tr><tr><td>Solana</td><td><code>Supported</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xf601f9988d62943cb842baae1e46be9b17d0b2a4</code></td></tr><tr><td>Avalanche</td><td><code>0x10018394905f70daa1d740040d64cbed5a82301e</code></td></tr><tr><td>Base Sepolia</td><td><code>0x1effdcfedc6d45e44b3133257debfb522adb1cae</code></td></tr><tr><td>Ink</td><td><code>0x63993ee08bda32ecb0ba5cdc751b404f5c5c0458</code></td></tr><tr><td>Linea Sepolia</td><td><code>0xe8Ad216e23fc9425E65aB315F0EC13737e75afEF</code></td></tr><tr><td>Monad Testnet</td><td><code>0x358bAd031d7A217ebA2d471cad5fD611AeC2aF17</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x49f386393c26439b74e62f5794062925dfb7c1db</code></td></tr><tr><td>Polygon</td><td><code>0x05da7c69db265b37b4d3530d476ec4b33bd9dd45</code></td></tr><tr><td>SeiEVM</td><td><code>0xDC735908C3eCF29f40D8CA5f6407F2d94d316a9F</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0xf082af7668f000f60bc519b378f6363708fc302b</code></td></tr></tbody></table>"}
{"page_id": "products-messaging-reference-executor-addresses", "page_title": "Executor Addresses", "index": 2, "depth": 2, "title": "NTT with Executor", "anchor": "ntt-with-executor", "start_char": 10193, "end_char": 15263, "estimated_token_count": 1699, "token_estimator": "heuristic-v1", "text": "## NTT with Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xD2D9c936165a85F27a5a7e07aFb974D022B89463</code><br>Multi Ntt: <code>0x03dB430D830601DB368991eE55DAa9A708df7912</code></td></tr><tr><td>Solana</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>0G</td><td><code>0xe175a8b838f3cdb2e1aaf4ff74c05cf2f3aea9a8</code></td></tr><tr><td>Arbitrum</td><td><code>0x0Af42A597b0C201D4dcf450DcD0c06d55ddC1C77</code></td></tr><tr><td>Avalanche</td><td><code>0x4e9Af03fbf1aa2b79A2D4babD3e22e09f18Bb8EE</code></td></tr><tr><td>Base</td><td><code>0x83216747fC21b86173D800E2960c0D5395de0F30</code></td></tr><tr><td>Berachain</td><td><code>0x0a2AF374Cc9CCCbB0Acc4E34B20b9d02a0f08c30</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x39B57Dd9908F8be02CfeE283b67eA1303Bc29fe1</code></td></tr><tr><td>Celo</td><td><code>0x3d69869fcB9e1CD1F4020b637fb8256030BAc8fC</code></td></tr><tr><td>CreditCoin</td><td><code>0x5454b995719626256C96fb57454b044ffb3Da2F9</code></td></tr><tr><td>Fogo</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x431017B1718b86898C7590fFcCC380DEf0456393</code></td></tr><tr><td>Ink</td><td><code>0x420370DC2ECC4D44b47514B7859fd11809BbeFF5</code></td></tr><tr><td>Linea</td><td><code>0xEAa5AddB5b8939Eb73F7faF46e193EefECaF13E9</code></td></tr><tr><td>MegaETH</td><td><code>0x3EFEc0c7Ee79135330DD03e995872f84b1AD49b6</code></td></tr><tr><td>Mezo</td><td><code>0x484b5593BbB90383f94FB299470F09427cf6cfE2</code></td></tr><tr><td>Moca</td><td><code>0xE612837749a0690BA2BCe490D6eFb5F8Fc347df3</code></td></tr><tr><td>Monad</td><td><code>0xc3F3dDa544815a440633176c7598f5B97500793e</code><br>Multi Ntt: <code>0xFEA937F7124E19124671f1685671d3f04a9Af4E4</code></td></tr><tr><td>Moonbeam</td><td><code>0x1365593C8bae71a55e48E105a2Bb76d5928c7DE3</code></td></tr><tr><td>Optimism</td><td><code>0x85C0129bE5226C9F0Cf4e419D2fefc1c3FCa25cF</code></td></tr><tr><td>Plume</td><td><code>0x6Eb53371f646788De6B4D0225a4Ed1d9267188AD</code></td></tr><tr><td>Polygon</td><td><code>0x6762157b73941e36cEd0AEf54614DdE545d0F990</code></td></tr><tr><td>Scroll</td><td><code>0x055625d48968f99409244E8c3e03FbE73B235a62</code></td></tr><tr><td>SeiEVM</td><td><code>0x3F2D6441C7a59Dfe80f8e14142F9E28F6D440445</code></td></tr><tr><td>Sonic</td><td><code>0xaCa00703bb87F31D6F9fCcc963548b48FA46DfeB</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0x607723D6353Dae3ef62B7B277Cfabd0F4bc6CB4C</code></td></tr><tr><td>World Chain</td><td><code>0x66b1644400D51e104272337226De3EF1A820eC79</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x6bBd1ff3bB303F88835A714EE3241bF45DE26d29</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x54DD7080aE169DD923fE56d0C4f814a0a17B8f41</code></td></tr><tr><td>Solana</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>0G Galileo</td><td><code>0xA8CA118f4C8d44Ab651Dad52B5E1a212e5d5c55b</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xd048170F1ECB8D47E499D3459aC379DA023E2C1B</code></td></tr><tr><td>Avalanche</td><td><code>0x4e9Af03fbf1aa2b79A2D4babD3e22e09f18Bb8EE</code></td></tr><tr><td>Base Sepolia</td><td><code>0x5845E08d890E21687F7Ebf7CbAbD360cD91c6245</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x39B57Dd9908F8be02CfeE283b67eA1303Bc29fe1</code></td></tr><tr><td>Celo</td><td><code>0x3d69869fcB9e1CD1F4020b637fb8256030BAc8fC</code></td></tr><tr><td>Converge</td><td><code>0x3d8c26b67BDf630FBB44F09266aFA735F1129197</code></td></tr><tr><td>Fogo</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>Ink</td><td><code>0xF420BFFf922D11c2bBF587C9dF71b83651fAf8Bc</code></td></tr><tr><td>Linea Sepolia</td><td><code>0xaA469cb84C91D5a63bf4B370dE35f0831F2CE4FF</code></td></tr><tr><td>Mezo</td><td><code>0x484b5593BbB90383f94FB299470F09427cf6cfE2</code></td></tr><tr><td>Moca</td><td><code>0x47f26bF9253Eb398fBAf825D7565FE975D839a71</code></td></tr><tr><td>Monad Testnet</td><td><code>0xc8F014FE6a8521259D9ADDc2170bA9e59305D306</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xaDB1C56D363FF5A75260c3bd27dd7C1fC8421EF5</code></td></tr><tr><td>Plume</td><td><code>0x6Eb53371f646788De6B4D0225a4Ed1d9267188AD</code></td></tr><tr><td>Polygon</td><td><code>0x2982B9566E912458fE711FB1Fd78158264596937</code></td></tr><tr><td>SeiEVM</td><td><code>0x3F2D6441C7a59Dfe80f8e14142F9E28F6D440445</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0x607723D6353Dae3ef62B7B277Cfabd0F4bc6CB4C</code></td></tr><tr><td>XRPL EVM Testnet</td><td><code>0xcDD9d7C759b29680f7a516d0058de8293b2AC7b1</code></td></tr></tbody></table>"}
{"page_id": "products-messaging-reference-executor-addresses", "page_title": "Executor Addresses", "index": 3, "depth": 2, "title": "WTT Executor", "anchor": "wtt-executor", "start_char": 15263, "end_char": 19588, "estimated_token_count": 1457, "token_estimator": "heuristic-v1", "text": "## WTT Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xa8969F3f8D97b3Ed89D4e2EC19B6B0CfD504b212</code></td></tr><tr><td>Solana</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x3dBb4dCf25dBA8F0C2417E1c34e527De0E465ecc</code></td></tr><tr><td>Arbitrum</td><td><code>0x04C98824a64d75CD1E9Bc418088b4c9A99048153</code></td></tr><tr><td>Avalanche</td><td><code>0x8849F05675E034b54506caB84450c8C82694a786</code></td></tr><tr><td>Base</td><td><code>0xD8B736EF27Fc997b1d00F22FE37A58145D3BDA07</code></td></tr><tr><td>Berachain</td><td><code>0xFAeFa20CB3759AEd2310E25015F05d62D8567A3F</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x2513515340fF71DD5AF02fC1BdB9615704d91524</code></td></tr><tr><td>Celo</td><td><code>0xe478DEe705BEae591395B08934FA19F54df316BE</code></td></tr><tr><td>Fantom</td><td><code>0xcafd2f0a35a4459fa40c0517e17e6fa2939441ca</code></td></tr><tr><td>Fogo</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>Ink</td><td><code>0x4bFB47F4c8A904d2C24e73601D175FE3a38aAb5B</code></td></tr><tr><td>MegaETH</td><td><code>0x4eEC1c908aD6e778664Efb03386C429fE5710D77</code></td></tr><tr><td>Monad</td><td><code>0xf7E051f93948415952a2239582823028DacA948e</code></td></tr><tr><td>Moonbeam</td><td><code>0xF6b9616C63Fa48D07D82c93CE02B5d9111c51a3d</code></td></tr><tr><td>Optimism</td><td><code>0x37aC29617AE74c750a1e4d55990296BAF9b8De73</code></td></tr><tr><td>Polygon</td><td><code>0x1d98CA4221516B9ac4869F5CeA7E6bb9C41609D6</code></td></tr><tr><td>Scroll</td><td><code>0x05129e142e7d5A518D81f19Db342fBF5f7E26A18</code></td></tr><tr><td>SeiEVM</td><td><code>0x7C129bc8F6188d12c0d1BBDE247F134148B97618</code></td></tr><tr><td>Sui</td><td><code>0x9b68b36399a3cd87680878d72253b3e8fdf82edb8ed74f7ec440b8bddd51f85d</code></td></tr><tr><td>Unichain</td><td><code>0x9Bca817F67f01557aeD615130825A28F4C5f3b87</code></td></tr><tr><td>World Chain</td><td><code>0xc0565Bd29b34603C0383598E16843d95Ae9c4f65</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x37bCc9d175124F77Bfce68589d2a8090eF846B85</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xb0b2119067cF04fa959f654250BD49fE1BD6F53c</code></td></tr><tr><td>Solana</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x57188fC61ce92c8E941504562811660Ab883E895</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xaE8dc4a7438801Ec4edC0B035EcCCcF3807F4CC1</code></td></tr><tr><td>Avalanche</td><td><code>0x10Ce9a35883C44640e8B12fea4Cc1e77F77D8c52</code></td></tr><tr><td>Base Sepolia</td><td><code>0x523d25D33B975ad72283f73B1103354352dBCBb8</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x26e7e3869b781f360A108728EE8391Cee6051E17</code></td></tr><tr><td>Celo</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Fantom</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Fogo</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>Linea</td><td><code>0x1C5CC8522b5eE1e528159989A163167bC9264D07</code></td></tr><tr><td>Mezo</td><td><code>0x2002a44b1106DF83671Fb419A2079a75e2a34808</code></td></tr><tr><td>Moca</td><td><code>0x36b91D24BAba19Af3aD1b5D5E2493A571044f14F</code></td></tr><tr><td>Monad Testnet</td><td><code>0x03D9739c91a26d30f4B35f7e55B9FF995ef13dDb</code></td></tr><tr><td>Moonbeam</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xD9AA4f8Ac271B3149b8C3d1D0f999Ef7cb9af9EC</code></td></tr><tr><td>Polygon Amoy</td><td><code>0xC5c0bF6A8419b3d47150B2a6146b7Ed598C9d736</code></td></tr><tr><td>SeiEVM</td><td><code>0x595712bA7e4882af338d60ae37058082a5d0331A</code></td></tr><tr><td>Sui</td><td><code>0xb4b86c12d4ee0a813d976fb452b7afb325a2b381d00ccb2e54c5342f5ef2e684</code></td></tr><tr><td>Unichain</td><td><code>0x74D37B2bcD2f8CaB6409c5a5f81C8cF5b4156963</code></td></tr><tr><td>XRPL-EVM</td><td><code>0xb00224c60fe6ab134c8544dc29350286545f8dcc</code></td></tr></tbody></table>"}
{"page_id": "products-messaging-reference-executor-addresses", "page_title": "Executor Addresses", "index": 4, "depth": 2, "title": "WTT Executor with Referrer", "anchor": "wtt-executor-with-referrer", "start_char": 19588, "end_char": 22906, "estimated_token_count": 1128, "token_estimator": "heuristic-v1", "text": "## WTT Executor with Referrer\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Arbitrum</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Avalanche</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Base</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Berachain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Celo</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Ink</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>MegaETH</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Monad</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Moonbeam</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Optimism</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Polygon</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Scroll</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>SeiEVM</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Unichain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>World Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x13a35c075D6Acc1Fb9BddFE5FE38e7672789e4db</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Avalanche</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Base Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Linea</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Mezo</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Moca</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Monad Testnet</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>SeiEVM</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Unichain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x17CFAAf9e8a5ABb1eee758dB9040F945c9EAC907</code></td></tr></tbody></table>"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 0, "depth": 2, "title": "Wormhole Overview", "anchor": "wormhole-overview", "start_char": 1750, "end_char": 2702, "estimated_token_count": 186, "token_estimator": "heuristic-v1", "text": "## Wormhole Overview\n\nWe'll interact with two key Wormhole components: the [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.\n\nAdditionally, we'll rely on the 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.\n\n![Wormhole architecture detailed diagram: source to target chain communication.](/docs/images/protocol/architecture/architecture-1.webp)"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 2702, "end_char": 3246, "estimated_token_count": 163, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore starting this tutorial, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- [Foundry](https://getfoundry.sh/introduction/installation/){target=\\_blank} for deploying contracts.\n- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\\_blank} and [Base-Sepolia](https://docs.base.org/docs/tools/network-faucets/){target=\\_blank} to cover gas fees.\n- Wallet private key."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 2, "depth": 2, "title": "Build Cross-Chain Messaging Contracts", "anchor": "build-cross-chain-messaging-contracts", "start_char": 3246, "end_char": 3789, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "## Build Cross-Chain Messaging Contracts\n\nIn this section, we'll deploy two smart contracts: one to send a message from Avalanche Fuji and another to receive it on Base Sepolia. The contracts interact with the relayer to transmit messages across chains.\n\nAt a high level, our contracts will:\n\n1. Send a message from Avalanche to Base Sepolia using the relayer.\n2. Receive and process the message on Base Sepolia, logging the content of the message.\n\nBefore diving into the deployment steps, let's first break down key parts of the contracts."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 3, "depth": 3, "title": "Sender Contract: MessageSender", "anchor": "sender-contract-messagesender", "start_char": 3789, "end_char": 6169, "estimated_token_count": 376, "token_estimator": "heuristic-v1", "text": "### Sender Contract: MessageSender\n\nThe `MessageSender` contract is responsible for quoting the cost of sending a message cross-chain and then sending that message. \n\nKey functions include:\n\n - **`quoteCrossChainCost`**: Calculates the cost of delivering a message to the target chain using the relayer.\n - **`sendMessage`**: Encodes the message and sends it to the target chain and contract address using the relayer.\n\nHere's the core of the contract:\n\n```solidity\n    function sendMessage(\n        uint16 targetChain,\n        address targetAddress,\n        string memory message\n    ) external payable {\n        uint256 cost = quoteCrossChainCost(targetChain);\n\n        require(\n            msg.value >= cost,\n            \"Insufficient funds for cross-chain delivery\"\n        );\n\n        wormholeRelayer.sendPayloadToEvm{value: cost}(\n            targetChain,\n            targetAddress,\n            abi.encode(message, msg.sender),\n            0,\n            GAS_LIMIT\n        );\n    }\n```\n\nYou can find the full code for the `MessageSender.sol` below.\n\n??? code \"MessageSender.sol\"\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.18;\n\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol\";\n\n    contract MessageSender {\n        IWormholeRelayer public wormholeRelayer;\n        uint256 constant GAS_LIMIT = 50000;\n\n        constructor(address _wormholeRelayer) {\n            wormholeRelayer = IWormholeRelayer(_wormholeRelayer);\n        }\n\n        function quoteCrossChainCost(\n            uint16 targetChain\n        ) public view returns (uint256 cost) {\n            (cost, ) = wormholeRelayer.quoteEVMDeliveryPrice(\n                targetChain,\n                0,\n                GAS_LIMIT\n            );\n        }\n\n        function sendMessage(\n            uint16 targetChain,\n            address targetAddress,\n            string memory message\n        ) external payable {\n            uint256 cost = quoteCrossChainCost(targetChain);\n\n            require(\n                msg.value >= cost,\n                \"Insufficient funds for cross-chain delivery\"\n            );\n\n            wormholeRelayer.sendPayloadToEvm{value: cost}(\n                targetChain,\n                targetAddress,\n                abi.encode(message, msg.sender),\n                0,\n                GAS_LIMIT\n            );\n        }\n    }\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 4, "depth": 3, "title": "Receiver Contract: MessageReceiver", "anchor": "receiver-contract-messagereceiver", "start_char": 6169, "end_char": 11380, "estimated_token_count": 826, "token_estimator": "heuristic-v1", "text": "### Receiver Contract: MessageReceiver\n\nThe `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.\n\n#### Emitter Validation and Registration\n\nIn 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.\n\nKey implementation details include:\n\n - **`registeredSender`**: Stores the address of the registered sender contract.\n - **`setRegisteredSender`**: Registers the sender's contract address on the source chain. It ensures that only registered contracts can send messages, preventing unauthorized senders.\n - **`isRegisteredSender`**: Restricts the processing of messages to only those from registered senders, preventing unauthorized cross-chain communication.\n\n```solidity\n    mapping(uint16 => bytes32) public registeredSenders;\n    modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) {\n        require(\n            registeredSenders[sourceChain] == sourceAddress,\n            \"Not registered sender\"\n        );\n        _;\n    }\n\n    function setRegisteredSender(\n        uint16 sourceChain,\n        bytes32 sourceAddress\n    ) public {\n        require(\n            msg.sender == registrationOwner,\n            \"Not allowed to set registered sender\"\n        );\n        registeredSenders[sourceChain] = sourceAddress;\n    }\n```\n\n#### Message Processing\n\nThe `receiveWormholeMessages` is the core function that processes the received message. It checks that the 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.\n\n```solidity\n    function receiveWormholeMessages(\n        bytes memory payload,\n        bytes[] memory,\n        bytes32 sourceAddress,\n        uint16 sourceChain,\n        bytes32\n    ) public payable override isRegisteredSender(sourceChain, sourceAddress) {\n        require(\n            msg.sender == address(wormholeRelayer),\n            \"Only the Wormhole relayer can call this function\"\n        );\n\n        // Decode the payload to extract the message\n        string memory message = abi.decode(payload, (string));\n\n        // Example use of sourceChain for logging\n        if (sourceChain != 0) {\n            emit SourceChainLogged(sourceChain);\n        }\n\n        // Emit an event with the received message\n        emit MessageReceived(message);\n    }\n```\n\nYou can find the full code for the `MessageReceiver.sol` below.\n\n??? code \"MessageReceiver.sol\"\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.18;\n\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IWormholeRelayer.sol\";\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IWormholeReceiver.sol\";\n\n    contract MessageReceiver is IWormholeReceiver {\n        IWormholeRelayer public wormholeRelayer;\n        address public registrationOwner;\n\n        // Mapping to store registered senders for each chain\n        mapping(uint16 => bytes32) public registeredSenders;\n\n        event MessageReceived(string message);\n        event SourceChainLogged(uint16 sourceChain);\n\n        constructor(address _wormholeRelayer) {\n            wormholeRelayer = IWormholeRelayer(_wormholeRelayer);\n            registrationOwner = msg.sender; // Set contract deployer as the owner\n        }\n\n        modifier isRegisteredSender(uint16 sourceChain, bytes32 sourceAddress) {\n            require(\n                registeredSenders[sourceChain] == sourceAddress,\n                \"Not registered sender\"\n            );\n            _;\n        }\n\n        function setRegisteredSender(\n            uint16 sourceChain,\n            bytes32 sourceAddress\n        ) public {\n            require(\n                msg.sender == registrationOwner,\n                \"Not allowed to set registered sender\"\n            );\n            registeredSenders[sourceChain] = sourceAddress;\n        }\n\n        // Update receiveWormholeMessages to include the source address check\n        function receiveWormholeMessages(\n            bytes memory payload,\n            bytes[] memory,\n            bytes32 sourceAddress,\n            uint16 sourceChain,\n            bytes32\n        ) public payable override isRegisteredSender(sourceChain, sourceAddress) {\n            require(\n                msg.sender == address(wormholeRelayer),\n                \"Only the Wormhole relayer can call this function\"\n            );\n\n            // Decode the payload to extract the message\n            string memory message = abi.decode(payload, (string));\n\n            // Example use of sourceChain for logging\n            if (sourceChain != 0) {\n                emit SourceChainLogged(sourceChain);\n            }\n\n            // Emit an event with the received message\n            emit MessageReceived(message);\n        }\n    }\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 5, "depth": 2, "title": "Deploy Contracts", "anchor": "deploy-contracts", "start_char": 11380, "end_char": 11590, "estimated_token_count": 37, "token_estimator": "heuristic-v1", "text": "## Deploy Contracts\n\nThis section will guide you through deploying the cross-chain messaging contracts on the Avalanche Fuji and Base Sepolia Testnets. Follow these steps to get your contracts up and running."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 6, "depth": 3, "title": "Deployment Tools", "anchor": "deployment-tools", "start_char": 11590, "end_char": 12298, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Deployment Tools\nWe use _Foundry_ to deploy our smart contracts. However, you can use any tool you're comfortable with, such as:\n\n - [Remix](https://remix.ethereum.org/){target=\\_blank} for a browser-based IDE.\n - [Hardhat](https://hardhat.org/hardhat-runner/docs/getting-started#installation){target=\\_blank} for a more extensive JavaScript/TypeScript workflow.\n - [Foundry](https://getfoundry.sh/introduction/installation/){target=\\_blank} for a CLI-focused experience with built-in scripting and testing features.\n\nThe 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."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 7, "depth": 3, "title": "Repository Setup", "anchor": "repository-setup", "start_char": 12298, "end_char": 14225, "estimated_token_count": 434, "token_estimator": "heuristic-v1", "text": "### Repository Setup\n\nTo 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.\n\nThis 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`.\n\nTo configure the dependencies properly, run the following command:\n\n```bash\nnpm install\n```\n\nThe repository includes:\n\n- Two Solidity contracts:\n\n    - **`MessageSender.sol`**: Contract that sends the cross-chain message from Avalanche.\n    - **`MessageReceiver.sol`**: Contract that receives the cross-chain message on Base Sepolia.\n\n- Deployment scripts located in the `script` directory:\n\n    - **`deploySender.ts`**: Deploys the `MessageSender` contract to Avalanche.\n    - **`deployReceiver.ts`**: Deploys the `MessageReceiver` contract to Base Sepolia.\n    - **`sendMessage.ts`**: Sends a message from Avalanche to Base Sepolia.\n\n- Configuration files and ABI JSON files for easy deployment and interaction:\n\n    - **`chains.json`**: Configuration file that stores key information for the supported Testnets, including the relayer addresses, RPC URLs, and chain IDs. You likely won't need to modify this file unless you're working with different networks.\n\n - A dedicated `interfaces` directory inside the `src` folder for TypeScript type definitions:\n\n    - **`ChainsConfig.ts`**: Defines the types for the `chains.json` configuration file.\n    - **`DeployedContracts.ts`**: Contains types for deployed contract addresses and related information.\n    - **`MessageJsons.ts`**: Includes types for ABI and bytecode JSONs used by the deployment scripts.\n    - **`index.ts`**: Serves as an export aggregator for the interfaces, simplifying imports in other files."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 8, "depth": 3, "title": "Important Setup Steps", "anchor": "important-setup-steps", "start_char": 14225, "end_char": 15080, "estimated_token_count": 262, "token_estimator": "heuristic-v1", "text": "### Important Setup Steps\n\n1. **Add your private key**: Create a `.env` file in the root of the project and add your private key.\n    \n    ```env\n    touch .env\n    ```\n\n    Inside `.env`, add your private key in the following format:\n\n    ```env\n    PRIVATE_KEY=INSERT_PRIVATE_KEY\n    ```\n\n2. **Compile the contracts**: Ensure everything is set up correctly by compiling the contracts.\n\n    ```bash\n    forge build\n    ```\n\nThe expected output should be similar to this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>forge build</span>\n\t<span data-ty> > [⠒] Compiling...</span>\n\t<span data-ty> > [⠰] Compiling 30 files with 0.8.23</span>\n\t<span data-ty> [⠔] Solc 0.8.23 finished in 2.29s</span>\n\t<span data-ty>Compiler run successful!</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 9, "depth": 3, "title": "Deployment Process", "anchor": "deployment-process", "start_char": 15080, "end_char": 26284, "estimated_token_count": 2072, "token_estimator": "heuristic-v1", "text": "### Deployment Process\n\nBoth deployment scripts, `deploySender.ts` and `deployReceiver.ts`, perform the following key tasks:\n\n1. **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.\n\n    === \"`chains.json`\"\n\n        ```json\n        {\n            \"chains\": [\n                {\n                    \"description\": \"Avalanche testnet fuji\",\n                    \"chainId\": 6,\n                    \"rpc\": \"https://api.avax-test.network/ext/bc/C/rpc\",\n                    \"tokenBridge\": \"0x61E44E506Ca5659E6c0bba9b678586fA2d729756\",\n                    \"wormholeRelayer\": \"0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB\",\n                    \"wormhole\": \"0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C\"\n                },\n                {\n                    \"description\": \"Base Sepolia testnet\",\n                    \"chainId\": 10004,\n                    \"rpc\": \"https://sepolia.base.org\",\n                    \"tokenBridge\": \"0x86F55A04690fd7815A3D802bD587e83eA888B239\",\n                    \"wormholeRelayer\": \"0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE\",\n                    \"wormhole\": \"0x79A1027a6A159502049F10906D333EC57E95F083\"\n                }\n            ]\n        }\n        ```\n\n    === \"`deploySender.ts`\"\n\n        ```typescript\n          // Load the chain configuration from JSON\n          const chains: ChainsConfig = JSON.parse(\n            fs.readFileSync(\n              path.resolve(__dirname, '../deploy-config/chains.json'),\n              'utf8'\n            )\n          );\n\n          // Get the Avalanche Fuji configuration\n          const avalancheChain = chains.chains.find((chain) =>\n            chain.description.includes('Avalanche testnet')\n          );\n        ```\n\n    === \"`deployReceiver.ts`\"\n\n        ```typescript\n          // Load the chain configuration from the JSON file\n          const chains: ChainsConfig = JSON.parse(\n            fs.readFileSync(\n              path.resolve(__dirname, '../deploy-config/chains.json'),\n              'utf8'\n            )\n          );\n\n          // Get the Base Sepolia configuration\n          const baseSepoliaChain = chains.chains.find((chain) =>\n            chain.description.includes('Base Sepolia testnet')\n          );\n        ```\n\n    !!! note\n        The `chains.json` file contains the configuration details for the Avalanche Fuji and Base Sepolia 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}.\n\n2. **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.\n\n    === \"`deploySender.ts`\"\n\n        ```typescript\n          const provider = new ethers.JsonRpcProvider(avalancheChain.rpc);\n          const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n        ```\n\n    === \"`deployReceiver.ts`\"\n\n        ```typescript\n          const provider = new ethers.JsonRpcProvider(baseSepoliaChain.rpc);\n          const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n        ```\n\n3. **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.\n\n    === \"`deploySender.ts`\"\n\n        ```typescript\n          const senderContract = await MessageSender.deploy(\n            avalancheChain.wormholeRelayer\n          );\n          await senderContract.waitForDeployment();\n        ```\n\n    === \"`deployReceiver.ts`\"\n\n        ```typescript\n          const receiverContract = await MessageReceiver.deploy(\n            baseSepoliaChain.wormholeRelayer\n          );\n          await receiverContract.waitForDeployment();\n        ```\n\n4. **Register the `MessageSender` on the target chain**: After you deploy the `MessageReceiver` contract on the Base Sepolia network, the sender contract address from Avalanche Fuji needs to be registered. This ensures that only messages from the registered `MessageSender` contract are processed.\n\n    This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `MessageReceiver` contract\n\n    ```typescript\n      // Retrieve the address of the MessageSender from the deployedContracts.json file\n      const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender;\n      if (!avalancheSenderAddress) {\n        throw new Error('Avalanche MessageSender address not found.');\n      }\n\n      // Define the source chain ID for Avalanche Fuji\n      const sourceChainId = 6;\n\n      // Call setRegisteredSender on the MessageReceiver contract\n      const tx = await (receiverContract as any).setRegisteredSender(\n        sourceChainId,\n        ethers.zeroPadValue(avalancheSenderAddress, 32)\n      );\n      await tx.wait();\n    ```\n\nYou can find the full code for the `deploySender.ts` and `deployReceiver.ts` below.\n\n??? code \"deploySender.ts\"\n\n    ```typescript\n    import { ethers } from 'ethers';\n    import fs from 'fs';\n    import path from 'path';\n    import dotenv from 'dotenv';\n    import {\n      ChainsConfig,\n      DeployedContracts,\n      MessageSenderJson,\n    } from './interfaces';\n\n    dotenv.config();\n\n    async function main(): Promise<void> {\n      // Load the chain configuration from JSON\n      const chains: ChainsConfig = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/chains.json'),\n          'utf8'\n        )\n      );\n\n      // Get the Avalanche Fuji configuration\n      const avalancheChain = chains.chains.find((chain) =>\n        chain.description.includes('Avalanche testnet')\n      );\n      if (!avalancheChain) {\n        throw new Error(\n          'Avalanche testnet configuration not found in chains.json.'\n        );\n      }\n\n      // Set up the provider and wallet\n      const provider = new ethers.JsonRpcProvider(avalancheChain.rpc);\n      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n\n      // Load the ABI and bytecode of the MessageSender contract\n      const messageSenderJson: MessageSenderJson = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'),\n          'utf8'\n        )\n      );\n\n      const { abi, bytecode } = messageSenderJson;\n\n      // Create a ContractFactory for MessageSender\n      const MessageSender = new ethers.ContractFactory(abi, bytecode, wallet);\n\n      // Deploy the contract using the Wormhole Relayer address for Avalanche Fuji\n      const senderContract = await MessageSender.deploy(\n        avalancheChain.wormholeRelayer\n      );\n      await senderContract.waitForDeployment();\n\n      console.log('MessageSender deployed to:', senderContract.target); // `target` is the address in ethers.js v6\n\n      // Update the deployedContracts.json file\n      const deployedContractsPath = path.resolve(\n        __dirname,\n        '../deploy-config/deployedContracts.json'\n      );\n      const deployedContracts: DeployedContracts = JSON.parse(\n        fs.readFileSync(deployedContractsPath, 'utf8')\n      );\n\n      deployedContracts.avalanche = {\n        MessageSender: senderContract.target as any,\n        deployedAt: new Date().toISOString(),\n      };\n\n      fs.writeFileSync(\n        deployedContractsPath,\n        JSON.stringify(deployedContracts, null, 2)\n      );\n    }\n\n    main().catch((error) => {\n      console.error(error);\n      process.exit(1);\n    });\n    ```\n\n??? code \"deployReceiver.ts\"\n\n    ```typescript\n    import { ethers } from 'ethers';\n    import fs from 'fs';\n    import path from 'path';\n    import dotenv from 'dotenv';\n    import {\n      ChainsConfig,\n      DeployedContracts,\n      MessageReceiverJson,\n    } from './interfaces';\n\n    dotenv.config();\n\n    async function main(): Promise<void> {\n      // Load the chain configuration from the JSON file\n      const chains: ChainsConfig = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/chains.json'),\n          'utf8'\n        )\n      );\n\n      // Get the Base Sepolia configuration\n      const baseSepoliaChain = chains.chains.find((chain) =>\n        chain.description.includes('Base Sepolia testnet')\n      );\n      if (!baseSepoliaChain) {\n        throw new Error('Base Sepolia testnet configuration not found.');\n      }\n\n      // Set up the provider and wallet\n      const provider = new ethers.JsonRpcProvider(baseSepoliaChain.rpc);\n      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n\n      // Load the ABI and bytecode of the MessageReceiver contract\n      const messageReceiverJson: MessageReceiverJson = JSON.parse(\n        fs.readFileSync(\n          path.resolve(\n            __dirname,\n            '../out/MessageReceiver.sol/MessageReceiver.json'\n          ),\n          'utf8'\n        )\n      );\n\n      const { abi, bytecode } = messageReceiverJson;\n\n      // Create a ContractFactory for MessageReceiver\n      const MessageReceiver = new ethers.ContractFactory(abi, bytecode, wallet);\n\n      // Deploy the contract using the Wormhole Relayer address for Base Sepolia\n      const receiverContract = await MessageReceiver.deploy(\n        baseSepoliaChain.wormholeRelayer\n      );\n      await receiverContract.waitForDeployment();\n\n      console.log('MessageReceiver deployed to:', receiverContract.target); // `target` is the contract address in ethers.js v6\n\n      // Update the deployedContracts.json file\n      const deployedContractsPath = path.resolve(\n        __dirname,\n        '../deploy-config/deployedContracts.json'\n      );\n      const deployedContracts: DeployedContracts = JSON.parse(\n        fs.readFileSync(deployedContractsPath, 'utf8')\n      );\n\n      // Retrieve the address of the MessageSender from the deployedContracts.json file\n      const avalancheSenderAddress = deployedContracts.avalanche?.MessageSender;\n      if (!avalancheSenderAddress) {\n        throw new Error('Avalanche MessageSender address not found.');\n      }\n\n      // Define the source chain ID for Avalanche Fuji\n      const sourceChainId = 6;\n\n      // Call setRegisteredSender on the MessageReceiver contract\n      const tx = await (receiverContract as any).setRegisteredSender(\n        sourceChainId,\n        ethers.zeroPadValue(avalancheSenderAddress, 32)\n      );\n      await tx.wait();\n\n      console.log(\n        `Registered MessageSender (${avalancheSenderAddress}) for Avalanche chain (${sourceChainId})`\n      );\n\n      deployedContracts.baseSepolia = {\n        MessageReceiver: receiverContract.target as any,\n        deployedAt: new Date().toISOString(),\n      };\n\n      fs.writeFileSync(\n        deployedContractsPath,\n        JSON.stringify(deployedContracts, null, 2)\n      );\n    }\n\n    main().catch((error) => {\n      console.error(error);\n      process.exit(1);\n    });\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 10, "depth": 3, "title": "Deploy the Sender Contract", "anchor": "deploy-the-sender-contract", "start_char": 26284, "end_char": 27069, "estimated_token_count": 220, "token_estimator": "heuristic-v1", "text": "### Deploy the Sender Contract\n\nThe sender contract will handle quoting and sending messages cross-chain.\n\n1. Run the following command to deploy the sender contract:\n\n    ```bash\n    npm run deploy:sender\n    ```\n\n2. Once deployed, the contract address will be displayed. You may check the contract on the [Avalanche Fuji Explorer](https://testnet.snowtrace.io/){target=\\_blank}.\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"\n\t\t><span class=\"file-path\"></span>npm run deploy:sender</span\n\t>\n\t<span data-ty> > wormhole-cross-chain@1.0.0 deploy:sender</span>\n\t<span data-ty> > node script/deploySender.ts</span>\n\t<span data-ty> MessageSender deployed to: 0xf5c474f335fFf617fA6FD04DCBb17E20ee0cEfb1</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 11, "depth": 3, "title": "Deploy the Receiver Contract", "anchor": "deploy-the-receiver-contract", "start_char": 27069, "end_char": 27454, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "### Deploy the Receiver Contract\n\nThe receiver contract listens for cross-chain messages and logs them when received.\n\n1. Deploy the receiver contract with this command:\n    \n    ```bash\n    npm run deploy:receiver\n    ```\n\n2. After deployment, note down the contract address. You may check the contract on the [Base Sepolia Explorer](https://sepolia.basescan.org/){target=\\_blank}."}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 12, "depth": 2, "title": "Send a Cross-Chain Message", "anchor": "send-a-cross-chain-message", "start_char": 27454, "end_char": 35961, "estimated_token_count": 1798, "token_estimator": "heuristic-v1", "text": "## Send a Cross-Chain Message\n\nNow 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 Base Sepolia.\n\nIn this example, we will use the `sendMessage.ts` script to transmit a message from the sender contract on Avalanche to the receiver contract on Base Sepolia. 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.\n\nLet's break down the script step by step.\n\n1. **Load configuration files**:\n\n    1. **`chains.json`**: Contains details about the supported Testnet chains, such as RPC URLs and relayer addresses.\n    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.\n\n    ```typescript\n      const chains: ChainsConfig = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/chains.json'),\n          'utf8'\n        )\n      );\n\n      const deployedContracts: DeployedContracts = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/deployedContracts.json'),\n          'utf8'\n        )\n      );\n    ```\n\n2. **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.\n\n    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.\n        \n    ```typescript\n      const provider = new ethers.JsonRpcProvider(avalancheChain.rpc);\n      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n    ```\n\n    After setting up the wallet, the script loads the ABI for the `MessageSender.sol` contract and creates an instance of it.\n\n    ```typescript\n      const messageSenderJson = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'),\n          'utf8'\n        )\n      );\n    ```\n\n3. **Set up the message details**: The next part of the script defines the target chain (Base Sepolia) and the target address (the receiver contract on Base Sepolia).\n\n    ```typescript\n      const targetChain = 10004; // Wormhole chain ID for Base Sepolia\n      const targetAddress = deployedContracts.baseSepolia.MessageReceiver;\n    ```\n\n    You can customize the message that will be sent across chains.\n\n    ```typescript\n      const message = 'Hello from Avalanche to Base Sepolia!';\n    ```\n\n4. **Estimate cross-chain cost**: Before sending the message, we dynamically calculate the cross-chain cost using the `quoteCrossChainCost` function.\n\n    ```typescript\n      const txCost = await MessageSender.quoteCrossChainCost(targetChain);\n    ```\n\n    This ensures that the transaction includes enough funds to cover the gas fees for the cross-chain message.\n\n5. **Send a message**: With everything set up, the message is sent using the `sendMessage` function.\n\n    ```typescript\n      const tx = await MessageSender.sendMessage(\n        targetChain,\n        targetAddress,\n        message,\n        {\n          value: txCost,\n        }\n      );\n    ```\n\n    After sending, the script waits for the transaction to be confirmed.\n\n    ```typescript\n      await tx.wait();\n    ```\n\n6. **Run the script**: To send the message, run the following command:\n\n    ```bash\n    npm run send:message\n    ```\n\nIf everything is set up correctly, the message will be sent from the Avalanche Fuji Testnet to the Base Sepolia Testnet. You can monitor the transaction and verify that the message was received on Base Sepolia using the [Wormhole Explorer](https://wormholescan.io/#/?network=TESTNET){target=\\_blank}.\n\nThe console should output something similar to this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"\n\t\t><span class=\"file-path\"></span>npm run send:message</span\n\t>\n\t<span data-ty> > wormhole-cross-chain@1.0.0 send:message</span>\n\t<span data-ty> > node script/sendMessage.ts</span>\n\t<span data-ty\n\t\t>Sender Contract Address: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1</span\n\t>\n\t<span data-ty\n\t\t>Receiver Contract Address: 0x692550997C252cC5044742D1A2BD91E4f4b46D39</span\n\t>\n\t<span data-ty>...</span>\n\t<span data-ty>Transaction sent, waiting for confirmation...</span>\n\t<span data-ty>...</span>\n\t<span data-ty\n\t\t>Message sent! Transaction hash:\n\t\t0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6</span\n\t>\n\t<span data-ty\n\t\t>You may see the transaction status on the Wormhole Explorer:\n\t\thttps://wormholescan.io/#/tx/0x9d359a66ba42baced80062229c0b02b4f523fe304aff3473dcf53117aee13fb6?network=TESTNET</span\n\t>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>\nYou can find the full code for the `sendMessage.ts` below.\n\n??? code \"sendMessage.ts\"\n\n    ```solidity\n    import { ethers } from 'ethers';\n    import fs from 'fs';\n    import path from 'path';\n    import dotenv from 'dotenv';\n    import { ChainsConfig, DeployedContracts } from './interfaces';\n\n    dotenv.config();\n\n    async function main(): Promise<void> {\n      // Load the chain configuration and deployed contract addresses\n      const chains: ChainsConfig = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/chains.json'),\n          'utf8'\n        )\n      );\n\n      const deployedContracts: DeployedContracts = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../deploy-config/deployedContracts.json'),\n          'utf8'\n        )\n      );\n\n      console.log(\n        'Sender Contract Address: ',\n        deployedContracts.avalanche.MessageSender\n      );\n      console.log(\n        'Receiver Contract Address: ',\n        deployedContracts.baseSepolia.MessageReceiver\n      );\n      console.log('...');\n\n      // Get the Avalanche Fuji configuration\n      const avalancheChain = chains.chains.find((chain) =>\n        chain.description.includes('Avalanche testnet')\n      );\n\n      if (!avalancheChain) {\n        throw new Error(\n          'Avalanche testnet configuration not found in chains.json.'\n        );\n      }\n\n      // Set up the provider and wallet\n      const provider = new ethers.JsonRpcProvider(avalancheChain.rpc);\n      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);\n\n      // Load the ABI of the MessageSender contract\n      const messageSenderJson = JSON.parse(\n        fs.readFileSync(\n          path.resolve(__dirname, '../out/MessageSender.sol/MessageSender.json'),\n          'utf8'\n        )\n      );\n\n      const abi = messageSenderJson.abi;\n\n      // Create a contract instance for MessageSender\n      const MessageSender = new ethers.Contract(\n        deployedContracts.avalanche.MessageSender, // Automatically use the deployed address\n        abi,\n        wallet\n      );\n\n      // Define the target chain and target address (the Base Sepolia receiver contract)\n      const targetChain = 10004; // Wormhole chain ID for Base Sepolia\n      const targetAddress = deployedContracts.baseSepolia.MessageReceiver;\n\n      // The message you want to send\n      const message = 'Hello from Avalanche to Base Sepolia!';\n\n      // Dynamically quote the cross-chain cost\n      const txCost = await MessageSender.quoteCrossChainCost(targetChain);\n\n      // Send the message (make sure to send enough gas in the transaction)\n      const tx = await MessageSender.sendMessage(\n        targetChain,\n        targetAddress,\n        message,\n        {\n          value: txCost,\n        }\n      );\n\n      console.log('Transaction sent, waiting for confirmation...');\n      await tx.wait();\n      console.log('...');\n\n      console.log('Message sent! Transaction hash:', tx.hash);\n      console.log(\n        `You may see the transaction status on the Wormhole Explorer: https://wormholescan.io/#/tx/${tx.hash}?network=TESTNET`\n      );\n    }\n\n    main().catch((error) => {\n      console.error(error);\n      process.exit(1);\n    });\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-contracts", "page_title": "Create Cross-Chain Contracts", "index": 13, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 35961, "end_char": 36497, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nYou're now fully equipped to build cross-chain contracts using the Wormhole protocol! With this tutorial, you've learned how to:\n\n- Deploy sender and receiver contracts on different testnets.\n- Send a cross-chain message from one blockchain to another.\n- Monitor the status of your cross-chain transactions using Wormholescan and the Wormhole Solidity SDK.\n\nLooking for more? Check out the [Wormhole Tutorial Demo repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank} for additional examples."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 934, "end_char": 1587, "estimated_token_count": 195, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- [Foundry](https://getfoundry.sh/introduction/installation/){target=\\_blank} for deploying contracts.\n- Testnet tokens for [Avalanche-Fuji](https://core.app/tools/testnet-faucet/?token=C){target=\\_blank} and [Base Sepolia](https://faucets.chain.link/base-sepolia){target=\\_blank} to cover gas fees.\n- [USDC Testnet](https://faucet.circle.com/){target=\\_blank} tokens on Avalanche-Fuji or/and Base Sepolia for cross-chain transfer.\n- Wallet private key."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 1, "depth": 2, "title": "Valid Tokens for Transfer", "anchor": "valid-tokens-for-transfer", "start_char": 1587, "end_char": 4447, "estimated_token_count": 670, "token_estimator": "heuristic-v1", "text": "## Valid Tokens for Transfer\n\nIt'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.\n\nTo 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.\n\n???- tip \"Check Token Attestation\"\n    1. Clone the [repository](https://github.com/wormhole-foundation/demo-cross-chain-token-transfer){target=\\_blank} and navigate to the project directory:\n\n        ```bash\n        git clone https://github.com/wormhole-foundation/demo-cross-chain-token-transfer.git\n        cd cross-chain-token-transfers\n        ```\n\n    2. Install the dependencies:\n\n        ```bash\n        npm install\n        ```\n    \n    3. Run the script to check token attestation:\n\n        ```bash\n        npm run verify\n        ```\n\n    4. Follow the prompts:\n\n        1. Enter the RPC URL of the target chain.\n        2. Enter the `TokenBridge` contract address on the target chain.\n        3. Enter the token contract address on the source chain.\n        4. Enter the source chain ID.\n\n    5. The expected output when the token has an attestation:\n        \n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npm run verify</span>\n        \t<span data-ty> > cross-chain-token-transfer@1.0.0 verify</span>\n        \t<span data-ty> > npx ts-node script/check-attestation.ts</span>\n          <span data-ty> </span>\n        \t<span data-ty> Enter the TARGET chain RPC URL: https://base-sepolia-rpc.publicnode.com</span>\n        \t<span data-ty> Enter the WTT contract address on the TARGET chain: 0x05...E153</span>\n          <span data-ty> Enter the token contract address on the SOURCE chain: 0x54...bc65</span>\n          <span data-ty> Enter the SOURCE chain ID: 6</span>\n          <span data-ty> The token is attested on the target chain. Wrapped token address: 0xDDB349c976cA2C873644F21f594767Eb5390C831</span>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n    Using this tool ensures that you only attempt to transfer tokens with verified attestations, avoiding any potential issues during the cross-chain transfer process."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 2, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 4447, "end_char": 5377, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nLet's start by initializing a new Foundry project. This will set up a basic structure for our smart contracts.\n\n1. Open your terminal and run the following command to initialize a new Foundry project:\n    \n    ```bash\n    forge init cross-chain-token-transfers\n    ```\n\n    This will create a new directory named `cross-chain-token-transfers` with a basic project structure. This also initializes a new `git` repository.\n\n2. Navigate into the newly created project directory:\n\n    ```bash\n    cd cross-chain-token-transfers\n    ```\n\n3. Install the Wormhole Solidity SDK:\n\n    ```bash\n    forge install wormhole-foundation/wormhole-solidity-sdk\n    ```\n\n    To ease development, we'll use the Wormhole Solidity SDK, which provides useful helpers for cross-chain development.\n    This SDK includes the `TokenSender` and `TokenReceiver` abstract classes, which simplify sending and receiving tokens across chains."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 3, "depth": 2, "title": "Build Cross-Chain Contracts", "anchor": "build-cross-chain-contracts", "start_char": 5377, "end_char": 5996, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "## Build Cross-Chain Contracts\n\nIn 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.\n\nAt a high level, our contracts will:\n\n1. Send tokens from one blockchain to another using the Wormhole protocol.\n2. Receive and process the tokens on the target chain, ensuring they are correctly transferred to the intended recipient.\n\nBefore diving into the contract implementation steps, let’s first break down the key parts of the contracts."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 4, "depth": 3, "title": "Sender Contract: CrossChainSender", "anchor": "sender-contract-crosschainsender", "start_char": 5996, "end_char": 12688, "estimated_token_count": 1133, "token_estimator": "heuristic-v1", "text": "### Sender Contract: CrossChainSender\n\nThe `CrossChainSender` contract calculates the cost of sending tokens across chains and then facilitates the actual token transfer.\n\nLet's start writing the `CrossChainSender` contract:\n\n1. Create a new file named `CrossChainSender.sol` in the `/src` directory:\n    \n    ```bash\n    touch src/CrossChainSender.sol\n    ```\n\n2. Open the file. First, we'll start with the imports and the contract setup:\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.13;\n\n    import \"lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol\";\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol\";\n\n    contract CrossChainSender is TokenSender {\n        uint256 constant GAS_LIMIT = 250_000;\n\n        constructor(\n            address _wormholeRelayer,\n            address _tokenBridge,\n            address _wormhole\n        ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {}\n    }\n    ```\n\n    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.\n\n    With the contract structure in place, define the following functions within its body to enable multichain token transfers.\n\n3. Next, let's add a function that estimates the cost of sending tokens across chains:\n\n    ```solidity\n        function quoteCrossChainDeposit(\n            uint16 targetChain\n        ) public view returns (uint256 cost) {\n            uint256 deliveryCost;\n            (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice(\n                targetChain,\n                0,\n                GAS_LIMIT\n            );\n\n            cost = deliveryCost + wormhole.messageFee();\n        }\n    ```\n\n    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.\n\n4. Finally, we'll add the function that sends the tokens across chains:\n\n    ```solidity\n        function sendCrossChainDeposit(\n            uint16 targetChain,\n            address targetReceiver,\n            address recipient,\n            uint256 amount,\n            address token\n        ) public payable {\n            uint256 cost = quoteCrossChainDeposit(targetChain);\n            require(\n                msg.value == cost,\n                \"msg.value must equal quoteCrossChainDeposit(targetChain)\"\n            );\n\n            IERC20(token).transferFrom(msg.sender, address(this), amount);\n\n            bytes memory payload = abi.encode(recipient);\n\n            sendTokenWithPayloadToEvm(\n                targetChain,\n                targetReceiver,\n                payload,\n                0,\n                GAS_LIMIT,\n                token,\n                amount\n            );\n        }\n    ```\n\n    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.\n\nHere’s a breakdown of what happens in each step of the `sendCrossChainDeposit` function:\n\n1. **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`).\n\n2. **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.\n\n3. **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.\n\n4. **Cross-chain transfer**: The `sendTokenWithPayloadToEvm` function is called to initiate the cross-chain token transfer. This function does the following:\n    - Specifies the `targetChain` (the Wormhole chain ID of the destination blockchain).\n    - Sends the `targetReceiver` contract address on the target chain that will receive the tokens.\n    - Attaches the payload containing the recipient's address.\n    - Sets the `GAS_LIMIT` for the transaction.\n    - Passes the token `address` and `amount` to transfer.\n\n    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.\n\nYou can find the complete code for the `CrossChainSender.sol` below.\n\n??? code \"CrossChainSender.sol\"\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.13;\n\n    import \"lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol\";\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol\";\n\n    contract CrossChainSender is TokenSender {\n        uint256 constant GAS_LIMIT = 250_000;\n\n        constructor(\n            address _wormholeRelayer,\n            address _tokenBridge,\n            address _wormhole\n        ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {}\n\n        // Function to get the estimated cost for cross-chain deposit\n        function quoteCrossChainDeposit(\n            uint16 targetChain\n        ) public view returns (uint256 cost) {\n            uint256 deliveryCost;\n            (deliveryCost, ) = wormholeRelayer.quoteEVMDeliveryPrice(\n                targetChain,\n                0,\n                GAS_LIMIT\n            );\n\n            cost = deliveryCost + wormhole.messageFee();\n        }\n\n        // Function to send tokens and payload across chains\n        function sendCrossChainDeposit(\n            uint16 targetChain,\n            address targetReceiver,\n            address recipient,\n            uint256 amount,\n            address token\n        ) public payable {\n            uint256 cost = quoteCrossChainDeposit(targetChain);\n            require(\n                msg.value == cost,\n                \"msg.value must equal quoteCrossChainDeposit(targetChain)\"\n            );\n\n            IERC20(token).transferFrom(msg.sender, address(this), amount);\n\n            bytes memory payload = abi.encode(recipient);\n\n            sendTokenWithPayloadToEvm(\n                targetChain,\n                targetReceiver,\n                payload,\n                0,\n                GAS_LIMIT,\n                token,\n                amount\n            );\n        }\n    }\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 5, "depth": 3, "title": "Receiver Contract: CrossChainReceiver", "anchor": "receiver-contract-crosschainreceiver", "start_char": 12688, "end_char": 19258, "estimated_token_count": 1179, "token_estimator": "heuristic-v1", "text": "### Receiver Contract: CrossChainReceiver\n\nThe `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.\n\nLet's start writing the `CrossChainReceiver` contract:\n\n1. Create a new file named `CrossChainReceiver.sol` in the `/src` directory:\n\n    ```bash\n    touch src/CrossChainReceiver.sol\n    ```\n\n2. Open the file. First, we'll start with the imports and the contract setup:\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.13;\n\n    import \"lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol\";\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol\";\n\n    contract CrossChainReceiver is TokenReceiver {\n        // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract\n\n        constructor(\n            address _wormholeRelayer,\n            address _tokenBridge,\n            address _wormhole\n        ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {}\n    }\n    ```\n\n    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.\n\n3. Next, let's add a function inside the contract to handle receiving the payload and tokens:\n\n    ```solidity\n        function receivePayloadAndTokens(\n            bytes memory payload,\n            TokenReceived[] memory receivedTokens,\n            bytes32 sourceAddress,\n            uint16 sourceChain,\n            bytes32 // deliveryHash\n        )\n            internal\n            override\n            onlyWormholeRelayer\n            isRegisteredSender(sourceChain, sourceAddress)\n        {\n            require(receivedTokens.length == 1, \"Expected 1 token transfer\");\n\n            // Decode the recipient address from the payload\n            address recipient = abi.decode(payload, (address));\n\n            // Transfer the received tokens to the intended recipient\n            IERC20(receivedTokens[0].tokenAddress).transfer(\n                recipient,\n                receivedTokens[0].amount\n            );\n        }\n    ```\n\n    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.\n\n    This function ensures that:\n\n    - It only processes one token transfer at a time.\n    - 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.\n    - The recipient address is decoded from the payload, and the received tokens are transferred to them using the ERC-20 interface.\n\nAfter 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.\n\n??? tip \"Understanding the `TokenReceived` Struct\"\n\n    Let’s delve into the fields provided to us in the `TokenReceived` struct:\n\n    ```solidity\n    struct TokenReceived {\n        bytes32 tokenHomeAddress;\n        uint16 tokenHomeChain;\n        address tokenAddress;\n        uint256 amount;\n        uint256 amountNormalized;\n    }\n    ```\n\n    - **`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).\n\n    - **`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.\n\n    - **`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.\n\n    - **`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.\n\n    - **`amountNormalized`**: The amount of token divided by (1 if decimals ≤ 8, else 10^(decimals - 8)).\n\nYou can find the complete code for the `CrossChainReceiver.sol` contract below:\n\n??? code \"CrossChainReceiver.sol\"\n\n    ```solidity\n    // SPDX-License-Identifier: MIT\n    pragma solidity ^0.8.13;\n\n    import \"lib/wormhole-solidity-sdk/src/WormholeRelayerSDK.sol\";\n    import \"lib/wormhole-solidity-sdk/src/interfaces/IERC20.sol\";\n\n    contract CrossChainReceiver is TokenReceiver {\n        // The Wormhole relayer and registeredSenders are inherited from the Base.sol contract\n\n        constructor(\n            address _wormholeRelayer,\n            address _tokenBridge,\n            address _wormhole\n        ) TokenBase(_wormholeRelayer, _tokenBridge, _wormhole) {}\n\n        // Function to receive the cross-chain payload and tokens with emitter validation\n        function receivePayloadAndTokens(\n            bytes memory payload,\n            TokenReceived[] memory receivedTokens,\n            bytes32 sourceAddress,\n            uint16 sourceChain,\n            bytes32 // deliveryHash\n        )\n            internal\n            override\n            onlyWormholeRelayer\n            isRegisteredSender(sourceChain, sourceAddress)\n        {\n            require(receivedTokens.length == 1, \"Expected 1 token transfer\");\n\n            // Decode the recipient address from the payload\n            address recipient = abi.decode(payload, (address));\n\n            // Transfer the received tokens to the intended recipient\n            IERC20(receivedTokens[0].tokenAddress).transfer(\n                recipient,\n                receivedTokens[0].amount\n            );\n        }\n    }\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 6, "depth": 2, "title": "Deploy the Contracts", "anchor": "deploy-the-contracts", "start_char": 19258, "end_char": 45346, "estimated_token_count": 4704, "token_estimator": "heuristic-v1", "text": "## Deploy the Contracts\n\nNow that you've written the `CrossChainSender` and `CrossChainReceiver` contracts, it's time to deploy them to your chosen networks.\n\n1. **Set up deployment configuration**: Before deploying, you must configure the networks and the deployment environment. This information is stored in a configuration file.\n\n    1. Create a directory named deploy-config in the root of your project:\n\n        ```bash\n        mkdir deploy-config\n        ```\n\n    2. Create a `config.json` file in the `deploy-config` directory:\n\n        ```bash\n        touch deploy-config/config.json\n        ```\n\n    3. Open the `config.json` file and add the following configuration:\n\n        ```json\n        {\n            \"chains\": [\n                {\n                    \"description\": \"Avalanche testnet fuji\",\n                    \"chainId\": 6,\n                    \"rpc\": \"https://api.avax-test.network/ext/bc/C/rpc\",\n                    \"tokenBridge\": \"0x61E44E506Ca5659E6c0bba9b678586fA2d729756\",\n                    \"wormholeRelayer\": \"0xA3cF45939bD6260bcFe3D66bc73d60f19e49a8BB\",\n                    \"wormhole\": \"0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C\"\n                },\n                {\n                    \"description\": \"Base Sepolia\",\n                    \"chainId\": 10004,\n                    \"rpc\": \"https://base-sepolia-rpc.publicnode.com\",\n                    \"tokenBridge\": \"0x86F55A04690fd7815A3D802bD587e83eA888B239\",\n                    \"wormholeRelayer\": \"0x93BAD53DDfB6132b0aC8E37f6029163E63372cEE\",\n                    \"wormhole\": \"0x79A1027a6A159502049F10906D333EC57E95F083\"\n                }\n            ]\n        }\n        ```\n\n        This file specifies the details for each chain where you plan to deploy your contracts, including the RPC URL, the `TokenBridge` address, the relayer, and the Wormhole Core contract.\n\n        For a complete list of Wormhole contract addresses on various blockchains, refer to the [Wormhole Contract Addresses](/docs/products/reference/contract-addresses/){target=\\_blank}.\n\n        !!! note\n            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 Base Sepolia Testnets.\n\n    4. Create a `contracts.json` file in the `deploy-config` directory:\n\n        ```bash\n        echo '{}' > deploy-config/contracts.json\n        ```\n\n        This file can be left blank initially. It will be automatically updated with the deployed contract addresses after a successful deployment.\n\n2. **Set up your Node.js environment**: You'll need to set up your Node.js environment to run the deployment script.\n\n    1. Initialize a Node.js project:\n\n        ```bash\n        npm init -y\n        ```\n\n    2. Create a `.gitignore` file to ensure your private key isn't accidentally exposed or committed to version control:\n\n    ```bash\n    echo \".env\" >> .gitignore\n    ```\n    \n    3. Install the necessary dependencies:\n\n        ```bash\n        npm install ethers dotenv readline-sync @types/readline-sync\n        ```\n\n        These dependencies are required for the deployment script to work properly.\n\n3. **Compile your smart contracts**: Compile your smart contracts using Foundry. This ensures that your contracts are up-to-date and ready for deployment.\n\n    - Run the following command to compile your contracts:\n\n        ```bash\n        forge build\n        ```\n\n        This will generate the necessary ABI and bytecode files in a directory named `/out`.\n\n    The expected output should be similar to this:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>forge build</span>\n    \t<span data-ty> > [⠒] Compiling...</span>\n    \t<span data-ty> > [⠰] Compiling 30 files with 0.8.23</span>\n    \t<span data-ty> > [⠔] Solc 0.8.23 finished in 2.29s</span>\n    \t<span data-ty>Compiler run successful!</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n4. **Write the deployment script**: You’ll need a script to automate the deployment of your contracts. Let’s create the deployment script.\n\n    1. Create a new file named `deploy.ts` in the `/script` directory:\n\n        ```bash\n        touch script/deploy.ts\n        ```\n\n    2. Open the file and load imports and configuration:\n\n        ```typescript\n        import { BytesLike, ethers } from 'ethers';\n        import * as fs from 'fs';\n        import * as path from 'path';\n        import * as dotenv from 'dotenv';\n        import readlineSync from 'readline-sync';\n\n        dotenv.config();\n        ```\n\n        Import the required libraries and modules to interact with Ethereum, handle file paths, load environment variables, and enable user interaction via the terminal.\n\n    3. Define interfaces to use for chain configuration and contract deployment:\n\n        ```typescript\n        interface ChainConfig {\n          description: string;\n          chainId: number;\n          rpc: string;\n          tokenBridge: string;\n          wormholeRelayer: string;\n          wormhole: string;\n        }\n\n        interface DeployedContracts {\n          [chainId: number]: {\n            networkName: string;\n            CrossChainSender?: string;\n            CrossChainReceiver?: string;\n            deployedAt: string;\n          };\n        }\n        ```\n\n        These interfaces define the structure of the chain configuration and the contract deployment details.\n\n    4. Load and select the chains for deployment:\n\n        ```typescript\n        function loadConfig(): ChainConfig[] {\n          const configPath = path.resolve(__dirname, '../deploy-config/config.json');\n          return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains;\n        }\n\n        function selectChain(\n          chains: ChainConfig[],\n          role: 'source' | 'target'\n        ): ChainConfig {\n          console.log(`\\nSelect the ${role.toUpperCase()} chain:`);\n          chains.forEach((chain, index) => {\n            console.log(`${index + 1}: ${chain.description}`);\n          });\n\n          const chainIndex =\n            readlineSync.questionInt(\n              `\\nEnter the number for the ${role.toUpperCase()} chain: `\n            ) - 1;\n          return chains[chainIndex];\n        }\n        ```\n\n        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.\n\n    5. Define the main function for deployment and load the chain configuration:\n\n        ```typescript\n        async function main() {\n          const chains = loadConfig();\n\n          const sourceChain = selectChain(chains, 'source');\n          const targetChain = selectChain(chains, 'target');\n        ```\n\n        - The `main` function is the entry point for the deployment script.\n        - We then call the `loadConfig` function we previously defined to load the chain configuration from the `config.json` file.\n\n    6. Set up provider and wallet: \n    \n        ```typescript\n          const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc);\n          const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc);\n          const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider);\n        ```\n        \n        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.\n\n    7. Read the compiled contracts:\n\n        ```typescript\n          const senderJson = JSON.parse(\n            fs.readFileSync(\n              path.resolve(\n                __dirname,\n                '../out/CrossChainSender.sol/CrossChainSender.json'\n              ),\n              'utf8'\n            )\n          );\n        ```\n\n        - This code reads the `CrossChainSender.json` file, the compiled output of the `CrossChainSender.sol` contract.\n        - The file is in the `../out/` directory, which contains the ABI (Application Binary Interface) and bytecode generated during contract compilation.\n        - 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.\n\n    8. Extract the contract ABI and bytecode:\n\n        ```typescript\n          const abi = senderJson.abi;\n          const bytecode = senderJson.bytecode;\n        ```\n\n        - **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.\n        - **Bytecode**: This is the compiled machine code that will be deployed to the blockchain to create the contract.\n\n    9. Create the Contract Factory:\n\n        ```typescript\n          const CrossChainSenderFactory = new ethers.ContractFactory(\n            abi,\n            bytecode,\n            wallet\n          );\n        ```\n\n        - **`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.\n        - This is a crucial step for deploying the contract since the factory will create and deploy the `CrossChainSender` contract.\n\n    10. Deploy the `CrossChainSender` and `CrossChainReceiver` contracts:\n\n        === \"`CrossChainSender`\"\n            ```typescript\n              try {\n                const senderContract = await CrossChainSenderFactory.deploy(\n                  sourceChain.wormholeRelayer,\n                  sourceChain.tokenBridge,\n                  sourceChain.wormhole\n                );\n                await senderContract.waitForDeployment();\n            ```\n\n        === \"`CrossChainReceiver`\"\n            ```typescript\n                const targetWallet = new ethers.Wallet(\n                  process.env.PRIVATE_KEY!,\n                  targetProvider\n                );\n                const receiverJson = JSON.parse(\n                  fs.readFileSync(\n                    path.resolve(\n                      __dirname,\n                      '../out/CrossChainReceiver.sol/CrossChainReceiver.json'\n                    ),\n                    'utf8'\n                  )\n                );\n                const CrossChainReceiverFactory = new ethers.ContractFactory(\n                  receiverJson.abi,\n                  receiverJson.bytecode,\n                  targetWallet\n                );\n\n                const receiverContract = await CrossChainReceiverFactory.deploy(\n                  targetChain.wormholeRelayer,\n                  targetChain.tokenBridge,\n                  targetChain.wormhole\n                );\n                await receiverContract.waitForDeployment();\n            ```\n\n        Both functions deploy the respective contracts to the selected chains.\n\n        For the `CrossChainReceiver` contract:\n\n        - It defines the wallet related to the target chain.\n        - The logic reads the compiled ABI and bytecode from the JSON file generated during compilation.\n        - It creates a new contract factory using the ABI, bytecode, and wallet.\n        - It deploys the contract to the selected chain passing in the relayer, `TokenBridge`, and Wormhole addresses.\n\n    11. Save the deployed contract addresses:\n\n        === \"`senderAddress`\"\n            ```typescript\n                const senderAddress = (senderContract as ethers.Contract).target;\n                console.log(\n                  `CrossChainSender on ${sourceChain.description}: ${senderAddress}`\n                );\n            ```\n\n        === \"`receiverAddress`\"\n            ```typescript\n                const receiverAddress = (receiverContract as ethers.Contract).target;\n                console.log(\n                  `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}`\n                );\n            ```\n\n        You may display the deployed contract addresses in the terminal or save them to a JSON file for future reference.\n\n    12. Register the `CrossChainSender` address on the target chain:\n\n        ```typescript\n            const CrossChainReceiverContract = new ethers.Contract(\n              receiverAddress,\n              receiverJson.abi,\n              targetWallet\n            );\n\n            const tx = await CrossChainReceiverContract.setRegisteredSender(\n              sourceChain.chainId,\n              ethers.zeroPadValue(senderAddress as BytesLike, 32)\n            );\n\n            await tx.wait();\n        ```\n\n        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.\n\n        This additional step is essential to enforce emitter validation, preventing unauthorized senders from delivering messages to the `CrossChainReceiver` contract.\n\n    13. Save the deployment details:\n\n        ???- example \"Save Deployment Details Example\"\n            ```typescript\n                const deployedContractsPath = path.resolve(\n                  __dirname,\n                  '../deploy-config/contracts.json'\n                );\n                let deployedContracts: DeployedContracts = {};\n\n                if (fs.existsSync(deployedContractsPath)) {\n                  deployedContracts = JSON.parse(\n                    fs.readFileSync(deployedContractsPath, 'utf8')\n                  );\n                }\n\n                // Update the contracts.json file:\n                // If a contract already exists on a chain, update its address; otherwise, add a new entry.\n                if (!deployedContracts[sourceChain.chainId]) {\n                  deployedContracts[sourceChain.chainId] = {\n                    networkName: sourceChain.description,\n                    deployedAt: new Date().toISOString(),\n                  };\n                }\n                deployedContracts[sourceChain.chainId].CrossChainSender =\n                  senderAddress.toString();\n                deployedContracts[sourceChain.chainId].deployedAt =\n                  new Date().toISOString();\n\n                if (!deployedContracts[targetChain.chainId]) {\n                  deployedContracts[targetChain.chainId] = {\n                    networkName: targetChain.description,\n                    deployedAt: new Date().toISOString(),\n                  };\n                }\n                deployedContracts[targetChain.chainId].CrossChainReceiver =\n                  receiverAddress.toString();\n                deployedContracts[targetChain.chainId].deployedAt =\n                  new Date().toISOString();\n\n                // Save the updated contracts.json file\n                fs.writeFileSync(\n                  deployedContractsPath,\n                  JSON.stringify(deployedContracts, null, 2)\n                );\n            ```\n        \n        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.\n\n    14. Handle errors and finalize the script:\n\n        ```typescript\n          } catch (error: any) {\n            if (error.code === 'INSUFFICIENT_FUNDS') {\n              console.error(\n                'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.'\n              );\n            } else {\n              console.error('An unexpected error occurred:', error.message);\n            }\n            process.exit(1);\n          }\n        }\n\n        main().catch((error) => {\n          console.error(error);\n          process.exit(1);\n        });\n        ```\n\n        The try-catch block wraps the deployment logic to catch any errors that may occur.\n\n        - If the error is due to insufficient funds, it logs a clear message about needing more gas fees.\n        - For any other errors, it logs the specific error message to help with debugging.\n\n        The `process.exit(1)` ensures that the script exits with a failure status code if any error occurs.\n\n    You can find the full code for the `deploy.ts` file below:\n\n    ??? code \"deploy.ts\"\n\n        ```solidity\n        import { BytesLike, ethers } from 'ethers';\n        import * as fs from 'fs';\n        import * as path from 'path';\n        import * as dotenv from 'dotenv';\n        import readlineSync from 'readline-sync';\n\n        dotenv.config();\n\n        interface ChainConfig {\n          description: string;\n          chainId: number;\n          rpc: string;\n          tokenBridge: string;\n          wormholeRelayer: string;\n          wormhole: string;\n        }\n\n        interface DeployedContracts {\n          [chainId: number]: {\n            networkName: string;\n            CrossChainSender?: string;\n            CrossChainReceiver?: string;\n            deployedAt: string;\n          };\n        }\n\n        function loadConfig(): ChainConfig[] {\n          const configPath = path.resolve(__dirname, '../deploy-config/config.json');\n          return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains;\n        }\n\n        function selectChain(\n          chains: ChainConfig[],\n          role: 'source' | 'target'\n        ): ChainConfig {\n          console.log(`\\nSelect the ${role.toUpperCase()} chain:`);\n          chains.forEach((chain, index) => {\n            console.log(`${index + 1}: ${chain.description}`);\n          });\n\n          const chainIndex =\n            readlineSync.questionInt(\n              `\\nEnter the number for the ${role.toUpperCase()} chain: `\n            ) - 1;\n          return chains[chainIndex];\n        }\n\n        async function main() {\n          const chains = loadConfig();\n\n          const sourceChain = selectChain(chains, 'source');\n          const targetChain = selectChain(chains, 'target');\n\n          const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc);\n          const targetProvider = new ethers.JsonRpcProvider(targetChain.rpc);\n          const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider);\n\n          const senderJson = JSON.parse(\n            fs.readFileSync(\n              path.resolve(\n                __dirname,\n                '../out/CrossChainSender.sol/CrossChainSender.json'\n              ),\n              'utf8'\n            )\n          );\n\n          const abi = senderJson.abi;\n          const bytecode = senderJson.bytecode;\n\n          const CrossChainSenderFactory = new ethers.ContractFactory(\n            abi,\n            bytecode,\n            wallet\n          );\n\n          try {\n            const senderContract = await CrossChainSenderFactory.deploy(\n              sourceChain.wormholeRelayer,\n              sourceChain.tokenBridge,\n              sourceChain.wormhole\n            );\n            await senderContract.waitForDeployment();\n\n            // Safely access the deployed contract's address\n            const senderAddress = (senderContract as ethers.Contract).target;\n            console.log(\n              `CrossChainSender on ${sourceChain.description}: ${senderAddress}`\n            );\n\n            const targetWallet = new ethers.Wallet(\n              process.env.PRIVATE_KEY!,\n              targetProvider\n            );\n            const receiverJson = JSON.parse(\n              fs.readFileSync(\n                path.resolve(\n                  __dirname,\n                  '../out/CrossChainReceiver.sol/CrossChainReceiver.json'\n                ),\n                'utf8'\n              )\n            );\n            const CrossChainReceiverFactory = new ethers.ContractFactory(\n              receiverJson.abi,\n              receiverJson.bytecode,\n              targetWallet\n            );\n\n            const receiverContract = await CrossChainReceiverFactory.deploy(\n              targetChain.wormholeRelayer,\n              targetChain.tokenBridge,\n              targetChain.wormhole\n            );\n            await receiverContract.waitForDeployment();\n\n            // Safely access the deployed contract's address\n            const receiverAddress = (receiverContract as ethers.Contract).target;\n            console.log(\n              `CrossChainReceiver on ${targetChain.description}: ${receiverAddress}`\n            );\n\n            // Register the sender contract in the receiver contract\n            console.log(\n              `Registering CrossChainSender (${senderAddress}) as a valid sender in CrossChainReceiver (${receiverAddress})...`\n            );\n\n            const CrossChainReceiverContract = new ethers.Contract(\n              receiverAddress,\n              receiverJson.abi,\n              targetWallet\n            );\n\n            const tx = await CrossChainReceiverContract.setRegisteredSender(\n              sourceChain.chainId,\n              ethers.zeroPadValue(senderAddress as BytesLike, 32)\n            );\n\n            await tx.wait();\n            console.log(\n              `CrossChainSender registered as a valid sender on ${targetChain.description}`\n            );\n\n            // Load existing deployed contract addresses from contracts.json\n            const deployedContractsPath = path.resolve(\n              __dirname,\n              '../deploy-config/contracts.json'\n            );\n            let deployedContracts: DeployedContracts = {};\n\n            if (fs.existsSync(deployedContractsPath)) {\n              deployedContracts = JSON.parse(\n                fs.readFileSync(deployedContractsPath, 'utf8')\n              );\n            }\n\n            // Update the contracts.json file:\n            // If a contract already exists on a chain, update its address; otherwise, add a new entry.\n            if (!deployedContracts[sourceChain.chainId]) {\n              deployedContracts[sourceChain.chainId] = {\n                networkName: sourceChain.description,\n                deployedAt: new Date().toISOString(),\n              };\n            }\n            deployedContracts[sourceChain.chainId].CrossChainSender =\n              senderAddress.toString();\n            deployedContracts[sourceChain.chainId].deployedAt =\n              new Date().toISOString();\n\n            if (!deployedContracts[targetChain.chainId]) {\n              deployedContracts[targetChain.chainId] = {\n                networkName: targetChain.description,\n                deployedAt: new Date().toISOString(),\n              };\n            }\n            deployedContracts[targetChain.chainId].CrossChainReceiver =\n              receiverAddress.toString();\n            deployedContracts[targetChain.chainId].deployedAt =\n              new Date().toISOString();\n\n            // Save the updated contracts.json file\n            fs.writeFileSync(\n              deployedContractsPath,\n              JSON.stringify(deployedContracts, null, 2)\n            );\n          } catch (error: any) {\n            if (error.code === 'INSUFFICIENT_FUNDS') {\n              console.error(\n                'Error: Insufficient funds for deployment. Please make sure your wallet has enough funds to cover the gas fees.'\n              );\n            } else {\n              console.error('An unexpected error occurred:', error.message);\n            }\n            process.exit(1);\n          }\n        }\n\n        main().catch((error) => {\n          console.error(error);\n          process.exit(1);\n        });\n        ```\n\n5. **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.\n\n    Create a `.env` file in the root of the project and add your private key:\n\n    ```bash\n    touch .env\n    ```\n\n    Inside `.env`, add your private key in the following format:\n\n    ```env\n    PRIVATE_KEY=INSERT_PRIVATE_KEY\n    ```\n    \n6. **Run the deployment script**:\n\n    1. Open a terminal and run the following command:\n\n        ```bash\n        npx ts-node script/deploy.ts\n        ```\n\n        This will execute the deployment script, deploying both contracts to the selected chains.\n\n    2. Check the deployment output:\n\n        - You will see the deployed contract addresses printed in the terminal if successful. The `contracts.json` file will be updated with these addresses.\n        - If you encounter an error, the script will provide feedback, such as insufficient funds for gas.\n\nIf you followed the logic provided in the full code above, your terminal output should look something like this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>npx ts-node deploy.ts</span>\n\t<span data-ty> > cross-chain-token-transfer@1.0.0 deploy</span>\n\t<span data-ty> > npx ts-node script/deploy.ts</span>\n\t<span data-ty> Select the SOURCE chain:</span>\n\t<span data-ty> 1: Avalanche testnet fuji</span>\n  <span data-ty> 2: Base Sepolia</span>\n  <span data-ty> </span>\n  <span data-ty> Enter the number for the SOURCE chain: 1</span>\n  <span data-ty> </span>\n  <span data-ty> Select the TARGET chain:</span>\n  <span data-ty> 1: Avalanche testnet fuji</span>\n  <span data-ty> 2: Base Sepolia</span>\n  <span data-ty> </span>\n  <span data-ty> Enter the number for the TARGET chain: 2</span>\n  <span data-ty> CrossChainSender Avalanche testnet fuji: 0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3</span>\n  <span data-ty> CrossChainReceiver Base Sepolia: 0xD720BFF42a0960cfF1118454A907a44dB358f2b1</span>\n  <span data-ty> </span>\n  <span data-ty> Registering CrossChainSender (0x1Cac52a183D02F9002fdb37b13eC2fAB950d44E3) as a valid sender in CrossChainReceiver (0xD720BFF42a0960cfF1118454A907a44dB358f2b1)...</span>\n  <span data-ty> </span>\n  <span data-ty> CrossChainSender registered as a valid sender on Base Sepolia</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 7, "depth": 2, "title": "Transfer Tokens Across Chains", "anchor": "transfer-tokens-across-chains", "start_char": 45346, "end_char": 45380, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## Transfer Tokens Across Chains"}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 8, "depth": 3, "title": "Quick Recap", "anchor": "quick-recap", "start_char": 45380, "end_char": 46048, "estimated_token_count": 125, "token_estimator": "heuristic-v1", "text": "### Quick Recap\n\nUp 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.\n\nIn 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."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 9, "depth": 3, "title": "Transfer Script", "anchor": "transfer-script", "start_char": 46048, "end_char": 62592, "estimated_token_count": 3040, "token_estimator": "heuristic-v1", "text": "### Transfer Script\n\n1. Set up the transfer script:\n\n    1. Create a new file named `transfer.ts` in the `/script` directory:\n\n        ```bash\n        touch script/transfer.ts\n        ```\n\n    2. Open the file. Start with the necessary imports, interfaces and configurations:\n\n        ```typescript\n        import { ethers } from 'ethers';\n        import * as fs from 'fs';\n        import * as path from 'path';\n        import * as dotenv from 'dotenv';\n        import readlineSync from 'readline-sync';\n\n        dotenv.config();\n\n        interface ChainConfig {\n          description: string;\n          chainId: number;\n          rpc: string;\n          tokenBridge: string;\n          wormholeRelayer: string;\n          wormhole: string;\n        }\n\n        interface DeployedContracts {\n          [chainId: number]: {\n            networkName: string;\n            CrossChainSender?: string;\n            CrossChainReceiver?: string;\n            deployedAt: string;\n          };\n        }\n        ```\n\n        These imports include the essential libraries for interacting with Ethereum, handling file paths, loading environment variables, and managing user input.\n\n    3. Load configuration and contracts:\n\n\n        ```typescript\n        function loadConfig(): ChainConfig[] {\n          const configPath = path.resolve(__dirname, '../deploy-config/config.json');\n          return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains;\n        }\n\n        function loadDeployedContracts(): DeployedContracts {\n          const contractsPath = path.resolve(\n            __dirname,\n            '../deploy-config/contracts.json'\n          );\n          if (\n            !fs.existsSync(contractsPath) ||\n            fs.readFileSync(contractsPath, 'utf8').trim() === ''\n          ) {\n            console.error(\n              'No contracts found. Please deploy contracts first before transferring tokens.'\n            );\n            process.exit(1);\n          }\n          return JSON.parse(fs.readFileSync(contractsPath, 'utf8'));\n        }\n        ```\n\n        These functions load the network and contract details that were saved during deployment.\n\n    4. Allow users to select source and target chains:\n\n        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.\n\n        ```typescript\n        function selectSourceChain(deployedContracts: DeployedContracts): {\n          chainId: number;\n          networkName: string;\n        } {\n          const sourceOptions = Object.entries(deployedContracts).filter(\n            ([, contracts]) => contracts.CrossChainSender\n          );\n\n          if (sourceOptions.length === 0) {\n            console.error('No source chains available with CrossChainSender deployed.');\n            process.exit(1);\n          }\n\n          console.log('\\nSelect the source chain:');\n          sourceOptions.forEach(([chainId, contracts], index) => {\n            console.log(`${index + 1}: ${contracts.networkName}`);\n          });\n\n          const selectedIndex =\n            readlineSync.questionInt(`\\nEnter the number for the source chain: `) - 1;\n          return {\n            chainId: Number(sourceOptions[selectedIndex][0]),\n            networkName: sourceOptions[selectedIndex][1].networkName,\n          };\n        }\n\n        function selectTargetChain(deployedContracts: DeployedContracts): {\n          chainId: number;\n          networkName: string;\n        } {\n          const targetOptions = Object.entries(deployedContracts).filter(\n            ([, contracts]) => contracts.CrossChainReceiver\n          );\n\n          if (targetOptions.length === 0) {\n            console.error(\n              'No target chains available with CrossChainReceiver deployed.'\n            );\n            process.exit(1);\n          }\n\n          console.log('\\nSelect the target chain:');\n          targetOptions.forEach(([chainId, contracts], index) => {\n            console.log(`${index + 1}: ${contracts.networkName}`);\n          });\n\n          const selectedIndex =\n            readlineSync.questionInt(`\\nEnter the number for the target chain: `) - 1;\n          return {\n            chainId: Number(targetOptions[selectedIndex][0]),\n            networkName: targetOptions[selectedIndex][1].networkName,\n          };\n        }\n        ```\n\n2. Implement the token transfer logic:\n\n    1. **Create the `main` function**: Add the token transfer logic, including the chain and contract details, wallet and provider for the source chain, and the `CrossChainSender` contract for interaction.\n    \n        ```typescript\n        async function main() {\n          const chains = loadConfig();\n          const deployedContracts = loadDeployedContracts();\n\n          // Select the source chain (only show chains with CrossChainSender deployed)\n          const { chainId: sourceChainId, networkName: sourceNetworkName } =\n            selectSourceChain(deployedContracts);\n          const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!;\n\n          // Select the target chain (only show chains with CrossChainReceiver deployed)\n          const { chainId: targetChainId, networkName: targetNetworkName } =\n            selectTargetChain(deployedContracts);\n          const targetChain = chains.find((chain) => chain.chainId === targetChainId)!;\n\n          // Set up providers and wallets\n          const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc);\n          const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider);\n\n          // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat)\n          const CrossChainSenderArtifact = JSON.parse(\n            fs.readFileSync(\n              path.resolve(\n                __dirname,\n                '../out/CrossChainSender.sol/CrossChainSender.json'\n              ),\n              'utf8'\n            )\n          );\n\n          const abi = CrossChainSenderArtifact.abi;\n\n          // Create the contract instance using the full ABI\n          const CrossChainSender = new ethers.Contract(\n            deployedContracts[sourceChainId].CrossChainSender!,\n            abi,\n            wallet\n          );\n        ```\n\n    2. **Ask the user for token transfer details**: 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.\n\n        ```typescript\n          const tokenAddress = readlineSync.question(\n            'Enter the token contract address: '\n          );\n          const recipientAddress = readlineSync.question(\n            'Enter the recipient address on the target chain: '\n          );\n\n          // Get the token contract\n          const tokenContractDecimals = new ethers.Contract(\n            tokenAddress,\n            [\n              'function decimals() view returns (uint8)',\n              'function approve(address spender, uint256 amount) public returns (bool)',\n            ],\n            wallet\n          );\n\n          // Fetch the token decimals\n          const decimals = await tokenContractDecimals.decimals();\n\n          // Get the amount from the user, then parse it according to the token's decimals\n          const amount = ethers.parseUnits(\n            readlineSync.question('Enter the amount of tokens to transfer: '),\n            decimals\n          );\n        ```\n\n        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.\n\n    3. **Initiate the transfer**: Finally, initiate the cross-chain transfer and log the details.\n\n        ```typescript\n          const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId);\n\n          // Approve the CrossChainSender contract to transfer tokens on behalf of the user\n          const tokenContract = new ethers.Contract(\n            tokenAddress,\n            ['function approve(address spender, uint256 amount) public returns (bool)'],\n            wallet\n          );\n\n          const approveTx = await tokenContract.approve(\n            deployedContracts[sourceChainId].CrossChainSender!,\n            amount\n          );\n          await approveTx.wait();\n          console.log(`Approved tokens for cross-chain transfer.`);\n\n          // Initiate the cross-chain transfer\n          const transferTx = await CrossChainSender.sendCrossChainDeposit(\n            targetChainId,\n            deployedContracts[targetChainId].CrossChainReceiver!,\n            recipientAddress,\n            amount,\n            tokenAddress,\n            { value: cost } // Attach the necessary fee for cross-chain transfer\n          );\n          await transferTx.wait();\n          console.log(\n            `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}`\n          );\n        }\n        ```\n\n        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.\n\n    4. **Finalize the script**: Call the `main` function and handle any errors that may occur during the token transfer process.\n\n        ```typescript\n        main().catch((error) => {\n          console.error(error);\n          process.exit(1);\n        });\n        ```\n\nYou can find the full code for the `transfer.ts` file below:\n\n??? code \"transfer.ts\"\n\n    ```solidity\n    import { ethers } from 'ethers';\n    import * as fs from 'fs';\n    import * as path from 'path';\n    import * as dotenv from 'dotenv';\n    import readlineSync from 'readline-sync';\n\n    dotenv.config();\n\n    interface ChainConfig {\n      description: string;\n      chainId: number;\n      rpc: string;\n      tokenBridge: string;\n      wormholeRelayer: string;\n      wormhole: string;\n    }\n\n    interface DeployedContracts {\n      [chainId: number]: {\n        networkName: string;\n        CrossChainSender?: string;\n        CrossChainReceiver?: string;\n        deployedAt: string;\n      };\n    }\n\n    function loadConfig(): ChainConfig[] {\n      const configPath = path.resolve(__dirname, '../deploy-config/config.json');\n      return JSON.parse(fs.readFileSync(configPath, 'utf8')).chains;\n    }\n\n    function loadDeployedContracts(): DeployedContracts {\n      const contractsPath = path.resolve(\n        __dirname,\n        '../deploy-config/contracts.json'\n      );\n      if (\n        !fs.existsSync(contractsPath) ||\n        fs.readFileSync(contractsPath, 'utf8').trim() === ''\n      ) {\n        console.error(\n          'No contracts found. Please deploy contracts first before transferring tokens.'\n        );\n        process.exit(1);\n      }\n      return JSON.parse(fs.readFileSync(contractsPath, 'utf8'));\n    }\n\n    function selectSourceChain(deployedContracts: DeployedContracts): {\n      chainId: number;\n      networkName: string;\n    } {\n      const sourceOptions = Object.entries(deployedContracts).filter(\n        ([, contracts]) => contracts.CrossChainSender\n      );\n\n      if (sourceOptions.length === 0) {\n        console.error('No source chains available with CrossChainSender deployed.');\n        process.exit(1);\n      }\n\n      console.log('\\nSelect the source chain:');\n      sourceOptions.forEach(([chainId, contracts], index) => {\n        console.log(`${index + 1}: ${contracts.networkName}`);\n      });\n\n      const selectedIndex =\n        readlineSync.questionInt(`\\nEnter the number for the source chain: `) - 1;\n      return {\n        chainId: Number(sourceOptions[selectedIndex][0]),\n        networkName: sourceOptions[selectedIndex][1].networkName,\n      };\n    }\n\n    function selectTargetChain(deployedContracts: DeployedContracts): {\n      chainId: number;\n      networkName: string;\n    } {\n      const targetOptions = Object.entries(deployedContracts).filter(\n        ([, contracts]) => contracts.CrossChainReceiver\n      );\n\n      if (targetOptions.length === 0) {\n        console.error(\n          'No target chains available with CrossChainReceiver deployed.'\n        );\n        process.exit(1);\n      }\n\n      console.log('\\nSelect the target chain:');\n      targetOptions.forEach(([chainId, contracts], index) => {\n        console.log(`${index + 1}: ${contracts.networkName}`);\n      });\n\n      const selectedIndex =\n        readlineSync.questionInt(`\\nEnter the number for the target chain: `) - 1;\n      return {\n        chainId: Number(targetOptions[selectedIndex][0]),\n        networkName: targetOptions[selectedIndex][1].networkName,\n      };\n    }\n\n    async function main() {\n      const chains = loadConfig();\n      const deployedContracts = loadDeployedContracts();\n\n      // Select the source chain (only show chains with CrossChainSender deployed)\n      const { chainId: sourceChainId, networkName: sourceNetworkName } =\n        selectSourceChain(deployedContracts);\n      const sourceChain = chains.find((chain) => chain.chainId === sourceChainId)!;\n\n      // Select the target chain (only show chains with CrossChainReceiver deployed)\n      const { chainId: targetChainId, networkName: targetNetworkName } =\n        selectTargetChain(deployedContracts);\n      const targetChain = chains.find((chain) => chain.chainId === targetChainId)!;\n\n      // Set up providers and wallets\n      const sourceProvider = new ethers.JsonRpcProvider(sourceChain.rpc);\n      const wallet = new ethers.Wallet(process.env.PRIVATE_KEY!, sourceProvider);\n\n      // Load the ABI from the JSON file (use the compiled ABI from Forge or Hardhat)\n      const CrossChainSenderArtifact = JSON.parse(\n        fs.readFileSync(\n          path.resolve(\n            __dirname,\n            '../out/CrossChainSender.sol/CrossChainSender.json'\n          ),\n          'utf8'\n        )\n      );\n\n      const abi = CrossChainSenderArtifact.abi;\n\n      // Create the contract instance using the full ABI\n      const CrossChainSender = new ethers.Contract(\n        deployedContracts[sourceChainId].CrossChainSender!,\n        abi,\n        wallet\n      );\n\n      // Display the selected chains\n      console.log(\n        `\\nInitiating transfer from ${sourceNetworkName} to ${targetNetworkName}.`\n      );\n\n      // Ask the user for token transfer details\n      const tokenAddress = readlineSync.question(\n        'Enter the token contract address: '\n      );\n      const recipientAddress = readlineSync.question(\n        'Enter the recipient address on the target chain: '\n      );\n\n      // Get the token contract\n      const tokenContractDecimals = new ethers.Contract(\n        tokenAddress,\n        [\n          'function decimals() view returns (uint8)',\n          'function approve(address spender, uint256 amount) public returns (bool)',\n        ],\n        wallet\n      );\n\n      // Fetch the token decimals\n      const decimals = await tokenContractDecimals.decimals();\n\n      // Get the amount from the user, then parse it according to the token's decimals\n      const amount = ethers.parseUnits(\n        readlineSync.question('Enter the amount of tokens to transfer: '),\n        decimals\n      );\n\n      // Calculate the cross-chain transfer cost\n      const cost = await CrossChainSender.quoteCrossChainDeposit(targetChainId);\n\n      // Approve the CrossChainSender contract to transfer tokens on behalf of the user\n      const tokenContract = new ethers.Contract(\n        tokenAddress,\n        ['function approve(address spender, uint256 amount) public returns (bool)'],\n        wallet\n      );\n\n      const approveTx = await tokenContract.approve(\n        deployedContracts[sourceChainId].CrossChainSender!,\n        amount\n      );\n      await approveTx.wait();\n      console.log(`Approved tokens for cross-chain transfer.`);\n\n      // Initiate the cross-chain transfer\n      const transferTx = await CrossChainSender.sendCrossChainDeposit(\n        targetChainId,\n        deployedContracts[targetChainId].CrossChainReceiver!,\n        recipientAddress,\n        amount,\n        tokenAddress,\n        { value: cost } // Attach the necessary fee for cross-chain transfer\n      );\n      await transferTx.wait();\n      console.log(\n        `Transfer initiated from ${sourceNetworkName} to ${targetNetworkName}. Transaction Hash: ${transferTx.hash}`\n      );\n    }\n\n    main().catch((error) => {\n      console.error(error);\n      process.exit(1);\n    });\n    ```"}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 10, "depth": 3, "title": "Transfer Tokens", "anchor": "transfer-tokens", "start_char": 62592, "end_char": 65674, "estimated_token_count": 743, "token_estimator": "heuristic-v1", "text": "### Transfer Tokens\n\nNow that your transfer script is ready, it’s time to execute it and perform a cross-chain token transfer.\n\n1. **Run the transfer script**: Open your terminal and run the transfer script.\n\n    ```bash\n    npx ts-node script/transfer.ts\n    ```\n\n    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.\n\n2. **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.\n\n3. **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.\n\nYou can verify the transaction on the [Wormhole Explorer](https://wormholescan.io/){target=\\_blank} using the link provided in the terminal output. This explorer also offers the option to add the transferred token to your MetaMask wallet automatically.\n\nIf you followed the logic provided in the `transfer.ts` file above, your terminal output should look something like this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>npx ts-node transfer.ts</span>\n\t<span data-ty> > cross-chain-token-transfer@1.0.0 transfer</span>\n\t<span data-ty> > npx ts-node script/transfer.ts</span>\n  <span data-ty> </span>\n\t<span data-ty> Select the source chain:</span>\n\t<span data-ty> 1: Avalanche testnet fuji</span>\n  <span data-ty> 2: Base Sepolia</span>\n  <span data-ty> </span>\n  <span data-ty> Enter the number for the SOURCE chain: 1</span>\n  <span data-ty> </span>\n  <span data-ty> Select the target chain:</span>\n  <span data-ty> 1: Avalanche testnet fuji</span>\n  <span data-ty> 2: Base Sepolia</span>\n  <span data-ty> </span>\n  <span data-ty> Enter the number for the TARGET chain: 2</span>\n  <span data-ty> </span>\n  <span data-ty> Initiating transfer from Avalanche testnet fuji to Base Sepolia</span>\n  <span data-ty> Enter the token contract address: 0x5425890298aed601595a70ab815c96711a31bc65</span>\n  <span data-ty> Enter the recipient address on the target chain: INSERT_YOUR_WALLET_ADDRESS</span>\n  <span data-ty> Enter the amount of tokens to transfer: 2</span>\n  <span data-ty> Approved tokens for cross-chain transfer.</span>\n  <span data-ty> Transfer initiated from Avalanche testnet fuji to Base Sepolia. Transaction Hash: 0x4a923975d955c1f226a1c2f61a1a0fa1ab1a9e229dc29ceaeadf8ef40acd071f</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>\n!!! note\n    In this example, we demonstrated a token transfer from the Avalanche Fuji Testnet to the Base Sepolia 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."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 11, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 65674, "end_char": 66116, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "## Resources\n\nIf 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."}
{"page_id": "products-messaging-tutorials-cross-chain-token-contracts", "page_title": "Cross-Chain Token Transfers", "index": 12, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 66116, "end_char": 66652, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nCongratulations! You've successfully built and deployed a cross-chain token transfer system using Solidity and the Wormhole protocol. You've learned how to:\n\n - Set up a new Solidity project using Foundry.\n - Develop smart contracts to send and receive tokens across chains.\n - Write deployment scripts to manage and deploy contracts on different networks.\n\nLooking for more? Check out the [Wormhole Tutorial Demo repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank} for additional examples."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1458, "end_char": 1752, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n - [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 1, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 1752, "end_char": 7263, "estimated_token_count": 1290, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nIn this section, you will create the directory, initialize a Node.js project, install dependencies, and configure TypeScript.\n\n1. **Create the project**: Set up the directory and navigate into it.\n\n    ```bash\n    mkdir wormhole-scan-api-demo\n    cd wormhole-scan-api-demo\n    ```\n\n2. **Initialize a Node.js project**: Generate a `package.json` file.\n\n    ```bash\n    npm init -y\n    ```\n\n3. **Set up TypeScript**: Create a `tsconfig.json` file.\n\n    ```bash\n    touch tsconfig.json\n    ```\n\n    Then, add the following configuration:\n\n    ```json title=\"tsconfig.json\"\n    {\n        \"compilerOptions\": {\n            \"target\": \"es2016\",\n            \"module\": \"commonjs\",\n            \"esModuleInterop\": true,\n            \"forceConsistentCasingInFileNames\": true,\n            \"strict\": true,\n            \"skipLibCheck\": true\n        }\n    }\n    ```\n\n4. **Install dependencies**: Add the required packages. This tutorial uses the SDK version `4.14.1`.\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1 axios web3 tsx @types/node\n    ```\n\n     - **`@wormhole-foundation/sdk`**: Handles VAAs and cross-chain interactions.  \n     - **`axios`**: Makes HTTP requests to the Wormholescan API.  \n     - **`web3`**: Interacts with Ethereum transactions and contracts.  \n     - **`tsx`**: Executes TypeScript files without compilation.  \n     - **`@types/node`**: Provides Node.js type definitions. \n\n5. **Create the project structure**: Set up the required directories and files.\n\n    ```bash\n    mkdir -p src/config && touch src/config/constants.ts src/config/layouts.ts\n    mkdir -p src/helpers && touch src/helpers/vaaHelper.ts\n    mkdir -p src/scripts && touch scripts/replaceSignatures.ts\n    ```\n\n     - **`src/config/*`**: Stores public configuration variables and layouts for serializing and deserializing data structures.\n     - **`src/helpers/*`**: Contains utility functions.\n     - **`src/scripts/*`**: Contains scripts for fetching and replacing signatures.\n\n6. **Set variables**: Define key constants in `src/config/constants.ts`.\n\n    ```bash title=\"src/config/constants.ts\"\n    export const RPC = 'https://ethereum-rpc.publicnode.com';\n\n    export const ETH_CORE =\n      '0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B'.toLowerCase();\n\n    export const WORMHOLESCAN_API = 'https://api.wormholescan.io/v1';\n\n    export const LOG_MESSAGE_PUBLISHED_TOPIC =\n      '0x6eb224fb001ed210e379b335e35efe88672a8ce935d981a6896b27ffdf52a3b2';\n\n    export const TXS = [\n      '0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367',\n      '0x3c989a6bb40dcd4719453fbe7bbac420f23962c900ae75793124fc9cc614368c',\n    ];\n    ```\n\n     - **`RPC`**: Endpoint for interacting with an Ethereum RPC node.\n     - **`ETH_CORE`**: [Wormhole's Core Contract address on Ethereum](/docs/products/reference/contract-addresses/#core-contracts){target=\\_blank} responsible for verifying VAAs.\n     - **`WORMHOLESCAN_API`**: Base URL for querying the Wormholescan API to fetch VAA data and Guardian sets.\n     - **`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.\n     - **`TXS`**: List of example transaction hashes that will be used for testing.\n\n7. **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.\n\n    ```typescript title=\"src/config/layouts.ts\"\n    export const PARSE_AND_VERIFY_VM_ABI = {\n      inputs: [{ internalType: 'bytes', name: 'encodedVM', type: 'bytes' }],\n      name: 'parseAndVerifyVM',\n      outputs: [\n        {\n          components: [\n            { internalType: 'uint8', name: 'version', type: 'uint8' },\n            { internalType: 'uint32', name: 'timestamp', type: 'uint32' },\n            { internalType: 'uint32', name: 'nonce', type: 'uint32' },\n            { internalType: 'uint16', name: 'emitterChainId', type: 'uint16' },\n            { internalType: 'bytes32', name: 'emitterAddress', type: 'bytes32' },\n            { internalType: 'uint64', name: 'sequence', type: 'uint64' },\n            { internalType: 'uint8', name: 'consistencyLevel', type: 'uint8' },\n            { internalType: 'bytes', name: 'payload', type: 'bytes' },\n            { internalType: 'uint32', name: 'guardianSetIndex', type: 'uint32' },\n            {\n              components: [\n                { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n                { internalType: 'bytes32', name: 's', type: 'bytes32' },\n                { internalType: 'uint8', name: 'v', type: 'uint8' },\n                { internalType: 'uint8', name: 'guardianIndex', type: 'uint8' },\n              ],\n              internalType: 'struct Structs.Signature[]',\n              name: 'signatures',\n              type: 'tuple[]',\n            },\n            { internalType: 'bytes32', name: 'hash', type: 'bytes32' },\n          ],\n          internalType: 'struct Structs.VM',\n          name: 'vm',\n          type: 'tuple',\n        },\n        { internalType: 'bool', name: 'valid', type: 'bool' },\n        { internalType: 'string', name: 'reason', type: 'string' },\n      ],\n      stateMutability: 'view',\n      type: 'function',\n    };\n    ```"}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 2, "depth": 2, "title": "Create VAA Handling Functions", "anchor": "create-vaa-handling-functions", "start_char": 7263, "end_char": 7939, "estimated_token_count": 150, "token_estimator": "heuristic-v1", "text": "## Create VAA Handling Functions\n\nIn 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.\n\nTo get started, import the necessary dependencies:\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\nimport axios from 'axios';\nimport { eth } from 'web3';\nimport {\n  deserialize,\n  serialize,\n  VAA,\n  Signature,\n} from '@wormhole-foundation/sdk';\nimport {\n  RPC,\n  ETH_CORE,\n  LOG_MESSAGE_PUBLISHED_TOPIC,\n  WORMHOLESCAN_API,\n} from '../config/constants';\nimport { PARSE_AND_VERIFY_VM_ABI } from '../config/layouts';\n```"}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 3, "depth": 3, "title": "Fetch a VAA ID from a Transaction", "anchor": "fetch-a-vaa-id-from-a-transaction", "start_char": 7939, "end_char": 11900, "estimated_token_count": 961, "token_estimator": "heuristic-v1", "text": "### Fetch a VAA ID from a Transaction\n\nTo 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.\nThe VAA ID is structured as follows:\n\n```bash\nchain/emitter/sequence\n```\n\n - **`chain`**: The [Wormhole chain ID](/docs/products/reference/chain-ids/){target=\\_blank} (Ethereum is 2).\n - **`emitter`**: The contract address that emitted the VAA.\n - **`sequence`**: A unique identifier for the event.\n\nWe must assemble the ID correctly since this is the format the Wormholescan API expects when querying VAAs.\n\nFollow the below steps to process the transaction logs and construct the VAA ID:\n\n1. **Get the transaction receipt**: Iterate over the array of transaction hashes and fetch the receipt to access its logs.\n\n2. **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.\n\n3. **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.\n\n4. **Construct the VAA ID**: Format the extracted data in `chain/emitter/sequence` format.\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\nexport async function fetchVaaId(txHashes: string[]): Promise<string[]> {\n  const vaaIds: string[] = [];\n\n  for (const tx of txHashes) {\n    try {\n      const result = (\n        await axios.post(RPC, {\n          jsonrpc: '2.0',\n          id: 1,\n          method: 'eth_getTransactionReceipt',\n          params: [tx],\n        })\n      ).data.result;\n\n      if (!result)\n        throw new Error(`Unable to fetch transaction receipt for ${tx}`);\n\n      for (const log of result.logs) {\n        if (\n          log.address === ETH_CORE &&\n          log.topics?.[0] === LOG_MESSAGE_PUBLISHED_TOPIC\n        ) {\n          const emitter = log.topics[1].substring(2);\n          const seq = BigInt(log.data.substring(0, 66)).toString();\n          vaaIds.push(`2/${emitter}/${seq}`);\n        }\n      }\n    } catch (error) {\n      console.error(`Error processing ${tx}:`, error);\n    }\n  }\n\n  return vaaIds;\n}\n```\n\n???- code \"Try it out: VAA ID retrieval\"\n    If you want to try out the function before moving forward, create a test file inside the `test` directory: \n\n    1. Create the directory and file:\n\n        ```bash\n        mkdir -p test\n        touch test/fetchVaaId.run.ts\n        ```  \n\n    2. Add the function call:  \n\n        ```typescript title=\"test/fetchVaaId.run.ts\"\n        import { fetchVaaId } from '../src/helpers/vaaHelper';\n        import { TXS } from '../src/config/constants';\n\n        const testFetchVaaId = async () => {\n          for (const tx of TXS) {\n            const vaaIds = await fetchVaaId([tx]);\n\n            if (vaaIds.length > 0) {\n              console.log(`Transaction: ${tx}`);\n              vaaIds.forEach((vaaId) => console.log(`VAA ID: ${vaaId}`));\n            } else {\n              console.log(`No VAA ID found for transaction: ${tx}`);\n            }\n          }\n        };\n\n        testFetchVaaId();\n        ```  \n\n    3. Run the script:  \n\n        ```bash\n        npx tsx test/fetchVaaId.run.ts\n        ```  \n\n        If successful, the output will be:\n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/fetchVaaId.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty\n        \t\t>Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367</span\n        \t>\n        \t<span data-ty\n        \t\t>VAA ID: 2/0000000000000000000000003ee18b2214aff97000d974cf647e7c347e8fa585/164170</span\n        \t>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n        If no VAA ID is found, the script will log an error message."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 4, "depth": 3, "title": "Fetch the Full VAA", "anchor": "fetch-the-full-vaa", "start_char": 11900, "end_char": 14608, "estimated_token_count": 639, "token_estimator": "heuristic-v1", "text": "### Fetch the Full VAA\n\nNow 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.\n\nOpen `src/helpers/vaaHelper.ts` and create the `fetchVaa()` function to iterate through VAA IDs and extract the `vaaBytes` payload.\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\nexport async function fetchVaa(\n  vaaIds: string[]\n): Promise<{ id: string; vaaBytes: string }[]> {\n  const results: { id: string; vaaBytes: string }[] = [];\n\n  for (const id of vaaIds) {\n    try {\n      const response = await axios.get(`${WORMHOLESCAN_API}/signed_vaa/${id}`);\n      const vaaBytes = response.data.vaaBytes;\n      results.push({ id, vaaBytes });\n    } catch (error) {\n      console.error(`Error fetching VAA for ${id}:`, error);\n    }\n  }\n  return results;\n}\n```\n\n???- code \"Try it out: VAA retrieval\"\n    If you want to try the function before moving forward, create a script inside the `test` directory  \n\n    1. Create the script file:\n\n        ```bash\n        touch test/fetchVaa.run.ts\n        ```\n\n    2. Add the function call:\n\n        ```typescript title=\"test/fetchVaa.run.ts\"\n        import { fetchVaaId, fetchVaa } from '../src/helpers/vaaHelper';\n        import { TXS } from '../src/config/constants';\n\n        const testFetchVaa = async () => {\n          for (const tx of TXS) {\n            const vaaIds = await fetchVaaId([tx]);\n\n            if (vaaIds.length === 0) {\n              console.log(`No VAA ID found for transaction: ${tx}`);\n              continue;\n            }\n\n            for (const vaaId of vaaIds) {\n              const vaaBytes = await fetchVaa([vaaId]);\n\n              console.log(\n                `Transaction: ${tx}\\nVAA ID: ${vaaId}\\nVAA Bytes: ${\n                  vaaBytes.length > 0 ? vaaBytes[0].vaaBytes : 'Not found'\n                }`\n              );\n            }\n          }\n        };\n\n        testFetchVaa();\n        ```\n\n    3. Run the script:\n\n        ```bash\n        npx tsx test/fetchVaa.run.ts\n        ```\n\n        If successful, the output will be:\n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/fetchVaa.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty\n        \t\t>Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367</span\n        \t>\n        \t<span data-ty\n        \t\t>VAA Bytes: AQAAAAMNANQSwD/HRPcKp7Yxypl1ON8dZeMBzgYJrd2KYz6l9Tq9K9fj72fYJgkMeMaB9h...</span\n        \t>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n        If no VAA is found, the script will log an error message."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 5, "depth": 3, "title": "Validate VAA Signatures", "anchor": "validate-vaa-signatures", "start_char": 14608, "end_char": 18935, "estimated_token_count": 1010, "token_estimator": "heuristic-v1", "text": "### Validate VAA Signatures\n\nNow, 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.\n\nOpen `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.  \n\nFollow these steps to implement the function:  \n\n1. **Prepare the VAA for verification**: Construct the VAA payload in a format that can be sent to the Wormhole Core contract.\n\n2. **Send an `eth_call` request**: Submit the VAA to an Ethereum RPC node, calling the `parseAndVerifyVM` function on the Wormhole Core contract.\n\n3. **Decode the response**: Check whether the VAA is valid. If it contains outdated signatures, further action will be required to replace them.\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\nexport async function checkVaaValidity(vaaBytes: string) {\n  try {\n    const vaa = Buffer.from(vaaBytes, 'base64');\n    vaa[4] = 4; // Set guardian set index to 4\n\n    const result = (\n      await axios.post(RPC, {\n        jsonrpc: '2.0',\n        id: 1,\n        method: 'eth_call',\n        params: [\n          {\n            from: null,\n            to: ETH_CORE,\n            data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [\n              `0x${vaa.toString('hex')}`,\n            ]),\n          },\n          'latest',\n        ],\n      })\n    ).data.result;\n\n    const decoded = eth.abi.decodeParameters(\n      PARSE_AND_VERIFY_VM_ABI.outputs,\n      result\n    );\n    console.log(\n      `${decoded.valid ? '✅' : '❌'} VAA Valid: ${decoded.valid}${\n        decoded.valid ? '' : `, Reason: ${decoded.reason}`\n      }`\n    );\n\n    return { valid: decoded.valid, reason: decoded.reason };\n  } catch (error) {\n    console.error(`Error checking VAA validity:`, error);\n    return { valid: false, reason: 'RPC error' };\n  }\n}\n```\n\n???- code \"Try it out: VAA Validity\"\n    If you want to try the function before moving forward, create a script inside the `test` directory\n\n    1. Create the script file:\n\n        ```bash\n        touch test/checkVaaValidity.run.ts\n        ```\n\n    2. Add the function call:\n\n        ```typescript title=\"test/checkVaaValidity.run.ts\"\n        import {\n          fetchVaaId,\n          fetchVaa,\n          checkVaaValidity,\n        } from '../src/helpers/vaaHelper';\n        import { TXS } from '../src/config/constants';\n\n        const testCheckVaaValidity = async () => {\n          for (const tx of TXS) {\n            const vaaIds = await fetchVaaId([tx]);\n\n            if (vaaIds.length === 0) {\n              console.log(`No VAA ID found for transaction: ${tx}`);\n              continue;\n            }\n\n            for (const vaaId of vaaIds) {\n              const vaaData = await fetchVaa([vaaId]);\n\n              if (vaaData.length === 0 || !vaaData[0].vaaBytes) {\n                console.log(`VAA not found for ID: ${vaaId}`);\n                continue;\n              }\n\n              const result = await checkVaaValidity(vaaData[0].vaaBytes);\n              console.log(\n                `Transaction: ${tx}\\nVAA ID: ${vaaId}\\nVAA Validity:`,\n                result\n              );\n            }\n          }\n        };\n\n        testCheckVaaValidity();\n        ```\n\n    3. Run the script:\n\n        ```bash\n        npx tsx test/checkVaaValidity.run.ts\n        ```\n\n        If the VAA is valid, the output will be:  \n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/checkVaaValidity.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty>✅ VAA Valid: true</span>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n        If invalid, the output will include the reason:\n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/checkVaaValidity.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty>❌ VAA Valid: false, Reason: VM signature invalid</span>\n        \t<span data-ty\n        \t\t>Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367</span\n        \t>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>"}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 6, "depth": 3, "title": "Fetch Observations (VAA Signatures)", "anchor": "fetch-observations-vaa-signatures", "start_char": 18935, "end_char": 22556, "estimated_token_count": 709, "token_estimator": "heuristic-v1", "text": "### Fetch Observations (VAA Signatures)\n\nBefore 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.\n\nInside `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.\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\nexport async function fetchObservations(vaaId: string) {\n  try {\n    console.log(`Fetching observations`);\n\n    const response = await axios.get(\n      `https://api.wormholescan.io/api/v1/observations/${vaaId}`\n    );\n\n    return response.data.map((obs: any) => ({\n      guardianAddr: obs.guardianAddr.toLowerCase(),\n      signature: obs.signature,\n    }));\n  } catch (error) {\n    console.error(`Error fetching observations:`, error);\n    return [];\n  }\n}\n```\n\n???- code \"Try it out: Fetch Observations\"\n    If you want to try the function before moving forward, create a script inside the `test` directory\n\n    1. Create the script file:\n\n        ```bash\n        touch test/fetchObservations.run.ts\n        ```\n\n    2. Add the function call:\n\n        ```typescript title=\"test/fetchObservations.run.ts\"\n        import { fetchVaaId, fetchObservations } from '../src/helpers/vaaHelper';\n        import { TXS } from '../src/config/constants';\n\n        const testFetchObservations = async () => {\n          for (const tx of TXS) {\n            const vaaIds = await fetchVaaId([tx]);\n\n            if (vaaIds.length === 0) {\n              console.log(`No VAA ID found for transaction: ${tx}`);\n              continue;\n            }\n\n            for (const vaaId of vaaIds) {\n              const observations = await fetchObservations(vaaId);\n\n              if (observations.length === 0) {\n                console.log(`No observations found for VAA ID: ${vaaId}`);\n                continue;\n              }\n\n              console.log(\n                `Transaction: ${tx}\\nVAA ID: ${vaaId}\\nObservations:`,\n                observations\n              );\n            }\n          }\n        };\n\n        testFetchObservations();\n        ```\n\n    3. Run the script:\n\n        ```bash\n        npx tsx test/fetchObservations.run.ts\n        ```\n\n        If successful, the output will be:\n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/fetchObservations.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty>Fetching observations</span>\n        \t<span data-ty\n        \t\t>Transaction: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367</span\n        \t>\n        \t<span data-ty\n        \t\t>Observations: [ { guardianAddr: '0xda798f6896a3331f64b48c12d1d57fd9cbe70811', signature:\n        \t\t'ZGFlMDYyOGNjZjFjMmE0ZTk5YzE2OThhZjAzMDM4NzZlYTM1OWMxMzczNDA3YzdlMDMxZTkyNzk0ODkwYjRiYjRiOWFmNzM3NjRiMzIyOTE0ZTQwYzNlMjllMWEzNmM2NTc3ZDc5ZTdhNTM2MzA5YjA4YjExZjE3YzE3MDViNWIwMQ=='\n        \t\t}, { guardianAddr: '0x74a3bf913953d695260d88bc1aa25a4eee363ef0', signature:\n        \t\t'MzAyOTU4OGU4MWU0ODc0OTAwNDU3N2EzMGZlM2UxMDJjOWYwMjM0NWVhY2VmZWQ0ZGJlNTFkNmI3YzRhZmQ5ZTNiODFjNTg3MDNmYzUzNmJiYWFiZjNlODc1YTY3OTQwMGE4MmE3ZjZhNGYzOGY3YmRmNDNhM2VhNGQyNWNlNGMwMA=='\n        \t\t},</span\n        \t>\n        \t<span data-ty>...]</span>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n        If no observations are found, the script will log an error message."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 7, "depth": 3, "title": "Fetch the Latest Guardian Set", "anchor": "fetch-the-latest-guardian-set", "start_char": 22556, "end_char": 25175, "estimated_token_count": 569, "token_estimator": "heuristic-v1", "text": "### Fetch the Latest Guardian Set\n\nNow 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.\n\nCreate the `fetchGuardianSet()` function inside `src/helpers/vaaHelper.ts` to fetch the latest Guardian set.\n\n```typescript title=\"src/helpers/vaaHelper.ts\"\n\nexport async function fetchGuardianSet() {\n  try {\n    console.log('Fetching current guardian set');\n\n    const response = await axios.get(`${WORMHOLESCAN_API}/guardianset/current`);\n    const guardians = response.data.guardianSet.addresses.map((addr: string) =>\n      addr.toLowerCase()\n    );\n    const guardianSet = response.data.guardianSet.index;\n\n    return [guardians, guardianSet];\n  } catch (error) {\n    console.error('Error fetching guardian set:', error);\n    return [];\n  }\n}\n```\n\n???- code \"Try it out: Fetch Guardian Set\"\n    If you want to try the function before moving forward, create a script inside the `test` directory\n\n    1. Create the script file:\n\n        ```bash\n        touch test/fetchGuardianSet.run.ts\n        ```\n\n    2. Add the function call:\n\n        ```typescript title=\"test/fetchGuardianSet.run.ts\"\n        import { fetchGuardianSet } from '../src/helpers/vaaHelper';\n\n        const testFetchGuardianSet = async () => {\n          const [guardians, guardianSetIndex] = await fetchGuardianSet();\n\n          console.log('Current Guardian Set Index:', guardianSetIndex);\n          console.log('Guardian Addresses:', guardians);\n        };\n\n        testFetchGuardianSet();\n        ```\n\n    3. Run the script:\n\n        ```bash\n        npx tsx test/fetchGuardianSet.run.ts\n        ```\n\n        If successful, the output will be:\n\n        <div id=\"termynal\" data-termynal>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx test/fetchGuardianSet.run.ts</span>\n        \t<span data-ty> </span>\n        \t<span data-ty>Fetching current guardian set</span>\n        \t<span data-ty>Current Guardian Set Index: 4</span>\n            <span data-ty>Guardian Addresses: [\n                '0x5893b5a76c3f739645648885bdccc06cd70a3cd3',\n                '0xff6cb952589bde862c25ef4392132fb9d4a42157',\n                '0x114de8460193bdf3a2fcf81f86a09765f4762fd1',\n                '0x107a0086b32d7a0977926a205131d8731d39cbeb',\n            </span>\n            <span data-ty>...]</span>\n        \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n        If an error occurs while fetching the Guardian set, a `500` status error will be logged."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 8, "depth": 3, "title": "Replace Outdated Signatures", "anchor": "replace-outdated-signatures", "start_char": 25175, "end_char": 37496, "estimated_token_count": 2470, "token_estimator": "heuristic-v1", "text": "### Replace Outdated Signatures\n\nWith the full VAA, Guardian signatures, and the latest Guardian set, we can now update outdated signatures while maintaining the required signature count.\n\n1. **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.\n\n    ```typescript title=\"src/helpers/vaaHelper.ts\"\n    export async function replaceSignatures(\n      vaa: string | Uint8Array<ArrayBufferLike>,\n      observations: { guardianAddr: string; signature: string }[],\n      currentGuardians: string[],\n      guardianSetIndex: number\n    ) {\n      console.log('Replacing Signatures...');\n\n      try {\n        // Add logic in the following steps here\n      } catch (error) {\n        console.error('Unexpected error in replaceSignatures:', error);\n      }\n    }\n    ```\n\n     - **`vaa`**: Original VAA bytes.\n     - **`observations`**: Observed signatures from the network.\n     - **`currentGuardians`**: Latest Guardian set.\n     - **`guardianSetIndex`**: Current Guardian set index.\n\n2. **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.\n\n    ```typescript\n        if (!vaa) throw new Error('VAA is undefined or empty.');\n        if (currentGuardians.length === 0)\n          throw new Error('Guardian set is empty.');\n        if (observations.length === 0) throw new Error('No observations provided.');\n    ```\n\n3. **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.\n\n    ```typescript\n        const validSigs = observations.filter((sig) =>\n          currentGuardians.includes(sig.guardianAddr)\n        );\n\n        if (validSigs.length === 0)\n          throw new Error('No valid signatures found. Cannot proceed.');\n    ```\n\n4. **Convert valid signatures**: Ensure signatures are correctly formatted for verification. Convert hex-encoded signatures if necessary and extract their components.\n\n    ```typescript\n        const formattedSigs = validSigs\n          .map((sig) => {\n            try {\n              const sigBuffer = Buffer.from(sig.signature, 'base64');\n              // If it's 130 bytes, it's hex-encoded and needs conversion\n              const sigBuffer1 =\n                sigBuffer.length === 130\n                  ? Buffer.from(sigBuffer.toString(), 'hex')\n                  : sigBuffer;\n\n              const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex'));\n              const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex'));\n              const vRaw = sigBuffer1[64];\n              const v = vRaw < 27 ? vRaw : vRaw - 27;\n\n              return {\n                guardianIndex: currentGuardians.indexOf(sig.guardianAddr),\n                signature: new Signature(r, s, v),\n              };\n            } catch (error) {\n              console.error(\n                `Failed to process signature for guardian: ${sig.guardianAddr}`,\n                error\n              );\n              return null;\n            }\n          })\n          .filter(\n            (sig): sig is { guardianIndex: number; signature: Signature } =>\n              sig !== null\n          ); // Remove null values\n    ```\n\n5. **Deserialize the VAA**: Convert the raw VAA data into a structured format for further processing.\n\n    ```typescript\n        let parsedVaa: VAA<'Uint8Array'>;\n        try {\n          parsedVaa = deserialize('Uint8Array', vaa);\n        } catch (error) {\n          throw new Error(`Error deserializing VAA: ${error}`);\n        }\n    ```\n\n6. **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.\n\n    ```typescript\n        const outdatedGuardianIndexes = parsedVaa.signatures\n          .filter(\n            (vaaSig) =>\n              !formattedSigs.some(\n                (sig) => sig.guardianIndex === vaaSig.guardianIndex\n              )\n          )\n          .map((sig) => sig.guardianIndex);\n\n        console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes);\n\n        let updatedSignatures = parsedVaa.signatures.filter(\n          (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex)\n        );\n    ```\n\n7. **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.\n\n    ```typescript\n        const validReplacements = formattedSigs.filter(\n          (sig) =>\n            !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex)\n        );\n\n        // Check if we have enough valid signatures to replace outdated ones**\n        if (outdatedGuardianIndexes.length > validReplacements.length) {\n          console.warn(\n            `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.`\n          );\n          return;\n        }\n\n        updatedSignatures = [\n          ...updatedSignatures,\n          ...validReplacements.slice(0, outdatedGuardianIndexes.length),\n        ];\n\n        updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex);\n    ```\n\n8. **Serialize the updated VAA**: Reconstruct the VAA with the updated signatures and convert it into a format suitable for submission.\n\n    ```typescript\n        const updatedVaa: VAA<'Uint8Array'> = {\n          ...parsedVaa,\n          guardianSet: guardianSetIndex,\n          signatures: updatedSignatures,\n        };\n\n        let patchedVaa: Uint8Array;\n        try {\n          patchedVaa = serialize(updatedVaa);\n        } catch (error) {\n          throw new Error(`Error serializing updated VAA: ${error}`);\n        }\n    ```\n\n9. **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.\n\n    ```typescript\n        try {\n          if (!(patchedVaa instanceof Uint8Array))\n            throw new Error('Patched VAA is not a Uint8Array!');\n\n          const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`;\n\n          console.log('Sending updated VAA to RPC...');\n\n          const result = await axios.post(RPC, {\n            jsonrpc: '2.0',\n            id: 1,\n            method: 'eth_call',\n            params: [\n              {\n                from: null,\n                to: ETH_CORE,\n                data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]),\n              },\n              'latest',\n            ],\n          });\n\n          const verificationResult = result.data.result;\n          console.log('Updated VAA (hex):', vaaHex);\n          return verificationResult;\n        } catch (error) {\n          throw new Error(`Error sending updated VAA to RPC: ${error}`);\n        }\n    ```\n\n???- code \"Complete Function\"\n    ```typescript\n    export async function replaceSignatures(\n      vaa: string | Uint8Array<ArrayBufferLike>,\n      observations: { guardianAddr: string; signature: string }[],\n      currentGuardians: string[],\n      guardianSetIndex: number\n    ) {\n      console.log('Replacing Signatures...');\n\n      try {\n        if (!vaa) throw new Error('VAA is undefined or empty.');\n        if (currentGuardians.length === 0)\n          throw new Error('Guardian set is empty.');\n        if (observations.length === 0) throw new Error('No observations provided.');\n\n        const validSigs = observations.filter((sig) =>\n          currentGuardians.includes(sig.guardianAddr)\n        );\n\n        if (validSigs.length === 0)\n          throw new Error('No valid signatures found. Cannot proceed.');\n\n        const formattedSigs = validSigs\n          .map((sig) => {\n            try {\n              const sigBuffer = Buffer.from(sig.signature, 'base64');\n              // If it's 130 bytes, it's hex-encoded and needs conversion\n              const sigBuffer1 =\n                sigBuffer.length === 130\n                  ? Buffer.from(sigBuffer.toString(), 'hex')\n                  : sigBuffer;\n\n              const r = BigInt('0x' + sigBuffer1.subarray(0, 32).toString('hex'));\n              const s = BigInt('0x' + sigBuffer1.subarray(32, 64).toString('hex'));\n              const vRaw = sigBuffer1[64];\n              const v = vRaw < 27 ? vRaw : vRaw - 27;\n\n              return {\n                guardianIndex: currentGuardians.indexOf(sig.guardianAddr),\n                signature: new Signature(r, s, v),\n              };\n            } catch (error) {\n              console.error(\n                `Failed to process signature for guardian: ${sig.guardianAddr}`,\n                error\n              );\n              return null;\n            }\n          })\n          .filter(\n            (sig): sig is { guardianIndex: number; signature: Signature } =>\n              sig !== null\n          ); // Remove null values\n\n        let parsedVaa: VAA<'Uint8Array'>;\n        try {\n          parsedVaa = deserialize('Uint8Array', vaa);\n        } catch (error) {\n          throw new Error(`Error deserializing VAA: ${error}`);\n        }\n\n        const outdatedGuardianIndexes = parsedVaa.signatures\n          .filter(\n            (vaaSig) =>\n              !formattedSigs.some(\n                (sig) => sig.guardianIndex === vaaSig.guardianIndex\n              )\n          )\n          .map((sig) => sig.guardianIndex);\n\n        console.log('Outdated Guardian Indexes:', outdatedGuardianIndexes);\n\n        let updatedSignatures = parsedVaa.signatures.filter(\n          (sig) => !outdatedGuardianIndexes.includes(sig.guardianIndex)\n        );\n\n        const validReplacements = formattedSigs.filter(\n          (sig) =>\n            !updatedSignatures.some((s) => s.guardianIndex === sig.guardianIndex)\n        );\n\n        // Check if we have enough valid signatures to replace outdated ones**\n        if (outdatedGuardianIndexes.length > validReplacements.length) {\n          console.warn(\n            `Not enough valid replacement signatures! Need ${outdatedGuardianIndexes.length}, but only ${validReplacements.length} available.`\n          );\n          return;\n        }\n\n        updatedSignatures = [\n          ...updatedSignatures,\n          ...validReplacements.slice(0, outdatedGuardianIndexes.length),\n        ];\n\n        updatedSignatures.sort((a, b) => a.guardianIndex - b.guardianIndex);\n\n        const updatedVaa: VAA<'Uint8Array'> = {\n          ...parsedVaa,\n          guardianSet: guardianSetIndex,\n          signatures: updatedSignatures,\n        };\n\n        let patchedVaa: Uint8Array;\n        try {\n          patchedVaa = serialize(updatedVaa);\n        } catch (error) {\n          throw new Error(`Error serializing updated VAA: ${error}`);\n        }\n\n        try {\n          if (!(patchedVaa instanceof Uint8Array))\n            throw new Error('Patched VAA is not a Uint8Array!');\n\n          const vaaHex = `0x${Buffer.from(patchedVaa).toString('hex')}`;\n\n          console.log('Sending updated VAA to RPC...');\n\n          const result = await axios.post(RPC, {\n            jsonrpc: '2.0',\n            id: 1,\n            method: 'eth_call',\n            params: [\n              {\n                from: null,\n                to: ETH_CORE,\n                data: eth.abi.encodeFunctionCall(PARSE_AND_VERIFY_VM_ABI, [vaaHex]),\n              },\n              'latest',\n            ],\n          });\n\n          const verificationResult = result.data.result;\n          console.log('Updated VAA (hex):', vaaHex);\n          return verificationResult;\n        } catch (error) {\n          throw new Error(`Error sending updated VAA to RPC: ${error}`);\n        }\n      } catch (error) {\n        console.error('Unexpected error in replaceSignatures:', error);\n      }\n    }\n    ```"}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 9, "depth": 2, "title": "Create Script to Replace Outdated VAA Signatures", "anchor": "create-script-to-replace-outdated-vaa-signatures", "start_char": 37496, "end_char": 41041, "estimated_token_count": 769, "token_estimator": "heuristic-v1", "text": "## Create Script to Replace Outdated VAA Signatures\n\nNow 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.\n\n1. **Open the file**: Inside `src/scripts/replaceSignatures.ts`, import the required helper functions needed to process the VAAs.\n\n    ```typescript title=\"src/scripts/replaceSignatures.ts\"\n    import {\n      fetchVaaId,\n      fetchVaa,\n      checkVaaValidity,\n      fetchObservations,\n      fetchGuardianSet,\n      replaceSignatures,\n    } from '../helpers/vaaHelper';\n    import { TXS } from '../config/constants';\n    ```\n\n2. **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.\n\n    ```typescript\n    async function main() {\n      try {\n        for (const tx of TXS) {\n          console.log(`\\nProcessing TX: ${tx}\\n`);\n\n          // 1. Fetch Transaction VAA IDs:\n          const vaaIds = await fetchVaaId([tx]);\n          if (!vaaIds.length) continue;\n\n          // 2. Fetch VAA Data:\n          const vaaData = await fetchVaa(vaaIds);\n          if (!vaaData.length) continue;\n\n          const vaaBytes = vaaData[0].vaaBytes;\n          if (!vaaBytes) continue;\n\n          // 3. Check VAA Validity:\n          const { valid } = await checkVaaValidity(vaaBytes);\n          if (valid) continue;\n\n          // 4. Fetch Observations (VAA signatures):\n          const observations = await fetchObservations(vaaIds[0]);\n\n          // 5. Fetch Current Guardian Set:\n          const [currentGuardians, guardianSetIndex] = await fetchGuardianSet();\n\n          // 6. Replace Signatures:\n          const response = await replaceSignatures(\n            Buffer.from(vaaBytes, 'base64'),\n            observations,\n            currentGuardians,\n            guardianSetIndex\n          );\n\n          if (!response) continue;\n        }\n      } catch (error) {\n        console.error('❌ Error in execution:', error);\n        process.exit(1);\n      }\n    }\n    ```\n\n3. **Make the script executable**: Ensure it runs when executed.\n\n    ```typescript\n    main();\n    ```\n\n    To run the script, use the following command:\n\n    ```bash\n    npx tsx src/scripts/replaceSignatures.ts\n    ```\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx src/scripts/replaceSignatures.ts</span>\n    \t<span data-ty> </span>\n    \t<span data-ty>Processing TX: 0x3ad91ec530187bb2ce3b394d587878cd1e9e037a97e51fbc34af89b2e0719367</span>\n        <span data-ty>❌ VAA Valid: false, Reason: VM signature invalid</span>\n        <span data-ty>Fetching observations</span>\n        <span data-ty>Fetching current guardian set</span>\n        <span data-ty>Replacing Signatures...</span>\n        <span data-ty>Outdated Guardian Indexes: [ 0 ]</span>\n        <span data-ty>Sending updated VAA to RPC...</span>\n        <span data-ty>Updated VAA (hex): 0x01000000040d010019447b72d51e33923a3d6b28496ccd3722d5f1e33e2...</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\nThe 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."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 10, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 41041, "end_char": 41471, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## Resources\n\nYou 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}.\n\nThe 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."}
{"page_id": "products-messaging-tutorials-replace-signatures", "page_title": "Replace Outdated Signatures in VAAs", "index": 11, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 41471, "end_char": 41968, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nYou've successfully built a script to fetch, validate, and replace outdated signatures in VAAs using Wormholescan and the Wormhole SDK.\n\nIt'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.\n\nLooking for more? Check out the [Wormhole Tutorial Demo repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank} for additional examples."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 0, "depth": 2, "title": "Key Components", "anchor": "key-components", "start_char": 947, "end_char": 966, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## Key Components"}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 1, "depth": 3, "title": "Hub Chain Contracts", "anchor": "hub-chain-contracts", "start_char": 966, "end_char": 1761, "estimated_token_count": 158, "token_estimator": "heuristic-v1", "text": "### Hub Chain Contracts\n\nThe hub chain is the central point for managing proposals, tallying votes, executing decisions, and coordinating governance across connected chains.\n\n   - **`HubGovernor`**: Central governance contract managing proposals and vote tallying.\n   - **`HubVotePool`**: Receives aggregated votes from spokes and submits them to `HubGovernor`.\n   - **`HubMessageDispatcher`**: Relays approved proposal executions to spoke chains.\n   - **`HubProposalExtender`**: Allows trusted actors to extend voting periods if needed.\n   - **`HubProposalMetadata`**: Helper contract returning `proposalId` and vote start for `HubGovernor` proposals.\n   - **`HubEvmSpokeAggregateProposer`**: Aggregates cross-chain voting weight for an address and proposes via the `HubGovernor` if eligible."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 2, "depth": 3, "title": "Spoke Chains Contracts", "anchor": "spoke-chains-contracts", "start_char": 1761, "end_char": 2310, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "### Spoke Chains Contracts\n\nSpoke chains handle local voting, forward votes to the hub, and execute approved proposals from the hub for decentralized governance.\n\n   - **`SpokeVoteAggregator`**: Collects votes on the spoke chain and forwards them to the hub.\n   - **`SpokeMessageExecutor`**: Receives and executes approved proposals from the hub.\n   - **`SpokeMetadataCollector`**: Fetches proposal metadata from the hub for spoke chain voters.\n   - **`SpokeAirlock`**: Acts as governance's \"admin\" on the spoke, has permissions, and its treasury."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 3, "depth": 3, "title": "Spoke Solana Staking Program", "anchor": "spoke-solana-staking-program", "start_char": 2310, "end_char": 4159, "estimated_token_count": 372, "token_estimator": "heuristic-v1", "text": "### Spoke Solana Staking Program\n\nThe 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.\n\nThe program implements its functionality through instructions, using specialized PDA accounts where data is stored. Below are the key accounts in the program:\n\n - **`GlobalConfig`**: Global program configuration.\n - **`StakeAccountMetadata`**: Stores user's staking information.\n - **`CustodyAuthority`**: PDA account managing custody and overseeing token operations related to stake accounts.\n - **`StakeAccountCustody`**: Token account associated with a stake account for securely storing staked tokens.\n - **`CheckpointData`**: Tracks delegation history.\n - **`SpokeMetadataCollector`**: Collects and updates proposal metadata from the hub chain.\n - **`GuardianSignatures`**: Stores guardian signatures for message verification.\n - **`ProposalData`**: Stores data about a specific proposal, including votes and start time.\n - **`ProposalVotersWeightCast`**: Tracks individual voter's weight for a proposal.\n - **`SpokeMessageExecutor`**: Processes messages from a spoke chain via the Wormhole protocol.\n - **`SpokeAirlock`**: Manages PDA signing and seed validation for secure instruction execution.\n - **`VestingBalance`**: Stores total vesting balance and related staking information of a vester.\n - **`VestingConfig`**: Defines vesting configuration, including mint and admin details.\n - **`Vesting`**: Represents individual vesting allocations with maturation data.\n - **`VoteWeightWindowLengths`**: Tracks lengths of vote weight windows.\n\nEach account is implemented as a Solana PDA (Program Derived Address) and utilizes Anchor's account framework for serialization and management."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 4, "depth": 2, "title": "Key Components in Action", "anchor": "key-components-in-action", "start_char": 4159, "end_char": 4520, "estimated_token_count": 65, "token_estimator": "heuristic-v1", "text": "## Key Components in Action\n\nThis 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.\n\n![detailed multigov architecture diagram](/docs/images/products/multigov/concepts/architecture/architecture-2.webp)"}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 5, "depth": 2, "title": "Multichain Communication", "anchor": "multichain-communication", "start_char": 4520, "end_char": 4977, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "## Multichain Communication\n\nMultiGov relies on Wormhole's infrastructure for all multichain 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."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 6, "depth": 2, "title": "Security Measures", "anchor": "security-measures", "start_char": 4977, "end_char": 5527, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "## Security Measures\n\n- **Vote weight window**: Implements a moving window for vote weight checkpoints to mitigate cross-chain double voting.\n    - **Proposal extension**: `HubProposalExtender` allows for extending voting periods by a trusted actor in the case of network issues or high-stakes decisions.\n- **Timelock**: A timelock period between proposal approval and execution allows for additional security checks and community review.\n- **Wormhole verification**: All multichain messages are verified using Wormhole's secure messaging protocol."}
{"page_id": "products-multigov-concepts-architecture", "page_title": "MultiGov Architecture", "index": 7, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 5527, "end_char": 6227, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nMultiGov’s hub-and-spoke architecture centralizes proposal authority on the hub while distributing participation and execution to spokes. [Wormhole Messaging](/docs/products/messaging/overview/){target=\\_blank} carries authenticated multichain actions, and [Wormhole Queries](/docs/products/queries/overview/){target=\\_blank} provide reliable state reads for metadata and vote proofs. With clear trust boundaries, timelocks, Guardian verification, and checkpointing, the system remains coherent across heterogeneous chains.\n\nFor the end-to-end lifecycle—from proposal creation to multichain execution, see the [Flow of a Proposal](/docs/products/multigov/concepts/proposal-flow/) page."}
{"page_id": "products-multigov-concepts-proposal-flow", "page_title": "Flow of a MultiGov Proposal", "index": 0, "depth": 2, "title": "Proposal Flow", "anchor": "proposal-flow", "start_char": 447, "end_char": 3348, "estimated_token_count": 568, "token_estimator": "heuristic-v1", "text": "## Proposal Flow \n\n1. **Proposal Creation (Hub)**\n\n    The proposer, typically a DAO member or smart contract, creates a proposal and submits it to the [`HubGovernor`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubGovernor.sol){target=\\_blank} contract on the hub chain. This proposal includes proposal targets, calldata, metadata, payloads, and the voting timeline. Once submitted, it becomes immutable and is broadcast to all supported spoke chains.\n\n2. **Voting Period Begins**\n\n    When the proposal is activated, both the `HubGovernor` and each `SpokeGovernor` enter a voting state. On each chain, governance participants can review the proposal and prepare to cast votes using their local voting power.\n\n3. **Users Vote on Spokes**\n\n    Individual voters interact with their local spoke voting module to cast a vote (for, against, or abstain). Votes are validated and recorded on the spoke chain and prepared as a spoke-level aggregate.\n\n4. **Votes Relayed to Hub**\n\n    Spokes submit their aggregated votes back to the hub using Wormhole: either by emitting a vote message (VAA) or by exposing the aggregate via [Queries](/docs/products/queries/overview){target=\\_blank} and submitting the Guardian-signed response on the hub. The hub verifies each aggregate before including it in the tally.\n\n5. **Voting Period Ends**\n\n    After the vote deadline (defined at proposal creation), the `HubGovernor` contract stops accepting new votes. All final tallies are frozen and no additional state transitions can occur until result finalization.   \n\n6. **Tally Finalized and Proposal Queued for Execution**\n\n    The `HubGovernor` evaluates the total votes, checks quorum thresholds, and determines whether the proposal passed or failed. If successful, it marks the proposal as ready for execution. Failed proposals are simply archived.\n\n7. **Proposal Executed**\n\n    The `HubGovernor` executes the proposal. If the action payload is on the hub chain, it’s executed directly. If actions target spoke chains, messages are composed and sent via Wormhole Messaging, then delivered by a relayer to the target executor contract or system.\n\n\n```mermaid\nsequenceDiagram\n  participant Proposer\n  participant HubGovernor\n  participant SpokeGovernor1\n  participant SpokeGovernor2\n  participant Wormhole\n  participant Executor\n\n  Proposer->>HubGovernor: Create proposal\n  Note right of HubGovernor: Proposal ID assigned\n  \n  SpokeGovernor1->>SpokeGovernor1: User votes\n  SpokeGovernor2->>SpokeGovernor2: User votes\n\n  SpokeGovernor1->>Wormhole: Relay vote VAA\n  SpokeGovernor2->>Wormhole: Relay vote VAA\n\n  Wormhole->>HubGovernor: Deliver vote VAAs\n  HubGovernor->>HubGovernor: Tally votes\n\n  HubGovernor->>HubGovernor: Finalize proposal status\n  alt Proposal Passed\n    HubGovernor->>Executor: Execute actions\n  else Proposal Failed\n    Note right of HubGovernor: No action taken\n  end\n```"}
{"page_id": "products-multigov-concepts-proposal-flow", "page_title": "Flow of a MultiGov Proposal", "index": 1, "depth": 2, "title": "EVM Proposal Flow Details", "anchor": "evm-proposal-flow-details", "start_char": 3348, "end_char": 5328, "estimated_token_count": 499, "token_estimator": "heuristic-v1", "text": "## EVM Proposal Flow Details\n\n1. On EVM, proposals are created using [`HubGovernor.propose(...)`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubGovernor.sol#L135){target=\\_blank} or via [`HubEvmSpokeAggregateProposer`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubEvmSpokeAggregateProposer.sol), which aggregates proposer voting power across registered spokes to meet the threshold. [`HubProposalMetadata`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubProposalMetadata.sol){target=\\_blank} exposes proposal metadata and is typically surfaced on each spoke by a [`SpokeMetadataCollector`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/SpokeMetadataCollector.sol){target=\\_blank}, keeping local views consistent with the hub.\n\n2. Voters cast on the spoke’s [`SpokeVoteAggregator`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/SpokeVoteAggregator.sol), which validates eligibility and produces a spoke-level aggregate. That aggregate is relayed to the hub as a Wormhole message; a relayer submits the resulting VAA to [`HubVotePool`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubVotePool.sol), which verifies and forwards totals to `HubGovernor` for inclusion in the global tally. \n\n3. After the timelock, cross-chain actions are dispatched via [`HubMessageDispatcher.dispatch(...)`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubMessageDispatcher.sol#L29){target=\\_blank} and executed by each [`SpokeMessageExecutor`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/SpokeMessageExecutor.sol) under the authority of [`SpokeAirlock`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/SpokeAirlock.sol). In practice, configure timestamped snapshots compatible with cross-chain voting (e.g., `ERC20Votes` with the appropriate `CLOCK_MODE`) and register all expected spokes on `HubVotePool`."}
{"page_id": "products-multigov-concepts-proposal-flow", "page_title": "Flow of a MultiGov Proposal", "index": 2, "depth": 2, "title": "Solana (SVM) Proposal Flow Details", "anchor": "solana-svm-proposal-flow-details", "start_char": 5328, "end_char": 7690, "estimated_token_count": 608, "token_estimator": "heuristic-v1", "text": "## Solana (SVM) Proposal Flow Details\n\n1. Proposals that target Solana include a [`SolanaPayload`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/e2e/01_createProposeWithSolanaExecution.ts#L40){target=\\_blank} in hub calldata describing the destination program and instructions to run. \n\n2. The Solana spoke ingests hub proposals by fetching `HubProposalMetadata` via [Wormhole Queries](/docs/products/queries/overview/), initializing local state with [`AddProposal`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/e2e/02_addProposal.ts){target=\\_blank}, and posting Guardian signatures. Verification artifacts and proposal states live in [Anchor PDAs](https://www.anchor-lang.com/docs/basics/pda) (e.g., `ProposalData`, [`GuardianSignatures`](https://github.com/wormhole-foundation/multigov/blob/main/solana/programs/staking/src/state/guardian_signatures.rs){target=\\_blank}), ensuring the spoke view remains cryptographically aligned with the hub.\n\n3. Voters interact with [`CastVote`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/e2e/03_castVote.ts){target=\\_blank}, which derives weight from checkpointed stake/vesting PDAs and records for/against/abstain. The vote aggregate is exposed in a PDA and read via a Query; Guardians sign the response, and the signed result is submitted to [`HubVotePool.crossChainVote(...)`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/e2e/04_crossChainVoteSolana.ts){target=\\_blank} for verification and forwarding to [`HubGovernor`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/e2e/abi/HubGovernor.json){target=\\_blank}. \n\n4. When execution targets Solana, the hub dispatches a Solana-bound message. On Solana, [`ReceiveMessage`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/deploy/devnet/tests/receive_message.ts){target=\\_blank} verifies the VAA, and [`SpokeAirlock`](https://github.com/wormhole-foundation/multigov/blob/main/solana/programs/staking/src/state/spoke_airlock.rs){target=\\_blank} performs the authorized instructions. Program-level specifics include PDAs for custody and replay safety, as well as [`VoteWeightWindowLengths`](https://github.com/wormhole-foundation/multigov/blob/main/solana/app/vote_weight_window_lengths.ts){target=\\_blank} to prevent double-counting."}
{"page_id": "products-multigov-concepts-proposal-flow", "page_title": "Flow of a MultiGov Proposal", "index": 3, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 7690, "end_char": 8683, "estimated_token_count": 207, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nMultiGov keeps proposal authority unified at the hub while distributing participation and execution across spokes. The lifecycle is consistent, create on the hub, vote on spokes, deliver aggregates back to the hub, then dispatch execution, while the delivery mechanics differ per chain (vote VAAs vs. Queries with signed responses).\n\nCore guarantees:\n\n- **Single source of truth**: The hub finalizes tallies, enforces quorum/timelock, and authorizes any cross-chain actions.\n- **Local first**: Votes are cast and validated on each spoke; only aggregates cross chains.\n- **Verified transport**: All multichain messages are Guardian-verified; spoke execution is gated by the spoke’s authority module.\n- **Replay and double-count safety**: Checkpoint windows, PDAs/decoders, and replay guards prevent re-execution and double voting.\n\nFor components and more architecture details, see the [MultiGov Architecture](/docs/products/multigov/concepts/architecture/){target=\\_blank} page."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 0, "depth": 2, "title": "What is MultiGov?", "anchor": "what-is-multigov", "start_char": 17, "end_char": 284, "estimated_token_count": 41, "token_estimator": "heuristic-v1", "text": "## What is MultiGov?\n\nMultiGov 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 1, "depth": 2, "title": "How does MultiGov ensure security in cross-chain communication?", "anchor": "how-does-multigov-ensure-security-in-cross-chain-communication", "start_char": 284, "end_char": 802, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "## How does MultiGov ensure security in cross-chain communication?\n\nMultiGov leverages Wormhole's robust cross-chain communication protocol. It implements several security measures:\n\n- Message origin verification to prevent unauthorized governance actions.\n- Timely and consistent data checks to ensure vote aggregation is based on recent and synchronized chain states.\n- Authorized participant validation to maintain the integrity of the governance process.\n- Replay attack prevention by tracking executed messages."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 2, "depth": 2, "title": "Can MultiGov integrate with any blockchain?", "anchor": "can-multigov-integrate-with-any-blockchain", "start_char": 802, "end_char": 1282, "estimated_token_count": 90, "token_estimator": "heuristic-v1", "text": "## Can MultiGov integrate with any blockchain?\n\nMultiGov 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 3, "depth": 2, "title": "How are votes aggregated across different chains?", "anchor": "how-are-votes-aggregated-across-different-chains", "start_char": 1282, "end_char": 1627, "estimated_token_count": 58, "token_estimator": "heuristic-v1", "text": "## How are votes aggregated across different chains?\n\nVotes 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 4, "depth": 2, "title": "Can governance upgrade from a single chain to MultiGov?", "anchor": "can-governance-upgrade-from-a-single-chain-to-multigov", "start_char": 1627, "end_char": 1890, "estimated_token_count": 46, "token_estimator": "heuristic-v1", "text": "## Can governance upgrade from a single chain to MultiGov?\n\nYes! 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 5, "depth": 2, "title": "How can I create a proposal in MultiGov?", "anchor": "how-can-i-create-a-proposal-in-multigov", "start_char": 1890, "end_char": 2261, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "## How can I create a proposal in MultiGov?\n\nProposals 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 6, "depth": 2, "title": "How do I vote on a proposal if I hold tokens on a spoke chain?", "anchor": "how-do-i-vote-on-a-proposal-if-i-hold-tokens-on-a-spoke-chain", "start_char": 2261, "end_char": 2529, "estimated_token_count": 53, "token_estimator": "heuristic-v1", "text": "## How do I vote on a proposal if I hold tokens on a spoke chain?\n\nYou 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 7, "depth": 2, "title": "How are approved proposals executed across multiple chains?", "anchor": "how-are-approved-proposals-executed-across-multiple-chains", "start_char": 2529, "end_char": 3013, "estimated_token_count": 96, "token_estimator": "heuristic-v1", "text": "## How are approved proposals executed across multiple chains?\n\nWhen 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`."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 8, "depth": 2, "title": "What are the requirements for using MultiGov?", "anchor": "what-are-the-requirements-for-using-multigov", "start_char": 3013, "end_char": 3510, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "## What are the requirements for using MultiGov?\n\nTo use MultiGov, your DAO must meet the following requirements:\n\n- **ERC20Votes token**: Your DAO's token must implement the `ERC20Votes` standard and support `CLOCK_MODE` timestamps for compatibility with cross-chain governance.\n- **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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 9, "depth": 2, "title": "What do I need to set up MultiGov for my project?", "anchor": "what-do-i-need-to-set-up-multigov-for-my-project", "start_char": 3510, "end_char": 4003, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "## What do I need to set up MultiGov for my project?\n\nTo set up testing MultiGov for your DAO, you'll need:\n\n- [Foundry](https://getfoundry.sh/introduction/installation/){target=\\_blank} and [Git](https://git-scm.com/downloads){target=\\_blank} installed.\n- Test ETH on the testnets you plan to use (e.g., Sepolia for hub, Optimism Sepolia for spoke).\n- Modify and deploy the hub and spoke contracts using the provided scripts.\n- Set up the necessary environment variables and configurations."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 10, "depth": 2, "title": "Can MultiGov be used with non-EVM chains?", "anchor": "can-multigov-be-used-with-non-evm-chains", "start_char": 4003, "end_char": 4226, "estimated_token_count": 46, "token_estimator": "heuristic-v1", "text": "## Can MultiGov be used with non-EVM chains?\n\nThe 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 11, "depth": 2, "title": "How can I customize voting parameters in MultiGov?", "anchor": "how-can-i-customize-voting-parameters-in-multigov", "start_char": 4226, "end_char": 4801, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "## How can I customize voting parameters in MultiGov?\n\nVoting 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.\n\nRemember to thoroughly test your MultiGov implementation on testnets before deploying to Mainnet, and have your contracts audited for additional security."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 12, "depth": 2, "title": "How does MultiGov handle potential network issues or temporary chain unavailability?", "anchor": "how-does-multigov-handle-potential-network-issues-or-temporary-chain-unavailability", "start_char": 4801, "end_char": 5847, "estimated_token_count": 177, "token_estimator": "heuristic-v1", "text": "## How does MultiGov handle potential network issues or temporary chain unavailability?\n\nMultiGov includes several mechanisms to handle network issues or temporary chain unavailability:\n\n1. **Asynchronous vote aggregation**: Votes are aggregated periodically, allowing the system to continue functioning even if one chain is temporarily unavailable.\n2. **Proposal extension**: The `HubGovernorProposalExtender` allows trusted actors to extend voting periods if needed, which can help mitigate issues caused by temporary network problems.\n3. **Wormhole retry mechanism**: Wormhole's infrastructure includes retry mechanisms for failed message deliveries, helping ensure cross-chain messages eventually get through.\n4. **Decentralized relayer network**: Wormhole's decentralized network of relayers helps maintain system availability even if some relayers are offline.\n\nHowever, prolonged outages on the hub chain or critical spoke chains could potentially disrupt governance activities. Projects should have contingency plans for such scenarios."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 13, "depth": 2, "title": "How does MultiGov differ from traditional DAO governance?", "anchor": "how-does-multigov-differ-from-traditional-dao-governance", "start_char": 5847, "end_char": 6222, "estimated_token_count": 59, "token_estimator": "heuristic-v1", "text": "## How does MultiGov differ from traditional DAO governance?\n\nUnlike 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."}
{"page_id": "products-multigov-faqs", "page_title": "MultiGov FAQs", "index": 14, "depth": 2, "title": "What are the main components of MultiGov?", "anchor": "what-are-the-main-components-of-multigov", "start_char": 6222, "end_char": 6640, "estimated_token_count": 85, "token_estimator": "heuristic-v1", "text": "## What are the main components of MultiGov?\n\nThe main components of MultiGov include:\n\n- **Hub chain**: Central coordination point for governance activities.\n- **Spoke chains**: Additional chains where token holders can participate in governance.\n- **Wormhole integration**: Enables secure cross-chain message passing.\n- **Governance token**: Allows holders to participate in governance across all integrated chains."}
{"page_id": "products-multigov-get-started", "page_title": "Get Started with Multigov", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 456, "end_char": 1046, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore deploying MultiGov, you need a governance token deployed on multiple chains (ERC-20 or SPL):\n\n- **EVM chains**:\n     - Your token must implement the [`ERC20Votes`](https://docs.openzeppelin.com/contracts/4.x/governance#erc20votes){target=\\_blank} standard.\n     - It must support `CLOCK_MODE` timestamps for compatibility with cross-chain voting.\n\n- **Solana**:\n     - Use an SPL token.\n     - Voting eligibility and weight are managed by the [MultiGov staking program](/docs/products/multigov/concepts/architecture/#spoke-solana-staking-program){target=\\_blank}."}
{"page_id": "products-multigov-get-started", "page_title": "Get Started with Multigov", "index": 1, "depth": 2, "title": "Deployment Flow", "anchor": "deployment-flow", "start_char": 1046, "end_char": 1398, "estimated_token_count": 81, "token_estimator": "heuristic-v1", "text": "## Deployment Flow\n\nMultiGov 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).\n\n[timeline(docs/.snippets/text/products/multigov/deployment-flow-timeline.json)]"}
{"page_id": "products-multigov-get-started", "page_title": "Get Started with Multigov", "index": 2, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 1398, "end_char": 2012, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nContinue to the deployment guide that matches your governance architecture.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy on EVM Chains**\n\n    ---\n\n    Configure and deploy MultiGov smart contracts to EVM-compatible chains.\n\n    [:custom-arrow: Deploy to EVM Chains](/docs/products/multigov/guides/deploy-to-evm/)\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy on Solana**\n\n    ---\n\n    Launch the Solana staking program and configure spoke chain participation.\n\n    [:custom-arrow: Deploy to Solana](/docs/products/multigov/guides/deploy-to-solana/)\n\n</div>"}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 621, "end_char": 993, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "## Prerequisites \n\nTo interact with MultiGov, you'll need the following:\n\n- Install [Foundry](https://getfoundry.sh/introduction/installation/){target=\\_blank}.\n- Install [Git](https://git-scm.com/downloads){target=\\_blank}.\n- Clone the repository:\n\n    ```bash\n    git clone https://github.com/wormhole-foundation/multigov\n    cd evm # For evm testing/deploying\n    ```"}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 1, "depth": 2, "title": "Development Setup", "anchor": "development-setup", "start_char": 993, "end_char": 1742, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Development Setup\n\nFor developers looking to set up a local MultiGov environment:\n\n1. Install dependencies:\n\n    ```bash\n    forge install\n    ```\n\n2. Set up environment variables:\n\n    ```bash\n    cp .env.example .env\n    ```\n\n    Edit `.env` with your specific [configuration](#configuration){target=\\_blank}.\n\n3. Compile contracts:\n\n    ```bash\n    forge build\n    ```\n\n4. Deploy contracts (example for Sepolia testnet): \n\n    For hub chains:\n\n    ```bash\n    forge script script/DeployHubContractsSepolia.s.sol --rpc-url $SEPOLIA_RPC_URL --broadcast\n    ```\n\n    For spoke chains (e.g., Optimism Sepolia):\n\n    ```bash\n    forge script script/DeploySpokeContractsOptimismSepolia.s.sol --rpc-url $OPTIMISM_SEPOLIA_RPC_URL --broadcast\n    ```"}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 2, "depth": 2, "title": "Configuration", "anchor": "configuration", "start_char": 1742, "end_char": 1875, "estimated_token_count": 23, "token_estimator": "heuristic-v1", "text": "## Configuration\n\nWhen deploying MultiGov, several key parameters need to be set. Here are the most important configuration points:"}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 3, "depth": 3, "title": "Hub Governor Key Parameters", "anchor": "hub-governor-key-parameters", "start_char": 1875, "end_char": 2629, "estimated_token_count": 186, "token_estimator": "heuristic-v1", "text": "### Hub Governor Key Parameters\n\n- **`initialVotingDelay` ++\"uint256\"++**: The delay measured in seconds before voting on a proposal begins. For example, `86400` is one day.\n- **`initialProposalThreshold` ++\"uint256\"++**: The number of tokens needed to create a proposal.\n- **`initialQuorum` ++\"uint256\"++**: The minimum number of votes needed for a proposal to be successful.\n- **`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.\n\n    !!! note\n        This helps mitigate cross-chain double voting."}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 4, "depth": 3, "title": "Hub Proposal Extender Key Parameters", "anchor": "hub-proposal-extender-key-parameters", "start_char": 2629, "end_char": 2962, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "### Hub Proposal Extender Key Parameters\n\n- **`extensionDuration` ++\"uint256\"++**: The amount of time, in seconds, for which target proposals will be extended. For example, `10800` is three hours.\n- **`minimumExtensionDuration` ++\"uint256\"++**: Lower time limit, in seconds, for extension duration. For example, `3600` is one hour."}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 5, "depth": 3, "title": "Spoke Vote Aggregator Key Parameters", "anchor": "spoke-vote-aggregator-key-parameters", "start_char": 2962, "end_char": 3309, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### Spoke Vote Aggregator Key Parameters\n\n- **`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.\n\n    !!! note\n        This is crucial for mitigating cross-chain double voting"}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 6, "depth": 3, "title": "Hub Evm Spoke Vote Aggregator Key Parameters", "anchor": "hub-evm-spoke-vote-aggregator-key-parameters", "start_char": 3309, "end_char": 3570, "estimated_token_count": 61, "token_estimator": "heuristic-v1", "text": "### Hub Evm Spoke Vote Aggregator Key Parameters\n\n- **`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."}
{"page_id": "products-multigov-guides-deploy-to-evm", "page_title": "Deploy MultiGov on EVM Chains", "index": 7, "depth": 3, "title": "Updateable Governance Parameters", "anchor": "updateable-governance-parameters", "start_char": 3570, "end_char": 4470, "estimated_token_count": 198, "token_estimator": "heuristic-v1", "text": "### Updateable Governance Parameters\n\nThe following key parameters can be updated through governance proposals:\n\n- **`votingDelay`**: Delay before voting starts (in seconds).\n- **`votingPeriod`**: Duration of the voting period (in seconds).\n- **`proposalThreshold`**: Threshold for creating proposals (in tokens).\n- **`quorum`**: Number of votes required for quorum.\n- **`extensionDuration`**: The amount of time for which target proposals will be extended (in seconds).\n- **`voteWeightWindow`**: Window for vote weight checkpoints (in seconds).\n- **`maxQueryTimestampOffset`**: Max timestamp difference allowed between a query's target time and the hub's block time.\n\nThese parameters can be queried using their respective getter functions on the applicable contract.\n\nTo update these parameters, a governance proposal must be created, voted on, and executed through the standard MultiGov process."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 610, "end_char": 1270, "estimated_token_count": 246, "token_estimator": "heuristic-v1", "text": "## Prerequisites \n\nTo deploy MultiGov on Solana, ensure you have the following installed:  \n\n - [Git](https://git-scm.com/downloads){target=\\_blank}  \n - [Node.js](https://nodejs.org/){target=\\_blank} **`v20.10.0`**\n - [Solana CLI](https://docs.anza.xyz/cli/install/){target=\\_blank} **`v1.18.20`**\n - [Anchor](https://www.anchor-lang.com/docs/installation){target=\\_blank} **`v0.30.1`**\n - [Rust](https://rust-lang.org/tools/install/){target=\\_blank} **`v1.80.1`**\n - [Docker](https://www.docker.com/get-started/){target=\\_blank}\n\nThen, clone the repository:  \n\n```bash\ngit clone https://github.com/wormhole-foundation/multigov.git  \ncd multigov/solana/\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 1, "depth": 2, "title": "Build the Project", "anchor": "build-the-project", "start_char": 1270, "end_char": 1539, "estimated_token_count": 54, "token_estimator": "heuristic-v1", "text": "## Build the Project\n\nTo create a verifiable build of the MultiGov Staking Program, run the following command:    \n\n```bash\n./scripts/build_verifiable_staking_program.sh\n```\n\nOnce the build is complete, the compiled artifacts will be available in the `target` folder."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 2, "depth": 2, "title": "Set Up the Deployer Account", "anchor": "set-up-the-deployer-account", "start_char": 1539, "end_char": 1939, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Set Up the Deployer Account\n\nFor a successful deployment, you need a funded deployer account on Solana. This account will store the program and execute deployment transactions. \n\nIn 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."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 3, "depth": 3, "title": "Generate a New Keypair", "anchor": "generate-a-new-keypair", "start_char": 1939, "end_char": 2116, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "### Generate a New Keypair  \n\nTo create a new keypair and save it to a file, run the following command:  \n\n```bash\nsolana-keygen new --outfile ./app/keypairs/deployer.json\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 4, "depth": 3, "title": "Check the Deployer Account Address", "anchor": "check-the-deployer-account-address", "start_char": 2116, "end_char": 2309, "estimated_token_count": 44, "token_estimator": "heuristic-v1", "text": "### Check the Deployer Account Address  \n\nTo retrieve the public address of the newly created keypair, run the following command:  \n\n```bash\nsolana address -k ./app/keypairs/deployer.json\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 5, "depth": 3, "title": "Check the Deployer Account Balance", "anchor": "check-the-deployer-account-balance", "start_char": 2309, "end_char": 2731, "estimated_token_count": 85, "token_estimator": "heuristic-v1", "text": "### Check the Deployer Account Balance  \n\nTo verify the current balance of the deployer account, run the following command:  \n\n```bash\nsolana balance -k ./app/keypairs/deployer.json\n```\n\n!!! warning \n    When deploying the MultiGov Staking Program, the deployer account must have enough SOL to cover deployment costs and transaction fees:\n\n    - 7.60219224 SOL for deployment costs\n    - 0.00542 SOL for transaction fees"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 6, "depth": 3, "title": "Fund the Deployer Account", "anchor": "fund-the-deployer-account", "start_char": 2731, "end_char": 3438, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "### Fund the Deployer Account  \n\nIf the account does not have enough SOL, use one of the following methods to add funds.  \n\n - **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.\n\n    ```bash\n    solana transfer <deployer_account_address> <amount> --from /path/to/funder.json\n    ```\n\n - **Request an airdrop (devnet only)**: If deploying to devnet, you can request free SOL.\n\n    ```bash\n    solana airdrop 2 -k ./app/keypairs/deployer.json\n    ```\n\n - **Use a Solana faucet (devnet only)**: You can use the official [Solana faucet](https://faucet.solana.com/){target=\\_blank} to receive 10 free SOL."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 7, "depth": 2, "title": "Deploy the MultiGov Staking Program", "anchor": "deploy-the-multigov-staking-program", "start_char": 3438, "end_char": 3826, "estimated_token_count": 67, "token_estimator": "heuristic-v1", "text": "## Deploy the MultiGov Staking Program\n\nWith 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."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 8, "depth": 3, "title": "Deploy the Program", "anchor": "deploy-the-program", "start_char": 3826, "end_char": 4028, "estimated_token_count": 53, "token_estimator": "heuristic-v1", "text": "### Deploy the Program  \n\nDeploy the MultiGov Staking Program using Anchor:  \n\n```bash\nanchor deploy --provider.cluster https://api.devnet.solana.com --provider.wallet ./app/keypairs/deployer.json\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 9, "depth": 3, "title": "Verify the Deployment", "anchor": "verify-the-deployment", "start_char": 4028, "end_char": 4209, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### Verify the Deployment  \n\nAfter deployment, check if the program is successfully deployed by running the following command:  \n\n```bash\nsolana program show INSERT_PROGRAM_ID\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 10, "depth": 3, "title": "Extend Program Storage", "anchor": "extend-program-storage", "start_char": 4209, "end_char": 4446, "estimated_token_count": 40, "token_estimator": "heuristic-v1", "text": "### Extend Program Storage  \n\nIf the deployed program requires additional storage space for updates or functionality, extend the program storage using the following command:  \n\n```bash\nsolana program extend INSERT_PROGRAM_ID 800000\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 11, "depth": 3, "title": "Initialize the IDL", "anchor": "initialize-the-idl", "start_char": 4446, "end_char": 4687, "estimated_token_count": 60, "token_estimator": "heuristic-v1", "text": "### Initialize the IDL  \n\nTo associate an IDL file with the deployed program, run the following command:  \n\n```bash\nanchor idl init --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json INSERT_PROGRAM_ID\n```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 12, "depth": 2, "title": "Configure the Staking Program", "anchor": "configure-the-staking-program", "start_char": 4687, "end_char": 5042, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "## Configure the Staking Program\n\nThe 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."}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 13, "depth": 3, "title": "Run Deployment Scripts", "anchor": "run-deployment-scripts", "start_char": 5042, "end_char": 6014, "estimated_token_count": 202, "token_estimator": "heuristic-v1", "text": "### Run Deployment Scripts  \n\nAfter deploying the program and initializing the IDL, execute the following scripts **in order** to set up the staking environment and necessary accounts.  \n\n1. Initialize the MultiGov Staking Program with default settings:\n\n    ```bash\n    npx ts-node app/deploy/01_init_staking.ts\n    ```\n\n2. Create an Account Lookup Table (ALT) to optimize transaction processing:\n\n    ```bash\n    npx ts-node app/deploy/02_create_account_lookup_table.ts\n    ```\n\n3. Set up airlock accounts:\n\n    ```bash\n    npx ts-node app/deploy/03_create_airlock.ts\n    ```\n\n4. Deploy a metadata collector:\n\n    ```bash\n    npx ts-node app/deploy/04_create_spoke_metadata_collector.ts\n    ```\n\n5. Configure vote weight window lengths:\n\n    ```bash\n    npx ts-node app/deploy/05_initializeVoteWeightWindowLengths.ts\n    ```\n\n6. Deploy the message executor for handling governance messages:\n\n    ```bash\n    npx ts-node app/deploy/06_create_message_executor.ts\n    ```"}
{"page_id": "products-multigov-guides-deploy-to-solana", "page_title": "MultiGov Deployment to Solana", "index": 14, "depth": 3, "title": "Set MultiGov Staking Program Key Parameters", "anchor": "set-multigov-staking-program-key-parameters", "start_char": 6014, "end_char": 7855, "estimated_token_count": 417, "token_estimator": "heuristic-v1", "text": "### Set MultiGov Staking Program Key Parameters  \n\nWhen deploying MultiGov on Solana, several key parameters need to be set. Here are the most important configuration points:  \n\n - **`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.\n - **`hubChainId` ++\"u16\"++**: The chain ID of the hub network where proposals are primarily managed. For example, `10002` for Sepolia testnet.\n - **`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.\n - **`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.\n - **`votingTokenMint` ++\"Pubkey\"++**: The mint address of the token used for voting.\n - **`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.\n - **`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.\n - **`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."}
{"page_id": "products-multigov-guides-upgrade-evm", "page_title": "Upgrading MultiGov on EVM", "index": 0, "depth": 2, "title": "Key Considerations for Upgrades", "anchor": "key-considerations-for-upgrades", "start_char": 317, "end_char": 1787, "estimated_token_count": 299, "token_estimator": "heuristic-v1", "text": "## Key Considerations for Upgrades\n\n- `HubGovernor`:\n    - 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.\n\n- `HubVotePool`:\n    - Can be replaced by setting a new `HubVotePool` on the `HubGovernor`.\n    - Requires re-registering all spokes on the new `HubVotePool`.\n    - Must register the query type and implementation for vote decoding by calling [`registerQueryType`](https://github.com/wormhole-foundation/multigov/blob/main/evm/src/HubVotePool.sol#L87){target=\\_blank} on the new `HubVotePool`.\n    - 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`.\n\n- `SpokeMessageExecutor`:\n    - Upgradeable via [UUPS](https://rareskills.io/post/uups-proxy){target=\\_blank} proxy pattern.\n    - Stores critical parameters in `SpokeMessageExecutorStorage`.\n\n- `HubEvmSpokeAggregateProposer`:\n    - Needs redeployment if `HubGovernor` changes.\n    - Requires re-registering all spokes after redeployment.\n\n- `HubProposalMetadata`:\n    - Needs redeployment if `HubGovernor` changes, as it references `HubGovernor` as a parameter.\n\n- `SpokeMetadataCollector`:\n    - Requires redeployment if the hub chain ID changes or if `HubProposalMetadata` changes."}
{"page_id": "products-multigov-guides-upgrade-evm", "page_title": "Upgrading MultiGov on EVM", "index": 1, "depth": 2, "title": "Process for Major System Upgrade", "anchor": "process-for-major-system-upgrade", "start_char": 1787, "end_char": 2806, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "## Process for Major System Upgrade \n\n1. Deploy the new `HubGovernor` contract.\n1. Redeploy the following contracts:\n    - `HubEvmSpokeAggregateProposer` with the new `HubGovernor` address.\n    - `HubProposalMetadata` referencing the new `HubGovernor`.\n    - If hub chain ID changes, redeploy `SpokeMetadataCollector` on all spoke chains.\n1. Update the `HubVotePool` contract:\n    - Set the new `HubVotePool` on the new `HubGovernor`.\n    - Register all spokes on the new `HubVotePool`.\n    - Register the query type and implementation for vote decoding (`HubEvmSpokeVoteDecoder`).\n1. Re-register all spokes on the new `HubEvmSpokeAggregateProposer`.\n1. Conduct thorough testing of the new system setup and verify all cross-chain interactions are functioning correctly.\n1. Create a proposal to switch the timelock to the new governor and communicate clearly to the community what changes were made.\n1. Implement a transition period where the new system is closely monitored and address any issues that arise promptly."}
{"page_id": "products-multigov-guides-upgrade-evm", "page_title": "Upgrading MultiGov on EVM", "index": 2, "depth": 2, "title": "Important Considerations", "anchor": "important-considerations", "start_char": 2806, "end_char": 3289, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Important Considerations\n\n- Always prioritize system stability, upgrades should only be performed when absolutely necessary.\n- Thoroughly audit all new contract implementations before proposing an upgrade.\n- Account for all affected components across all chains in the upgrade plan.\n- Provide comprehensive documentation for the community about the upgrade process and any changes in functionality.\n- Always test upgrades extensively on testnets before implementing in production."}
{"page_id": "products-multigov-guides-upgrade-solana", "page_title": "Upgrading MultiGov on Solana", "index": 0, "depth": 2, "title": "Key Considerations for Upgrades", "anchor": "key-considerations-for-upgrades", "start_char": 524, "end_char": 1388, "estimated_token_count": 170, "token_estimator": "heuristic-v1", "text": "## Key Considerations for Upgrades\n\n- **Program upgradeability**: You can upgrade the MultiGov Staking Program on Solana using the `anchor upgrade` command.\n    - 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.\n    - The program's authority (deployer) must execute the upgrade.\n\n- **`HubProposalMetadata`**: Can be updated without redeploying the entire program. You can do this by invoking the `updateHubProposalMetadata` instruction.\n    - You must carefully validate updates to `HubProposalMetadata` to ensure compatibility with the existing system.\n\n- **Cross-chain compatibility**: Ensure any changes to the Solana program do not break compatibility with the Ethereum-based `HubGovernor`.\n    - Test upgrades thoroughly on devnet before deploying to mainnet."}
{"page_id": "products-multigov-guides-upgrade-solana", "page_title": "Upgrading MultiGov on Solana", "index": 1, "depth": 2, "title": "Upgrade the MultiGov Program", "anchor": "upgrade-the-multigov-program", "start_char": 1388, "end_char": 2961, "estimated_token_count": 316, "token_estimator": "heuristic-v1", "text": "## Upgrade the MultiGov Program\n\nFollow these steps to upgrade the MultiGov Staking Program on Solana:\n\n1. **Prepare the new program binary**: Build the updated program using the provided script.\n\n    ```bash\n    ./scripts/build_verifiable_staking_program.sh\n    ```\n\n    The new program binary will be located at:\n\n    ```bash\n    target/deploy/staking.so\n    ```\n\n2. **Upgrade the program**: Use the anchor upgrade command to deploy the new program binary.\n\n    ```bash\n    anchor upgrade --program-id INSERT_PROGRAM_ID --provider.cluster INSERT_CLUSTER_URL INSERT_PATH_TO_PROGRAM_BINARY\n    ```\n\n    Your completed anchor upgrade command should resemble the following:\n    ```bash\n    anchor upgrade --program-id DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY --provider.cluster https://api.devnet.solana.com ./target/deploy/staking.so\n    ```\n\n3. **Update the IDL**: After upgrading the program, update the IDL to reflect any changes in the program's interface.\n\n    ```bash\n    anchor idl upgrade INSERT_PROGRAM_ID --filepath INSERT_PATH_TO_IDL_FILE\n    ```\n\n    Your completed IDL upgrade command should resemble the following:\n    ```bash\n    anchor idl upgrade --provider.cluster https://api.devnet.solana.com --filepath ./target/idl/staking.json DgCSKsLDXXufYeEkvf21YSX5DMnFK89xans5WdSsUbeY\n    ```\n\n4. **Update `HubProposalMetadata`**: If `HubProposalMetadata` requires an update, run the following script to invoke the `updateHubProposalMetadata` instruction and apply the changes.\n\n    ```bash\n    npx ts-node app/deploy/07_update_HubProposalMetadata.ts\n    ```"}
{"page_id": "products-multigov-overview", "page_title": "MultiGov Overview", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 435, "end_char": 1282, "estimated_token_count": 163, "token_estimator": "heuristic-v1", "text": "## Key Features\n\nMultiGov expands DAO governance across blockchains, increasing participation, improving security with Wormhole messaging, and enabling unified decision-making at scale. Key features include:\n\n- **Multichain governance**: Token holders can vote and execute proposals from any supported chain.\n- **Hub-and-spoke model**: Proposals are created on a central hub chain and voted on from spoke chains, where governance tokens live.\n- **Secure vote aggregation**: Vote weights are checkpointed and verified to prevent double voting.\n- **Cross-chain proposal execution**: Approved proposals can be executed across multiple chains.\n- **Flexible architecture**: Can integrate with any Wormhole-supported blockchain.\n- **Upgradeable and extensible**: Supports upgrades across components while preserving vote history and system continuity."}
{"page_id": "products-multigov-overview", "page_title": "MultiGov Overview", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 1282, "end_char": 2188, "estimated_token_count": 203, "token_estimator": "heuristic-v1", "text": "## How It Works\n\n1. **Create proposal on hub chain**: Proposals are created on the hub chain, which manages the core governance logic, including vote aggregation and execution scheduling.\n2. **Vote from spoke chains**: Token holders on spoke chains vote locally using `SpokeVoteAggregators`, with checkpoints tracking their voting power.\n3. **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.\n4. **Aggregate and finalize on hub**: The hub chain receives votes from all spokes, tallies results, and finalizes the outcome once the voting period ends.\n5. **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."}
{"page_id": "products-multigov-overview", "page_title": "MultiGov Overview", "index": 2, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 2188, "end_char": 3434, "estimated_token_count": 332, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\n- **Cross-Chain Treasury Management**\n\n    - **[MultiGov](/docs/products/multigov/get-started/){target=\\_blank}**: Vote on treasury actions from any supported chain.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Transmit proposal execution to target chains.\n    - **[Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}**: Optionally move assets.\n\n- **Coordinated Protocol Upgrades Across Chains**\n\n    - **[MultiGov](/docs/products/multigov/get-started/){target=\\_blank}**: Create a unified proposal to upgrade contracts across networks.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Send upgrade instructions as VAAs and deliver execution payloads to target chains.\n    \n- **Progressive Decentralization for Multichain DAOs**\n\n    - **[MultiGov](/docs/products/multigov/get-started/){target=\\_blank}**: Extend governance to new chains while preserving coordination.\n    - **[Queries](/docs/products/queries/overview/){target=\\_blank}**: Fetch on-chain vote weights from remote spokes.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Aggregate results and execute actions via the hub."}
{"page_id": "products-multigov-overview", "page_title": "MultiGov Overview", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3434, "end_char": 3572, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nFollow these steps to get started with MultiGov:\n\n[timeline(docs/.snippets/text/products/multigov/multigov-timeline.json)]"}
{"page_id": "products-multigov-tutorials-treasury-proposal", "page_title": "MultiGov Guides", "index": 0, "depth": 2, "title": "Create a Proposal", "anchor": "create-a-proposal", "start_char": 394, "end_char": 3896, "estimated_token_count": 656, "token_estimator": "heuristic-v1", "text": "## Create a Proposal\n\nThe 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.\n\nIn 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.\n\nKey actions:\n\n- Define the proposal targets (two transactions to the Message Dispatcher).\n- Set values for each transaction (in this case, both are 0 as we're not transferring any native ETH).\n- Encode the calldata for minting 10 W tokens on Optimism and sending 15 ETH to Arbitrum.\n- Finally, we submit the proposal to the `HubGovernor` contract.\n\n```solidity\nHubGovernor governor = HubGovernor(GOVERNOR_ADDRESS);\n// Prepare proposal details\naddress[] memory targets = new address[](2);\ntargets[0] = HUB_MESSAGE_DISPATCHER_ADDRESS;\ntargets[1] = HUB_MESSAGE_DISPATCHER_ADDRESS;\nuint256[] memory values = new uint256[](2);\nvalues[0] = 0;\nvalues[1] = 0;\nbytes[] memory calldatas = new bytes[](2);\n// Prepare message for Optimism to mint 10 W tokens\n// bytes created using abi.encodeWithSignature(\"mint(address,uint256)\", 0xB0fFa8000886e57F86dd5264b9582b2Ad87b2b91, 10e18)\ncalldatas[0] = abi.encodeWithSignature(\n    \"dispatch(bytes)\", \n    abi.encode(\n        OPTIMISM_WORMHOLE_CHAIN_ID,\n        [OPTIMISM_WORMHOLE_TREASURY_ADDRESS],\n        [uint256(10 ether)],\n        [hex\"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000\"] \n    )\n);\n// Prepare message for Arbitrum to receive 15 ETH\ncalldatas[1] = abi.encodeWithSignature(\n    \"dispatch(bytes)\", \n    abi.encode(\n        ARBITRUM_WORMHOLE_CHAIN_ID,\n        [ARBITRUM_WORMHOLE_TREASURY_ADDRESS],\n        [uint256(15 ether)],\n        [hex\"0x40c10f19000000000000000000000000b0ffa8000886e57f86dd5264b9582b2ad87b2b910000000000000000000000000000000000000000000000008ac7230489e8000000000000000000000000000000000000000000000000000000000000\"] \n    )\n);\nstring memory description = \"Mint 10 W to Optimism treasury and 10 W to Arbitrum treasury via Wormhole\";\n// Create the proposal\nuint256 proposalId = governor.propose(\n    targets, values, calldatas, description\n)\n```\n\n??? interface \"Parameters\"\n\n    `GOVERNOR_ADDRESS` ++\"address\"++\n\n    The address of the `HubGovernor` contract on Ethereum Mainnet.\n\n    ---\n\n    `targets` ++\"address[]\"++\n\n    An array that specifies the addresses that will receive the proposal's actions. Here, both are set to the `HUB_MESSAGE_DISPATCHER_ADDRESS`.\n\n    ---\n\n    `values` ++\"uint256[]\"++\n\n    An array containing the value of each transaction (in Wei). In this case, both are set to zero because no ETH is being transferred.\n\n    ---\n\n    `calldatas` ++\"bytes[]\"++\n\n    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.\n\n    ---\n\n    `description` ++\"string\"++\n\n    A description of the proposal, outlining the intent to mint tokens to Optimism and send ETH to Arbitrum.\n\n??? interface \"Returns\"\n\n    `proposalId` ++\"uint256\"++\n\n    The ID of the newly created proposal on the hub chain."}
{"page_id": "products-multigov-tutorials-treasury-proposal", "page_title": "MultiGov Guides", "index": 1, "depth": 2, "title": "Vote on the Proposal via Spoke", "anchor": "vote-on-the-proposal-via-spoke", "start_char": 3896, "end_char": 5290, "estimated_token_count": 300, "token_estimator": "heuristic-v1", "text": "## Vote on the Proposal via Spoke\n\nOnce 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.\n\nKey actions:\n\n- Connect to the `SpokeVoteAggregator` contract on the spoke chain. This contract aggregates votes from the spoke chains and relays them to the hub chain.\n- Cast a vote in support of the proposal.\n\n```solidity\n// Connect to the SpokeVoteAggregator contract of the desired chain\nSpokeVoteAggregator voteAggregator = SpokeVoteAggregator(VOTE_AGGREGATOR_ADDRESS);\n// Cast a vote\nuint8 support = 1; // 1 for supporting, 0 for opposing\nuint256 weight = voteAggregator.castVote(proposalId, support);\n```\n\n??? interface \"Parameters\"\n\n    `VOTE_AGGREGATOR_ADDRESS` ++\"address\"++\n\n    The address of the `SpokeVoteAggregator` contract on the spoke chain (Optimism or Arbitrum).\n\n    ---\n\n    `proposalId` ++\"uint256\"++\n\n    The ID of the proposal created on the hub chain, which is being voted on.\n\n    ---\n\n    `support` ++\"uint8\"++\n\n    The vote being cast (`1` for supporting the proposal, `0` for opposing).\n\n??? interface \"Returns\"\n\n    `weight` ++\"uint256\"++\n\n    The weight of the vote, determined by the voter’s token holdings on the spoke chain."}
{"page_id": "products-multigov-tutorials-treasury-proposal", "page_title": "MultiGov Guides", "index": 2, "depth": 2, "title": "Vote Aggregation", "anchor": "vote-aggregation", "start_char": 5290, "end_char": 6080, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Vote Aggregation\n\nIn 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.\n\nKey actions:\n\n- Aggregate votes from different chains and submit them to the hub chain for tallying.\n\n```solidity\n// Aggregate votes sent to Hub (this would typically be done by a \"crank turner\" off-chain)\nhubVotePool.crossChainVote(queryResponseRaw, signatures);\n```\n\n??? interface \"Parameters\"\n\n    `queryResponseRaw` ++\"bytes\"++\n\n    The raw vote data from the spoke chains.\n\n    ---\n\n    `signatures` ++\"bytes\"++\n\n    Cryptographic signatures that verify the validity of the votes from the spoke chains."}
{"page_id": "products-multigov-tutorials-treasury-proposal", "page_title": "MultiGov Guides", "index": 3, "depth": 2, "title": "Execute Proposal and Dispatch Cross-Chain Messages", "anchor": "execute-proposal-and-dispatch-cross-chain-messages", "start_char": 6080, "end_char": 7917, "estimated_token_count": 373, "token_estimator": "heuristic-v1", "text": "## Execute Proposal and Dispatch Cross-Chain Messages\n\nAfter 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.\n\nKey actions:\n\n- Execute the proposal after the voting period ends and the proposal passes.\n- 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.\n\n```solidity\nHubGovernor governor = HubGovernor(GOVERNOR_ADDRESS);\n// Standard timelock execution\ngovernor.execute(targets, values, calldatas, descriptionHash);\n```\n\n??? interface \"Parameters\"\n\n    `governor` ++\"HubGovernor\"++\n\n    The `HubGovernor` contract instance.\n\n    ---\n\n    `targets` ++\"address[]\"++\n\n    An array containing the target addresses for the proposal’s transactions (in this case, the `HUB_MESSAGE_DISPATCHER_ADDRESS` for both).\n\n    ---\n\n    `values` ++\"uint256[]\"++\n\n    An array of values (in Wei) associated with each transaction (both are zero in this case).\n\n    ---\n\n    `calldatas` ++\"bytes[]\"++\n\n    The encoded transaction data to dispatch the governance actions (e.g., minting tokens and transferring ETH).\n\n    ---\n\n    `descriptionHash` ++\"bytes32\"++\n\n    A hash of the proposal’s description, used to verify the proposal before execution.\n\n??? interface \"Returns\"\n\n    No direct return, but executing this function finalizes the cross-chain governance actions by dispatching the encoded messages via Wormhole to the spoke chains.\n\nOnce 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."}
{"page_id": "products-overview", "page_title": "Compare Wormhole's Cross-Chain Solutions", "index": 0, "depth": 2, "title": "Transfer Products", "anchor": "transfer-products", "start_char": 610, "end_char": 3494, "estimated_token_count": 628, "token_estimator": "heuristic-v1", "text": "## Transfer Products\n\nWormhole offers different solutions for cross-chain asset transfer, each designed for various use cases and integration requirements.\n\n- **[Native Token Transfers (NTT)](/docs/products/token-transfers/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.\n- **[Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/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.\n- **[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.\n\n<div markdown class=\"full-width\">\n\n::spantable::\n\n|                                | Criteria                              | NTT                | WTT                | Settlement         |\n|--------------------------------|---------------------------------------|--------------------|--------------------|--------------------|\n| Supported Transfer Types @span | Token Transfers                       | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n|                                | Token Transfers with Payloads         | :white_check_mark: | :white_check_mark: | :white_check_mark: |\n| Supported Assets @span         | Wrapped Assets                        | :x:                | :white_check_mark: | :white_check_mark: |\n|                                | Native Assets                         | :white_check_mark: | :x:                | :white_check_mark: |\n| Features @span                 | Out-of-the-Box UI                     | :x:                | :x:                | :white_check_mark: |\n|                                | Event-Based Actions                   | :white_check_mark: | :white_check_mark: | :x:                |\n|                                | Intent-Based Execution                | :x:                | :x:                | :white_check_mark: |\n|                                | Fast Settlement                       | :x:                | :x:                | :white_check_mark: |\n| Requirements @span             | Contract Deployment                   | :white_check_mark: | :x:                |:x:                 |\n\n::end-spantable::\n\n</div>\n\nFor a deeper dive into how token transfers work and the differences between NTT and WTT, see the [Token Transfers Overview](/docs/products/token-transfers/overview/){target=\\_blank}.\n\nBeyond asset transfers, Wormhole provides additional tools for cross-chain data and governance."}
{"page_id": "products-overview", "page_title": "Compare Wormhole's Cross-Chain Solutions", "index": 1, "depth": 2, "title": "Bridging UI", "anchor": "bridging-ui", "start_char": 3494, "end_char": 3752, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "## Bridging UI\n\n[**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."}
{"page_id": "products-overview", "page_title": "Compare Wormhole's Cross-Chain Solutions", "index": 2, "depth": 2, "title": "Real-time Data", "anchor": "real-time-data", "start_char": 3752, "end_char": 3997, "estimated_token_count": 58, "token_estimator": "heuristic-v1", "text": "## Real-time Data\n\n[**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."}
{"page_id": "products-overview", "page_title": "Compare Wormhole's Cross-Chain Solutions", "index": 3, "depth": 2, "title": "Multichain Governance", "anchor": "multichain-governance", "start_char": 3997, "end_char": 4266, "estimated_token_count": 53, "token_estimator": "heuristic-v1", "text": "## Multichain Governance\n\n[**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."}
{"page_id": "products-queries-faqs", "page_title": "Queries FAQs", "index": 0, "depth": 2, "title": "What is Queries?", "anchor": "what-is-queries", "start_char": 16, "end_char": 459, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "## What is Queries?\n\nQueries is Wormhole's on-demand, Guardian-attested data service. It lets you fetch real-time, verifiable on-chain data via a simple REST endpoint and use the signed result on-chain without sending a transaction or paying gas. You can request data on one chain and use the verified result on another. For a quick video summary, watch the [Queries speed round](https://www.youtube.com/watch?v=q-s8j7GAlfQ){target=\\_blank}."}
{"page_id": "products-queries-faqs", "page_title": "Queries FAQs", "index": 1, "depth": 2, "title": "What libraries are available to handle queries?", "anchor": "what-libraries-are-available-to-handle-queries", "start_char": 459, "end_char": 1828, "estimated_token_count": 346, "token_estimator": "heuristic-v1", "text": "## What libraries are available to handle queries?\n\n - The [Query TypeScript SDK](https://www.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.\n\n- 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.\n\n- [`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.\n\n- 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.\n\n!!! note\n    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."}
{"page_id": "products-queries-faqs", "page_title": "Queries FAQs", "index": 2, "depth": 2, "title": "Are there any query examples?", "anchor": "are-there-any-query-examples", "start_char": 1828, "end_char": 2578, "estimated_token_count": 205, "token_estimator": "heuristic-v1", "text": "## Are there any query examples?\n\nCertainly. 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:\n\n- [Basic Example Query Demo](https://github.com/wormholelabs-xyz/example-queries-demo/){target=\\_blank}\n- [Solana Stake Pool Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-stake-pool){target=\\_blank}\n- [Solana Program Derived Address (PDA) / Token Account Balance Example Query](https://github.com/wormholelabs-xyz/example-queries-solana-pda){target=\\_blank}\n- [Solana Queries Verification Example](https://github.com/wormholelabs-xyz/example-queries-solana-verify){target=\\_blank}"}
{"page_id": "products-queries-faqs", "page_title": "Queries FAQs", "index": 3, "depth": 2, "title": "What is the format of the response signature?", "anchor": "what-is-the-format-of-the-response-signature", "start_char": 2578, "end_char": 4467, "estimated_token_count": 437, "token_estimator": "heuristic-v1", "text": "## What is the format of the response signature?\n\nThe 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:\n\n```keccak256(\"query_response_0000000000000000000|\"+keccak256(responseBytes))``` \n\nSee 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.\n\n!!! note\n    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://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\\_blank} accounts for this as well as structuring the signatures into an `IWormhole.SignatureStruct[]`.\n\n## Can anyone run a query proxy server?\n\nPermissions 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.\n\nIt 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.\n\n## What Does Queries Offer over an RPC Service\n\nWormhole 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."}
{"page_id": "products-queries-get-started", "page_title": "Get Started with Queries", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 525, "end_char": 854, "estimated_token_count": 88, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, make sure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n - A basic understanding of JavaScript or TypeScript.\n - An RPC endpoint for a supported chain (e.g., Ethereum Sepolia).\n - A Wormhole Queries API key."}
{"page_id": "products-queries-get-started", "page_title": "Get Started with Queries", "index": 1, "depth": 2, "title": "Request an API Key", "anchor": "request-an-api-key", "start_char": 854, "end_char": 1445, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "## Request an API Key\n\nWormhole Queries is in closed beta, but you can start building today.\n\nTo 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.\n\nTo 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."}
{"page_id": "products-queries-get-started", "page_title": "Get Started with Queries", "index": 2, "depth": 2, "title": "Construct a Query and Decode the Response", "anchor": "construct-a-query-and-decode-the-response", "start_char": 1445, "end_char": 5832, "estimated_token_count": 1024, "token_estimator": "heuristic-v1", "text": "## Construct a Query and Decode the Response\n\nUsing 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.\n\n1. Create a new directory for your script and initialize a Node.js project:\n\n    ```bash\n    mkdir queries\n    cd queries\n    npm init -y\n    ```\n\n2. 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. This example uses the Queries SDK version `0.0.14`:\n\n    ```bash\n    npm install axios web3 @wormhole-foundation/wormhole-query-sdk@0.0.14\n    npm install -D tsx typescript\n    ```\n\n3. Add a new `query.ts` script where you will write and run your query logic:\n\n    ```bash\n    touch query.ts\n    ```\n\n4. 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:\n\n    ```typescript\n    // Import the SDK types and helpers for making the query\n    import {\n      EthCallQueryRequest,\n      EthCallQueryResponse,\n      PerChainQueryRequest,\n      QueryRequest,\n      QueryResponse,\n    } from '@wormhole-foundation/wormhole-query-sdk';\n    import axios from 'axios';\n    import * as eth from 'web3';\n\n    // Define the endpoint and query parameters\n    const query_url = 'https://testnet.query.wormhole.com/v1/query';\n    const rpc = 'https://ethereum-sepolia.rpc.subquery.network/public';\n    const chain_id = 10002; // Sepolia (Wormhole chain ID)\n    const token = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'; // USDC contract\n    const data = '0x06fdde03'; // function selector for `name()`\n\n    // Load your API key from environment variables\n    const apiKey = process.env.API_KEY;\n    if (!apiKey) throw new Error('API_KEY is not set in your environment');\n\n    (async () => {\n      // Fetch the latest block number (required to anchor the query)\n      const latestBlock = (\n        await axios.post(rpc, {\n          method: 'eth_getBlockByNumber',\n          params: ['latest', false],\n          id: 1,\n          jsonrpc: '2.0',\n        })\n      ).data?.result?.number;\n\n      // Build the query targeting the token contract's name() function\n      const request = new QueryRequest(1, [\n        new PerChainQueryRequest(\n          chain_id,\n          new EthCallQueryRequest(latestBlock, [{ to: token, data: data }])\n        ),\n      ]);\n      const serialized = request.serialize();\n\n      // Send the query to the Wormhole Query Proxy\n      const response = await axios.post(\n        query_url,\n        { bytes: Buffer.from(serialized).toString('hex') },\n        { headers: { 'X-API-Key': apiKey } }\n      );\n\n      // Decode the response returned by the Guardian network\n      const queryResponse = QueryResponse.from(response.data.bytes);\n      const chainResponse = queryResponse.responses[0]\n        .response as EthCallQueryResponse;\n      const name = eth.eth.abi.decodeParameter('string', chainResponse.results[0]);\n\n      // Output the results\n      console.log('\\n\\nParsed chain response:');\n      console.log(chainResponse);\n      console.log('\\nToken name:', name);\n    })();\n    ```\n\n5. Use your API key to execute the script:\n\n    ```bash\n    API_KEY=INSERT_QUERIES_API_KEY npx tsx query.ts\n    ```\n\nThe expected output should be similar to this:\n\n<div id=\"termynal\" data-termynal>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>API_KEY=123_456_789 npx tsx query.ts</span>\n\t<span data-ty>Parsed chain response:</span>\n\t<span data-ty>EthCallQueryResponse {</span>\n\t<span data-ty>blockNumber: 8193548n,</span>\n\t<span data-ty>blockHash: '0xef97290e043a530dd2cdf2d4c513397495029cdf2ef3e916746c837dadda51a8',</span>\n    <span data-ty>blockTime: 1745595132000000n,</span>\n    <span data-ty>results: [ '0x000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000045553444300000000000000000000000000000000000000000000000000000000']</span>\n    <span data-ty>} </span>\n    <span data-ty>  </span>\n    <span data-ty>Token name: USDC</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>"}
{"page_id": "products-queries-get-started", "page_title": "Get Started with Queries", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 5832, "end_char": 6766, "estimated_token_count": 247, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow 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.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Query Solana**\n\n    ---\n\n    Try fetching Solana stake pools to see how cross-chain queries apply beyond EVM.\n\n    [:custom-arrow: See the Queries Demo](https://github.com/wormhole-foundation/demo-queries-ts/blob/main/src/query_solana_stake_pool.ts){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Use Queries**\n\n    ---\n\n    Take a deeper look at the complete Queries lifecycle.\n\n    [:custom-arrow: Use Queries](/docs/products/queries/guides/use-queries/)\n\n-   :octicons-book-16:{ .lg .middle } **Supported Networks**\n\n    ---\n\n    See where Queries are supported.\n\n    [:custom-arrow: Browse Supported Networks](/docs/products/queries/reference/supported-networks/)\n\n</div>"}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 0, "depth": 2, "title": "Construct a Query {: #construct-a-query}", "anchor": "construct-a-query-construct-a-query", "start_char": 424, "end_char": 2565, "estimated_token_count": 544, "token_estimator": "heuristic-v1", "text": "## Construct a Query {: #construct-a-query}\n\nYou 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. \n\n```jsx\nnpm i @wormhole-foundation/wormhole-query-sdk axios\n```\n\nIn order to make an `EthCallQueryRequest`, you need a specific block number or hash as well as the call data to request.\n\nYou can request the latest block from a public node using `eth_getBlockByNumber`.\n\n```jsx\nconst rpc = 'https://ethereum.publicnode.com';\n  const latestBlock: string = (\n    await axios.post(rpc, {\n      method: 'eth_getBlockByNumber',\n      params: ['latest', false],\n      id: 1,\n      jsonrpc: '2.0',\n    })\n  ).data?.result?.number;\n```\n\nThen construct the call data.\n\n```jsx\nconst callData: EthCallData = {\n  to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH\n  data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature(\"totalSupply()\")\n};\n```\n\nFinally, put it all together in a `QueryRequest`.\n\n```jsx\n  // Form the query request\n  const request = new QueryRequest(\n    0, // Nonce\n    [\n      new PerChainQueryRequest(\n        2, // Ethereum Wormhole Chain ID\n        new EthCallQueryRequest(latestBlock, [callData])\n      ),\n    ]\n  );\n```\n\nThis 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.\n\n```jsx\n  console.log(JSON.stringify(request, undefined, 2));\n  // {\n  //   \"nonce\": 0,\n  //   \"requests\": [\n  //     {\n  //       \"chainId\": 2,\n  //       \"query\": {\n  //         \"callData\": [\n  //           {\n  //             \"to\": \"0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2\",\n  //             \"data\": \"0x18160ddd\"\n  //           }\n  //         ],\n  //         \"blockTag\": \"0x11e9068\"\n  //       }\n  //     }\n  //   ],\n  //   \"version\": 1\n  // }\n```"}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 1, "depth": 2, "title": "Mock a Query", "anchor": "mock-a-query", "start_char": 2565, "end_char": 5608, "estimated_token_count": 734, "token_estimator": "heuristic-v1", "text": "## Mock a Query\n\nFor 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.\n\n```jsx\n  const mock = new QueryProxyMock({ 2: rpc });\n  const mockData = await mock.mock(request);\n  console.log(mockData);\n  // {\n  //   signatures: ['...'],\n  //   bytes: '...'\n  // }\n```\n\nThis response is suited for on-chain use, but the SDK also includes a parser to make the results readable via the client.\n\n```jsx\n  const mockQueryResponse = QueryResponse.from(mockData.bytes);\n  const mockQueryResult = (\n    mockQueryResponse.responses[0].response as EthCallQueryResponse\n  ).results[0];\n  console.log(\n    `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})`\n  );\n  // Mock Query Result:\n  // 0x000000000000000000000000000000000000000000029fd09d4d81addb3ccfee\n  // (3172556167631284394053614)\n```\n\nTesting this all together might look like the following:\n\n```jsx\nimport {\n  EthCallData,\n  EthCallQueryRequest,\n  EthCallQueryResponse,\n  PerChainQueryRequest,\n  QueryProxyMock,\n  QueryRequest,\n  QueryResponse,\n} from '@wormhole-foundation/wormhole-query-sdk';\nimport axios from 'axios';\n\nconst rpc = 'https://ethereum.publicnode.com';\nconst callData: EthCallData = {\n  to: '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', // WETH\n  data: '0x18160ddd', // web3.eth.abi.encodeFunctionSignature(\"totalSupply()\")\n};\n\n(async () => {\n  const latestBlock: string = (\n    await axios.post(rpc, {\n      method: 'eth_getBlockByNumber',\n      params: ['latest', false],\n      id: 1,\n      jsonrpc: '2.0',\n    })\n  ).data?.result?.number;\n  if (!latestBlock) {\n    console.error(`❌ Invalid block returned`);\n    return;\n  }\n  console.log('Latest Block:     ', latestBlock, `(${BigInt(latestBlock)})`);\n  const targetResponse = await axios.post(rpc, {\n    method: 'eth_call',\n    params: [callData, latestBlock],\n    id: 1,\n    jsonrpc: '2.0',\n  });\n  // console.log(finalizedResponse.data);\n  if (targetResponse.data.error) {\n    console.error(`❌ ${targetResponse.data.error.message}`);\n  }\n  const targetResult = targetResponse.data?.result;\n  console.log('Target Result:    ', targetResult, `(${BigInt(targetResult)})`);\n  // Form the query request\n  const request = new QueryRequest(\n    0, // Nonce\n    [\n      new PerChainQueryRequest(\n        2, // Ethereum Wormhole Chain ID\n        new EthCallQueryRequest(latestBlock, [callData])\n      ),\n    ]\n  );\n  console.log(JSON.stringify(request, undefined, 2));\n  const mock = new QueryProxyMock({ 2: rpc });\n  const mockData = await mock.mock(request);\n  console.log(mockData);\n  const mockQueryResponse = QueryResponse.from(mockData.bytes);\n  const mockQueryResult = (\n    mockQueryResponse.responses[0].response as EthCallQueryResponse\n  ).results[0];\n  console.log(\n    `Mock Query Result: ${mockQueryResult} (${BigInt(mockQueryResult)})`\n  );\n})();\n```"}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 2, "depth": 3, "title": "Fork Testing", "anchor": "fork-testing", "start_char": 5608, "end_char": 6746, "estimated_token_count": 269, "token_estimator": "heuristic-v1", "text": "### Fork Testing\n\nIt is common to test against a local fork of Mainnet with something like\n\n```jsx\nanvil --fork-url https://ethereum.publicnode.com\n```\n\nIn 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.\n\nHere'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.\n\n```jsx\nnpx @wormhole-foundation/wormhole-cli evm hijack -a 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B -g 0xbeFA429d57cD18b7F8A4d91A2da9AB4AF05d0FBe\n```\n\nIf you are using `EthCallWithFinality`, you will need to mine additional blocks (32 if using [Anvil](https://getfoundry.sh/anvil/overview#anvil){target=\\_blank}) after the latest transaction for it to become finalized. Anvil supports [auto-mining](https://getfoundry.sh/anvil/reference#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`."}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 3, "depth": 2, "title": "Make a Query Request", "anchor": "make-a-query-request", "start_char": 6746, "end_char": 7414, "estimated_token_count": 169, "token_estimator": "heuristic-v1", "text": "## Make a Query Request\n\nThe standardized means of making a `QueryRequest` with an API key is as follows:\n\n```jsx\nconst serialized = request.serialize();\nconst proxyResponse =\n  (await axios.post) <\n  QueryProxyQueryResponse >\n  (QUERY_URL,\n  {\n    bytes: Buffer.from(serialized).toString(\"hex\"),\n  },\n  { headers: { \"X-API-Key\": YOUR_API_KEY } });\n```\n\nRemember to always take steps to protect your sensitive API keys, such as defining them in `.env` files and including such files in your `.gitignore`.\n\nA Testnet Query Proxy is available at `https://testnet.query.wormhole.com/v1/query`\n\nA Mainnet Query Proxy is available at `https://query.wormhole.com/v1/query`"}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 4, "depth": 2, "title": "Verify a Query Response On-Chain", "anchor": "verify-a-query-response-on-chain", "start_char": 7414, "end_char": 14643, "estimated_token_count": 1323, "token_estimator": "heuristic-v1", "text": "## Verify a Query Response On-Chain\n\nA [`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:\n\n```bash\nforge install wormhole-foundation/wormhole-solidity-sdk\n```\n\nBroadly, using a query response on-chain comes down to three main steps:\n\n   1. Parse and verify the query response.\n   2. The `parseAndVerifyQueryResponse` handles verifying the Guardian signatures against the current Guardian set stored in the Core bridge contract.\n   3. Validate the request details. This may be different for every integrator depending on their use case, but generally checks the following:\n    - Is the request against the expected chain?\n    - Is the request of the expected type? The `parseEthCall` helpers perform this check when parsing.\n    - 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.\n    - Is the request for the expected contract and function signature? The `validateMultipleEthCallData` can help with non-parameter-dependent cases.\n    - Is the result of the expected length for the expected result type?\n   4. Run `abi.decode` on the result.\n\nSee 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.\n\n??? code \"View the complete `QueryDemo`\"\n    ```solidity\n    // contracts/query/QueryDemo.sol\n    // SPDX-License-Identifier: Apache 2\n\n    pragma solidity ^0.8.0;\n\n    import \"wormhole-solidity-sdk/libraries/BytesParsing.sol\";\n    import \"wormhole-solidity-sdk/interfaces/IWormhole.sol\";\n    import \"wormhole-solidity-sdk/QueryResponse.sol\";\n\n    error InvalidOwner();\n    // @dev for the onlyOwner modifier\n    error InvalidCaller();\n    error InvalidCalldata();\n    error InvalidForeignChainID();\n    error ObsoleteUpdate();\n    error StaleUpdate();\n    error UnexpectedResultLength();\n    error UnexpectedResultMismatch();\n\n    /// @dev QueryDemo is an example of using the QueryResponse library to parse and verify Cross Chain Query (CCQ) responses.\n    contract QueryDemo is QueryResponse {\n        using BytesParsing for bytes;\n\n        struct ChainEntry {\n            uint16 chainID;\n            address contractAddress;\n            uint256 counter;\n            uint256 blockNum;\n            uint256 blockTime;\n        }\n\n        address private immutable owner;\n        uint16 private immutable myChainID;\n        mapping(uint16 => ChainEntry) private counters;\n        uint16[] private foreignChainIDs;\n\n        bytes4 public GetMyCounter = bytes4(hex\"916d5743\");\n\n        constructor(address _owner, address _wormhole, uint16 _myChainID) QueryResponse(_wormhole) {\n            if (_owner == address(0)) {\n                revert InvalidOwner();\n            }\n            owner = _owner;\n\n            myChainID = _myChainID;\n            counters[_myChainID] = ChainEntry(_myChainID, address(this), 0, 0, 0);\n        }\n\n        // updateRegistration should be used to add the other chains and to set / update contract addresses.\n        function updateRegistration(uint16 _chainID, address _contractAddress) public onlyOwner {\n            if (counters[_chainID].chainID == 0) {\n                foreignChainIDs.push(_chainID);\n                counters[_chainID].chainID = _chainID;\n            }\n\n            counters[_chainID].contractAddress = _contractAddress;\n        }\n\n        // getMyCounter (call signature 916d5743) returns the counter value for this chain. It is meant to be used in a cross chain query.\n        function getMyCounter() public view returns (uint256) {\n            return counters[myChainID].counter;\n        }\n\n        // getState() returns this chain's view of all the counters. It is meant to be used in the front end.\n        function getState() public view returns (ChainEntry[] memory) {\n            ChainEntry[] memory ret = new ChainEntry[](foreignChainIDs.length + 1);\n            ret[0] = counters[myChainID];\n            uint256 length = foreignChainIDs.length;\n\n            for (uint256 i = 0; i < length;) {\n                ret[i + 1] = counters[foreignChainIDs[i]];\n                unchecked {\n                    ++i;\n                }\n            }\n\n            return ret;\n        }\n\n        // @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.\n        function updateCounters(bytes memory response, IWormhole.Signature[] memory signatures) public {\n            ParsedQueryResponse memory r = parseAndVerifyQueryResponse(response, signatures);\n            uint256 numResponses = r.responses.length;\n            if (numResponses != foreignChainIDs.length) {\n                revert UnexpectedResultLength();\n            }\n\n            for (uint256 i = 0; i < numResponses;) {\n                // Create a storage pointer for frequently read and updated data stored on the blockchain\n                ChainEntry storage chainEntry = counters[r.responses[i].chainId];\n                if (chainEntry.chainID != foreignChainIDs[i]) {\n                    revert InvalidForeignChainID();\n                }\n\n                EthCallQueryResponse memory eqr = parseEthCallQueryResponse(r.responses[i]);\n\n                // Validate that update is not obsolete\n                validateBlockNum(eqr.blockNum, chainEntry.blockNum);\n\n                // Validate that update is not stale\n                validateBlockTime(eqr.blockTime, block.timestamp - 300);\n\n                if (eqr.result.length != 1) {\n                    revert UnexpectedResultMismatch();\n                }\n\n                // Validate addresses and function signatures\n                address[] memory validAddresses = new address[](1);\n                bytes4[] memory validFunctionSignatures = new bytes4[](1);\n                validAddresses[0] = chainEntry.contractAddress;\n                validFunctionSignatures[0] = GetMyCounter;\n\n                validateMultipleEthCallData(eqr.result, validAddresses, validFunctionSignatures);\n\n                require(eqr.result[0].result.length == 32, \"result is not a uint256\");\n\n                chainEntry.blockNum = eqr.blockNum;\n                chainEntry.blockTime = eqr.blockTime / 1_000_000;\n                chainEntry.counter = abi.decode(eqr.result[0].result, (uint256));\n\n                unchecked {\n                    ++i;\n                }\n            }\n\n            counters[myChainID].blockNum = block.number;\n            counters[myChainID].blockTime = block.timestamp;\n            counters[myChainID].counter += 1;\n        }\n\n        modifier onlyOwner() {\n            if (owner != msg.sender) {\n                revert InvalidOwner();\n            }\n            _;\n        }\n    }\n    ```"}
{"page_id": "products-queries-guides-use-queries", "page_title": "Use Queries", "index": 5, "depth": 2, "title": "Submit a Query Response On-Chain", "anchor": "submit-a-query-response-on-chain", "start_char": 14643, "end_char": 15173, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "## Submit a Query Response On-Chain\n\nThe `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.\n\nThis example submits the transaction to the demo contract:\n\n```jsx\nconst tx = await contract.updateCounters(\n  `0x${response.data.bytes}`,\n  signaturesToEvmStruct(response.data.signatures)\n);\n```"}
{"page_id": "products-queries-overview", "page_title": "Queries Overview", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 230, "end_char": 904, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **On-demand data access**: Fetch price feeds, interest rates, and other data in real-time.\n- **Guardian attested**: All data is signed by [Guardians](/docs/protocol/infrastructure/guardians/){target=\\_blank} for trustless validation.\n- **Cross-chain ready**: Request data on one chain, use it on another.\n- **Smart contract integration**: Results are delivered as [Verified Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\\_blank}, readable by smart contracts.\n- **Chain agnostic**: Works across supported EVM chains, Solana, Sui, and [other supported networks](/docs/products/queries/reference/supported-networks/){target=\\_blank}."}
{"page_id": "products-queries-overview", "page_title": "Queries Overview", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 904, "end_char": 2069, "estimated_token_count": 254, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nA 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.\n\n1. An off-chain app sends a query to the CCQ Server via HTTPS.\n2. The CCQ Server checks the request and shares it with [Guardians](/docs/protocol/infrastructure/guardians/){target=\\_blank}.\n3. [Guardians](/docs/protocol/infrastructure/guardians/){target=\\_blank} independently fetch the data, verify it, and sign the result.\n4. Once enough Guardians (2/3 quorum) return matching results, the CCQ Server aggregates and sends the final response.\n5. The off-chain app submits this result to a smart contract, which verifies the Guardian signatures and uses the data.\n\nThe 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.\n\n![The architecture flow of a query](/docs/images/products/queries/overview/overview-1.webp)"}
{"page_id": "products-queries-overview", "page_title": "Queries Overview", "index": 2, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 2069, "end_char": 4107, "estimated_token_count": 621, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\nQueries enable a wide range of cross-chain applications. Below are common use cases and the Wormhole stack components you can use to build them.\n\n- **Borrowing and Lending Across Chains (e.g., [Folks Finance](https://wormhole.com/case-studies/folks-finance){target=\\_blank})**\n\n    - **[Queries](/docs/products/queries/get-started/){target=\\_blank}**: Fetch rates and prices in real-time.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Sync actions between chains.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}**: Transfer collateral as native assets.\n\n- **Cross-Chain Swaps and Liquidity Aggregation (e.g., [StellaSwap](https://app.stellaswap.com/exchange/swap){target=\\_blank})**\n\n    - **[Queries](/docs/products/queries/get-started/){target=\\_blank}**: Fetch live prices for optimal trade execution.\n    - **[Connect](/docs/products/connect/overview/){target=\\_blank}**: Handle user-friendly asset transfers.\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}**: Moves native tokens.\n\n- **Real-Time Price Feeds and Trading Strategies (e.g., [Infinex](https://wormhole.com/case-studies/infinex){target=\\_blank})**\n\n    - **[Queries](/docs/products/queries/get-started/){target=\\_blank}**: Fetch price feeds.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Trigger trades.\n\n- **Multichain Prediction Markets**\n\n    - **[Queries](/docs/products/queries/get-started/){target=\\_blank}**: Fetch market data and odds.\n    - **[Settlement](/docs/products/settlement/overview/){target=\\_blank}**: Automates token execution.\n\n- **Oracle Networks (e.g., [Pyth](https://wormhole.com/case-studies/pyth){target=\\_blank})**\n\n    - **[Queries](/docs/products/queries/get-started/){target=\\_blank}**: Source data from chains.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Ensures tamper-proof data relay across networks."}
{"page_id": "products-queries-overview", "page_title": "Queries Overview", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 4107, "end_char": 4242, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nFollow these steps to get started with Queries:\n\n[timeline(docs/.snippets/text/products/queries/queries-timeline.json)]"}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 0, "depth": 2, "title": "Supported Query Types", "anchor": "supported-query-types", "start_char": 608, "end_char": 983, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "## Supported Query Types\n\nWormhole currently supports five distinct query types, each designed for specific data retrieval tasks across various chains.\n\n!!! note \n    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)."}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 1, "depth": 3, "title": "eth_call", "anchor": "eth_call", "start_char": 983, "end_char": 1638, "estimated_token_count": 160, "token_estimator": "heuristic-v1", "text": "### eth_call\n\nThe [`eth_call`](https://ethereum.org/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: \n\n- **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.\n- **Capacity**: Batch up to 255 individual in a single `eth_call` query.\n- **Result data**: Provides the specified block's number, hash, timestamp, and the output from the contract call."}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 2, "depth": 3, "title": "eth_call_by_timestamp", "anchor": "eth_call_by_timestamp", "start_char": 1638, "end_char": 2246, "estimated_token_count": 125, "token_estimator": "heuristic-v1", "text": "### eth_call_by_timestamp\n\nThe [`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.\n\nThe query returns your target timestamp and the latest block details at or before your specified `target_time` immediately preceding the subsequent block."}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 3, "depth": 3, "title": "eth_call_with_finality", "anchor": "eth_call_with_finality", "start_char": 2246, "end_char": 3217, "estimated_token_count": 199, "token_estimator": "heuristic-v1", "text": "### eth_call_with_finality\n\nThe [`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.\n\nYou can specify one of two finality levels for your query:\n\n- **Finalized**: Indicates the highest level of assurance that a block is permanent and will not be altered or removed from the chain.\n- **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.\n\n!!! note\n    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."}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 4, "depth": 3, "title": "sol_account", "anchor": "sol_account", "start_char": 3217, "end_char": 3691, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "### sol_account\n\nThe [`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"}
{"page_id": "products-queries-reference-supported-methods", "page_title": "Queries Supported Methods", "index": 5, "depth": 3, "title": "sol_pda", "anchor": "sol_pda", "start_char": 3691, "end_char": 4373, "estimated_token_count": 165, "token_estimator": "heuristic-v1", "text": "### sol_pda\n\nThe [`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/basics/pda){target=\\_blank}. It streamlines the standard process of deriving a PDA and fetching its account data.\n\nThis 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://www.solana-program.com/docs/associated-token-account){target=\\_blank}."}
{"page_id": "products-queries-reference-supported-networks", "page_title": "Queries Supported Networks", "index": 0, "depth": 2, "title": "Mainnet", "anchor": "mainnet", "start_char": 1389, "end_char": 2984, "estimated_token_count": 623, "token_estimator": "heuristic-v1", "text": "## Mainnet\n\n|     Chain     | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History |\n|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:|\n| Solana | 1 | ✅ | ❌ | - | - |\n| Ethereum | 2 | ✅ | ✅ | ✅ | 128 blocks |\n| BNB Smart Chain | 4 | ✅ | ✅ | ✅ | 128 blocks |\n| Polygon | 5 | ✅ | ✅ | ✅ | 128 blocks |\n| Avalanche | 6 | ✅ | ✅ | ✅ | 32 blocks |\n| Fantom | 10 | ✅ | ✅ | ✅ | 16 blocks |\n| Kaia | 13 | ✅ | ✅ | ✅ | 128 blocks |\n| Celo | 14 | ✅ | ℹ️ | ✅ | 128 blocks |\n| Moonbeam | 16 | ✅ | ℹ️ | ✅ | 256 blocks |\n| Arbitrum | 23 | ✅ | ✅ | ✅ | ~6742 blocks |\n| Optimism | 24 | ✅ | ✅ | ❌ | 128 blocks |\n| Base | 30 | ✅ | ✅ | ✅ | archive |\n| Scroll | 34 | ✅ | ✅ | - | - |\n| Mantle | 35 | ✅ | ✅ | - | - |\n| X Layer | 37 | ✅ | ✅ | - | - |\n| Linea | 38 | ✅ | ✅ | - | - |\n| Berachain | 39 | ✅ | ✅ | - | - |\n| SeiEVM | 40 | ✅ | ✅ | - | - |\n| Unichain | 44 | ✅ | ✅ | - | - |\n| World Chain | 45 | ✅ | ✅ | - | - |\n| Ink | 46 | ✅ | ✅ | - | - |\n| HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' } | 47 | ✅ | ✅ | - | - |\n| Monad | 48 | ✅ | ✅ | - | - |\n| Mezo | 50 | ✅ | ✅ | - | - |\n| Fogo | 51 | ✅ | ✅ | - | - |\n| Converge | 53 | ✅ | ✅ | - | - |\n| Plume | 55 | ✅ | ✅ | - | - |\n| XRPL-EVM | 57 | ✅ | ✅ | - | - |\n| Plasma | 58 | ✅ | ✅ | - | - |\n| CreditCoin | 59 | ✅ | ✅ | - | - |\n| Moca | 63 | ✅ | ✅ | - | - |\n| MegaETH | 64 | ✅ | ✅ | - | - |\n| 0G (Zero Gravity) | 67 | ✅ | ✅ | - | - |"}
{"page_id": "products-queries-reference-supported-networks", "page_title": "Queries Supported Networks", "index": 1, "depth": 2, "title": "Testnet", "anchor": "testnet", "start_char": 2984, "end_char": 3676, "estimated_token_count": 259, "token_estimator": "heuristic-v1", "text": "## Testnet\n\n|     Chain     | Wormhole Chain ID | eth_call | eth_call_by_timestamp | eth_call_with_finality | Expected History |\n|:-------------:|:-----------------:|:--------:|:---------------------:|:----------------------:|:----------------:|\n| Ethereum Sepolia | 10002 | ✅ | ✅ | - | - |\n| Arbitrum Sepolia | 10003 | ✅ | ✅ | - | - |\n| Base Sepolia | 10004 | ✅ | ✅ | - | - |\n| Optimism Sepolia | 10005 | ✅ | ✅ | - | - |\n| Ethereum Holesky | 10006 | ✅ | ✅ | - | - |\n| Polygon Amoy | 10007 | ✅ | ✅ | - | - |\n| Monad Testnet | 10009 | ✅ | ✅ | - | - |\n\nℹ️`EthCallByTimestamp` arguments for `targetBlock` and `followingBlock` are currently required for requests to be successful on these chains."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1116, "end_char": 1899, "estimated_token_count": 211, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore starting, make sure you have the following set up:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your system\n - A [Wormhole Queries API key](/docs/products/queries/get-started/#request-an-api-key){target=\\_blank}\n - Access to an EVM-compatible [testnet RPC](https://chainlist.org/?testnets=true){target=\\_blank}, such as Arbitrum Sepolia\n - A [Witnet data feed identifier](https://docs.witnet.io/smart-contracts/witnet-data-feeds/addresses){target=\\_blank} (this tutorial uses the ETH/USD feed as an example)\n\n    You can use a different Witnet feed or testnet if you prefer. Make sure to update the environment variables later in this tutorial with the correct values for your setup."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 1, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 1899, "end_char": 4541, "estimated_token_count": 621, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nIn this section, you will create a new Next.js project, install the required dependencies, and configure the environment variables needed to fetch data from Wormhole Queries.\n\n1. **Create a new Next.js app**: Enable TypeScript, Tailwind CSS, and the `src/` directory when prompted. You can configure the remaining options as you like. Create your app using the following command: \n\n    ```bash\n    npx create-next-app@latest live-crypto-prices\n    cd live-crypto-prices\n    ```\n\n2. **Install dependencies**: Add the required packages.\n\n    ```bash\n    npm install @wormhole-foundation/wormhole-query-sdk axios ethers\n    ```\n\n    - [`@wormhole-foundation/wormhole-query-sdk`](https://www.npmjs.com/package/@wormhole-foundation/wormhole-query-sdk){target=\\_blank}: Build, send, and decode Wormhole Queries.\n    - [`axios`](https://www.npmjs.com/package/axios){target=\\_blank}: Make JSON-RPC and Query Proxy requests.\n    - [`ethers`](https://www.npmjs.com/package/ethers){target=\\_blank}: Handle ABI encoding and decoding for Witnet calls.\n\n3. **Add environment variables**: Create a file named `.env.local` in the project root.\n\n    ```env\n    # Wormhole Query Proxy\n    QUERY_URL=https://testnet.query.wormhole.com/v1/query\n    QUERIES_API_KEY=INSERT_API_KEY\n\n    # Chain and RPC\n    WORMHOLE_CHAIN_ID=10003\n    RPC_URL=https://arbitrum-sepolia.drpc.org\n\n    # Witnet Price Router on Arbitrum Sepolia\n    CALL_TO=0x1111AbA2164AcdC6D291b08DfB374280035E1111\n\n    # ETH/USD feed on Witnet, six decimals\n    FEED_ID4=0x3d15f701\n    FEED_DECIMALS=6\n    FEED_HEARTBEAT_SEC=86400\n    ```\n\n    !!! warning\n        Make sure to add the `.env.local` file to your `.gitignore` to exclude it from version control. Never commit API keys to your repository.\n\n    You can use a different Witnet feed or network by updating `CALL_TO`, `FEED_ID4`, `FEED_DECIMALS`, and `WORMHOLE_CHAIN_ID`. These values allow the app to fetch a live ETH/USD price with proper scaling, timestamps, and a signed response.\n    \n\n4. **Add a configuration file**: Create `src/lib/config.ts` to access environment variables throughout the app.\n\n    ```ts title=\"src/lib/config.ts\"\n    export const QUERY_URL = process.env.QUERY_URL!;\n    export const QUERIES_API_KEY = process.env.QUERIES_API_KEY!;\n    export const RPC_URL = process.env.RPC_URL!;\n\n    export const DEFAULTS = {\n      chainId: Number(process.env.WORMHOLE_CHAIN_ID || 0),\n      to: process.env.CALL_TO || '',\n      feedId4: process.env.FEED_ID4 || '',\n      feedDecimals: Number(process.env.FEED_DECIMALS || 0),\n      feedHeartbeatSec: Number(process.env.FEED_HEARTBEAT_SEC || 0),\n    };\n    ```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 2, "depth": 2, "title": "Build the Server Logic", "anchor": "build-the-server-logic", "start_char": 4541, "end_char": 4778, "estimated_token_count": 48, "token_estimator": "heuristic-v1", "text": "## Build the Server Logic\n\nIn this section, you will implement the backend that powers the widget. You will encode the Witnet call, create and send a Wormhole Query, decode the signed response, and expose an API route for the frontend."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 3, "depth": 3, "title": "Encode Witnet Call and Build the Request", "anchor": "encode-witnet-call-and-build-the-request", "start_char": 4778, "end_char": 7125, "estimated_token_count": 545, "token_estimator": "heuristic-v1", "text": "### Encode Witnet Call and Build the Request\n\nFirst, encode the function call for Witnet's Price Router using the feed ID and package it into a Wormhole Query request. This query will be anchored to the latest block, ensuring the data you receive is verifiably tied to a recent snapshot of the chain state. This helper will return a serialized request that can be sent to the Wormhole Query Proxy.\n\n```ts title=\"src/lib/queries/buildRequest.ts\"\nimport axios from 'axios';\nimport {\n  EthCallQueryRequest,\n  PerChainQueryRequest,\n  QueryRequest,\n} from '@wormhole-foundation/wormhole-query-sdk';\nimport { Interface } from 'ethers';\n\n// ABI interface for Witnet's Price Router\nconst WITNET_IFACE = new Interface([\n  // Function signature for reading the latest price feed\n  'function latestPrice(bytes4 id) view returns (int256 value, uint256 timestamp, bytes32 drTxHash, uint8 status)',\n]);\n\n// Encode calldata for Witnet Router: latestPrice(bytes4)\nexport function encodeWitnetLatestPrice(id4: string): string {\n  // Validate feed ID format (must be a 4-byte hex)\n  if (!/^0x[0-9a-fA-F]{8}$/.test(id4)) {\n    throw new Error(`Invalid FEED_ID4: ${id4}`);\n  }\n  // Return ABI-encoded call data for latestPrice(bytes4)\n  return WITNET_IFACE.encodeFunctionData('latestPrice', [id4 as `0x${string}`]);\n}\n\nexport async function buildEthCallRequest(params: {\n  rpcUrl: string;\n  chainId: number; // Wormhole chain id\n  to: string;\n  data: string; // 0x-prefixed calldata\n}) {\n  const { rpcUrl, chainId, to, data } = params;\n\n  // Get the latest block number via JSON-RPC\n  // Short timeout prevents long hangs in the dev environment\n  const latestBlock: string = (\n    await axios.post(\n      rpcUrl,\n      {\n        method: 'eth_getBlockByNumber',\n        params: ['latest', false],\n        id: 1,\n        jsonrpc: '2.0',\n      },\n      { timeout: 5_000, headers: { 'Content-Type': 'application/json' } }\n    )\n  ).data?.result?.number;\n\n  if (!latestBlock) throw new Error('Failed to fetch latest block');\n\n  // Build a Wormhole Query that wraps an EthCall to the Witnet contract\n  const request = new QueryRequest(1, [\n    new PerChainQueryRequest(\n      chainId,\n      new EthCallQueryRequest(latestBlock, [{ to, data }])\n    ),\n  ]);\n\n  // Serialize to bytes for sending to the Wormhole Query Proxy\n  return request.serialize(); // Uint8Array\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 4, "depth": 3, "title": "Send Request to the Query Proxy", "anchor": "send-request-to-the-query-proxy", "start_char": 7125, "end_char": 8102, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "### Send Request to the Query Proxy\n\nNext, you will send the serialized query to the Wormhole Query Proxy, which forwards it to the Guardians for verification. The proxy returns a signed response containing the requested data and proof that the Guardians verified it. This step ensures that all the data your app consumes comes from a trusted and authenticated source.\n\n```ts title=\"src/lib/queries/client.ts\"\nimport axios from 'axios';\n\nexport async function postQuery({\n  queryUrl,\n  apiKey,\n  bytes,\n  timeoutMs = 25_000,\n}: {\n  queryUrl: string;\n  apiKey: string;\n  bytes: Uint8Array;\n  timeoutMs?: number;\n}) {\n  // Convert the query bytes to hex and POST to the proxy\n  const res = await axios.post(\n    queryUrl,\n    { bytes: Buffer.from(bytes).toString('hex') },\n    {\n      timeout: timeoutMs,\n      headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },\n      validateStatus: (s) => s === 200,\n    }\n  );\n  return res.data; // throws on non-200\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 5, "depth": 3, "title": "Decode and Verify Response", "anchor": "decode-and-verify-response", "start_char": 8102, "end_char": 10435, "estimated_token_count": 546, "token_estimator": "heuristic-v1", "text": "### Decode and Verify Response\n\nOnce you receive the signed response, you will decode it to extract the Witnet price data.\nHere, you will use ethers to parse the ABI-encoded return values and scale the raw integer to a readable decimal value based on the feed's configured number of decimals. This function will output a clean result containing the latest price, timestamp, and transaction reference from the Witnet feed.\n\n```ts title=\"src/lib/queries/decode.ts\"\nimport {\n  EthCallQueryResponse,\n  QueryResponse,\n} from '@wormhole-foundation/wormhole-query-sdk';\nimport { Interface, Result } from 'ethers';\n\n// ABI interface for decoding Witnet's latestPrice response\nconst WITNET_IFACE = new Interface([\n  'function latestPrice(bytes4 id) view returns (int256 value, uint256 timestamp, bytes32 drTxHash, uint8 status)',\n]);\n\n// Parse the first EthCall result from the proxy's response\nexport function parseFirstEthCallResult(proxyResponse: { bytes: string }): {\n  chainResp: EthCallQueryResponse;\n  raw: string;\n} {\n  // Decode the top-level QueryResponse from Wormhole Guardians\n  const qr = QueryResponse.from(proxyResponse.bytes);\n\n  // Extract the first chain response and its raw call result\n  const chainResp = qr.responses[0].response as EthCallQueryResponse;\n  const raw = chainResp.results[0];\n  return { chainResp, raw };\n}\n\n// Decode Witnet's latestPrice return tuple into readable fields\nexport function decodeWitnetLatestPrice(\n  raw: string,\n  decimals: number\n): { price: string; timestampSec: number; drTxHash: string } {\n  // Decode ABI-encoded result from the router call\n  const r: Result = WITNET_IFACE.decodeFunctionResult('latestPrice', raw);\n  const value = BigInt(r[0].toString());\n  const timestampSec = Number(r[1].toString());\n  const drTxHash = r[2] as string;\n\n  return {\n    price: scaleBigintToDecimalString(value, decimals),\n    timestampSec,\n    drTxHash,\n  };\n}\n\n// Convert a bigint price into a human-readable decimal string\nfunction scaleBigintToDecimalString(value: bigint, decimals: number): string {\n  const zero = BigInt(0);\n  const neg = value < zero ? '-' : '';\n  const v = value < zero ? -value : value;\n  const s = v.toString().padStart(decimals + 1, '0');\n  const i = s.slice(0, -decimals);\n  const f = s.slice(-decimals).replace(/0+$/, '');\n  return neg + (f ? `${i}.${f}` : i);\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 6, "depth": 3, "title": "Add Shared Types", "anchor": "add-shared-types", "start_char": 10435, "end_char": 11112, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "### Add Shared Types\n\nCreate a `src/lib/types.ts` file to define the structure of your API responses. These types ensure consistency between the backend and the frontend, keeping the data shape predictable and type-safe.  You will import these types in both the API route and the widget to keep your responses aligned across the app.\n\n```ts title=\"src/lib/types.ts\"\nexport interface QueryApiSuccess {\n  ok: true;\n  blockNumber: string;\n  blockTimeMicros: string;\n  price: string;\n  decimals: number;\n  updatedAt: string;\n  stale?: boolean;\n}\n\nexport interface QueryApiError {\n  ok: false;\n  error: string;\n}\nexport type QueryApiResponse = QueryApiSuccess | QueryApiError;\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 7, "depth": 3, "title": "Add  API Route for Frontend", "anchor": "add-api-route-for-frontend", "start_char": 11112, "end_char": 13972, "estimated_token_count": 623, "token_estimator": "heuristic-v1", "text": "### Add  API Route for Frontend\n\nFinally, expose an API endpoint at `/api/queries`. This route ties everything together: it builds the query, sends it, decodes the response, and returns a structured JSON payload containing the current price, timestamp, block number, and a stale flag indicating whether the feed data is still fresh. The frontend widget will call this endpoint every few seconds to display the live, verified price data.\n\n```ts title=\"src/app/api/queries/route.ts\"\nimport { NextResponse } from 'next/server';\nimport {\n  buildEthCallRequest,\n  encodeWitnetLatestPrice,\n} from '@/lib/queries/buildRequest';\nimport { postQuery } from '@/lib/queries/client';\nimport { QUERY_URL, QUERIES_API_KEY, RPC_URL, DEFAULTS } from '@/lib/config';\nimport {\n  parseFirstEthCallResult,\n  decodeWitnetLatestPrice,\n} from '@/lib/queries/decode';\nimport type { QueryApiSuccess, QueryApiError } from '@/lib/types';\n\nexport async function GET() {\n  const t0 = Date.now();\n  try {\n    // Encode the call for Witnet’s latestPrice(bytes4)\n    const data = encodeWitnetLatestPrice(DEFAULTS.feedId4);\n\n    // Build a Wormhole Query request anchored to the latest block\n    const bytes = await buildEthCallRequest({\n      rpcUrl: RPC_URL,\n      chainId: DEFAULTS.chainId,\n      to: DEFAULTS.to,\n      data,\n    });\n    const t1 = Date.now();\n\n    // Send the query to the Wormhole Query Proxy and await the signed response\n    const proxyResponse = await postQuery({\n      queryUrl: QUERY_URL,\n      apiKey: QUERIES_API_KEY,\n      bytes,\n      timeoutMs: 25_000,\n    });\n    const t2 = Date.now();\n\n    // Decode the signed Guardian response and extract Witnet data\n    const { chainResp, raw } = parseFirstEthCallResult(proxyResponse);\n    const { price, timestampSec } = decodeWitnetLatestPrice(\n      raw,\n      DEFAULTS.feedDecimals\n    );\n\n    // Log the latency of each leg for debugging\n    console.log(`RPC ${t1 - t0}ms → Proxy ${t2 - t1}ms`);\n\n    // Mark data as stale if older than the feed’s heartbeat interval\n    const heartbeat = Number(process.env.FEED_HEARTBEAT_SEC || 0);\n    const stale = heartbeat > 0 && Date.now() / 1000 - timestampSec > heartbeat;\n\n    // Return a normalized JSON payload for the frontend\n    const body: QueryApiSuccess = {\n      ok: true,\n      blockNumber: chainResp.blockNumber.toString(),\n      blockTimeMicros: chainResp.blockTime.toString(),\n      price,\n      decimals: DEFAULTS.feedDecimals,\n      updatedAt: new Date(timestampSec * 1000).toISOString(),\n      stale,\n    };\n    return NextResponse.json(body);\n  } catch (e: unknown) {\n    // Catch and return a structured error\n    const message = e instanceof Error ? e.message : String(e);\n    console.error('Error in /api/queries:', message);\n    const body: QueryApiError = { ok: false, error: message };\n    return NextResponse.json(body, { status: 500 });\n  }\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 8, "depth": 2, "title": "Price Widget", "anchor": "price-widget", "start_char": 13972, "end_char": 14180, "estimated_token_count": 39, "token_estimator": "heuristic-v1", "text": "## Price Widget\n\nIn this section, you will build a client component that fetches the signed price from your API, renders it with a freshness badge, and refreshes on an interval without overlapping requests."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 9, "depth": 3, "title": "Create Widget Component", "anchor": "create-widget-component", "start_char": 14180, "end_char": 18120, "estimated_token_count": 1014, "token_estimator": "heuristic-v1", "text": "### Create Widget Component\n\nCreate a client component that calls `/api/queries`, renders the current price, shows the last update time and block number, and displays a freshness badge based on the heartbeat. The component uses a ref to avoid overlapping requests and a timed interval to refresh automatically.\n\n```ts title=\"src/components/PriceWidget.tsx\"\n'use client';\n\nimport { useEffect, useRef, useState } from 'react';\n\n// Expected API success shape from /api/queries\ntype ApiOk = {\n  ok: true;\n  price: string;\n  updatedAt: number | string;\n  blockNumber: string;\n  blockTimeMicros: number;\n  decimals: number;\n  stale: boolean;\n};\n\n// API error shape\ntype ApiErr = { ok: false; error: string };\n\n// Format timestamps for display\nfunction formatTime(ts: number | string) {\n  let n: number;\n  if (typeof ts === 'string') {\n    const numeric = Number(ts);\n    if (Number.isFinite(numeric)) {\n      n = numeric;\n    } else {\n      const parsed = new Date(ts);\n      return Number.isNaN(parsed.getTime()) ? '—' : parsed.toLocaleString();\n    }\n  } else {\n    n = ts;\n  }\n  if (!Number.isFinite(n)) return '—';\n  // If it looks like seconds, convert to ms\n  const ms = n < 1_000_000_000_000 ? n * 1000 : n;\n  const d = new Date(ms);\n  return Number.isNaN(d.getTime()) ? '—' : d.toLocaleString();\n}\n\nexport default function PriceWidget() {\n  // UI state: fetched data, loading state, and any errors\n  const [data, setData] = useState<ApiOk | null>(null);\n  const [error, setError] = useState<string | null>(null);\n  const [loading, setLoading] = useState(false);\n\n  // Keep track of polling and prevent overlapping requests\n  const timer = useRef<NodeJS.Timeout | null>(null);\n  const inFlight = useRef(false);\n\n  // Fetch price data from the API route\n  async function fetchPrice() {\n    if (inFlight.current) return; // avoid concurrent requests\n    inFlight.current = true;\n    setLoading(true);\n    setError(null);\n\n    try {\n      const res = await fetch('/api/queries', { cache: 'no-store' });\n      const json: ApiOk | ApiErr = await res.json();\n      if (!json.ok) throw new Error(json.error);\n      setData(json);\n    } catch (e: any) {\n      setError(e?.message || 'Failed to fetch price');\n    } finally {\n      setLoading(false);\n      inFlight.current = false;\n    }\n  }\n\n  // Fetch immediately and refresh every 30 seconds\n  useEffect(() => {\n    fetchPrice();\n    timer.current = setInterval(fetchPrice, 30_000);\n    return () => {\n      if (timer.current) clearInterval(timer.current);\n    };\n  }, []);\n\n  return (\n    <div className=\"mx-auto w-full max-w-md rounded-2xl border border-gray-200 p-6 shadow-sm\">\n      <div className=\"mb-4 flex items-center justify-between\">\n        <h2 className=\"text-lg font-semibold\">ETH/USD Live Price</h2>\n        {data?.stale ? (\n          <span className=\"rounded-full bg-yellow-100 px-3 py-1 text-xs font-medium text-yellow-800\">\n            Stale\n          </span>\n        ) : (\n          <span className=\"rounded-full bg-green-100 px-3 py-1 text-xs font-medium text-green-800\">\n            Fresh\n          </span>\n        )}\n      </div>\n\n      <div className=\"space-y-2\">\n        <div className=\"text-3xl font-bold tabular-nums\">\n          {loading && !data ? 'Loading…' : data ? data.price : '—'}\n        </div>\n\n        <div className=\"text-sm text-gray-600\">\n          {data ? (\n            <>\n              Updated at {formatTime(data.updatedAt)}, block {data.blockNumber}\n            </>\n          ) : error ? (\n            <span className=\"text-red-600\">{error}</span>\n          ) : (\n            'Fetching latest price'\n          )}\n        </div>\n      </div>\n\n      <div className=\"mt-4\">\n        <button\n          onClick={fetchPrice}\n          className=\"w-full rounded-xl bg-gray-900 px-4 py-2 text-white hover:opacity-90\"\n          disabled={loading}\n        >\n          {loading ? 'Refreshing…' : 'Refresh now'}\n        </button>\n      </div>\n    </div>\n  );\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 10, "depth": 3, "title": "Add the Widget to Home Page", "anchor": "add-the-widget-to-home-page", "start_char": 18120, "end_char": 18628, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### Add the Widget to Home Page\n\nRender the widget on the home page with a simple heading and container so users see the price as soon as they load the app.\n\n```ts title=\"src/app/page.tsx\"\nimport PriceWidget from '@/components/PriceWidget';\n\nexport default function Page() {\n  return (\n    <main className=\"mx-auto flex max-w-2xl flex-col items-center p-6\">\n      <h1 className=\"mb-6 text-center text-2xl font-bold\">\n        Live Crypto Price Widget\n      </h1>\n      <PriceWidget />\n    </main>\n  );\n}\n```"}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 11, "depth": 2, "title": "Run the App", "anchor": "run-the-app", "start_char": 18628, "end_char": 19615, "estimated_token_count": 216, "token_estimator": "heuristic-v1", "text": "## Run the App\n\nStart the development server and confirm that the live widget displays data correctly:\n\n```bash\nnpm run dev\n```\n\nOpen `http://localhost:3000/` to see your app running. You should see the widget display the current ETH/USD price, the last update time, the block number, and a freshness badge indicating whether the data is still within its heartbeat window.\n\nThe price may update only intermittently. Witnet feeds refresh only when a particular time or price deviation threshold is reached to prevent unnecessary network updates.\n\nYour app should look like this:\n\n![Frontend of Queries Live Prices Widget](/docs/images/products/queries/tutorials/live-crypto-prices/live-crypto-prices-1.webp){.half}\n\n???- tip \"Troubleshooting\"\n    If you encounter a “Request failed with status code 403” error, it likely means your Queries API key is missing or incorrect. Check the `QUERIES_API_KEY` value in your `.env.local` file and restart the development server after updating it."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 12, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 19615, "end_char": 19906, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "## Resources\n\nIf you'd like to explore the complete project or need a reference while following this tutorial, you can find the complete codebase in the Wormhole's Queries [Tutorial GitHub repository](https://github.com/wormhole-foundation/e2e-tutorial-live-crypto-prices){target=\\_blank}."}
{"page_id": "products-queries-tutorials-live-crypto-prices", "page_title": "Live Crypto Price Widget", "index": 13, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 19906, "end_char": 20484, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nYou've successfully built a live crypto price widget that fetches verified data from Wormhole Queries and Witnet. Your app encodes a feed request, sends it through the Guardian network for verification, and displays the latest signed price in a simple, responsive widget.\n\nThe Queries flow can be extended to fetch other on-chain data or integrate multiple feeds for dashboards and analytics tools.\n\nLooking for more? Check out the [Wormhole Tutorial Demo repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank} for additional examples."}
{"page_id": "products-reference-consistency-levels", "page_title": "Wormhole Finality | Consistency Levels", "index": 0, "depth": 2, "title": "Custom Consistency Levels (Advanced)", "anchor": "custom-consistency-levels-advanced", "start_char": 9081, "end_char": 10927, "estimated_token_count": 382, "token_estimator": "heuristic-v1", "text": "## Custom Consistency Levels (Advanced)\n\nOn supported EVM chains (currently Ethereum and Linea), integrators may specify a custom consistency level. See the [white paper](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0001_generic_message_passing.md#custom-handling){target=\\_blank} to learn how this works. \n\n!!!warning\n    **Custom finality is an advanced feature and Wormhole Contributors recommend to use this with caution.** Custom consistency should only be used when standard finality options do not meet the application’s requirements. Most integrations **do not** require custom consistency levels. Using custom finality exposes users to re-org risk. Lower finality levels increase the chance that a source-chain transaction may be reverted after assets are released or minted on the destination chain. Custom finality should be used only with a clear understanding of these risks.\n    \nHow to select a Custom Finality Level:\n\n- For L1s: Wormhole Contributors recommend referring to information on forked blocks in blockchain explorers such as [Etherscan](https://etherscan.io/blocks_forked?p=1){target=\\_blank}, [Polygonscan](https://polygonscan.com/blocks_forked){target=\\_blank}, and others, paying specific attention to the “ReorgDepth” column. Polygon, for instance, has been known to have reorgs with a depth of up to 128 blocks! \n- For L2s: Wormhole Contributors recommend reviewing L2 block explorers as well as details around whether the sequencer is centralized and how the L2 RPC node treats finality. Typically, the risks one is exposed to when not waiting for full finality from an L2 are: (1) a centralized (or compromised) sequencer censoring transactions, (2) re-orgs if sequencing is not centralized, and (3) L1 reorg risk and the L2 sequencer not re-submitting the transaction batch to the L1."}
{"page_id": "products-reference-consistency-levels", "page_title": "Wormhole Finality | Consistency Levels", "index": 1, "depth": 3, "title": "CCL Contract Addresses", "anchor": "ccl-contract-addresses", "start_char": 10927, "end_char": 12160, "estimated_token_count": 414, "token_estimator": "heuristic-v1", "text": "### CCL Contract Addresses\n\nCustom Consistency Level (CCL) enables advanced finality control for EVM chains. CCL is currently supported on select EVM chains. The contract addresses below are the on-chain contracts queried when 203 (Custom) is used.\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Ethereum</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr><tr><td>Linea</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Ethereum</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr><tr><td>Sepolia</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr><tr><td>Linea</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr></tbody></table>\n\n=== \"Devnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Ethereum</td><td><code>0x6A4B4A882F5F0a447078b4Fd0b4B571A82371ec2</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 0, "depth": 2, "title": "Core Contracts", "anchor": "core-contracts", "start_char": 22, "end_char": 9034, "estimated_token_count": 3012, "token_estimator": "heuristic-v1", "text": "## Core Contracts\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B</code></td></tr><tr><td>Solana</td><td><code>worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0xC699482c17d43b7D5349F2D3f58d61fEFA972B8c</code></td></tr><tr><td>Algorand</td><td><code>842125965</code></td></tr><tr><td>Aptos</td><td><code>0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625</code></td></tr><tr><td>Arbitrum</td><td><code>0xa5f208e072434bC67592E4C49C1B991BA79BCA46</code></td></tr><tr><td>Avalanche</td><td><code>0x54a8e5f9c4CbA08F9943965859F6c34eAF03E26c</code></td></tr><tr><td>Base</td><td><code>0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6</code></td></tr><tr><td>Berachain</td><td><code>0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B</code></td></tr><tr><td>Celo</td><td><code>0xa321448d90d4e5b0A732867c18eA198e75CAC48E</code></td></tr><tr><td>CreditCoin</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Fantom</td><td><code>0x126783A6Cb203a3E35344528B26ca3a0489a1485</code></td></tr><tr><td>Fogo</td><td><code>worm2mrQkG1B1KTz37erMfWN8anHkSK24nzca7UD8BB</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x7C0faFc4384551f063e05aee704ab943b8B53aB3</code></td></tr><tr><td>Injective</td><td><code>inj17p9rzwnnfxcjp32un9ug7yhhzgtkhvl9l2q74d</code></td></tr><tr><td>Ink</td><td><code>0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D</code></td></tr><tr><td>Kaia</td><td><code>0x0C21603c4f3a6387e241c0091A7EA39E43E90bb7</code></td></tr><tr><td>Linea</td><td><code>0x0C56aebD76E6D9e4a1Ec5e94F4162B4CBbf77b32</code></td></tr><tr><td>Mantle</td><td><code>0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6</code></td></tr><tr><td>MegaETH</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Mezo</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Moca</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Monad</td><td><code>0x194B123c5E96B9b2E49763619985790Dc241CAC0</code></td></tr><tr><td>Moonbeam</td><td><code>0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3</code></td></tr><tr><td>NEAR</td><td><code>contract.wormhole_crypto.near</code></td></tr><tr><td>Neutron</td><td><code>neutron16rerygcpahqcxx5t8vjla46ym8ccn7xz7rtc6ju5ujcd36cmc7zs9zrunh</code></td></tr><tr><td>Optimism</td><td><code>0xEe91C335eab126dF5fDB3797EA9d6aD93aeC9722</code></td></tr><tr><td>Plume</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Polygon</td><td><code>0x7A4B5a56256163F07b2C80A7cA55aBE66c4ec4d7</code></td></tr><tr><td>Pythnet</td><td><code>H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU</code></td></tr><tr><td>Scroll</td><td><code>0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6</code></td></tr><tr><td>Sei</td><td><code>sei1gjrrme22cyha4ht2xapn3f08zzw6z3d4uxx6fyy9zd5dyr3yxgzqqncdqn</code></td></tr><tr><td>SeiEVM</td><td><code>0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D</code></td></tr><tr><td>Sui</td><td><code>0xaeab97f96cf9877fee2883315d459552b2b921edc16d7ceac6eab944dd88919c</code></td></tr><tr><td>Unichain</td><td><code>0xCa1D5a146B03f6303baF59e5AD5615ae0b9d146D</code></td></tr><tr><td>World Chain</td><td><code>0xcbcEe4e081464A15d8Ad5f58BB493954421eB506</code></td></tr><tr><td>X Layer</td><td><code>0x194B123c5E96B9b2E49763619985790Dc241CAC0</code></td></tr><tr><td>XRPL-EVM</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Holesky</td><td><code>0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a</code></td></tr><tr><td>Ethereum Sepolia</td><td><code>0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78</code></td></tr><tr><td>Solana</td><td><code>3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x059560c0D626bdB982454b5EBd65DC8E7cF7973c</code></td></tr><tr><td>Algorand</td><td><code>86525623</code></td></tr><tr><td>Aptos</td><td><code>0x5bc11445584a763c1fa7ed39081f1b920954da14e04b32440cba863d03e19625</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35</code></td></tr><tr><td>Avalanche</td><td><code>0x7bbcE28e64B3F8b84d876Ab298393c38ad7aac4C</code></td></tr><tr><td>Base Sepolia</td><td><code>0x79A1027a6A159502049F10906D333EC57E95F083</code></td></tr><tr><td>Berachain</td><td><code>0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x68605AD7b15c732a30b1BbC62BE8F2A509D74b4D</code></td></tr><tr><td>Celo</td><td><code>0x88505117CA88e7dd2eC6EA1E13f0948db2D50D56</code></td></tr><tr><td>Converge</td><td><code>0x556B259cFaCd9896B2773310080c7c3bcE90Ff01</code></td></tr><tr><td>CreditCoin</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Fantom</td><td><code>0x1BB3B4119b7BA9dfad76B0545fb3F531383c3bB7</code></td></tr><tr><td>Fogo</td><td><code>BhnQyKoQQgpuRTRo6D8Emz93PvXCYfVgHhnrR4T3qhw4</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd</code></td></tr><tr><td>Injective</td><td><code>inj1xx3aupmgv3ce537c0yce8zzd3sz567syuyedpg</code></td></tr><tr><td>Ink</td><td><code>0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd</code></td></tr><tr><td>Kaia</td><td><code>0x1830CC6eE66c84D2F177B94D544967c774E624cA</code></td></tr><tr><td>Linea</td><td><code>0x79A1027a6A159502049F10906D333EC57E95F083</code></td></tr><tr><td>Mantle</td><td><code>0x376428e7f26D5867e69201b275553C45B09EE090</code></td></tr><tr><td>MegaETH</td><td><code>0x81705b969cDcc6FbFde91a0C6777bE0EF3A75855</code></td></tr><tr><td>Mezo</td><td><code>0x268557122Ffd64c85750d630b716471118F323c8</code></td></tr><tr><td>Moca</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Monad Testnet</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Moonbeam</td><td><code>0xa5B7D85a8f27dd7907dc8FdC21FA5657D5E2F901</code></td></tr><tr><td>NEAR</td><td><code>wormhole.wormhole.testnet</code></td></tr><tr><td>Neutron</td><td><code>neutron1enf63k37nnv9cugggpm06mg70emcnxgj9p64v2s8yx7a2yhhzk2q6xesk4</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x31377888146f3253211EFEf5c676D41ECe7D58Fe</code></td></tr><tr><td>Osmosis</td><td><code>osmo1hggkxr0hpw83f8vuft7ruvmmamsxmwk2hzz6nytdkzyup9krt0dq27sgyx</code></td></tr><tr><td>Plasma</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr><tr><td>Plume</td><td><code>0x81705b969cDcc6FbFde91a0C6777bE0EF3A75855</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x6b9C8671cdDC8dEab9c719bB87cBd3e782bA6a35</code></td></tr><tr><td>Pythnet</td><td><code>EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z</code></td></tr><tr><td>Scroll</td><td><code>0x055F47F1250012C6B20c436570a76e52c17Af2D5</code></td></tr><tr><td>Sei</td><td><code>sei1nna9mzp274djrgzhzkac2gvm3j27l402s4xzr08chq57pjsupqnqaj0d5s</code></td></tr><tr><td>SeiEVM</td><td><code>0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd</code></td></tr><tr><td>Stacks</td><td><code>ST37PDDGEA78QSPSBZM1ZHPCZV9GKAPDFHA32RWY8</code></td></tr><tr><td>Sui</td><td><code>0x31358d198147da50db32eda2562951d53973a0c0ad5ed738e9b17d88b213d790</code></td></tr><tr><td>Unichain</td><td><code>0xBB73cB66C26740F31d1FabDC6b7A46a038A300dd</code></td></tr><tr><td>World Chain</td><td><code>0xe5E02cD12B6FcA153b0d7fF4bF55730AE7B3C93A</code></td></tr><tr><td>X Layer</td><td><code>0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780</code></td></tr><tr><td>XRPL-EVM</td><td><code>0xaBf89de706B583424328B54dD05a8fC986750Da8</code></td></tr></tbody></table>\n\n=== \"Devnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xC89Ce4735882C9F0f0FE26686c53074E09B0D550</code></td></tr><tr><td>Solana</td><td><code>Bridge1p5gheXUvJ6jGWGeCsgPKgnE3YgdGKRVCMY9o</code></td></tr><tr><td>Algorand</td><td><code>1004</code></td></tr><tr><td>Aptos</td><td><code>0xde0036a9600559e295d5f6802ef6f3f802f510366e0c23912b0655d972166017</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xC89Ce4735882C9F0f0FE26686c53074E09B0D550</code></td></tr><tr><td>NEAR</td><td><code>wormhole.test.near</code></td></tr><tr><td>Stacks</td><td><code>ST1PQHQKV0RJXZFY1DGX8MNSNYVE3VGZJSRTPGZGM</code></td></tr><tr><td>Sui</td><td><code>0x5a5160ca3c2037f4b4051344096ef7a48ebf4400b3f385e57ea90e1628a8bde0</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 1, "depth": 2, "title": "Wrapped Token Transfers (WTT)", "anchor": "wrapped-token-transfers-wtt", "start_char": 9034, "end_char": 16313, "estimated_token_count": 2470, "token_estimator": "heuristic-v1", "text": "## Wrapped Token Transfers (WTT)\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x3ee18B2214AFF97000D974cf647E7C347E8fa585</code></td></tr><tr><td>Solana</td><td><code>wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0xee12EBDdF6E34A206e1798D185317C846BC21638</code></td></tr><tr><td>Algorand</td><td><code>842126029</code></td></tr><tr><td>Aptos</td><td><code>0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f</code></td></tr><tr><td>Arbitrum</td><td><code>0x0b2402144Bb366A632D14B83F244D2e0e21bD39c</code></td></tr><tr><td>Avalanche</td><td><code>0x0e082F06FF657D94310cB8cE8B0D9a04541d8052</code></td></tr><tr><td>Base</td><td><code>0x8d2de8d2f73F1F4cAB472AC9A881C9b123C79627</code></td></tr><tr><td>Berachain</td><td><code>0x3Ff72741fd67D6AD0668d93B41a09248F4700560</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xB6F6D86a8f9879A9c87f643768d9efc38c1Da6E7</code></td></tr><tr><td>Celo</td><td><code>0x796Dff6D74F3E27060B71255Fe517BFb23C93eed</code></td></tr><tr><td>Fantom</td><td><code>0x7C9Fc5741288cDFdD83CeB07f3ea7e22618D79D2</code></td></tr><tr><td>Fogo</td><td><code>wormQuCVWSSmPdjVmEzAWxAXViVyTSWnLyhff5hVYGS</code></td></tr><tr><td>Injective</td><td><code>inj1ghd753shjuwexxywmgs4xz7x2q732vcnxxynfn</code></td></tr><tr><td>Ink</td><td><code>0x3Ff72741fd67D6AD0668d93B41a09248F4700560</code></td></tr><tr><td>Kaia</td><td><code>0x5b08ac39EAED75c0439FC750d9FE7E1F9dD0193F</code></td></tr><tr><td>Mantle</td><td><code>0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d</code></td></tr><tr><td>MegaETH</td><td><code>0xF97B81E513f53c7a6B57Bd0b103a6c295b3096C5</code></td></tr><tr><td>Monad</td><td><code>0x0B2719cdA2F10595369e6673ceA3Ee2EDFa13BA7</code></td></tr><tr><td>Moonbeam</td><td><code>0xb1731c586ca89a23809861c6103f0b96b3f57d92</code></td></tr><tr><td>NEAR</td><td><code>contract.portalbridge.near</code></td></tr><tr><td>Optimism</td><td><code>0x1D68124e65faFC907325e3EDbF8c4d84499DAa8b</code></td></tr><tr><td>Polygon</td><td><code>0x5a58505a96D1dbf8dF91cB21B54419FC36e93fdE</code></td></tr><tr><td>Scroll</td><td><code>0x24850c6f61C438823F01B7A3BF2B89B72174Fa9d</code></td></tr><tr><td>Sei</td><td><code>sei1smzlm9t79kur392nu9egl8p8je9j92q4gzguewj56a05kyxxra0qy0nuf3</code></td></tr><tr><td>SeiEVM</td><td><code>0x3Ff72741fd67D6AD0668d93B41a09248F4700560</code></td></tr><tr><td>Sui</td><td><code>0xc57508ee0d4595e5a8728974a4a93a787d38f339757230d441e895422c07aba9</code></td></tr><tr><td>Unichain</td><td><code>0x3Ff72741fd67D6AD0668d93B41a09248F4700560</code></td></tr><tr><td>World Chain</td><td><code>0xc309275443519adca74c9136b02A38eF96E3a1f6</code></td></tr><tr><td>X Layer</td><td><code>0x5537857664B0f9eFe38C9f320F75fEf23234D904</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x47F5195163270345fb4d7B9319Eda8C64C75E278</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Holesky</td><td><code>0x76d093BbaE4529a342080546cAFEec4AcbA59EC6</code></td></tr><tr><td>Ethereum Sepolia</td><td><code>0xDB5492265f6038831E89f495670FF909aDe94bd9</code></td></tr><tr><td>Solana</td><td><code>DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x7d8eBc211C4221eA18E511E4f0fD50c5A539f275</code></td></tr><tr><td>Algorand</td><td><code>86525641</code></td></tr><tr><td>Aptos</td><td><code>0x576410486a2da45eee6c949c995670112ddf2fbeedab20350d506328eefc9d4f</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e</code></td></tr><tr><td>Avalanche</td><td><code>0x61E44E506Ca5659E6c0bba9b678586fA2d729756</code></td></tr><tr><td>Base Sepolia</td><td><code>0x86F55A04690fd7815A3D802bD587e83eA888B239</code></td></tr><tr><td>Berachain</td><td><code>0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x9dcF9D205C9De35334D646BeE44b2D2859712A09</code></td></tr><tr><td>Celo</td><td><code>0x05ca6037eC51F8b712eD2E6Fa72219FEaE74E153</code></td></tr><tr><td>Fantom</td><td><code>0x599CEa2204B4FaECd584Ab1F2b6aCA137a0afbE8</code></td></tr><tr><td>Fogo</td><td><code>78HdStBqCMioGii9D8mF3zQaWDqDZBQWTUwjjpdmbJKX</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78</code></td></tr><tr><td>Injective</td><td><code>inj1q0e70vhrv063eah90mu97sazhywmeegp7myvnh</code></td></tr><tr><td>Ink</td><td><code>0x376428e7f26D5867e69201b275553C45B09EE090</code></td></tr><tr><td>Kaia</td><td><code>0xC7A13BE098720840dEa132D860fDfa030884b09A</code></td></tr><tr><td>Linea</td><td><code>0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e</code></td></tr><tr><td>Mantle</td><td><code>0x75Bfa155a9D7A3714b0861c8a8aF0C4633c45b5D</code></td></tr><tr><td>MegaETH</td><td><code>0x3D5c2c2BEA15Af5D45F084834c535628C48c42A4</code></td></tr><tr><td>Mezo</td><td><code>0xA31aa3FDb7aF7Db93d18DDA4e19F811342EDF780</code></td></tr><tr><td>Moca</td><td><code>0xF97B81E513f53c7a6B57Bd0b103a6c295b3096C5</code></td></tr><tr><td>Monad Testnet</td><td><code>0xF97B81E513f53c7a6B57Bd0b103a6c295b3096C5</code></td></tr><tr><td>Moonbeam</td><td><code>0xbc976D4b9D57E57c3cA52e1Fd136C45FF7955A96</code></td></tr><tr><td>NEAR</td><td><code>token.wormhole.testnet</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x99737Ec4B815d816c49A385943baf0380e75c0Ac</code></td></tr><tr><td>Polygon Amoy</td><td><code>0xC7A204bDBFe983FCD8d8E61D02b475D4073fF97e</code></td></tr><tr><td>Scroll</td><td><code>0x22427d90B7dA3fA4642F7025A854c7254E4e45BF</code></td></tr><tr><td>Sei</td><td><code>sei1jv5xw094mclanxt5emammy875qelf3v62u4tl4lp5nhte3w3s9ts9w9az2</code></td></tr><tr><td>SeiEVM</td><td><code>0x23908A62110e21C04F3A4e011d24F901F911744A</code></td></tr><tr><td>Sui</td><td><code>0x6fb10cdb7aa299e9a4308752dadecb049ff55a892de92992a1edbd7912b3d6da</code></td></tr><tr><td>Unichain</td><td><code>0xa10f2eF61dE1f19f586ab8B6F2EbA89bACE63F7a</code></td></tr><tr><td>World Chain</td><td><code>0x430855B4D43b8AEB9D2B9869B74d58dda79C0dB2</code></td></tr><tr><td>X Layer</td><td><code>0xdA91a06299BBF302091B053c6B9EF86Eff0f930D</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x7d8eBc211C4221eA18E511E4f0fD50c5A539f275</code></td></tr></tbody></table>\n\n=== \"Devnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x0290FB167208Af455bB137780163b7B7a9a10C16</code></td></tr><tr><td>Solana</td><td><code>B6RHG3mfcckmrYN1UhmJzyS1XX3fZKbkeUcpJe9Sy3FE</code></td></tr><tr><td>Algorand</td><td><code>1006</code></td></tr><tr><td>Aptos</td><td><code>0x84a5f374d29fc77e370014dce4fd6a55b58ad608de8074b0be5571701724da31</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x0290FB167208Af455bB137780163b7B7a9a10C16</code></td></tr><tr><td>NEAR</td><td><code>token.test.near</code></td></tr><tr><td>Sui</td><td><code>0xa6a3da85bbe05da5bfd953708d56f1a3a023e7fb58e5a824a3d4de3791e8f690</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 2, "depth": 2, "title": "CCTP", "anchor": "cctp", "start_char": 16313, "end_char": 17623, "estimated_token_count": 447, "token_estimator": "heuristic-v1", "text": "## CCTP\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xAaDA05BD399372f0b0463744C09113c137636f6a</code></td></tr><tr><td>Arbitrum</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr><tr><td>Avalanche</td><td><code>0x09Fb06A271faFf70A651047395AaEb6265265F13</code></td></tr><tr><td>Base</td><td><code>0x03faBB06Fa052557143dC28eFCFc63FC12843f1D</code></td></tr><tr><td>Optimism</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr><tr><td>Polygon</td><td><code>0x0FF28217dCc90372345954563486528aa865cDd6</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr><tr><td>Avalanche</td><td><code>0x58f4c17449c90665891c42e14d34aae7a26a472e</code></td></tr><tr><td>Base Sepolia</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x2703483B1a5a7c577e8680de9Df8Be03c6f30e3c</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 3, "depth": 2, "title": "Settlement Token Router", "anchor": "settlement-token-router", "start_char": 17623, "end_char": 18864, "estimated_token_count": 431, "token_estimator": "heuristic-v1", "text": "## Settlement Token Router\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Ethereum</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr><tr><td>Solana</td><td><code>28topqjtJzMnPaGFmmZk68tzGmj9W9aMntaEK3QkgtRe</code></td></tr><tr><td>Arbitrum</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr><tr><td>Avalanche</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr><tr><td>Base</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr><tr><td>Optimism</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr><tr><td>Polygon</td><td><code>0x70287c79ee41C5D1df8259Cd68Ba0890cd389c47</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Solana</td><td><code>tD8RmtdcV7bzBeuFgyrFc8wvayj988ChccEzRQzo6md</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xe0418C44F06B0b0D7D1706E01706316DBB0B210E</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x6BAa7397c18abe6221b4f6C3Ac91C88a9faE00D8</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 4, "depth": 2, "title": "Executor", "anchor": "executor", "start_char": 18864, "end_char": 23923, "estimated_token_count": 1672, "token_estimator": "heuristic-v1", "text": "## Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x84EEe8dBa37C36947397E1E11251cA9A06Fc6F8a</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0xcD2BffD0C0289e8C0cb89c458dB1B74f1892Fa6c</code></td></tr><tr><td>Aptos</td><td><code>0x11aa75c059e1a7855be66b931bf340a2e0973274ac16b5f519c02ceafaf08a18</code></td></tr><tr><td>Arbitrum</td><td><code>0x3980f8318fc03d79033Bbb421A622CDF8d2Eeab4</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base</td><td><code>0x9E1936E91A4a5AE5A5F75fFc472D6cb8e93597ea</code></td></tr><tr><td>Berachain</td><td><code>0x0Dd7a5a32311b8D87A615Cc7f079B632D3d5e2D3</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Celo</td><td><code>0xe6Ea5087c6860B94Cf098a403506262D8F28cF05</code></td></tr><tr><td>CreditCoin</td><td><code>0xd2e420188f17607Aa6344ee19c3e76Cf86CA7BDe</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0xd7717899cc4381033Bc200431286D0AC14265F78</code></td></tr><tr><td>Ink</td><td><code>0x3e44a5F45cbD400acBEF534F51e616043B211Ddd</code></td></tr><tr><td>Linea</td><td><code>0x23aF2B5296122544A9A7861da43405D5B15a9bD3</code></td></tr><tr><td>MegaETH</td><td><code>0xD405E0A1f3f9edc25Ea32d0B079d6118328b2EcB</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0x7b8097af5459846c5A72fCc960D94F31C05915aD</code></td></tr><tr><td>Monad</td><td><code>0xC04dE634982cAdF2A677310b73630B7Ac56A3f65</code></td></tr><tr><td>Moonbeam</td><td><code>0x85D06449C78064c2E02d787e9DC71716786F8D19</code></td></tr><tr><td>Optimism</td><td><code>0x85B704501f6AE718205C0636260768C4e72ac3e7</code></td></tr><tr><td>Polygon</td><td><code>0x0B23efA164aB3eD08e9a39AC7aD930Ff4F5A5e81</code></td></tr><tr><td>Scroll</td><td><code>0xcFAdDE24640e395F5A71456A825D0D7C3741F075</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923fb7a5aefa5f0a2b419fc70f2368e66e5</code></td></tr><tr><td>Sonic</td><td><code>0x3Fdc36b4260Da38fBDba1125cCBD33DD0AC74812</code></td></tr><tr><td>Sui</td><td><code>0xdb0fe8bb1e2b5be628adbea0636063325073e1070ee11e4281457dfd7f158235</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>World Chain</td><td><code>0x8689b4E6226AdC8fa8FF80aCc3a60AcE31e8804B</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x8345E90Dcd92f5Cf2FAb0C8E2A56A5bc2c30d896</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xD0fb39f5a3361F21457653cB70F9D0C9bD86B66B</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x7C43825EeB76DF7aAf3e1D2e8f684d4876F0CC05</code></td></tr><tr><td>Aptos</td><td><code>0x139717c339f08af674be77143507a905aa28cbc67a0e53e7095c07b630d73815</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xBF161de6B819c8af8f2230Bcd99a9B3592f6F87b</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base Sepolia</td><td><code>0x51B47D493CBA7aB97e3F8F163D6Ce07592CE4482</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Converge</td><td><code>0xAab9935349B9c08e0e970720F6D640d5B91C293E</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>Linea</td><td><code>0x4f6c3a93a80DdC691312974DAAbf9B6e4Bb44111</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0xc4a03f2c47caA4b961101bAD6338DEf37376F052</code></td></tr><tr><td>Monad Testnet</td><td><code>0xe37D3E162B4B1F17131E4e0e6122DbA31243382f</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x5856651eB82aeb6979B4954317194d48e1891b3c</code></td></tr><tr><td>Plume</td><td><code>0x8fc2FbA8F962fbE89a9B02f03557a011c335A455</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x7056721C33De437f0997F67BC87521cA86b721d3</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923Fb7A5aEFA5F0A2b419fC70f2368e66e5</code></td></tr><tr><td>Sui</td><td><code>0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x4d9525D94D275dEB495b7C8840b154Ae04cfaC2A</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 5, "depth": 2, "title": "Quoter Router", "anchor": "quoter-router", "start_char": 23923, "end_char": 26149, "estimated_token_count": 727, "token_estimator": "heuristic-v1", "text": "## Quoter Router\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xF22F1c0A3a8Cb42F695601731974784C499C4EF3</code></td></tr><tr><td>Arbitrum</td><td><code>0x32eec14c963c23176bd8951f192292006756bDcC</code></td></tr><tr><td>Avalanche</td><td><code>0xA3a2A615774d34c6a4dF443C488B084eacaBd2D0</code></td></tr><tr><td>Base</td><td><code>0x265fd0500a430d65d6D79Cd8707F24C048604658</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xc921F293c27F332D47283174b11C872295624Edb</code></td></tr><tr><td>Ink</td><td><code>0xdEC050E66BEb2f0d5507761A0fE4867839bd88D2</code></td></tr><tr><td>Monad</td><td><code>0x3d9282A8e9a3cdd9b25AE969eff4705a1Fe75F34</code></td></tr><tr><td>Optimism</td><td><code>0xa3B6551cCbB5Fe1dc33b71EE3590B1Df22ae75B3</code></td></tr><tr><td>Plume</td><td><code>0x85BA1B2A2195be51Ab715be458B32B120532d230</code></td></tr><tr><td>Polygon</td><td><code>0x2a856931603930B827B1A4352FB4D66fA029F123</code></td></tr><tr><td>Sei</td><td><code>0x1D6FeA87671F7c5E184F4c59c3BdcEc5CFC3eC1c</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xc0C35D7bfBc4175e0991Ae294f561b433eA4158f</code></td></tr><tr><td>Solana</td><td><code>qtrrrV7W3E1jnX1145wXR6ZpthG19ur5xHC1n6PPhDV</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x5E8c14F436c9ed2ff2E8B042B0542136bf108C6f</code></td></tr><tr><td>Avalanche</td><td><code>0xA3a2A615774d34c6a4dF443C488B084eacaBd2D0</code></td></tr><tr><td>Base Sepolia</td><td><code>0x2507d6899C3D4b93BF46b555d0cB401f44065772</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x6a829dF7C91f35f9aD72Cd5d05550b95BbC9fd2F</code></td></tr><tr><td>Polygon Amoy</td><td><code>0xE00444636DA924FBAe94471d73D56b5E03cA781c</code></td></tr><tr><td>Sei</td><td><code>0x1D6FeA87671F7c5E184F4c59c3BdcEc5CFC3eC1c</code></td></tr></tbody></table>\n\n!!! note\n    Wormhole Labs’ Quoter uses the following public keys:\n\n    - **Mainnet**: `0xa54008017941EcE968623a0Dd8Ee907E2b133596`.\n    - **Testnet**: `0x5241c9276698439fef2780dbab76fec90b633fbd`."}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 6, "depth": 2, "title": "Wormhole Labs Quoter Implementation", "anchor": "wormhole-labs-quoter-implementation", "start_char": 26149, "end_char": 28397, "estimated_token_count": 729, "token_estimator": "heuristic-v1", "text": "## Wormhole Labs Quoter Implementation\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Arbitrum</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Avalanche</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Base</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Ink</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Monad</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Optimism</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Plume</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Polygon</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Sei</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Solana</td><td><code>qtrxiqVAfVS61utwZLUi7UKugjCgFaNxBGyskmGingz</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Avalanche</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Base Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Sei</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr></tbody></table>\n\n!!! note\n    Wormhole Labs’ Quoter uses the following public keys:\n\n    - **Mainnet**: `0xa54008017941EcE968623a0Dd8Ee907E2b133596`.\n    - **Testnet**: `0x5241c9276698439fef2780dbab76fec90b633fbd`."}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 7, "depth": 2, "title": "Guardian Governance", "anchor": "guardian-governance", "start_char": 28397, "end_char": 32003, "estimated_token_count": 1061, "token_estimator": "heuristic-v1", "text": "## Guardian Governance\n\n=== \"Mainnet\"\n\n    \n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x23Fea5514DFC9821479fBE18BA1D7e1A61f6FfCf</code></td></tr><tr><td>Solana</td><td><code>NGoD1yTeq5KaURrZo7MnCTFzTA4g62ygakJCnzMLCfm (see note below!)</code></td></tr><tr><td>Arbitrum</td><td><code>0x36CF4c88FA548c6Ad9fcDc696e1c27Bb3306163F</code></td></tr><tr><td>Avalanche</td><td><code>0x169D91C797edF56100F1B765268145660503a423</code></td></tr><tr><td>Base</td><td><code>0x838a95B6a3E06B6f11C437e22f3C7561a6ec40F1</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x8E4dc685e990379b8D53EcA47841E09B8d30043e</code></td></tr><tr><td>Fogo</td><td><code>ngoLQ35zgtP3SxWrjAJ8Mz2H8BPFVeZoxyBPotPYwnB (see note below!)</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x574B7864119C9223A9870Ea614dC91A8EE09E512</code></td></tr><tr><td>MegaETH</td><td><code>0x574B7864119C9223A9870Ea614dC91A8EE09E512</code></td></tr><tr><td>Monad</td><td><code>0x574B7864119C9223A9870Ea614dC91A8EE09E512</code></td></tr><tr><td>Optimism</td><td><code>0x0E09a3081837ff23D2e59B179E0Bc48A349Afbd8</code></td></tr><tr><td>Unichain</td><td><code>0x574b7864119c9223a9870ea614dc91a8ee09e512</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x574B7864119C9223A9870Ea614dC91A8EE09E512</code></td></tr><tr><td>Sui</td><td><code>See note below!</code></td></tr></tbody></table>\n    \n\n=== \"Testnet\"\n\n    \n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x9517F0164c1d089ad72E669E57b9088790966dBd</code></td></tr><tr><td>Solana</td><td><code>NGoD1yTeq5KaURrZo7MnCTFzTA4g62ygakJCnzMLCfm</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x81b65A48DCAccBA04aCa3C055C4112b0715b90c0</code></td></tr><tr><td>Base Sepolia</td><td><code>0x720A59128B96Eda6EC2940c7899406E4dc56d0DC</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xcE1DE1eA4b040D324a07719043A6234C94fd0b5d</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x574B7864119C9223A9870Ea614dC91A8EE09E512</code></td></tr></tbody></table>\n    \n!!! note\n    Guardian-governed ownership contracts are used where an owner is required, without adding new trust assumptions. They only accept instructions signed by a quorum of Wormhole Guardians, validated on-chain by the Wormhole Core contracts. Implementations: [EVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/wormhole/Governance.sol){target=\\_blank} and [SVM](https://github.com/wormhole-foundation/native-token-transfers/blob/main/solana/programs/wormhole-governance/src/instructions/governance.rs){target=\\_blank}.\n\n    On SVM chains (Solana, Fogo), deployments set the admin to a [governance PDA](https://solana.com/docs/core/pda){target=\\_blank} derived from the Guardian governance program. The admin address may differ from the program ID when inspecting deployments on-chain.\n\n    The following governance PDAs are used as the admin for deployments on SVM chains:\n\n    - **Solana:** `4iUtozoQLdJ2FV7vXe9q215ETSw1Mnt8WKP4NyqNgAxz`.\n    - **Fogo:** `nWfGbhWvREnvF1zCvhrXiKidzDJ8DzCdHb13YYZeVkV`.\n\n    On Sui, separate instances of the Move governance contract need to be deployed for each individual token due to technical reasons. The NTT CLI is able to perform such deployments for your token via \"ntt sui deploy-governance --transfer\"."}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 8, "depth": 2, "title": "Delegated Guardians", "anchor": "delegated-guardians", "start_char": 32003, "end_char": 32268, "estimated_token_count": 96, "token_estimator": "heuristic-v1", "text": "## Delegated Guardians\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Ethereum</td><td><code>0x1462800febd49232798132e8c8b721aa86c4c209</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 9, "depth": 2, "title": "IBC", "anchor": "ibc", "start_char": 32268, "end_char": 32603, "estimated_token_count": 107, "token_estimator": "heuristic-v1", "text": "## IBC\n\nThis configuration is for the `ibc` feature for guardians.\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Wormchain</td><td><code>wormhole1wkwy0xh89ksdgj9hr347dyd2dw7zesmtrue6kfzyml4vdtz6e5ws2y050r</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 10, "depth": 2, "title": "Gateway", "anchor": "gateway", "start_char": 32603, "end_char": 32955, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "## Gateway\n\nThis configuration is for the `gatewayContract` guardian configuration.\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><tr><th>Chain Name</th><th>Contract Address</th></tr></thead><tbody><tr><td>Wormchain</td><td><code>wormhole1ufs3tlq4umljk0qfe8k5ya0x6hpavn897u2cnf9k0en9jr7qarqqaqfk2j</code></td></tr></tbody></table>"}
{"page_id": "products-reference-contract-addresses", "page_title": "Contract Addresses", "index": 11, "depth": 2, "title": "Read-Only Deployments", "anchor": "read-only-deployments", "start_char": 32955, "end_char": 35045, "estimated_token_count": 614, "token_estimator": "heuristic-v1", "text": "## Read-Only Deployments\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody>\n    <tr><td>Acala</td><td><code>0xa321448d90d4e5b0A732867c18eA198e75CAC48E</code></td></tr>\n    <tr><td>Aurora</td><td><code>0x51b5123a7b0F9b2bA265f9c4C8de7D78D52f510F</code></td></tr>\n    <tr><td>Blast</td><td><code>0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6</code></td></tr>\n    <tr><td>Corn</td><td><code>0xa683c66045ad16abb1bCE5ad46A64d95f9A25785</code></td></tr>\n    <tr><td>Gnosis</td><td><code>0xa321448d90d4e5b0A732867c18eA198e75CAC48E</code></td></tr>\n    <tr><td>Goat</td><td><code>0x352A86168e6988A1aDF9A15Cb00017AAd3B67155</code></td></tr>\n    <tr><td>Karura</td><td><code>0xa321448d90d4e5b0A732867c18eA198e75CAC48E</code></td></tr>\n    <tr><td>LightLink</td><td><code>0x352A86168e6988A1aDF9A15Cb00017AAd3B67155</code></td></tr>\n    <tr><td>Oasis</td><td><code>0xfE8cD454b4A1CA468B57D79c0cc77Ef5B6f64585</code></td></tr>\n    <tr><td>Rootstock</td><td><code>0xbebdb6C8ddC678FfA9f8748f85C815C556Dd8ac6</code></td></tr>\n    <tr><td>Sonic</td><td><code>0x352A86168e6988A1aDF9A15Cb00017AAd3B67155</code></td></tr>\n    <tr><td>Telos</td><td><code>0x352A86168e6988A1aDF9A15Cb00017AAd3B67155</code></td></tr>\n    <tr><td>Terra</td><td><code>terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5</code></td></tr>\n    <tr><td>Terra 2.0</td><td><code>terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnhp</code></td></tr>\n    <tr><td>SNAXchain</td><td><code>0xc1BA3CC4bFE724A08FbbFbF64F8db196738665f4</code></td></tr>\n    <tr><td>XPLA</td><td><code>xpla1jn8qmdda5m6f6fqu9qv46rt7ajhklg40ukpqchkejcvy8x7w26cqxamv3w</code></td></tr>\n    </tbody>\n    </table>\n!!! note\n    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."}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 0, "depth": 2, "title": "Executor", "anchor": "executor", "start_char": 22, "end_char": 5081, "estimated_token_count": 1672, "token_estimator": "heuristic-v1", "text": "## Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x84EEe8dBa37C36947397E1E11251cA9A06Fc6F8a</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0xcD2BffD0C0289e8C0cb89c458dB1B74f1892Fa6c</code></td></tr><tr><td>Aptos</td><td><code>0x11aa75c059e1a7855be66b931bf340a2e0973274ac16b5f519c02ceafaf08a18</code></td></tr><tr><td>Arbitrum</td><td><code>0x3980f8318fc03d79033Bbb421A622CDF8d2Eeab4</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base</td><td><code>0x9E1936E91A4a5AE5A5F75fFc472D6cb8e93597ea</code></td></tr><tr><td>Berachain</td><td><code>0x0Dd7a5a32311b8D87A615Cc7f079B632D3d5e2D3</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Celo</td><td><code>0xe6Ea5087c6860B94Cf098a403506262D8F28cF05</code></td></tr><tr><td>CreditCoin</td><td><code>0xd2e420188f17607Aa6344ee19c3e76Cf86CA7BDe</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0xd7717899cc4381033Bc200431286D0AC14265F78</code></td></tr><tr><td>Ink</td><td><code>0x3e44a5F45cbD400acBEF534F51e616043B211Ddd</code></td></tr><tr><td>Linea</td><td><code>0x23aF2B5296122544A9A7861da43405D5B15a9bD3</code></td></tr><tr><td>MegaETH</td><td><code>0xD405E0A1f3f9edc25Ea32d0B079d6118328b2EcB</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0x7b8097af5459846c5A72fCc960D94F31C05915aD</code></td></tr><tr><td>Monad</td><td><code>0xC04dE634982cAdF2A677310b73630B7Ac56A3f65</code></td></tr><tr><td>Moonbeam</td><td><code>0x85D06449C78064c2E02d787e9DC71716786F8D19</code></td></tr><tr><td>Optimism</td><td><code>0x85B704501f6AE718205C0636260768C4e72ac3e7</code></td></tr><tr><td>Polygon</td><td><code>0x0B23efA164aB3eD08e9a39AC7aD930Ff4F5A5e81</code></td></tr><tr><td>Scroll</td><td><code>0xcFAdDE24640e395F5A71456A825D0D7C3741F075</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923fb7a5aefa5f0a2b419fc70f2368e66e5</code></td></tr><tr><td>Sonic</td><td><code>0x3Fdc36b4260Da38fBDba1125cCBD33DD0AC74812</code></td></tr><tr><td>Sui</td><td><code>0xdb0fe8bb1e2b5be628adbea0636063325073e1070ee11e4281457dfd7f158235</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>World Chain</td><td><code>0x8689b4E6226AdC8fa8FF80aCc3a60AcE31e8804B</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x8345E90Dcd92f5Cf2FAb0C8E2A56A5bc2c30d896</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xD0fb39f5a3361F21457653cB70F9D0C9bD86B66B</code></td></tr><tr><td>Solana</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x7C43825EeB76DF7aAf3e1D2e8f684d4876F0CC05</code></td></tr><tr><td>Aptos</td><td><code>0x139717c339f08af674be77143507a905aa28cbc67a0e53e7095c07b630d73815</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xBF161de6B819c8af8f2230Bcd99a9B3592f6F87b</code></td></tr><tr><td>Avalanche</td><td><code>0x4661F0E629E4ba8D04Ee90080Aee079740B00381</code></td></tr><tr><td>Base Sepolia</td><td><code>0x51B47D493CBA7aB97e3F8F163D6Ce07592CE4482</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xeC8cCCD058DbF28e5D002869Aa9aFa3992bf4ee0</code></td></tr><tr><td>Converge</td><td><code>0xAab9935349B9c08e0e970720F6D640d5B91C293E</code></td></tr><tr><td>Fogo</td><td><code>execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV</code></td></tr><tr><td>Linea</td><td><code>0x4f6c3a93a80DdC691312974DAAbf9B6e4Bb44111</code></td></tr><tr><td>Mezo</td><td><code>0x0f9b8E144Cc5C5e7C0073829Afd30F26A50c5606</code></td></tr><tr><td>Moca</td><td><code>0xc4a03f2c47caA4b961101bAD6338DEf37376F052</code></td></tr><tr><td>Monad Testnet</td><td><code>0xe37D3E162B4B1F17131E4e0e6122DbA31243382f</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x5856651eB82aeb6979B4954317194d48e1891b3c</code></td></tr><tr><td>Plume</td><td><code>0x8fc2FbA8F962fbE89a9B02f03557a011c335A455</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x7056721C33De437f0997F67BC87521cA86b721d3</code></td></tr><tr><td>SeiEVM</td><td><code>0x25f1c923Fb7A5aEFA5F0A2b419fC70f2368e66e5</code></td></tr><tr><td>Sui</td><td><code>0x4000cfe2955d8355b3d3cf186f854fea9f787a457257056926fde1ec977670eb</code></td></tr><tr><td>Unichain</td><td><code>0x764dD868eAdD27ce57BCB801E4ca4a193d231Aed</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x4d9525D94D275dEB495b7C8840b154Ae04cfaC2A</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 1, "depth": 2, "title": "CCTP With Executor", "anchor": "cctp-with-executor", "start_char": 5081, "end_char": 10193, "estimated_token_count": 1754, "token_estimator": "heuristic-v1", "text": "## CCTP With Executor\n\n\n\n=== \"Mainnet v1\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x6DDE92942DbB24F7c9B75765b74a33446980C1e3</code></td></tr><tr><td>Solana</td><td><code>CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs</code></td></tr><tr><td>Aptos</td><td><code>0xc89bf3746dfc70bb3f2de7c35a98f327a40b9d55a443743a5935c5e3de90b7ac</code></td></tr><tr><td>Arbitrum</td><td><code>0x772373214238F09a494828A5323574E3d7e27558</code></td></tr><tr><td>Avalanche</td><td><code>0x58aC806cd205083E7E048E196f36Ff6C4Ae17bE5</code></td></tr><tr><td>Base</td><td><code>0x4D1Cc8921e297155044C01761f581fa52a24C33d</code></td></tr><tr><td>Optimism</td><td><code>0x6826c075973a4393CEf0e131c4B16869426563a7</code></td></tr><tr><td>Polygon</td><td><code>0x7e6Ae241101B355447A4B471D0C6968b132eC4Ab</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0xa997Ef229E4D2a1fEca249eB41fBf5D4b2217d6E</code></td></tr></tbody></table>\n\n=== \"Testnet v1\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x2fcc7b2332d924764f17f1cf5eda1cd4b36751a2</code></td></tr><tr><td>Solana</td><td><code>CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs</code></td></tr><tr><td>Aptos</td><td><code>0x14a12d1fd6ef371b70c2113155534ec152ec7f779e281b54866c796c9a4a58d3</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x8158305d331594f3e8d18c33ca4e6d3cdc109b75</code></td></tr><tr><td>Avalanche</td><td><code>0x62819ab61cc7fcc864af7bcfc92e6c1965eb69a6</code></td></tr><tr><td>Base Sepolia</td><td><code>0x96846c31e4f87c0f186a322926c61d4183439f0a</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xe17de8e29f1f0941b541b053829af74ac81c89a6</code></td></tr><tr><td>Polygon</td><td><code>0xdce63172e9ad15243c97acafd01cc4fdda98bead</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0x2c1354296a11029056e0d7d7abbdd58743dbaf59</code></td></tr></tbody></table>\n\n=== \"Mainnet v2\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xDD68aBa3E04CB1a05082402B9325753314803005</code></td></tr><tr><td>Solana</td><td><code>Supported</code></td></tr><tr><td>Arbitrum</td><td><code>0x760feC4425B46E3D8FEf8E2CE49786e5a6f74446</code></td></tr><tr><td>Avalanche</td><td><code>0xE42aE9e352157fcEf74E971F2C5c74A5963a71D7</code></td></tr><tr><td>Base</td><td><code>0x52892976559fB2fc8b7f850440eD9AA5Dc26f7D9</code></td></tr><tr><td>Codex</td><td><code>0x0684286448140F75d4C3D2F2c02BF66f98CdEA51</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x001319beBA062d918d7007E4D2D76a0A9cc439Db</code></td></tr><tr><td>Ink</td><td><code>0xef0B43b49315A4aDF11bA2617Be81a304c5D6ecc</code></td></tr><tr><td>Linea</td><td><code>0x257dBB6AD7C7AC19360bEe1A107ebE631D568776</code></td></tr><tr><td>Monad</td><td><code>0x1FdCCf65318b34CFd3F5903fFb747C17e76330ac</code></td></tr><tr><td>Optimism</td><td><code>0x9b51579e67D4ab18D79609105509ad37B2a0D342</code></td></tr><tr><td>Plume</td><td><code>0x9be9C6B420eAfaaC1162D680fd7E61446b38Cf29</code></td></tr><tr><td>Polygon</td><td><code>0x5116F1358ae2445f571AA702dA1feB5e13094E59</code></td></tr><tr><td>SeiEVM</td><td><code>0xe067C0D378C50CDc34bCd973F202736D5A19e5D2</code></td></tr><tr><td>Sonic</td><td><code>0x8A850b2077F1eFccA89eAa9c35b45C4dC9227cdb</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0xaf7f4FbB6C220baf57ABC7babF81D47Fd628bdb4</code></td></tr><tr><td>World Chain</td><td><code>0xAA4841e5d9652593852403E3ce9e8003f8D579D0</code></td></tr></tbody></table>\n\n=== \"Testnet v2\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xc58475c97ebde9cf4fefa0d4fb2774df81905d43</code></td></tr><tr><td>Solana</td><td><code>Supported</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xf601f9988d62943cb842baae1e46be9b17d0b2a4</code></td></tr><tr><td>Avalanche</td><td><code>0x10018394905f70daa1d740040d64cbed5a82301e</code></td></tr><tr><td>Base Sepolia</td><td><code>0x1effdcfedc6d45e44b3133257debfb522adb1cae</code></td></tr><tr><td>Ink</td><td><code>0x63993ee08bda32ecb0ba5cdc751b404f5c5c0458</code></td></tr><tr><td>Linea Sepolia</td><td><code>0xe8Ad216e23fc9425E65aB315F0EC13737e75afEF</code></td></tr><tr><td>Monad Testnet</td><td><code>0x358bAd031d7A217ebA2d471cad5fD611AeC2aF17</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x49f386393c26439b74e62f5794062925dfb7c1db</code></td></tr><tr><td>Polygon</td><td><code>0x05da7c69db265b37b4d3530d476ec4b33bd9dd45</code></td></tr><tr><td>SeiEVM</td><td><code>0xDC735908C3eCF29f40D8CA5f6407F2d94d316a9F</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0xf082af7668f000f60bc519b378f6363708fc302b</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 2, "depth": 2, "title": "NTT With Executor", "anchor": "ntt-with-executor", "start_char": 10193, "end_char": 15263, "estimated_token_count": 1699, "token_estimator": "heuristic-v1", "text": "## NTT With Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xD2D9c936165a85F27a5a7e07aFb974D022B89463</code><br>Multi Ntt: <code>0x03dB430D830601DB368991eE55DAa9A708df7912</code></td></tr><tr><td>Solana</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>0G</td><td><code>0xe175a8b838f3cdb2e1aaf4ff74c05cf2f3aea9a8</code></td></tr><tr><td>Arbitrum</td><td><code>0x0Af42A597b0C201D4dcf450DcD0c06d55ddC1C77</code></td></tr><tr><td>Avalanche</td><td><code>0x4e9Af03fbf1aa2b79A2D4babD3e22e09f18Bb8EE</code></td></tr><tr><td>Base</td><td><code>0x83216747fC21b86173D800E2960c0D5395de0F30</code></td></tr><tr><td>Berachain</td><td><code>0x0a2AF374Cc9CCCbB0Acc4E34B20b9d02a0f08c30</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x39B57Dd9908F8be02CfeE283b67eA1303Bc29fe1</code></td></tr><tr><td>Celo</td><td><code>0x3d69869fcB9e1CD1F4020b637fb8256030BAc8fC</code></td></tr><tr><td>CreditCoin</td><td><code>0x5454b995719626256C96fb57454b044ffb3Da2F9</code></td></tr><tr><td>Fogo</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td><code>0x431017B1718b86898C7590fFcCC380DEf0456393</code></td></tr><tr><td>Ink</td><td><code>0x420370DC2ECC4D44b47514B7859fd11809BbeFF5</code></td></tr><tr><td>Linea</td><td><code>0xEAa5AddB5b8939Eb73F7faF46e193EefECaF13E9</code></td></tr><tr><td>MegaETH</td><td><code>0x3EFEc0c7Ee79135330DD03e995872f84b1AD49b6</code></td></tr><tr><td>Mezo</td><td><code>0x484b5593BbB90383f94FB299470F09427cf6cfE2</code></td></tr><tr><td>Moca</td><td><code>0xE612837749a0690BA2BCe490D6eFb5F8Fc347df3</code></td></tr><tr><td>Monad</td><td><code>0xc3F3dDa544815a440633176c7598f5B97500793e</code><br>Multi Ntt: <code>0xFEA937F7124E19124671f1685671d3f04a9Af4E4</code></td></tr><tr><td>Moonbeam</td><td><code>0x1365593C8bae71a55e48E105a2Bb76d5928c7DE3</code></td></tr><tr><td>Optimism</td><td><code>0x85C0129bE5226C9F0Cf4e419D2fefc1c3FCa25cF</code></td></tr><tr><td>Plume</td><td><code>0x6Eb53371f646788De6B4D0225a4Ed1d9267188AD</code></td></tr><tr><td>Polygon</td><td><code>0x6762157b73941e36cEd0AEf54614DdE545d0F990</code></td></tr><tr><td>Scroll</td><td><code>0x055625d48968f99409244E8c3e03FbE73B235a62</code></td></tr><tr><td>SeiEVM</td><td><code>0x3F2D6441C7a59Dfe80f8e14142F9E28F6D440445</code></td></tr><tr><td>Sonic</td><td><code>0xaCa00703bb87F31D6F9fCcc963548b48FA46DfeB</code></td></tr><tr><td>Sui</td><td><code>N/A*</code></td></tr><tr><td>Unichain</td><td><code>0x607723D6353Dae3ef62B7B277Cfabd0F4bc6CB4C</code></td></tr><tr><td>World Chain</td><td><code>0x66b1644400D51e104272337226De3EF1A820eC79</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x6bBd1ff3bB303F88835A714EE3241bF45DE26d29</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x54DD7080aE169DD923fE56d0C4f814a0a17B8f41</code></td></tr><tr><td>Solana</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>0G Galileo</td><td><code>0xA8CA118f4C8d44Ab651Dad52B5E1a212e5d5c55b</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xd048170F1ECB8D47E499D3459aC379DA023E2C1B</code></td></tr><tr><td>Avalanche</td><td><code>0x4e9Af03fbf1aa2b79A2D4babD3e22e09f18Bb8EE</code></td></tr><tr><td>Base Sepolia</td><td><code>0x5845E08d890E21687F7Ebf7CbAbD360cD91c6245</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x39B57Dd9908F8be02CfeE283b67eA1303Bc29fe1</code></td></tr><tr><td>Celo</td><td><code>0x3d69869fcB9e1CD1F4020b637fb8256030BAc8fC</code></td></tr><tr><td>Converge</td><td><code>0x3d8c26b67BDf630FBB44F09266aFA735F1129197</code></td></tr><tr><td>Fogo</td><td><code>nex1gkSWtRBheEJuQZMqHhbMG5A45qPU76KqnCZNVHR</code></td></tr><tr><td>Ink</td><td><code>0xF420BFFf922D11c2bBF587C9dF71b83651fAf8Bc</code></td></tr><tr><td>Linea Sepolia</td><td><code>0xaA469cb84C91D5a63bf4B370dE35f0831F2CE4FF</code></td></tr><tr><td>Mezo</td><td><code>0x484b5593BbB90383f94FB299470F09427cf6cfE2</code></td></tr><tr><td>Moca</td><td><code>0x47f26bF9253Eb398fBAf825D7565FE975D839a71</code></td></tr><tr><td>Monad Testnet</td><td><code>0xc8F014FE6a8521259D9ADDc2170bA9e59305D306</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xaDB1C56D363FF5A75260c3bd27dd7C1fC8421EF5</code></td></tr><tr><td>Plume</td><td><code>0x6Eb53371f646788De6B4D0225a4Ed1d9267188AD</code></td></tr><tr><td>Polygon</td><td><code>0x2982B9566E912458fE711FB1Fd78158264596937</code></td></tr><tr><td>SeiEVM</td><td><code>0x3F2D6441C7a59Dfe80f8e14142F9E28F6D440445</code></td></tr><tr><td>Unichain Sepolia</td><td><code>0x607723D6353Dae3ef62B7B277Cfabd0F4bc6CB4C</code></td></tr><tr><td>XRPL EVM Testnet</td><td><code>0xcDD9d7C759b29680f7a516d0058de8293b2AC7b1</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 3, "depth": 2, "title": "WTT Executor", "anchor": "wtt-executor", "start_char": 15263, "end_char": 19588, "estimated_token_count": 1457, "token_estimator": "heuristic-v1", "text": "## WTT Executor\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xa8969F3f8D97b3Ed89D4e2EC19B6B0CfD504b212</code></td></tr><tr><td>Solana</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x3dBb4dCf25dBA8F0C2417E1c34e527De0E465ecc</code></td></tr><tr><td>Arbitrum</td><td><code>0x04C98824a64d75CD1E9Bc418088b4c9A99048153</code></td></tr><tr><td>Avalanche</td><td><code>0x8849F05675E034b54506caB84450c8C82694a786</code></td></tr><tr><td>Base</td><td><code>0xD8B736EF27Fc997b1d00F22FE37A58145D3BDA07</code></td></tr><tr><td>Berachain</td><td><code>0xFAeFa20CB3759AEd2310E25015F05d62D8567A3F</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x2513515340fF71DD5AF02fC1BdB9615704d91524</code></td></tr><tr><td>Celo</td><td><code>0xe478DEe705BEae591395B08934FA19F54df316BE</code></td></tr><tr><td>Fantom</td><td><code>0xcafd2f0a35a4459fa40c0517e17e6fa2939441ca</code></td></tr><tr><td>Fogo</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>Ink</td><td><code>0x4bFB47F4c8A904d2C24e73601D175FE3a38aAb5B</code></td></tr><tr><td>MegaETH</td><td><code>0x4eEC1c908aD6e778664Efb03386C429fE5710D77</code></td></tr><tr><td>Monad</td><td><code>0xf7E051f93948415952a2239582823028DacA948e</code></td></tr><tr><td>Moonbeam</td><td><code>0xF6b9616C63Fa48D07D82c93CE02B5d9111c51a3d</code></td></tr><tr><td>Optimism</td><td><code>0x37aC29617AE74c750a1e4d55990296BAF9b8De73</code></td></tr><tr><td>Polygon</td><td><code>0x1d98CA4221516B9ac4869F5CeA7E6bb9C41609D6</code></td></tr><tr><td>Scroll</td><td><code>0x05129e142e7d5A518D81f19Db342fBF5f7E26A18</code></td></tr><tr><td>SeiEVM</td><td><code>0x7C129bc8F6188d12c0d1BBDE247F134148B97618</code></td></tr><tr><td>Sui</td><td><code>0x9b68b36399a3cd87680878d72253b3e8fdf82edb8ed74f7ec440b8bddd51f85d</code></td></tr><tr><td>Unichain</td><td><code>0x9Bca817F67f01557aeD615130825A28F4C5f3b87</code></td></tr><tr><td>World Chain</td><td><code>0xc0565Bd29b34603C0383598E16843d95Ae9c4f65</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x37bCc9d175124F77Bfce68589d2a8090eF846B85</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xb0b2119067cF04fa959f654250BD49fE1BD6F53c</code></td></tr><tr><td>Solana</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x57188fC61ce92c8E941504562811660Ab883E895</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0xaE8dc4a7438801Ec4edC0B035EcCCcF3807F4CC1</code></td></tr><tr><td>Avalanche</td><td><code>0x10Ce9a35883C44640e8B12fea4Cc1e77F77D8c52</code></td></tr><tr><td>Base Sepolia</td><td><code>0x523d25D33B975ad72283f73B1103354352dBCBb8</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x26e7e3869b781f360A108728EE8391Cee6051E17</code></td></tr><tr><td>Celo</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Fantom</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Fogo</td><td><code>tbr7Qje6qBzPwfM52csL5KFi8ps5c5vDyiVVBLYVdRf</code></td></tr><tr><td>Linea</td><td><code>0x1C5CC8522b5eE1e528159989A163167bC9264D07</code></td></tr><tr><td>Mezo</td><td><code>0x2002a44b1106DF83671Fb419A2079a75e2a34808</code></td></tr><tr><td>Moca</td><td><code>0x36b91D24BAba19Af3aD1b5D5E2493A571044f14F</code></td></tr><tr><td>Monad Testnet</td><td><code>0x03D9739c91a26d30f4B35f7e55B9FF995ef13dDb</code></td></tr><tr><td>Moonbeam</td><td><code>0x9563a59c15842a6f322b10f69d1dd88b41f2e97b</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0xD9AA4f8Ac271B3149b8C3d1D0f999Ef7cb9af9EC</code></td></tr><tr><td>Polygon Amoy</td><td><code>0xC5c0bF6A8419b3d47150B2a6146b7Ed598C9d736</code></td></tr><tr><td>SeiEVM</td><td><code>0x595712bA7e4882af338d60ae37058082a5d0331A</code></td></tr><tr><td>Sui</td><td><code>0xb4b86c12d4ee0a813d976fb452b7afb325a2b381d00ccb2e54c5342f5ef2e684</code></td></tr><tr><td>Unichain</td><td><code>0x74D37B2bcD2f8CaB6409c5a5f81C8cF5b4156963</code></td></tr><tr><td>XRPL-EVM</td><td><code>0xb00224c60fe6ab134c8544dc29350286545f8dcc</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 4, "depth": 2, "title": "WTT Executor With Referrer", "anchor": "wtt-executor-with-referrer", "start_char": 19588, "end_char": 22907, "estimated_token_count": 1128, "token_estimator": "heuristic-v1", "text": "## WTT Executor With Referrer\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Arbitrum</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Avalanche</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Base</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Berachain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Celo</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Ink</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>MegaETH</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Monad</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Moonbeam</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Optimism</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Polygon</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Scroll</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>SeiEVM</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Unichain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>World Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x13a35c075D6Acc1Fb9BddFE5FE38e7672789e4db</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>0G (Zero Gravity)</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Avalanche</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Base Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Linea</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Mezo</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Moca</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Monad Testnet</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>SeiEVM</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>Unichain</td><td><code>0x412f30e9f8B4a1e99eaE90209A6b00f5C3cc8739</code></td></tr><tr><td>XRPL-EVM</td><td><code>0x17CFAAf9e8a5ABb1eee758dB9040F945c9EAC907</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 5, "depth": 2, "title": "On-Chain Quoter", "anchor": "on-chain-quoter", "start_char": 22907, "end_char": 23125, "estimated_token_count": 42, "token_estimator": "heuristic-v1", "text": "## On-Chain Quoter\n\n!!! note\n    Wormhole Labs’ Quoter uses the following public keys:\n\n    - **Mainnet**: `0xa54008017941EcE968623a0Dd8Ee907E2b133596`.\n    - **Testnet**: `0x5241c9276698439fef2780dbab76fec90b633fbd`."}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 6, "depth": 3, "title": "Wormhole Labs Quoter Implementation", "anchor": "wormhole-labs-quoter-implementation", "start_char": 23125, "end_char": 25176, "estimated_token_count": 694, "token_estimator": "heuristic-v1", "text": "### Wormhole Labs Quoter Implementation\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Arbitrum</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Avalanche</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Base</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Ink</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Monad</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Optimism</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Plume</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Polygon</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr><tr><td>Sei</td><td><code>0xA25862D222Eb8343505c12d96e097e4332468D60</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Solana</td><td><code>qtrxiqVAfVS61utwZLUi7UKugjCgFaNxBGyskmGingz</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Avalanche</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Base Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Polygon Amoy</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr><tr><td>Sei</td><td><code>0x5a6c5A46082D029FDD7c5cF8265047E0c4BB2089</code></td></tr></tbody></table>"}
{"page_id": "products-reference-executor-addresses", "page_title": "Executor Addresses", "index": 7, "depth": 3, "title": "Quoter Router", "anchor": "quoter-router", "start_char": 25176, "end_char": 27204, "estimated_token_count": 692, "token_estimator": "heuristic-v1", "text": "### Quoter Router\n\n\n\n=== \"Mainnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum</td><td><code>0xF22F1c0A3a8Cb42F695601731974784C499C4EF3</code></td></tr><tr><td>Arbitrum</td><td><code>0x32eec14c963c23176bd8951f192292006756bDcC</code></td></tr><tr><td>Avalanche</td><td><code>0xA3a2A615774d34c6a4dF443C488B084eacaBd2D0</code></td></tr><tr><td>Base</td><td><code>0x265fd0500a430d65d6D79Cd8707F24C048604658</code></td></tr><tr><td>BNB Smart Chain</td><td><code>0xc921F293c27F332D47283174b11C872295624Edb</code></td></tr><tr><td>Ink</td><td><code>0xdEC050E66BEb2f0d5507761A0fE4867839bd88D2</code></td></tr><tr><td>Monad</td><td><code>0x3d9282A8e9a3cdd9b25AE969eff4705a1Fe75F34</code></td></tr><tr><td>Optimism</td><td><code>0xa3B6551cCbB5Fe1dc33b71EE3590B1Df22ae75B3</code></td></tr><tr><td>Plume</td><td><code>0x85BA1B2A2195be51Ab715be458B32B120532d230</code></td></tr><tr><td>Polygon</td><td><code>0x2a856931603930B827B1A4352FB4D66fA029F123</code></td></tr><tr><td>Sei</td><td><code>0x1D6FeA87671F7c5E184F4c59c3BdcEc5CFC3eC1c</code></td></tr></tbody></table>\n\n=== \"Testnet\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Chain Name</th><th>Contract Address</th></thead><tbody><tr><td>Ethereum Sepolia</td><td><code>0xc0C35D7bfBc4175e0991Ae294f561b433eA4158f</code></td></tr><tr><td>Solana</td><td><code>qtrrrV7W3E1jnX1145wXR6ZpthG19ur5xHC1n6PPhDV</code></td></tr><tr><td>Arbitrum Sepolia</td><td><code>0x5E8c14F436c9ed2ff2E8B042B0542136bf108C6f</code></td></tr><tr><td>Avalanche</td><td><code>0xA3a2A615774d34c6a4dF443C488B084eacaBd2D0</code></td></tr><tr><td>Base Sepolia</td><td><code>0x2507d6899C3D4b93BF46b555d0cB401f44065772</code></td></tr><tr><td>Optimism Sepolia</td><td><code>0x6a829dF7C91f35f9aD72Cd5d05550b95BbC9fd2F</code></td></tr><tr><td>Polygon Amoy</td><td><code>0xE00444636DA924FBAe94471d73D56b5E03cA781c</code></td></tr><tr><td>Sei</td><td><code>0x1D6FeA87671F7c5E184F4c59c3BdcEc5CFC3eC1c</code></td></tr></tbody></table>"}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 0, "depth": 2, "title": "Chain ID", "anchor": "chain-id", "start_char": 120, "end_char": 454, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "## Chain ID\n\nWormhole 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.\n\nYou can find each chain ID documented on the [Wormhole Chain IDs](/docs/products/reference/chain-ids/){target=\\_blank} page."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 1, "depth": 2, "title": "Consistency Level", "anchor": "consistency-level", "start_char": 454, "end_char": 692, "estimated_token_count": 52, "token_estimator": "heuristic-v1", "text": "## Consistency Level\n\nThe 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."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 2, "depth": 2, "title": "Delivery Provider", "anchor": "delivery-provider", "start_char": 692, "end_char": 847, "estimated_token_count": 24, "token_estimator": "heuristic-v1", "text": "## Delivery Provider\n\nA Delivery Provider monitors for Executor delivery requests and delivers those requests to the intended target chain as instructed."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 3, "depth": 2, "title": "Emitter", "anchor": "emitter", "start_char": 847, "end_char": 1045, "estimated_token_count": 36, "token_estimator": "heuristic-v1", "text": "## Emitter\n\nThe emitter contract makes the call to the Wormhole Core Contract. The published message includes the emitter contract address, and a sequence number is tracked to provide a unique ID."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 4, "depth": 2, "title": "Finality", "anchor": "finality", "start_char": 1045, "end_char": 1242, "estimated_token_count": 35, "token_estimator": "heuristic-v1", "text": "## Finality\n\nThe finality of a transaction depends on its blockchain properties. Once a transaction is considered final, you can assume the resulting state changes it caused will not be reverted."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 5, "depth": 2, "title": "Guardian", "anchor": "guardian", "start_char": 1242, "end_char": 1429, "estimated_token_count": 42, "token_estimator": "heuristic-v1", "text": "## Guardian\n\nA [Guardian](/docs/protocol/infrastructure/guardians/){target=\\_blank} is one of the 19 parties running validators in the Guardian Network contributing to the VAA multisig."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 6, "depth": 2, "title": "Guardian Network", "anchor": "guardian-network", "start_char": 1429, "end_char": 2009, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "## Guardian Network\n\nValidators operating in a dedicated P2P network that serve as Wormhole's oracle layer. Guardians monitor on-chain activity and generate signed messages (VAAs) attesting to it.\n\nFor full Guardian Set chains, all 19 Guardians perform direct on-chain observation. For delegated chains, a delegated subset monitors and broadcasts signed delegate observations to the rest of the network. Canonical Guardians wait for a delegate quorum before signing. Regardless of the observation path, VAAs are always finalized as standard 13-of-19 multisignature attestations."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 7, "depth": 2, "title": "Guardian Set", "anchor": "guardian-set", "start_char": 2009, "end_char": 2578, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Guardian Set\n\nThe Guardian Set is the canonical set of 19 Guardians responsible for producing VAAs. A supermajority of 13 signatures is required to generate a valid VAA.\n\nFor certain chains, governance may configure a delegated subset of the Guardian Set to perform direct on-chain observation with a smaller per-chain quorum. Canonical Guardians wait for a delegate quorum before signing, ensuring that the effective security threshold for a chain cannot fall below its configured level.\n\nThe composition of the Guardian Set may change through governance actions."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 8, "depth": 2, "title": "Delegated Guardian", "anchor": "delegated-guardian", "start_char": 2578, "end_char": 3220, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "## Delegated Guardian\n\nA Guardian configured to perform direct on-chain observation for a delegated chain. Delegated Guardians broadcast `SignedDelegateObservation` messages to the Guardian gossip network.\n\nIn contrast, a Canonical Guardian does not observe that chain directly, it waits for enough `DelegateObservation` messages (the delegate quorum) before contributing its signature to the VAA.\n\nThe key distinction: on a delegated chain, Delegated Guardians run full nodes and watch the chain themselves, while Canonical Guardians trust the delegate quorum before signing. The final VAA is still a standard 13-of-19 multisig regardless."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 9, "depth": 2, "title": "Heartbeat", "anchor": "heartbeat", "start_char": 3220, "end_char": 3580, "estimated_token_count": 85, "token_estimator": "heuristic-v1", "text": "## Heartbeat\n\nEach 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.\n\nYou can view the heartbeats on the [Wormhole dashboard](https://wormhole-foundation.github.io/wormhole-dashboard/#/?endpoint=Mainnet){target=\\_blank}."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 10, "depth": 2, "title": "Observation", "anchor": "observation", "start_char": 3580, "end_char": 3716, "estimated_token_count": 24, "token_estimator": "heuristic-v1", "text": "## Observation\n\nAn Observation is a data structure describing a message emitted by the Core Contract and noticed by the Guardian node."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 11, "depth": 2, "title": "Relayer", "anchor": "relayer", "start_char": 3716, "end_char": 3791, "estimated_token_count": 15, "token_estimator": "heuristic-v1", "text": "## Relayer\n\nA relayer is any process that delivers VAAs to a destination."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 12, "depth": 2, "title": "Sequence", "anchor": "sequence", "start_char": 3791, "end_char": 3927, "estimated_token_count": 26, "token_estimator": "heuristic-v1", "text": "## Sequence\n\nA nonce, strictly increasing, which is tracked by the Wormhole Core Contract and unique to the emitter chain and address."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 13, "depth": 2, "title": "Spy", "anchor": "spy", "start_char": 3927, "end_char": 4056, "estimated_token_count": 26, "token_estimator": "heuristic-v1", "text": "## Spy\n\nA Spy is a daemon that eavesdrops on the messages passed between Guardians, typically to track VAAs as they get signed."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 14, "depth": 2, "title": "VAA", "anchor": "vaa", "start_char": 4056, "end_char": 4306, "estimated_token_count": 53, "token_estimator": "heuristic-v1", "text": "## VAA\n\n[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."}
{"page_id": "products-reference-glossary", "page_title": "Glossary", "index": 15, "depth": 2, "title": "Validator", "anchor": "validator", "start_char": 4306, "end_char": 4425, "estimated_token_count": 20, "token_estimator": "heuristic-v1", "text": "## Validator\n\nA daemon configured to monitor a blockchain node and observe messages emitted by the Wormhole contracts."}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 0, "depth": 2, "title": "Supported Networks by Product", "anchor": "supported-networks-by-product", "start_char": 235, "end_char": 269, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## Supported Networks by Product"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 1, "depth": 3, "title": "Connect", "anchor": "connect", "start_char": 269, "end_char": 13570, "estimated_token_count": 5769, "token_estimator": "heuristic-v1", "text": "### Connect\n\n\n\n<div class=\"full-width\" markdown>\n\n<table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Aptos</td><td>Move VM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://aptosnetwork.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://aptos.dev/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.aptoslabs.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Berachain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.berachain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.berachain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://berascan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>BNB Smart Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.bnbchain.org/en/bnb-smart-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.bnbchain.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://bscscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Celo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://celo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.celo.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://celo.blockscout.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>CreditCoin</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://creditcoin.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.creditcoin.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://creditcoin.subscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fantom</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://fantom.foundation/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.fantom.foundation/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.fantom.network/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fogo</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.fogo.io/\" target=\"_blank\">Website</a><br>:octicons-package-16: <a href=\"https://fogoscan.com/?cluster=testnet\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>HyperCore</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://hyperfoundation.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>Ink</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://inkonchain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.inkonchain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer-sepolia.inkonchain.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Kaia</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.kaia.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.kaia.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://kaiascan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Linea</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://linea.build/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.linea.build/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.linea.build/get-started/build/block-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mantle</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.mantle.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.mantle.xyz/network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mantlescan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>MegaETH</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.megaeth.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.megaeth.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mega.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mezo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://mezo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mezo.org/docs/developers/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.test.mezo.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moca</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://mocachain.org/en\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mocacoin.gitbook.io/litepaper\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://devnet-scan.mocachain.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Monad</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.monad.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.monad.xyz/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://testnet.monvision.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moonbeam</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://moonbeam.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.moonbeam.network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://moonscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Plume</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://plume.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.plume.org/plume\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.plume.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Scroll</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://scroll.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.scroll.io/en/home/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://scrollscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/evm\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://seistream.app/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sonic</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.soniclabs.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.soniclabs.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sonicscan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://world.org/world-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.world.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.world.org/world-chain/providers/explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>X Layer</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://web3.okx.com/xlayer\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://web3.okx.com/explorer/x-layer\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>XRPL-EVM</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.xrplevm.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.xrplevm.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.xrplevm.org/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 2, "depth": 3, "title": "NTT", "anchor": "ntt", "start_char": 13570, "end_char": 26377, "estimated_token_count": 5559, "token_estimator": "heuristic-v1", "text": "### NTT\n\n\n\n<div class=\"full-width\" markdown>\n\n<table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>0G (Zero Gravity)</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://0g.ai/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.0g.ai/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://chainscan.0g.ai\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Berachain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.berachain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.berachain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://berascan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>BNB Smart Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.bnbchain.org/en/bnb-smart-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.bnbchain.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://bscscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Celo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://celo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.celo.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://celo.blockscout.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Converge</td><td>EVM</td><td>:x:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.convergeonchain.xyz/\" target=\"_blank\">Website</a><br></td></tr><tr><td>CreditCoin</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://creditcoin.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.creditcoin.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://creditcoin.subscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fantom</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://fantom.foundation/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.fantom.foundation/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.fantom.network/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fogo</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.fogo.io/\" target=\"_blank\">Website</a><br>:octicons-package-16: <a href=\"https://fogoscan.com/?cluster=testnet\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://hyperfoundation.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>Ink</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://inkonchain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.inkonchain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer-sepolia.inkonchain.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Kaia</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.kaia.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.kaia.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://kaiascan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Linea</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://linea.build/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.linea.build/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.linea.build/get-started/build/block-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mantle</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.mantle.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.mantle.xyz/network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mantlescan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>MegaETH</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.megaeth.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.megaeth.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mega.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mezo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://mezo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mezo.org/docs/developers/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.test.mezo.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moca</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://mocachain.org/en\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mocacoin.gitbook.io/litepaper\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://devnet-scan.mocachain.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Monad</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.monad.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.monad.xyz/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://testnet.monvision.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moonbeam</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://moonbeam.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.moonbeam.network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://moonscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Plume</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://plume.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.plume.org/plume\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.plume.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Scroll</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://scroll.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.scroll.io/en/home/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://scrollscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/evm\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://seistream.app/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://world.org/world-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.world.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.world.org/world-chain/providers/explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>X Layer</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://web3.okx.com/xlayer\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://web3.okx.com/explorer/x-layer\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>XRPL-EVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.xrplevm.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.xrplevm.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.xrplevm.org/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 3, "depth": 3, "title": "WTT", "anchor": "wtt", "start_char": 26377, "end_char": 40304, "estimated_token_count": 5963, "token_estimator": "heuristic-v1", "text": "### WTT\n\n\n\n<div class=\"full-width\" markdown>\n\n<table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>0G (Zero Gravity)</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://0g.ai/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.0g.ai/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://chainscan.0g.ai\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Algorand</td><td>AVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://algorandtechnologies.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://dev.algorand.co\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://allo.info/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Aptos</td><td>Move VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://aptosnetwork.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://aptos.dev/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.aptoslabs.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Berachain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.berachain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.berachain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://berascan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>BNB Smart Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.bnbchain.org/en/bnb-smart-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.bnbchain.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://bscscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Celo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://celo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.celo.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://celo.blockscout.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fantom</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://fantom.foundation/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.fantom.foundation/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.fantom.network/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fogo</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.fogo.io/\" target=\"_blank\">Website</a><br>:octicons-package-16: <a href=\"https://fogoscan.com/?cluster=testnet\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>:x:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://hyperfoundation.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>Injective</td><td>CosmWasm</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://injective.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.injective.network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://injscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Ink</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://inkonchain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.inkonchain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer-sepolia.inkonchain.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Kaia</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.kaia.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.kaia.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://kaiascan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Linea</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://linea.build/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.linea.build/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.linea.build/get-started/build/block-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mantle</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.mantle.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.mantle.xyz/network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mantlescan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>MegaETH</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.megaeth.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.megaeth.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mega.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mezo</td><td>EVM</td><td>:x:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://mezo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mezo.org/docs/developers/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.test.mezo.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moca</td><td>EVM</td><td>:x:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://mocachain.org/en\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mocacoin.gitbook.io/litepaper\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://devnet-scan.mocachain.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Monad</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.monad.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.monad.xyz/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://testnet.monvision.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moonbeam</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://moonbeam.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.moonbeam.network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://moonscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>NEAR</td><td>NEAR VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://near.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.near.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://nearblocks.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Scroll</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://scroll.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.scroll.io/en/home/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://scrollscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sei</td><td>CosmWasm</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.sei.io/learn/explorers#sei-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/evm\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://seistream.app/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://world.org/world-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.world.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.world.org/world-chain/providers/explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>X Layer</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://web3.okx.com/xlayer\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://web3.okx.com/explorer/x-layer\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>XRPL-EVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.xrplevm.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.xrplevm.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.xrplevm.org/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 4, "depth": 3, "title": "CCTP", "anchor": "cctp", "start_char": 40304, "end_char": 51230, "estimated_token_count": 4714, "token_estimator": "heuristic-v1", "text": "### CCTP\n\n\n\n<div class=\"full-width\" markdown>\n\n=== \"CCTP v1\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Aptos</td><td>Move VM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://aptosnetwork.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://aptos.dev/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.aptoslabs.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n=== \"CCTP v2\"\n\n    <table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://hyperfoundation.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>Ink</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://inkonchain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.inkonchain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer-sepolia.inkonchain.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Linea</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://linea.build/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.linea.build/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.linea.build/get-started/build/block-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Monad</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.monad.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.monad.xyz/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://testnet.monvision.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Plume</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://plume.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.plume.org/plume\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.plume.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/evm\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://seistream.app/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sonic</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.soniclabs.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.soniclabs.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sonicscan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://world.org/world-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.world.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.world.org/world-chain/providers/explorers\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 5, "depth": 3, "title": "Settlement", "anchor": "settlement", "start_char": 51230, "end_char": 54855, "estimated_token_count": 1598, "token_estimator": "heuristic-v1", "text": "### Settlement\n\n\n\n<div class=\"full-width\" markdown>\n\n<table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:x:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sui</td><td>Sui Move VM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.sui.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sui.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://suiscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:x:</td><td>:x:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-supported-networks", "page_title": "Supported Networks", "index": 6, "depth": 3, "title": "Multigov", "anchor": "multigov", "start_char": 54855, "end_char": 69189, "estimated_token_count": 5920, "token_estimator": "heuristic-v1", "text": "### Multigov\n\n\n\n<div class=\"full-width\" markdown>\n\n<table data-full-width=\"true\" markdown><thead><th>Blockchain</th><th>Environment</th><th>Mainnet</th><th>Testnet</th><th>Devnet</th><th>Quick Links</th></thead><tbody><tr><td>Ethereum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://ethereum.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://ethereum.org/developers/docs/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Solana</td><td>SVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://solana.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://solana.com/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.solana.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>0G (Zero Gravity)</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://0g.ai/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.0g.ai/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://chainscan.0g.ai\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Arbitrum</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://arbitrum.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.arbitrum.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://arbiscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.avax.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://build.avax.network/docs/primary-network\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://snowtrace.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Base</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://base.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.base.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://basescan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Berachain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.berachain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.berachain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://berascan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>BNB Smart Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.bnbchain.org/en/bnb-smart-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.bnbchain.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://bscscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Celo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://celo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.celo.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://celo.blockscout.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Converge</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.convergeonchain.xyz/\" target=\"_blank\">Website</a><br></td></tr><tr><td>CreditCoin</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://creditcoin.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.creditcoin.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://creditcoin.subscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Fantom</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://fantom.foundation/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.fantom.foundation/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.fantom.network/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>HyperCore</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs/hypercore\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://hyperfoundation.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://hyperliquid.gitbook.io/hyperliquid-docs\" target=\"_blank\">Developer Docs</a><br></td></tr><tr><td>Ink</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://inkonchain.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.inkonchain.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer-sepolia.inkonchain.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Kaia</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.kaia.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.kaia.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://kaiascan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Linea</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://linea.build/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.linea.build/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.linea.build/get-started/build/block-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mantle</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.mantle.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.mantle.xyz/network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mantlescan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>MegaETH</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.megaeth.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.megaeth.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://mega.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Mezo</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://mezo.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mezo.org/docs/developers/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.test.mezo.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moca</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://mocachain.org/en\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://mocacoin.gitbook.io/litepaper\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://devnet-scan.mocachain.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Monad</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.monad.xyz/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.monad.xyz/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://testnet.monvision.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Moonbeam</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://moonbeam.network/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.moonbeam.network/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://moonscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Optimism</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.optimism.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.optimism.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://optimistic.etherscan.io/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Plasma</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.plasma.to/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://www.plasma.to/docs/get-started/introduction/start-here\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://plasmascan.to/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Plume</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://plume.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.plume.org/plume\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.plume.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Polygon</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://polygon.technology/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.polygon.technology/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://polygonscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Scroll</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://scroll.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.scroll.io/en/home/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://scrollscan.com/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sei</td><td>CosmWasm</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.sei.io/learn/explorers#sei-explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.sei.io/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.sei.io/evm\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://seistream.app/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Sonic</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.soniclabs.com/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.soniclabs.com/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sonicscan.org/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.unichain.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.unichain.org/docs\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://sepolia.uniscan.xyz/\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://world.org/world-chain\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.world.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://docs.world.org/world-chain/providers/explorers\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>X Layer</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://web3.okx.com/xlayer\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://web3.okx.com/xlayer/docs/developer/build-on-xlayer/about-xlayer\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://web3.okx.com/explorer/x-layer\" target=\"_blank\">Block Explorer</a></td></tr><tr><td>XRPL-EVM</td><td>EVM</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:white_check_mark:</td><td>:material-web: <a href=\"https://www.xrplevm.org/\" target=\"_blank\">Website</a><br>:material-file-document: <a href=\"https://docs.xrplevm.org/\" target=\"_blank\">Developer Docs</a><br>:octicons-package-16: <a href=\"https://explorer.xrplevm.org/\" target=\"_blank\">Block Explorer</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 0, "depth": 3, "title": "EVM", "anchor": "evm", "start_char": 307, "end_char": 4826, "estimated_token_count": 2098, "token_estimator": "heuristic-v1", "text": "### EVM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Ethereum Holesky</td><td>EVM</td><td>ETH</td><td><a href=\"https://www.alchemy.com/faucets/ethereum-holesky\" target=\"_blank\">Alchemy Faucet</a></td></tr><tr><td>Ethereum Sepolia</td><td>EVM</td><td>ETH</td><td><a href=\"https://www.alchemy.com/faucets/ethereum-sepolia\" target=\"_blank\">Alchemy Faucet</a></td></tr><tr><td>0G (Zero Gravity)</td><td>EVM</td><td>0G</td><td><a href=\"https://faucet.0g.ai/\" target=\"_blank\">0G Official Faucet</a></td></tr><tr><td>Arbitrum Sepolia</td><td>EVM</td><td>ETH</td><td><a href=\"https://docs.arbitrum.io/for-devs/dev-tools-and-resources/chain-info#faucets\" target=\"_blank\">List of Faucets</a></td></tr><tr><td>Avalanche</td><td>EVM</td><td>AVAX</td><td><a href=\"https://core.app/tools/testnet-faucet/?subnet=c&token=c\" target=\"_blank\">Official Avalanche Faucet</a></td></tr><tr><td>Base Sepolia</td><td>EVM</td><td>ETH</td><td><a href=\"https://docs.base.org/docs/tools/network-faucets/\" target=\"_blank\">List of Faucets</a></td></tr><tr><td>Berachain</td><td>EVM</td><td>BERA</td><td><a href=\"https://bepolia.faucet.berachain.com/\" target=\"_blank\">Official Berachain Faucet</a></td></tr><tr><td>BNB Smart Chain</td><td>EVM</td><td>BNB</td><td><a href=\"https://www.bnbchain.org/en/testnet-faucet\" target=\"_blank\">Official BNB Faucet</a></td></tr><tr><td>Sonic</td><td>EVM</td><td>S</td><td><a href=\"https://testnet.soniclabs.com/account\" target=\"_blank\">Official Sonic Faucet</a></td></tr><tr><td>HyperEVM :material-alert:{ title='⚠️ The HyperEVM integration is experimental, as its node software is not open source. Use Wormhole messaging on HyperEVM with caution.' }</td><td>EVM</td><td>mock USDC</td><td><a href=\"https://app.hyperliquid-testnet.xyz/drip\" target=\"_blank\">Official Hyperliquid Faucet</a></td></tr><tr><td>Ink</td><td>EVM</td><td>ETH</td><td><a href=\"https://inkonchain.com/faucet\" target=\"_blank\">Official Ink Faucet</a></td></tr><tr><td>Kaia</td><td>EVM</td><td>KAIA</td><td><a href=\"https://www.kaia.io/faucet\" target=\"_blank\">Official Kaia Faucet</a></td></tr><tr><td>Linea</td><td>EVM</td><td>ETH</td><td><a href=\"https://docs.linea.build/get-started/how-to/get-testnet-eth\" target=\"_blank\">List of Faucets</a></td></tr><tr><td>Mantle</td><td>EVM</td><td>MNT</td><td><a href=\"https://faucet.sepolia.mantle.xyz/\" target=\"_blank\">Official Mantle Faucet</a></td></tr><tr><td>MegaETH</td><td>EVM</td><td>ETH</td><td><a href=\"https://testnet.megaeth.com/\" target=\"_blank\">Official MegaETH Faucet</a></td></tr><tr><td>Moca</td><td>EVM</td><td>MOCA</td><td><a href=\"https://devnet-scan.mocachain.org/faucet\" target=\"_blank\">Official Moca Faucet</a></td></tr><tr><td>Monad Testnet</td><td>EVM</td><td>MON</td><td><a href=\"https://testnet.monad.xyz/\" target=\"_blank\">Official Monad Faucet</a></td></tr><tr><td>Moonbeam</td><td>EVM</td><td>DEV</td><td><a href=\"https://faucet.moonbeam.network/\" target=\"_blank\">Official Moonbeam Faucet</a></td></tr><tr><td>Optimism Sepolia</td><td>EVM</td><td>ETH</td><td><a href=\"https://console.optimism.io/faucet\" target=\"_blank\">Superchain Faucet</a></td></tr><tr><td>Plasma</td><td>EVM</td><td>XPL</td><td><a href=\"https://faucet.quicknode.com/plasma\" target=\"_blank\">QuickNode Faucet</a></td></tr><tr><td>Plume</td><td>EVM</td><td>PLUME</td><td><a href=\"https://faucet.plume.org/\" target=\"_blank\">Official Plume Faucet</a></td></tr><tr><td>Polygon Amoy</td><td>EVM</td><td>POL</td><td><a href=\"https://faucet.polygon.technology/\" target=\"_blank\">Official Polygon Faucet</a></td></tr><tr><td>Scroll</td><td>EVM</td><td>SCR</td><td><a href=\"https://docs.scroll.io/en/developers/faq/#testnet-eth\" target=\"_blank\">List of Faucets</a></td></tr><tr><td>SeiEVM</td><td>EVM</td><td>SEI</td><td><a href=\"https://docs.sei.io/learn/faucet\" target=\"_blank\">Sei Atlantic-2 Faucet</a></td></tr><tr><td>Unichain</td><td>EVM</td><td>ETH</td><td><a href=\"https://faucet.quicknode.com/unichain/sepolia\" target=\"_blank\">QuickNode Faucet</a></td></tr><tr><td>World Chain</td><td>EVM</td><td>ETH</td><td><a href=\"https://www.alchemy.com/faucets/world-chain-sepolia\" target=\"_blank\">Alchemy Faucet</a></td></tr><tr><td>X Layer</td><td>EVM</td><td>OKB</td><td><a href=\"https://web3.okx.com/xlayer/faucet\" target=\"_blank\">X Layer Official Faucet</a></td></tr><tr><td>XRPL-EVM</td><td>EVM</td><td>XRP</td><td><a href=\"https://faucet.xrplevm.org/\" target=\"_blank\">XRPL Official Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 1, "depth": 3, "title": "SVM", "anchor": "svm", "start_char": 4826, "end_char": 5119, "estimated_token_count": 134, "token_estimator": "heuristic-v1", "text": "### SVM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Pythnet</td><td>SVM</td><td>ETH</td><td><a href=\"https://console.optimism.io/faucet\" target=\"_blank\">Superchain Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 2, "depth": 3, "title": "AVM", "anchor": "avm", "start_char": 5119, "end_char": 5423, "estimated_token_count": 137, "token_estimator": "heuristic-v1", "text": "### AVM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Algorand</td><td>AVM</td><td>ALGO</td><td><a href=\"https://lora.algokit.io/testnet/fund\" target=\"_blank\">Official Algorand Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 3, "depth": 3, "title": "CosmWasm", "anchor": "cosmwasm", "start_char": 5423, "end_char": 6980, "estimated_token_count": 697, "token_estimator": "heuristic-v1", "text": "### CosmWasm\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Celestia</td><td>CosmWasm</td><td>TIA</td><td><a href=\"https://discord.com/invite/celestiacommunity\" target=\"_blank\">Discord Faucet</a></td></tr><tr><td>Cosmos Hub</td><td>CosmWasm</td><td>ATOM</td><td><a href=\"https://discord.com/invite/cosmosnetwork\" target=\"_blank\">Discord Faucet</a></td></tr><tr><td>Injective</td><td>CosmWasm</td><td>INJ</td><td><a href=\"https://testnet.faucet.injective.network/\" target=\"_blank\">Official Injective Faucet</a></td></tr><tr><td>Kujira</td><td>CosmWasm</td><td>KUJI</td><td><a href=\"https://discord.com/channels/970650215801569330/1009931570263629854\" target=\"_blank\">Discord Faucet</a></td></tr><tr><td>Neutron</td><td>CosmWasm</td><td>NTRN</td><td><a href=\"https://docs.neutron.org/developers/faq#where-is-the-testnet-faucet\" target=\"_blank\">List of Faucets</a></td></tr><tr><td>Noble</td><td>CosmWasm</td><td>USDC</td><td><a href=\"https://faucet.circle.com/\" target=\"_blank\">Circle Faucet</a></td></tr><tr><td>Osmosis</td><td>CosmWasm</td><td>OSMO</td><td><a href=\"https://faucet.testnet.osmosis.zone/\" target=\"_blank\">Official Osmosis Faucet</a></td></tr><tr><td>SEDA</td><td>CosmWasm</td><td>SEDA</td><td><a href=\"https://devnet.explorer.seda.xyz/faucet\" target=\"_blank\">Official SEDA Faucet</a></td></tr><tr><td>Sei</td><td>CosmWasm</td><td>SEI</td><td><a href=\"https://docs.sei.io/learn/faucet\" target=\"_blank\">Sei Atlantic-2 Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 4, "depth": 3, "title": "Move VM", "anchor": "move-vm", "start_char": 6980, "end_char": 7277, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### Move VM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Aptos</td><td>Move VM</td><td>APT</td><td><a href=\"https://www.aptosfaucet.com/\" target=\"_blank\">Official Aptos Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 5, "depth": 3, "title": "NEAR VM", "anchor": "near-vm", "start_char": 7277, "end_char": 7568, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### NEAR VM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>NEAR</td><td>NEAR VM</td><td>NEAR</td><td><a href=\"https://near-faucet.io/\" target=\"_blank\">Official NEAR Faucet</a></td></tr></tbody></table>"}
{"page_id": "products-reference-testnet-faucets", "page_title": "Testnet Faucets", "index": 6, "depth": 3, "title": "Sui Move VM", "anchor": "sui-move-vm", "start_char": 7568, "end_char": 7906, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "### Sui Move VM\n\n<table data-full-width=\"true\" markdown><thead><th>Testnet</th><th>Environment</th><th>Token</th><th>Faucet</th></thead><tbody><tr><td>Sui</td><td>Sui Move VM</td><td>SUI</td><td><a href=\"https://docs.sui.io/guides/developer/getting-started/get-coins\" target=\"_blank\">List of Faucets</a></td></tr></tbody></table>\n\n</div>"}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 0, "depth": 2, "title": "Platform-Specific Address Formats", "anchor": "platform-specific-address-formats", "start_char": 687, "end_char": 1916, "estimated_token_count": 258, "token_estimator": "heuristic-v1", "text": "## Platform-Specific Address Formats\n\nEach 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.\n\nHere’s an overview of the native address formats and how they are normalized to the Wormhole format:\n\n| Platform        | Native Address Format            | Wormhole Formatted Address |\n|-----------------|----------------------------------|----------------------------|\n| EVM             |  Hex (e.g., 0x...)               |  32-byte Hex               |\n| Solana          |  Base58                          |  32-byte Hex               |\n| CosmWasm        |  Bech32                          |  32-byte Hex               |\n| Algorand        |  Algorand App ID                 |  32-byte Hex               |\n| Sui             |  Hex                             |  32-byte Hex               |\n| Aptos           |  Hex                             |  32-byte Hex               |\n| Near            |  SHA-256                         |  32-byte Hex               |\n\nThese conversions allow Wormhole to interact seamlessly with various chains using a uniform format for all addresses."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 1, "depth": 3, "title": "Address Format Handling", "anchor": "address-format-handling", "start_char": 1916, "end_char": 2774, "estimated_token_count": 228, "token_estimator": "heuristic-v1", "text": "### Address Format Handling\n\nThe 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}:\n\n```typescript\nconst platformAddressFormatEntries = [\n  ['Evm', 'hex'],\n  ['Solana', 'base58'],\n  ['Cosmwasm', 'bech32'],\n  ['Algorand', 'algorandAppId'],\n  ['Sui', 'hex'],\n  ['Aptos', 'hex'],\n  ['Near', 'sha256'],\n];\n```\n\nThese 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."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 2, "depth": 2, "title": "Universal Address Methods", "anchor": "universal-address-methods", "start_char": 2774, "end_char": 4080, "estimated_token_count": 277, "token_estimator": "heuristic-v1", "text": "## Universal Address Methods\n\nThe `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.\n\nKey functions:\n\n - **`new UniversalAddress()`**: Use the `UniversalAddress` constructor to convert native addresses into the Wormhole format.\n\n    ```typescript\n    const universalAddress = new UniversalAddress('0x123...', 'hex');\n    ```\n\n - **`toUniversalAddress()`**: Converts a platform-specific address into the Wormhole formatted 32-byte hex address.\n\n    ```typescript\n    const ethAddress: NativeAddress<'Evm'> = toNative('Ethereum', '0x0C9...');\n    const universalAddress = ethAddress.toUniversalAddress().toString();\n    ```\n\n - **`toNative()`**: Converts the Wormhole formatted address back to a native address for a specific blockchain platform.\n\n    ```typescript\n    const nativeAddress = universalAddress.toNative('Evm');\n    ```\n\n - **`toString()`**: Returns the Wormhole formatted address as a hex string, which can be used in various SDK operations.\n\n    ```typescript\n    console.log(universalAddress.toString());\n    ```\n\nThese methods allow developers to convert between native addresses and the Wormhole format, ensuring cross-chain compatibility."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 3, "depth": 2, "title": "Convert Between Native and Wormhole Formatted Addresses", "anchor": "convert-between-native-and-wormhole-formatted-addresses", "start_char": 4080, "end_char": 4292, "estimated_token_count": 31, "token_estimator": "heuristic-v1", "text": "## Convert Between Native and Wormhole Formatted Addresses\n\nThe Wormhole SDK allows developers to easily convert between native addresses and Wormhole formatted addresses when building cross-chain applications."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 4, "depth": 3, "title": "Convert a Native Address to a Wormhole Formatted Address", "anchor": "convert-a-native-address-to-a-wormhole-formatted-address", "start_char": 4292, "end_char": 5233, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "### Convert a Native Address to a Wormhole Formatted Address\n\nExample conversions for EVM and Solana:\n\n=== \"EVM\"\n\n    ```typescript\n    import { toNative } from '@wormhole-foundation/sdk-core';\n\n    const ethAddress: NativeAddress<'Evm'> = toNative(\n      'Ethereum',\n      '0x0C99567DC6f8f1864cafb580797b4B56944EEd28'\n    );\n    const universalAddress = ethAddress.toUniversalAddress().toString();\n    console.log('Universal Address (EVM):', universalAddress);\n    ```\n\n=== \"Solana\"\n\n    ```typescript\n    import { toNative } from '@wormhole-foundation/sdk-core';\n\n    const solAddress: NativeAddress<'Solana'> = toNative(\n      'Solana',\n      '6zZHv9EiqQYcdg52ueADRY6NbCXa37VKPngEHaokZq5J'\n    );\n    const universalAddressSol = solAddress.toUniversalAddress().toString();\n    console.log('Universal Address (Solana):', universalAddressSol);\n    ```\n\nThe result is a standardized address format that is ready for cross-chain operations."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 5, "depth": 3, "title": "Convert Back to Native Addresses", "anchor": "convert-back-to-native-addresses", "start_char": 5233, "end_char": 5751, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### Convert Back to Native Addresses\n\nBelow is how you can convert a Wormhole formatted address back to an EVM or Solana native address:\n\n```typescript\nconst nativeAddressEvm = universalAddress.toNative('Evm');\nconsole.log('EVM Native Address:', nativeAddressEvm);\n\nconst nativeAddressSolana = universalAddress.toNative('Solana');\nconsole.log('Solana Native Address:', nativeAddressSolana);\n```\n\nThese conversions ensure that your cross-chain applications can seamlessly handle addresses across different ecosystems."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 6, "depth": 2, "title": "Use Cases for Wormhole Formatted Addresses", "anchor": "use-cases-for-wormhole-formatted-addresses", "start_char": 5751, "end_char": 5798, "estimated_token_count": 8, "token_estimator": "heuristic-v1", "text": "## Use Cases for Wormhole Formatted Addresses"}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 7, "depth": 3, "title": "Cross-chain Token Transfers", "anchor": "cross-chain-token-transfers", "start_char": 5798, "end_char": 6174, "estimated_token_count": 65, "token_estimator": "heuristic-v1", "text": "### Cross-chain Token Transfers\n\nCross-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."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 8, "depth": 3, "title": "Smart Contract Interactions", "anchor": "smart-contract-interactions", "start_char": 6174, "end_char": 6537, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "### Smart Contract Interactions\n\nIn 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."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 9, "depth": 3, "title": "DApp Development", "anchor": "dapp-development", "start_char": 6537, "end_char": 6829, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "### DApp Development\n\nFor 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."}
{"page_id": "products-reference-wormhole-formatted-addresses", "page_title": "Wormhole Formatted Addresses", "index": 10, "depth": 3, "title": "Relayers and Infrastructure", "anchor": "relayers-and-infrastructure", "start_char": 6829, "end_char": 7135, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "### Relayers and Infrastructure\n\nFinally, 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."}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 0, "depth": 2, "title": "Mayan Swift", "anchor": "mayan-swift", "start_char": 800, "end_char": 992, "estimated_token_count": 35, "token_estimator": "heuristic-v1", "text": "## Mayan Swift\n\nMayan 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."}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 1, "depth": 3, "title": "On-Chain Competitive Price Discovery Mechanism", "anchor": "on-chain-competitive-price-discovery-mechanism", "start_char": 992, "end_char": 2259, "estimated_token_count": 226, "token_estimator": "heuristic-v1", "text": "### On-Chain Competitive Price Discovery Mechanism\n\nTraditional 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.\n\nFirst, 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.\n\nMayan 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.\n\n![Mayan Swift - Intent-centric design](/docs/images/products/settlement/concepts/architecture/architecture-2.webp)"}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 2, "depth": 3, "title": "Protocol Flow: How It Works", "anchor": "protocol-flow-how-it-works", "start_char": 2259, "end_char": 4581, "estimated_token_count": 457, "token_estimator": "heuristic-v1", "text": "### Protocol Flow: How It Works\n\n1. **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. \n\n    !!!note\n        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.\n\n    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.\n\n2. **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.\n3. **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.\n4. **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."}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 3, "depth": 2, "title": "Mayan MCTP", "anchor": "mayan-mctp", "start_char": 4581, "end_char": 4896, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "## Mayan MCTP\n\nMayan 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.\n\n![Mayan MCTP diagram](/docs/images/products/settlement/concepts/architecture/architecture-3.webp)"}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 4, "depth": 3, "title": "Protocol Flow: How It Works", "anchor": "protocol-flow-how-it-works-2", "start_char": 4896, "end_char": 6624, "estimated_token_count": 331, "token_estimator": "heuristic-v1", "text": "### Protocol Flow: How It Works\n\n1. **Initiation**: The user creates an order by signing a transaction that locks one USDC into the Mayan smart contract, specifying the desired outcome. \n\n    !!!note\n        If the input asset is not USDC, it is converted into a primary asset within the same transaction before the order is submitted.\n    \n    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.\n\n2. **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}.\n3. **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.\n\nThe 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."}
{"page_id": "products-settlement-concepts-architecture", "page_title": "Settlement Protocol Architecture", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 6624, "end_char": 7353, "estimated_token_count": 183, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Integrate Settlement Routes**\n\n    ---\n\n    Learn how to integrate settlement routes into your application using the SDK.\n\n    [:custom-arrow: See the Mayan Swift Demo](https://github.com/wormhole-foundation/demo-mayanswift){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena: Settlement Fundamentals**\n\n    ---\n\n    Check out the Settlement Fundamentals course on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/256e7446-5ed5-8167-89a5-f2102b0090a7){target=\\_blank}\n\n</div>"}
{"page_id": "products-settlement-faqs", "page_title": "Wormhole Settlement FAQs", "index": 0, "depth": 2, "title": "What happens if no solver participates in the auction?", "anchor": "what-happens-if-no-solver-participates-in-the-auction", "start_char": 19, "end_char": 268, "estimated_token_count": 52, "token_estimator": "heuristic-v1", "text": "## What happens if no solver participates in the auction?\n\nMayan Swift uses a refund mechanism. If an auction does not start within the specified deadline, it means no solvers placed a bid, and the user's funds will be refunded on the source chain."}
{"page_id": "products-settlement-get-started", "page_title": "Get Started", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1052, "end_char": 1822, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- One source-chain wallet funded with native gas on a [Swift-supported chain](/docs/products/reference/supported-networks/#settlement){target=\\_blank}.\n- A destination wallet address on the target chain (no destination signer or gas required).\n\nThis example utilizes Ethereum as the source chain and Solana as the destination chain. You’ll need ETH for gas on Ethereum only. You do not need SOL or a Solana signer; you’ll provide a Solana recipient address, and Mayan Swift’s relayer handles the destination leg. You can adapt the example to match your preferred chains."}
{"page_id": "products-settlement-get-started", "page_title": "Get Started", "index": 1, "depth": 2, "title": "Set Up a Project", "anchor": "set-up-a-project", "start_char": 1822, "end_char": 3353, "estimated_token_count": 361, "token_estimator": "heuristic-v1", "text": "## Set Up a Project\n\nStart by scaffolding a basic Node.js project and installing the required SDKs.\n\n1. Create a new project folder:\n\n    ```bash\n    mkdir settlement-swap\n    cd settlement-swap\n    npm init -y\n    ```\n\n2. Install the required dependencies. This example uses the Mayan Swift route version `1.26.0` and Wormhole SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk-connect@4.14.1 \\\n        @wormhole-foundation/sdk-evm@4.14.1 \\\n        @wormhole-foundation/sdk-solana@4.14.1 \\\n        @mayanfinance/wormhole-sdk-route@1.26.0 \\\n        dotenv\n    npm install -D typescript tsx\n    ```\n\n3. Create the file structure:\n\n    ```bash\n    mkdir src\n    touch src/helpers.ts src/swap.ts .gitignore\n    ```\n\n4. Set up secure access to your wallets. This guide assumes you are loading a source private key and an Ethereum mainnet RPC URL from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [cast wallet](https://www.getfoundry.sh/reference/cast/wallet){target=\\_blank}. The RPC is required so the SDK can sign and send the source-chain transaction reliably.\n\n    !!! note\n        Some auto-selected public RPCs may require API keys or rate-limit intermittently. Providing your own mainnet RPC URL avoids 401/500 errors and timeouts during `initiate` and status polling.\n\n    !!! warning\n        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."}
{"page_id": "products-settlement-get-started", "page_title": "Get Started", "index": 2, "depth": 2, "title": "Perform a Token Swap", "anchor": "perform-a-token-swap", "start_char": 3353, "end_char": 9686, "estimated_token_count": 1347, "token_estimator": "heuristic-v1", "text": "## Perform a Token Swap\n\nThis section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source chain signer.\n\nThen, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and lets the route complete the transfer on Solana.\n\n1. Open `helper.ts` and define the `getSigner` utility function to load private key, instantiate signer for your source chain, and return the signer along with the Wormhole-formatted address:\n\n    ```ts title=\"src/helpers.ts\"\n    import {\n      Chain,\n      ChainAddress,\n      ChainContext,\n      Network,\n      Signer,\n      Wormhole,\n    } from '@wormhole-foundation/sdk-connect';\n    import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm';\n    import { getSolanaSigner } from '@wormhole-foundation/sdk-solana';\n    import { JsonRpcProvider } from \"ethers\";\n\n    /**\n     * Create a helper function that returns a signer for the given chain using locally scoped credentials.\n     * The required values (MAINNET_ETH_PRIVATE_KEY, ETHEREUM_MAINNET_RPC)\n     * must be loaded securely beforehand, for example via a keystore,\n     * secrets manager, or environment variables (not recommended).\n     */\n\n    // Define transfer interface.\n    export interface SignerContext<N extends Network, C extends Chain> {\n      signer: Signer<N, C>;\n      address: ChainAddress<C>;\n    }\n\n    export async function getSigner<N extends Network, C extends Chain>(\n      chain: ChainContext<N, C>\n    ): Promise<SignerContext<N, C>> {\n      let signer: Signer;\n      const platform = chain.platform.utils()._platform;\n      switch (platform) {\n        case \"Solana\":\n          signer = await getSolanaSigner(\n            await chain.getRpc(),\n            \"MAINNET_SOL_PRIVATE_KEY\"\n          );\n          break;\n        case 'Evm':\n          signer = await getEvmSignerForKey(\n            await chain.getRpc(),\n            'MAINNET_ETH_PRIVATE_KEY'\n          );\n          break;\n        default:\n          throw new Error('Unrecognized platform: ' + platform);\n      }\n\n      return {\n        signer: signer as Signer<N, C>,\n        address: Wormhole.chainAddress(chain.chain, signer.address()),\n      };\n    }\n    ```\n\n2. In `swap.ts`, add the following script, which will handle all of the logic required to perform the token swap: \n\n    ```ts title=\"src/swap.ts\"\n    import { Wormhole, routes } from '@wormhole-foundation/sdk-connect';\n    import { EvmPlatform } from '@wormhole-foundation/sdk-evm';\n    import { SolanaPlatform } from '@wormhole-foundation/sdk-solana';\n    import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route';\n    import { getSigner } from './helpers';\n\n    (async function () {\n      const wh = new Wormhole(\"Mainnet\", [EvmPlatform, SolanaPlatform]);\n\n      const sendChain = wh.getChain('Ethereum');\n      const destChain = wh.getChain('Solana');\n      const destAddress = Wormhole.chainAddress(destChain.chain, \"INSERT_DESTINATION_ADDRESS\");\n\n      //  To transfer native ETH on Ethereum to native SOL on Solana.\n      const source = Wormhole.tokenId(sendChain.chain, 'native');\n      const destination = Wormhole.tokenId(destChain.chain, 'native');\n\n      // Create a new Wormhole route resolver, adding the Mayan route to the default list\n      // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type,\n      // but MayanRouteSWIFT is compatible and works as intended in this context.\n      const resolver = wh.resolver([MayanRouteSWIFT]);\n\n      // Show supported tokens\n      const dstTokens = await resolver.supportedDestinationTokens(\n        source,\n        sendChain,\n        destChain\n      );\n      console.log(dstTokens.slice(0, 5));\n\n      // Load signers and addresses from helpers.\n      const sender = await getSigner(sendChain);\n\n      // Creating a transfer request fetches token details\n      // since all routes will need to know about the tokens.\n      const tr = await routes.RouteTransferRequest.create(wh, {\n        source,\n        destination,\n      });\n\n      // Resolve the transfer request to a set of routes that can perform it\n      const foundRoutes = await resolver.findRoutes(tr);\n      const bestRoute = foundRoutes[0]!;\n\n      // Specify the amount as a decimal string.\n      const transferParams = {\n        amount: '0.001',\n        options: bestRoute.getDefaultOptions(),\n      };\n\n      // Validate the queries route\n      let validated = await bestRoute.validate(tr, transferParams);\n      if (!validated.valid) {\n        console.error(validated.error);\n        return;\n      }\n      console.log('Validated: ', validated);\n\n      const quote = await bestRoute.quote(tr, validated.params);\n      if (!quote.success) {\n        console.error(`Error fetching a quote: ${quote.error.message}`);\n        return;\n      }\n      console.log('Quote: ', quote);\n\n      // Initiate the transfer\n      const receipt = await bestRoute.initiate(\n        tr,\n        sender.signer,\n        quote,\n        destAddress\n      );\n      console.log('Initiated transfer with receipt: ', receipt);\n\n      const timeout = 15 * 60 * 1000;\n      await routes.checkAndCompleteTransfer(\n        bestRoute,\n        receipt,\n        undefined,\n        timeout\n      );\n    })();\n    ```\n\n3. Execute the script to initiate and complete the transfer:\n\n    ```bash\n    npx tsx src/swap.ts\n    ```\n\n    If successful, you’ll see terminal output like this:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx src/swap.ts</span>\n    \t<span data-ty>Validated: { valid: true, ... }</span>\n        <span data-ty>Quote: { success: true, ... }</span>\n        <span data-ty>Initiated transfer with receipt: ...</span>\n        <span data-ty>Checking transfer state...</span>\n        <span data-ty>Current Transfer State: SourceInitiated</span>\n        <span data-ty>Current Transfer State: SourceInitiated</span>\n        <span data-ty>Current Transfer State: SourceInitiated</span>\n        <span data-ty>Current Transfer State: DestinationFinalized</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n\nCongratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement."}
{"page_id": "products-settlement-get-started", "page_title": "Get Started", "index": 3, "depth": 2, "title": "Customize the Integration", "anchor": "customize-the-integration", "start_char": 9686, "end_char": 10103, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "## Customize the Integration\n\nYou can tailor the example to your use case by adjusting:\n\n- **Tokens and chains**: Use `getSupportedTokens()` to explore what's available.\n- **Source and destination chains**: Modify `sendChain` and `destChain` in `swap.ts`.\n- **Transfer settings**: Update the amount or route parameters.\n- **Signer management**: Modify `src/helpers.ts` to integrate with your preferred wallet setup."}
{"page_id": "products-settlement-get-started", "page_title": "Get Started", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 10103, "end_char": 10733, "estimated_token_count": 169, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nOnce you've chosen a path, follow the corresponding guide to start building:\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Mayan Swift Demo**\n\n    ---\n\n    Check out the repository for the full code example.\n\n    [:custom-arrow: See the Demo Repository](https://github.com/wormhole-foundation/demo-mayanswift){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 2533, "end_char": 3273, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **Intent-based architecture**: Users express what they want to happen (e.g., swap X for Y on chain Z), and solvers execute it.\n- **Solver auctions**: Solvers compete in on-chain auctions for the right to fulfill intents, improving execution quality.\n- **Fast and fallback-capable**: Combines high-speed execution with a reliable fallback path.\n- **Minimal slippage**: Settlement abstracts away complex balancing operations and uses shuttle assets like USDC and tokens deployed via NTT.\n- **On-chain verifiability**: Even though auctions are off-chain, all settlement steps remain verifiable on-chain via Wormhole messages.\n- **Two integrated routes**: Mayan Swift for speed, Mayan MCTP for compatibility and redundancy."}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 1, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 3273, "end_char": 3762, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nAt the core of Settlement are two components:\n\n- **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.\n- **Solvers**: Third-party agents that compete in auctions to fulfill these intents. They front capital, perform swaps or transfers, and receive fees in return.\n\nSettlement currently supports the following integrated protocols."}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 2, "depth": 3, "title": "Mayan Swift", "anchor": "mayan-swift", "start_char": 3762, "end_char": 5931, "estimated_token_count": 442, "token_estimator": "heuristic-v1", "text": "### Mayan Swift\n\nMayan 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.\n\nThe 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.\n\n1. **Solver initiates on Arbitrum**: Solver swaps ARB → ETH and deposits ETH into an escrow on Arbitrum.\n2. **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.\n3. **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.\n4. **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.\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Solver_ARB as Solver (Arbitrum)\n    participant Escrow\n    participant Wormhole\n    participant Solver_SOL as Solver (Solana)\n    participant Aggregator\n\n    Note over User,Aggregator: User has ARB and wants WIF\n\n    User->>Solver_ARB: Submit intent (ARB → WIF)\n    Solver_ARB->>Escrow: Swaps ARB → ETH and deposits ETH\n    Escrow-->>Wormhole: Emits VAA\n    Wormhole-->>Solver_SOL: Delivers VAA\n    Solver_SOL->>Aggregator: Releases SOL and swaps to WIF\n    Aggregator->>Solver_SOL: Receives WIF\n    Solver_SOL->>User: Sends WIF\n    User-->>Wormhole: Emits final VAA\n    Wormhole-->>Escrow: Confirms receipt\n    Escrow->>Solver_ARB: Releases ETH to solver\n```"}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 3, "depth": 3, "title": "Mayan MCTP", "anchor": "mayan-mctp", "start_char": 5931, "end_char": 6471, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### Mayan MCTP\n\nMayan 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."}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 4, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 6471, "end_char": 7294, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\n- **Cross-Chain Perpetuals** \n\n    - **[Settlement](/docs/products/settlement/get-started/){target=\\_blank}**: Provides fast token execution across chains.\n    - **[Queries](/docs/products/queries/overview/){target=\\_blank}**: Fetch live prices and manage position state across chains.\n\n- **Bridging Intent Library**\n\n    - **[Settlement](/docs/products/settlement/get-started/){target=\\_blank}**: Handles user-defined bridge intents.\n    - **[Messaging](/docs/products/messaging/overview/){target=\\_blank}**: Triggers cross-chain function calls.\n\n- **Multichain Prediction Markets**\n\n    - **[Settlement](/docs/products/settlement/get-started/){target=\\_blank}**: Executes token flows between chains.\n    - **[Queries](/docs/products/queries/overview/){target=\\_blank}**: Gets market data and tracks state."}
{"page_id": "products-settlement-overview", "page_title": "Settlement Overview", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 7294, "end_char": 8229, "estimated_token_count": 231, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nStart building with Settlement or dive deeper into specific components.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with Settlement**\n\n    ---\n\n    Follow a hands-on demo using Mayan Swift.\n\n    [:custom-arrow: Get Started](/docs/products/settlement/get-started/)\n\n-   :octicons-book-16:{ .lg .middle } **Architecture Overview**\n\n    ---\n\n    Explore the Settlement architecture and components.\n\n    [:custom-arrow: Learn More](/docs/products/settlement/concepts/architecture/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena: Settlement Fundamentals**\n\n    ---\n\n    Check out the Settlement Fundamentals course on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/256e7446-5ed5-8167-89a5-f2102b0090a7){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 0, "depth": 2, "title": "System Components", "anchor": "system-components", "start_char": 2216, "end_char": 2418, "estimated_token_count": 35, "token_estimator": "heuristic-v1", "text": "## System Components\n\nThe NTT framework is composed of managers, which oversee the transfer process, and transceivers, which handle cross-chain messaging, ensuring smooth and reliable token transfers."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 1, "depth": 3, "title": "Managers", "anchor": "managers", "start_char": 2418, "end_char": 5058, "estimated_token_count": 459, "token_estimator": "heuristic-v1", "text": "### Managers\n\n_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.\n\nEach 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.\n\nA manager is responsible for:\n\n- **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.\n- **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.\n    - **Outbound**: Transfers exceeding the outbound limit are queued (if `shouldQueue` is true) or reverted.\n    - **Inbound**: Similar limits apply on the destination chain, delaying transfers if capacity is exceeded.\n\n    Rate limit duration and queuing are customizable per chain, and events notify users when transfers hit the limit.\n\n- **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.\n- **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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 2, "depth": 3, "title": "Transceivers", "anchor": "transceivers", "start_char": 5058, "end_char": 8847, "estimated_token_count": 671, "token_estimator": "heuristic-v1", "text": "### Transceivers\n\n_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.\n\nWhile transceivers operate closely with Wormhole's ecosystem, they can also be configured independently of Wormhole's core system, allowing for flexibility. This adaptability enables them to be integrated with various verification backends, accommodating different security needs or platform-specific requirements.\n\nTransceivers are entrusted with several responsibilities:\n\n- **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.\n- **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.\n- **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.\n\nHow it works:\n\n1. The transceiver receives instructions from the manager to send messages across chains.\n2. It quotes delivery fees, handles cross-chain message relaying, and verifies delivery to ensure tokens are safely transferred.\n3. For each message, the transceiver coordinates with managers, ensuring only authorized transfers are processed on the destination chain.\n\n![NTT architecture diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-1.webp)\n\n!!! note\n    [Learn more](/docs/products/token-transfers/native-token-transfers/concepts/architecture/#lifecycle-of-a-message){target=\\_blank} about the architecture of Native Token Transfers message lifecycles.\n\n#### Custom Transceivers\n\nThe NTT framework supports advanced features, such as custom transceivers for specialized message verification, which enhance 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 SVM-compatible chains.\n\nNTT 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.\n\n![Custom Attestation with NTT diagram](/docs/images/products/native-token-transfers/concepts/architecture/architecture-2.webp)\n\nThe 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.\n\nFor more details, to collaborate, or to see examples of custom transceivers, [contact](https://discord.com/invite/wormholecrypto){target=\\_blank} Wormhole contributors."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 3, "depth": 2, "title": "On-Chain State", "anchor": "on-chain-state", "start_char": 8847, "end_char": 9799, "estimated_token_count": 180, "token_estimator": "heuristic-v1", "text": "## On-Chain State\n\nThe NTT contracts maintain minimal state on‑chain to safely route transfers, prevent replays, and manage throughput across multiple chains. This state is primarily managed by the NTT Manager, its Rate Limiter, and the Transceiver Registry:\n\n - **Message attestations**: Records which transceivers have attested to each cross‑chain message, enforces the M‑of‑N attestation threshold, and prevents re‑execution of processed messages.\n - **Peer registrations**: Maps each remote chain to its associated NTT Manager and token decimal configuration, ensuring only trusted peers can mint/unlock tokens.\n - **Rate limiting**: Enforces inbound and outbound throughput caps and queues transfers when limits are exceeded, protecting liquidity and downstream networks.\n - **Transceiver registry**: Maintains the list of registered and enabled transceivers, along with their bitmap index, allowing governance to add/remove messaging providers."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 4, "depth": 2, "title": "Lifecycle of a Message", "anchor": "lifecycle-of-a-message", "start_char": 9799, "end_char": 10302, "estimated_token_count": 88, "token_estimator": "heuristic-v1", "text": "## Lifecycle of a Message\n\nThe 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 SVM 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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 5, "depth": 3, "title": "Transfer", "anchor": "transfer", "start_char": 10302, "end_char": 11211, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "### Transfer\n\nThe process begins when a client initiates a transfer. For EVM, this is done using the `transfer` function, whereas in SVM, 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 SVM) to decide whether the transfer should be queued if it hits the rate limit.\n\nIn both cases:\n\n- If the source chain is in locking mode, the tokens are locked on the source chain to be unlocked on the destination chain.\n- 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.\n\nOnce initiated, an event (such as `TransferSent` on EVM or a corresponding log on SVM) is emitted to signal that the transfer process has started."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 6, "depth": 3, "title": "Rate Limit", "anchor": "rate-limit", "start_char": 11211, "end_char": 12061, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "### Rate Limit\n\nBoth EVM and SVM 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.\n\n- 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.\n- On SVM, 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.\n\nBoth chains emit events or logs when transfers are rate-limited or queued."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 7, "depth": 3, "title": "Send", "anchor": "send", "start_char": 12061, "end_char": 13153, "estimated_token_count": 201, "token_estimator": "heuristic-v1", "text": "### Send\n\nAfter 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 the Executor or other custom relaying solutions. Once the message is transmitted, an event is emitted to signal successful transmission.\n\n- In EVM, the message is sent using the `sendMessage` function, which handles the transmission based on the Transceiver's implementation. The Transceiver may use the Executor or custom relaying solutions to forward the message.\n- In SVM, the transfer message is placed in an Outbox and released via the `release_outbound` instruction. The SVM transceiver, such as the Wormhole Transceiver, may send the message using the `post_message` instruction, which Wormhole Guardians observe for verification.\n\nIn both cases, an event or log (e.g., `SendTransceiverMessage` on EVM or a similar log on SVM) is emitted to signal that the message has been transmitted."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 8, "depth": 3, "title": "Receive", "anchor": "receive", "start_char": 13153, "end_char": 14065, "estimated_token_count": 172, "token_estimator": "heuristic-v1", "text": "### Receive\n\nUpon receiving the message on the destination chain, an off-chain relayer forwards the message to the destination Transceiver for verification. \n\n- 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.\n- In SVM, 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.\n\nIn 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 SVM) to notify that the message has been successfully received."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 9, "depth": 3, "title": "Mint or Unlock", "anchor": "mint-or-unlock", "start_char": 14065, "end_char": 15025, "estimated_token_count": 187, "token_estimator": "heuristic-v1", "text": "### Mint or Unlock\n\nFinally, 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. \n\n- 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.\n- On SVM, 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.\n\nIn 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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-architecture", "page_title": "Native Token Transfers Architecture", "index": 10, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 15025, "end_char": 15456, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena: NTT Fundamentals**\n\n    ---\n\n    Check out the NTT Fundamentals course on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/256e7446-5ed5-818a-bd5d-f96481c79200){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-security", "page_title": "Native Token Transfers Security", "index": 0, "depth": 2, "title": "Global Accountant", "anchor": "global-accountant", "start_char": 12, "end_char": 832, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "## Global Accountant\n\nThe 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.\n\nThis 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.\n\n[Contact](https://discord.com/invite/wormholecrypto){target=\\_blank} Wormhole contributors if you are interested in configuring the Global Accountant for your multichain deployment."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-security", "page_title": "Native Token Transfers Security", "index": 1, "depth": 2, "title": "Governance and Upgradeability", "anchor": "governance-and-upgradeability", "start_char": 832, "end_char": 1914, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "## Governance and Upgradeability\n\nIntegrators 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.\n\nThe 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:\n\n- Adding or removing a transceiver address from the registry.\n- Setting the token contract address on a bridging contract.\n- Setting the Wormhole Core Contract address on a bridging contract.\n- Setting the registered bridging contract address on the token contract.\n\nThis governance model ensures that the system remains secure while being adaptable to new requirements in any environment where it is deployed."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 0, "depth": 2, "title": "Transfer Flow", "anchor": "transfer-flow", "start_char": 797, "end_char": 5770, "estimated_token_count": 957, "token_estimator": "heuristic-v1", "text": "## Transfer Flow\n\nCross-chain token transfers using NTT follow these steps:\n\n1. **Initiation on the Source Chain**  \n    The transfer begins when a user calls the NTT Manager contract on the source chain:\n\n    - **Burning mode**: The token is burned from the user's account.\n    - **Locking mode**: If the token is native to the source chain, the token is locked in the NTT Manager contract.\n\n2. **Outbound Rate Limiting Check**  \n    The NTT Manager checks if the transfer amount exceeds the current outbound capacity:\n\n    - **Within capacity**: Transfer proceeds immediately.\n    - **Exceeds capacity with queueing**: Transfer is queued for later completion after the rate limit window expires.\n    - **Exceeds capacity without queueing**: Transfer fails.\n\n3. **Message Creation and Distribution**  \n    The NTT Manager creates an NTT message containing transfer details and forwards it to all enabled transceivers. Each transceiver packages this into its own message format.\n\n4. **Cross-Chain Message Transmission**  \n    Each transceiver sends the message through its verification network:\n\n    - **Wormhole Transceiver**: Uses Wormhole's Guardian network for message attestation and optional automatic relaying.\n    - **Custom Transceivers**: Can use any verification backend (validators, multi-sig, etc.).\n\n5. **Message Reception and Attestation**  \n    On the destination chain, transceivers receive and verify their respective messages:\n\n    - Each transceiver validates the message according to its verification method.\n    - Transceivers forward verified messages to the destination NTT Manager.\n    - The NTT Manager collects attestations from transceivers.\n\n6. **Threshold Verification**  \n    The destination NTT Manager waits until enough transceivers have attested to the transfer (based on the configured threshold):\n\n    - **Threshold met**: Transfer proceeds to execution.\n    - **Threshold not met**: Transfer waits for more attestations.\n\n7. **Inbound Rate Limiting Check**  \n    The NTT Manager checks if the incoming transfer exceeds inbound capacity:\n\n    - **Within capacity**: Transfer completes immediately.\n    - **Exceeds capacity**: Transfer is queued for later completion.\n\n8. **Transfer Completion on Destination Chain**  \n    After rate limiting checks pass, the NTT Manager completes the transfer:\n\n    - **Burning mode**: New tokens are minted to the recipient.\n    - **Locking mode**: If tokens are native to the destination chain, they are released from the contract to the recipient.\n\n**Consider the following example**: Alice wants to send 100 ALICE tokens from Ethereum to Solana using NTT in burn mode. The ALICE is burned on Ethereum's NTT Manager, transceivers attest to the transfer, and an equivalent amount of ALICE is minted on Solana. The diagram below illustrates this transfer flow.\n\n```mermaid\nsequenceDiagram\n    participant Alice as Alice\n    participant NttManagerEth as NTT Manager Ethereum<br>(Source Chain)\n    participant TransceiverEth as Transceivers Ethereum<br>(e.g., Wormhole)\n    participant GuardianNetwork as Guardians\n    participant TransceiverSol as Transceivers Solana<br>(e.g., Wormhole)\n    participant NttManagerSol as NTT Manager Solana<br>(Destination Chain)\n\n    Alice->>NttManagerEth: Initiate ALICE transfer<br>(burn 100 ALICE)\n    NttManagerEth->>NttManagerEth: Check outbound capacity\n    NttManagerEth->>TransceiverEth: Forward NTT message<br>to transceivers\n    TransceiverEth->>GuardianNetwork: Send message via<br>verification network\n    GuardianNetwork->>TransceiverSol: Deliver verified<br>message\n    TransceiverSol->>NttManagerSol: Attest to transfer\n    NttManagerSol->>NttManagerSol: Check threshold &<br> inbound capacity\n    NttManagerSol-->>Alice: Mint 100 ALICE on Solana (complete transfer)\n```\n\nNow, consider Alice wants to send her ALICE back from Solana to Ethereum. The ALICE is burned on Solana's NTT Manager, and the equivalent amount is minted on Ethereum. The diagram below illustrates this reverse transfer flow.\n\n```mermaid\nsequenceDiagram\n    participant Alice as Alice\n    participant NttManagerSol as NTT Manager Solana<br>(Source Chain)\n    participant TransceiverSol as Transceivers Solana<br>(e.g., Wormhole)\n    participant GuardianNetwork as Guardians\n    participant TransceiverEth as Transceivers Ethereum<br>(e.g., Wormhole)\n    participant NttManagerEth as NTT Manager Ethereum<br>(Destination Chain)\n\n    Alice->>NttManagerSol: Initiate transfer<br>(burn 100 ALICE)\n    NttManagerSol->>NttManagerSol: Check outbound capacity\n    NttManagerSol->>TransceiverSol: Forward NTT message<br>to transceivers\n    TransceiverSol->>GuardianNetwork: Send message via<br>verification network\n    GuardianNetwork->>TransceiverEth: Deliver verified<br>message\n    TransceiverEth->>NttManagerEth: Attest to transfer\n    NttManagerEth->>NttManagerEth: Check threshold &<br> inbound capacity\n    NttManagerEth-->>Alice: Mint 100 ALICE on Ethereum (complete transfer)\n```"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 1, "depth": 2, "title": "EVM Transfer Flow Details", "anchor": "evm-transfer-flow-details", "start_char": 5770, "end_char": 5800, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## EVM Transfer Flow Details"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 2, "depth": 3, "title": "Transfer", "anchor": "transfer", "start_char": 5800, "end_char": 5924, "estimated_token_count": 26, "token_estimator": "heuristic-v1", "text": "### Transfer\n    \nThe `transfer` function is called with details of the transfer, and the `TransferSent` event is emitted."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 3, "depth": 3, "title": "Rate Limiting", "anchor": "rate-limiting", "start_char": 5924, "end_char": 7145, "estimated_token_count": 213, "token_estimator": "heuristic-v1", "text": "### Rate Limiting\n\nIf 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. \n\nIf the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `OutboundQueuedTransferStillQueued` error.\n\nSimilarly, 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.\n\nIf the client attempts to release the transfer from the queue before the `rateLimitDuration` expires, the contract reverts with an `InboundQueuedTransferStillQueued` error.\n\nTo 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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 4, "depth": 3, "title": "Sending the Message", "anchor": "sending-the-message", "start_char": 7145, "end_char": 7659, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "### Sending the Message\n\nOnce the `NttManager` forwards the message to the transceiver, the message is transmitted via the `sendMessage` method. The transceiver enforces the method signature, but transceivers are free to determine their implementation for transmitting messages (e.g., a message routed through the Wormhole transceiver can be sent via the Executor framework or manually published via the core bridge).\n\nOnce the message has been transmitted, the contract emits the `SendTransceiverMessage` event."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 5, "depth": 3, "title": "Receiving the Message", "anchor": "receiving-the-message", "start_char": 7659, "end_char": 9715, "estimated_token_count": 364, "token_estimator": "heuristic-v1", "text": "### Receiving the Message\n\nOnce 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.\n\nThis 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.\n\nThe `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.\n\nNTT implements replay protection, so if a given transceiver attempts to deliver a message attestation twice, the contract reverts with the `TransceiverAlreadyAttestedToMessage` error. NTT also implements replay protection against re-executing messages. This check also serves as reentrancy protection.\n\nIf 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 transceivers (i.e., threshold < totalTransceivers) and notifies the client (off-chain process) so they don't attempt redundant message delivery."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 6, "depth": 3, "title": "Minting or Unlocking", "anchor": "minting-or-unlocking", "start_char": 9715, "end_char": 10277, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "### Minting or Unlocking\n\nOnce 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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 7, "depth": 2, "title": "Solana Transfer Flow Details", "anchor": "solana-transfer-flow-details", "start_char": 10277, "end_char": 10310, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## Solana Transfer Flow Details"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 8, "depth": 3, "title": "Transfer", "anchor": "transfer-2", "start_char": 10310, "end_char": 11780, "estimated_token_count": 289, "token_estimator": "heuristic-v1", "text": "### Transfer\n\nA 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 is hit.\n\n!!! note\n    Using the wrong transfer instruction, i.e., `transfer_lock` for a program that is in `BURNING` mode, will result in an `InvalidMode` error.\n\nDepending on the mode and instruction, the following will be produced in the program logs:\n\n```ts\nProgram log: Instruction: TransferLock\nProgram log: Instruction: TransferBurn\n```\n\nOutbound 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."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 9, "depth": 3, "title": "Rate Limiting", "anchor": "rate-limiting-2", "start_char": 11780, "end_char": 12540, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "### Rate Limiting\n\nDuring 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.\n\nIf the transfer amount fits within the current capacity:\n\n- Reduce the current capacity.\n- Refill the inbound capacity for the destination chain.\n- Add the transfer to the Outbox with `release_timestamp` set to the current timestamp so it can be released immediately.\n\nIf the transfer amount doesn't fit within the current capacity:\n\n- If `shouldQueue = true`, add the transfer to the Outbox with `release_timestamp` set to the current timestamp plus the configured `RATE_LIMIT_DURATION`.\n- If `shouldQueue = false`, revert with a `TransferExceedsRateLimit` error."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 10, "depth": 3, "title": "Sending the Message", "anchor": "sending-the-message-2", "start_char": 12540, "end_char": 13449, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "### Sending the Message\n\nThe 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.\n\nFor example, the Wormhole transceiver sends messages by calling `post_message` on the Wormhole program, allowing Guardians to observe and verify the message.\n\n!!! note\n    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.\n\nThe following will be produced in the program logs:\n\n```ts\nProgram log: Instruction: ReleaseOutbound\n```"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 11, "depth": 3, "title": "Receiving the Message", "anchor": "receiving-the-message-2", "start_char": 13449, "end_char": 14323, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "### Receiving the Message\n\nSimilar to EVM, transceivers vary in how they receive messages since message relaying and verification methods may differ between implementations.\n\nThe Wormhole transceiver receives a verified Wormhole message on Solana via the `receive_message` entry point instruction. Callers can use the `receive_wormhole_message` Anchor library function to execute this instruction. The instruction verifies the Wormhole Verified Action Approval (VAA) and stores it in a `VerifiedTransceiverMessage` account.\n\nThe following will be produced in the program logs:\n\n```ts\nProgram log: Instruction: ReceiveMessage\n```\n\n`redeem` checks the inbound rate limit and places the message in an Inbox. Logic works similarly to the outbound rate limit mentioned previously.\n\nThe following will be produced in the program logs:\n\n```ts\nProgram log: Instruction: Redeem\n```"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 12, "depth": 3, "title": "Mint or Unlock", "anchor": "mint-or-unlock", "start_char": 14323, "end_char": 15136, "estimated_token_count": 162, "token_estimator": "heuristic-v1", "text": "### Mint or Unlock\n\nThe 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 an `InvalidMode` error.\n\n!!! note\n    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.\n\nDepending on the mode and instruction, the following will be produced in the program logs:\n\n```ts\nProgram log: Instruction: ReleaseInboundMint\nProgram log: Instruction: ReleaseInboundUnlock\n```"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 13, "depth": 2, "title": "Rate Limiting", "anchor": "rate-limiting-3", "start_char": 15136, "end_char": 15230, "estimated_token_count": 18, "token_estimator": "heuristic-v1", "text": "## Rate Limiting\n\nA transfer can be rate limited on both the source and destination chains."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 14, "depth": 3, "title": "Outbound Rate Limiting (Source Chain)", "anchor": "outbound-rate-limiting-source-chain", "start_char": 15230, "end_char": 15498, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "### Outbound Rate Limiting (Source Chain)\n\n- Limits the amount that can be sent from a chain within a time window.\n- **Queue enabled**: Transfers exceeding capacity are queued for later completion.\n- **Queue disabled**: Transfers exceeding capacity fail immediately."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 15, "depth": 3, "title": "Inbound Rate Limiting (Destination Chain)", "anchor": "inbound-rate-limiting-destination-chain", "start_char": 15498, "end_char": 15698, "estimated_token_count": 37, "token_estimator": "heuristic-v1", "text": "### Inbound Rate Limiting (Destination Chain)\n\n- Limits the amount that can be received on a chain within a time window.\n- Transfers exceeding capacity are automatically queued for later completion."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 16, "depth": 3, "title": "Cancel-Flows", "anchor": "cancel-flows", "start_char": 15698, "end_char": 16395, "estimated_token_count": 181, "token_estimator": "heuristic-v1", "text": "### Cancel-Flows\n\n- Outbound transfers refill inbound capacity on the source chain.\n- Inbound transfers refill outbound capacity on the destination chain.\n- Prevents capacity exhaustion from frequent bidirectional transfers.\n\n| Rate Limit Type | Exceeds Capacity | Queue Setting | Result                               |\n|-----------------|------------------|---------------|--------------------------------------|\n| Outbound        | Yes              | Enabled       | Transfer queued on source chain      |\n| Outbound        | Yes              | Disabled      | Transfer fails                       |\n| Inbound         | Yes              | N/A           | Transfer queued on destination chain |"}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 17, "depth": 2, "title": "Queued Transfer Management", "anchor": "queued-transfer-management", "start_char": 16395, "end_char": 16495, "estimated_token_count": 16, "token_estimator": "heuristic-v1", "text": "## Queued Transfer Management\n\nWhen transfers are rate limited, NTT provides management functions."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 18, "depth": 3, "title": "Outbound Queued Transfers", "anchor": "outbound-queued-transfers", "start_char": 16495, "end_char": 16704, "estimated_token_count": 47, "token_estimator": "heuristic-v1", "text": "### Outbound Queued Transfers\n\n- **Complete**: After the rate limit window expires, the user can complete the queued transfer.\n- **Cancel**: The user can cancel their queued transfer and receive tokens back."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 19, "depth": 3, "title": "Inbound Queued Transfers", "anchor": "inbound-queued-transfers", "start_char": 16704, "end_char": 16905, "estimated_token_count": 43, "token_estimator": "heuristic-v1", "text": "### Inbound Queued Transfers  \n\n- **Complete**: After the rate limit window expires, anyone can complete the queued transfer.\n- **Automatic**: Some implementations may auto-complete queued transfers."}
{"page_id": "products-token-transfers-native-token-transfers-concepts-transfer-flow", "page_title": "Flow of a NTT Transfer", "index": 20, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 16905, "end_char": 17336, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena: NTT Fundamentals**\n\n    ---\n\n    Check out the NTT Fundamentals course on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/256e7446-5ed5-818a-bd5d-f96481c79200){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-configuration-access-control", "page_title": "Native Token Transfers Access Control", "index": 0, "depth": 2, "title": "Owner and Pauser Roles", "anchor": "owner-and-pauser-roles", "start_char": 18, "end_char": 2142, "estimated_token_count": 432, "token_estimator": "heuristic-v1", "text": "## Owner and Pauser Roles\n\nPausing the Native Token Transfers (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).\n\nNTT 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.\n\n- **Owner**: Full control over NTT contracts, can perform administrative functions. Has the ability to un-pause contracts if they have been paused.\n- **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.\n\nYou may verify the current owner, pauser, and paused status of the NTT Manager contract on the `deployment.json` file in your NTT project directory.\n\n```json\n{\n    \"network\": \"Testnet\",\n    \"chains\": {\n        \"Sepolia\": {\n            \"version\": \"1.1.0\",\n            \"mode\": \"burning\",\n            \"paused\": true, // set to true to pause the contract\n            \"owner\": \"0x0088DFAC40029f266e0FF62B82E47A07467A0345\",\n            \"manager\": \"0x5592809cf5352a882Ad5E9d435C6B7355B716357\",\n            //...\n            \"pauser\": \"0x0088DFAC40029f266e0FF62B82E47A07467A0345\"\n        }\n    }\n}\n```\n\n!!! note\n    While the `Pauser` can pause contracts, the ability to un-pause contracts is callable only by the `Owner`.\n\nThe `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.\n\nConsider separating `Owner` and `Pauser` roles for your multichain deployment. `Owner` and `Pauser` roles are defined directly on the `NttManager` contract."}
{"page_id": "products-token-transfers-native-token-transfers-configuration-rate-limiting", "page_title": "Native Token Transfers Rate Limiting", "index": 0, "depth": 2, "title": "Update Rate Limits", "anchor": "update-rate-limits", "start_char": 1121, "end_char": 3306, "estimated_token_count": 403, "token_estimator": "heuristic-v1", "text": "## Update Rate Limits\n\nTo configure or update the sending and receiving rate limits, follow these steps:\n\n1. **Locate the deployment file**: Open the `deployment.json` file in your NTT project directory. This file contains the configuration for your deployed contracts.\n\n2. **Modify the limits section**: For each chain, locate the limits field and update the outbound and inbound values as needed.\n\n    ```json\n    \"limits\": {\n        \"outbound\": \"1000.000000000000000000\",\n        \"inbound\": {\n            \"Ethereum\": \"100.000000000000000000\",\n            \"Arbitrum\": \"50.000000000000000000\"\n        }\n    }\n    ```\n\n     - **`outbound`**: Sets the maximum tokens allowed to leave the chain.\n     - **`inbound`**: Configures per-chain receiving limits for tokens arriving from specific chains.\n\n3. **Push the configuration**: Use the NTT CLI to synchronize the updated configuration with the blockchain.\n\n    ```bash\n    ntt push\n    ```\n\n4. **Verify the changes**: After pushing, confirm the new rate limits by checking the deployment status.\n\n    ```bash\n    ntt status\n    ```\n\n???- note \"`deployment.json` example\"\n    ```json\n    {\n        \"network\": \"Testnet\",\n        \"chains\": {\n            \"Sepolia\": {\n                \"version\": \"1.1.0\",\n                \"mode\": \"burning\",\n                \"paused\": false,\n                \"owner\": \"0x0088DFAC40029f266e0FF62B82E47A07467A0345\",\n                \"manager\": \"0x5592809cf5352a882Ad5E9d435C6B7355B716357\",\n                \"token\": \"0x5CF5D6f366eEa7123BeECec1B7c44B2493569995\",\n                \"transceivers\": {\n                    \"threshold\": 1,\n                    \"wormhole\": {\n                        \"address\": \"0x91D4E9629545129D427Fd416860696a9659AD6a1\",\n                        \"pauser\": \"0x0088DFAC40029f266e0FF62B82E47A07467A0345\"\n                    }\n                },\n                \"limits\": {\n                    \"outbound\": \"184467440737.095516150000000000\",\n                    \"inbound\": {\n                        \"ArbitrumSepolia\": \"500.000000000000000000\"\n                    }\n                },\n                \"pauser\": \"0x0088DFAC40029f266e0FF62B82E47A07467A0345\"\n            }\n        }\n    }\n    ```"}
{"page_id": "products-token-transfers-native-token-transfers-configuration-rate-limiting", "page_title": "Native Token Transfers Rate Limiting", "index": 1, "depth": 2, "title": "Queuing Mechanism", "anchor": "queuing-mechanism", "start_char": 3306, "end_char": 4271, "estimated_token_count": 198, "token_estimator": "heuristic-v1", "text": "## Queuing Mechanism\n\nWhen 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:\n\n- **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.\n- **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.\n\nQueuing 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."}
{"page_id": "products-token-transfers-native-token-transfers-configuration-rate-limiting", "page_title": "Native Token Transfers Rate Limiting", "index": 2, "depth": 2, "title": "Cancel Flows", "anchor": "cancel-flows", "start_char": 4271, "end_char": 4858, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "## Cancel Flows\n\nIf 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 0, "depth": 2, "title": "What is NTT?", "anchor": "what-is-ntt", "start_char": 12, "end_char": 560, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "## What is NTT?\n\nNative Token Transfers (NTT) is a framework for moving your own token across multiple chains without wrapping. It preserves your token's native contract design on every chain and keeps control in your hands for metadata, ownership, upgrades, and custom features.\n\nNTT includes configurable controls like rate limiting and access control, and supports deployment modes that fit either new or existing tokens. For a quick video summary, watch the [NTT speed round](https://youtu.be/wdU_6tAeGyg?si=-2wWxC8IZegzB1vl){target=\\_blank}."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 1, "depth": 2, "title": "Does NTT support a “lock-and-lock” transfer model?", "anchor": "does-ntt-support-a-lock-and-lock-transfer-model", "start_char": 560, "end_char": 1458, "estimated_token_count": 173, "token_estimator": "heuristic-v1", "text": "## Does NTT support a “lock-and-lock” transfer model?\n\nNo. NTT does not support a lock-and-lock transfer model.\n\nIn locking mode, the NTT Manager completes inbound transfers by transferring tokens from its own balance on that chain. This means the NTT Manager can only release tokens that it already holds locally.\n\nA lock-and-lock setup would require both the source and destination chains to use locking mode. In that case, the destination NTT Manager would need to have already enough tokens available to release for every inbound transfer. Without those tokens, the transfer cannot be redeemed on the destination chain.\n\nBecause this model depends on maintaining sufficient token balances on each destination chain, NTT does not support lock-and-lock transfers. Instead, NTT relies on minting on chains that do not require pre-funded balances, avoiding destination-side liquidity constraints."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 2, "depth": 2, "title": "Do you have an example of how cross-chain lending can be implemented using Wormhole?", "anchor": "do-you-have-an-example-of-how-cross-chain-lending-can-be-implemented-using-wormhole", "start_char": 1458, "end_char": 2705, "estimated_token_count": 272, "token_estimator": "heuristic-v1", "text": "## Do you have an example of how cross-chain lending can be implemented using Wormhole?\n\nYes, we have an example of cross-chain lending that leverages [Wormhole’s Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/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.\n\nAlternatively, you can also implement cross-chain lending using [Wormhole’s core messaging](/docs/products/messaging/overview/){target=\\_blank} instead of WTT, 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 WTT limits."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 3, "depth": 2, "title": "What causes the \"No protocols registered for Evm\" error in Wormhole SDK?", "anchor": "what-causes-the-no-protocols-registered-for-evm-error-in-wormhole-sdk", "start_char": 2705, "end_char": 3753, "estimated_token_count": 220, "token_estimator": "heuristic-v1", "text": "## What causes the \"No protocols registered for Evm\" error in Wormhole SDK?\n\nThis 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.\n\nTo 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:\n\n```rust\nimport '@wormhole-foundation/sdk-evm-ntt';\n```\n\nBy 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 4, "depth": 2, "title": "How can I mint tokens after moving the treasury object to the NTT manager on Sui?", "anchor": "how-can-i-mint-tokens-after-moving-the-treasury-object-to-the-ntt-manager-on-sui", "start_char": 3753, "end_char": 5096, "estimated_token_count": 304, "token_estimator": "heuristic-v1", "text": "## How can I mint tokens after moving the treasury object to the NTT manager on Sui?\n\nTo mint tokens after moving the treasury object to the NTT manager on Sui, you need to use the `take_treasury_cap` function from the [NTT contract](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sui/packages/ntt/sources/state.move#L307C16-L307C33){target=\\_blank}. This function allows the admin to temporarily take the treasury cap to mint assets.\n\nThe flow works as follows:\n\n1. **Take the treasury cap**: Use `state.take_treasury_cap(admin_cap)` to extract the treasury cap.\n2. **Mint assets**: Perform your minting operations with the treasury cap.\n3. **Return the treasury cap**: Use `state.return_treasury_cap(treasury_cap)` to return it to the state.\n\n!!!Important \n    Return the Treasury Cap! If the treasury cap is not returned in the same transaction, the NTT deployment will stop working. The contract will break and become non-functional.\n\nIt is recommended to use [Programmable Transaction Blocks (PTBs)](https://docs.sui.io/concepts/transactions/prog-txn-blocks){target=\\_blank} for this operation. PTBs allow you to execute multiple operations atomically in a single transaction, ensuring that both the minting operation and returning the treasury cap happen together, preventing any risk of the contract breaking."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 5, "depth": 2, "title": "How can I specify a custom RPC for NTT?", "anchor": "how-can-i-specify-a-custom-rpc-for-ntt", "start_char": 5096, "end_char": 5841, "estimated_token_count": 197, "token_estimator": "heuristic-v1", "text": "## How can I specify a custom RPC for NTT?\n\nTo 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.\n\nBelow is an example of how the `overrides.json` file should be structured:\n\n???- code \"`overrides.json`\"\n    ```json\n    {\n    \"chains\": {\n        \"Bsc\": {\n            \"rpc\": \"http://127.0.0.1:8545\"\n        },\n        \"Sepolia\": {\n            \"rpc\": \"http://127.0.0.1:8546\"\n        },\n        \"Solana\": {\n            \"rpc\": \"http://127.0.0.1:8899\"\n        }\n        }\n    }\n    ```"}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 6, "depth": 2, "title": "Can I set outbound rate limits on a per-chain basis like inbound limits?", "anchor": "can-i-set-outbound-rate-limits-on-a-per-chain-basis-like-inbound-limits", "start_char": 5841, "end_char": 6844, "estimated_token_count": 219, "token_estimator": "heuristic-v1", "text": "## Can I set outbound rate limits on a per-chain basis like inbound limits?\n\nNo. Outbound rate limits are a single global value per chain—they cannot be configured for individual destination chains. This means if you set an outbound limit of 1000 tokens, that limit applies to all transfers leaving the chain, regardless of destination.\n\nInbound rate limits, however, can be configured on a per-chain basis. For example, you can allow 100 tokens to be received from Ethereum but only 50 tokens from Arbitrum.\n\nHere's what a properly configured `deployment.json` limits section looks like:\n\n```json\n\"limits\": {\n    \"outbound\": \"1000.000000000000000000\",\n    \"inbound\": {\n        \"Ethereum\": \"100.000000000000000000\",\n        \"Arbitrum\": \"50.000000000000000000\"\n    }\n}\n```\n\nFor detailed information on rate limiting behavior, queuing mechanisms, and cancel flows, see the [Rate Limiting](/docs/products/token-transfers/native-token-transfers/configuration/rate-limiting/){target=\\_blank} documentation."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 7, "depth": 2, "title": "How can I redeem tokens if NTT rate limits block them on the target chain?", "anchor": "how-can-i-redeem-tokens-if-ntt-rate-limits-block-them-on-the-target-chain", "start_char": 6844, "end_char": 7742, "estimated_token_count": 176, "token_estimator": "heuristic-v1", "text": "## How can I redeem tokens if NTT rate limits block them on the target chain?\n\nIf 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.\n\nTo resolve this:\n\n1. **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.\n2. **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.\n\nIn most cases, the transaction will resume automatically once the rate limits are adjusted, and the UI will guide you through the redemption process."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 8, "depth": 2, "title": "What are the challenges of deploying NTT to non-EVM chains?", "anchor": "what-are-the-challenges-of-deploying-ntt-to-non-evm-chains", "start_char": 7742, "end_char": 8235, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "## What are the challenges of deploying NTT to non-EVM chains?\n\nNTT 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 9, "depth": 2, "title": "Does the NTT manager function as an escrow account for a hub chain?", "anchor": "does-the-ntt-manager-function-as-an-escrow-account-for-a-hub-chain", "start_char": 8235, "end_char": 8590, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## Does the NTT manager function as an escrow account for a hub chain?\n\nYes, 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 10, "depth": 2, "title": "Which functions or events does Connect rely on for NTT integration?", "anchor": "which-functions-or-events-does-connect-rely-on-for-ntt-integration", "start_char": 8590, "end_char": 9422, "estimated_token_count": 193, "token_estimator": "heuristic-v1", "text": "## Which functions or events does Connect rely on for NTT integration?\n\nConnect relies on the NTT SDK for integration, with platform-specific implementations for both [SVM](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:\n\n- **Initiate and redeem functions**: These functions are essential for initiating token transfers and redeeming them on the destination chain.\n- **Rate capacity methods**: Methods for fetching inbound and outbound rate limits are also critical for controlling the flow of tokens and preventing congestion.\n\nThese functions ensure Connect can handle token transfers and manage chain-rate limits."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 11, "depth": 2, "title": "How does the relayer contract determine which transceiver to call?", "anchor": "how-does-the-relayer-contract-determine-which-transceiver-to-call", "start_char": 9422, "end_char": 9792, "estimated_token_count": 66, "token_estimator": "heuristic-v1", "text": "## How does the relayer contract determine which transceiver to call?\n\nThe 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 12, "depth": 2, "title": "How do I create a verifier or transceiver?", "anchor": "how-do-i-create-a-verifier-or-transceiver", "start_char": 9792, "end_char": 10356, "estimated_token_count": 135, "token_estimator": "heuristic-v1", "text": "## How do I create a verifier or transceiver?\n\nTo 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/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank}.\n\nFor 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}."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 13, "depth": 2, "title": "Can I use Hetzner for the NTT deployment?", "anchor": "can-i-use-hetzner-for-the-ntt-deployment", "start_char": 10356, "end_char": 10784, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## Can I use Hetzner for the NTT deployment?\n\nNo, 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 14, "depth": 2, "title": "How can I transfer tokens with NTT with an additional payload?", "anchor": "how-can-i-transfer-tokens-with-ntt-with-an-additional-payload", "start_char": 10784, "end_char": 11880, "estimated_token_count": 264, "token_estimator": "heuristic-v1", "text": "## How can I transfer tokens with NTT with an additional payload?\n\nYou 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}.\n\n- On the source chain, override the [`_handleMsg` function](https://github.com/wormhole-foundation/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.\n- On the destination chain override the [`_handleAdditionalPayload` function](https://github.com/wormhole-foundation/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.\n\n!!!Important\n    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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 15, "depth": 2, "title": "Why use NTT over xERC20?", "anchor": "why-use-ntt-over-xerc20", "start_char": 11880, "end_char": 12830, "estimated_token_count": 205, "token_estimator": "heuristic-v1", "text": "## Why use NTT over xERC20?\n\nShortcomings of xERC20:\n\n- **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.\n- **No pausing**: xERC20 lacks mechanisms to pause operations during emergencies.\n- **No access control**: There are no built-in access controls for managing token transfers securely.\n- **Limited rate limiting**: Rate limits are bridge-specific and cannot be set per chain, reducing flexibility and security.\n- **No integration with relaying systems**: xERC20 does not natively support relayer systems, limiting its usability in automated or dynamic setups.\n\nWhile 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 16, "depth": 2, "title": "How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet?", "anchor": "how-can-i-start-transferring-tokens-to-a-chain-that-is-in-burning-mode-if-no-tokens-are-locked-yet", "start_char": 12830, "end_char": 13160, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## How can I start transferring tokens to a chain that is in burning mode, if no tokens are locked yet?\n\nTo 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."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 17, "depth": 2, "title": "Is there a way to use NTT tokens with chains that don't currently support NTT?", "anchor": "is-there-a-way-to-use-ntt-tokens-with-chains-that-dont-currently-support-ntt", "start_char": 13160, "end_char": 14171, "estimated_token_count": 224, "token_estimator": "heuristic-v1", "text": "## Is there a way to use NTT tokens with chains that don't currently support NTT?\n\nYes. NTT tokens can be used with chains that do not support NTT by leveraging the [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}. For example:\n\n- **Wrapped token scenario**: A token, such as the W token, can be bridged to non-NTT networks using WTT. When the token is bridged to a chain like Sui, a wrapped version of the token is created (e.g., Wrapped W token).\n- **Unwrapping requirement**: Tokens bridged using WTT 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.\n- **Messaging consistency**: WTT exclusively uses Wormhole messaging, ensuring consistent communication across all chains, whether or not they support NTT.\n\nThis approach ensures interoperability while maintaining the integrity of the token's cross-chain movement."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 18, "depth": 2, "title": "Can I bridge native ETH or other gas tokens with NTT?", "anchor": "can-i-bridge-native-eth-or-other-gas-tokens-with-ntt", "start_char": 14171, "end_char": 14857, "estimated_token_count": 159, "token_estimator": "heuristic-v1", "text": "## Can I bridge native ETH or other gas tokens with NTT?\n\nYes. On EVM chains, you can use the `wethUnwrap` manager variant to bridge native gas tokens like ETH. This works in hub-and-spoke mode, where WETH is used as the locked token on the hub chain. When tokens are transferred back to the hub, the NTT Manager automatically unwraps WETH to native ETH and sends it to the recipient.\n\nTo deploy with this variant, pass `--manager-variant wethUnwrap` when adding the hub chain. For full setup instructions, see the [WethUnwrap variant](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-evm/#wethunwrap-variant){target=\\_blank} section in the EVM deployment guide."}
{"page_id": "products-token-transfers-native-token-transfers-faqs", "page_title": "Native Token Transfers FAQs", "index": 19, "depth": 2, "title": "How can I update my NTT CLI version?", "anchor": "how-can-i-update-my-ntt-cli-version", "start_char": 14857, "end_char": 15602, "estimated_token_count": 168, "token_estimator": "heuristic-v1", "text": "## How can I update my NTT CLI version?\n\nTo update an existing NTT CLI installation, run the following command in your terminal:\n\n```bash\nntt update\n```\n\nNTT 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.\n\nFor local development, you can update your CLI version from a specific branch or install from a local path.\n\nTo install from a specific branch, run:\n\n```bash\nntt update --branch foo\n```\n\nTo install locally, run:\n```bash\nntt update --path path/to/ntt/repo\n```\n\nGit 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."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 24, "end_char": 589, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nThe [Native Token Transfers (NTT)](/docs/products/token-transfers/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.\n\nFor a coding walkthrough on deploying NTT with the CLI, watch the [NTT deployment demo](https://www.youtube.com/watch?v=ltZmeyjUxRk&t=1686s){target=\\_blank}."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 589, "end_char": 895, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, make sure you have:\n\n- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n- A wallet private key with tokens on supported chains.\n- ERC-20 or SPL tokens already deployed on the source and destination chains."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 2, "depth": 2, "title": "Don’t Have a Token Yet?", "anchor": "dont-have-a-token-yet", "start_char": 895, "end_char": 7082, "estimated_token_count": 1341, "token_estimator": "heuristic-v1", "text": "## Don’t Have a Token Yet?\n\nTo 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.\n\n???- interface \"Deploy an ERC-20 Token on EVM\"\n    Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token-evm){target=\\_blank} to deploy a basic ERC-20 token contract on testnet.\n\n    1. **Install Foundry**: Install the [Forge CLI](https://getfoundry.sh/introduction/installation/){target=\\_blank}.\n\n    2. **Clone the repository**: Fetch the example contract repository.\n\n        ```bash\n        git clone https://github.com/wormhole-foundation/example-ntt-token-evm.git\n        cd example-ntt-token\n        ```\n    3. **Deploy the token contract**: Deploy to testnet with your preferred name, symbol, minter, and owner addresses.\n\n        ```bash\n        forge create --broadcast \\\n            --rpc-url INSERT_RPC_URL \\\n            --private-key INSERT_YOUR_PRIVATE_KEY \\\n            src/PeerToken.sol:PeerToken \\\n            --constructor-args \"INSERT_TOKEN_NAME\" \"INSERT_TOKEN_SYMBOL\" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS\n        ```\n\n    4. **Mint tokens**: Send tokens to your address.\n\n        ```bash\n        cast send INSERT_TOKEN_ADDRESS \\\n            \"mint(address,uint256)\" \\\n            INSERT_RECIPIENT_ADDRESS \\\n            INSERT_AMOUNT_IN_WEI \\\n            --private-key INSERT_YOUR_PRIVATE_KEY \\\n            --rpc-url INSERT_RPC_URL\n        ```\n\n    !!! note\n        This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18).\n???- interface \"Create and Mint an SPL Token\"\n    This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens.\n\n    1. **Generate a key pair**: Run the following command to create a new wallet compatible with supported SVM chains.\n\n        ```bash\n        solana-keygen grind --starts-with w:1 --ignore-case\n        ```\n\n    2. **Set CLI keypair configuration**: Configure the Solana CLI to use the generated key pair.\n\n        ```bash\n        solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON\n        ```\n\n    3. **Select an RPC URL**: Configure the CLI to use the appropriate network using one of the following commands.\n\n        === \"Mainnet\"\n            ```bash\n            solana config set -um\n            ```\n\n        === \"Testnet (Solana's Devnet)\"\n            ```bash\n            solana config set -ud\n            ```\n\n        === \"Fogo Testnet\"\n            ```bash\n            solana config set --url INSERT_FOGO_TESTNET_RPC_URL\n            ```\n                    \n        !!! note\n            Solana's official testnet cluster is not supported for token creation or deployment with NTT. You must use the Solana devnet instead.\n\n    4. **Fund your wallet**: Ensure your wallet has enough native tokens to cover transaction fees.\n\n        - On Solana Devnet, you can request an airdrop:\n\n            ```bash\n            solana airdrop 2\n            solana balance\n            ```\n\n    5. **Install SPL Token CLI**: Install or update the required [CLI tool](https://www.solana-program.com/docs/token#setup){target=\\_blank}.\n\n        ```bash\n        cargo install spl-token-cli\n        ```\n\n    6. **Create a new SPL token**: Initialize the token on your connected SVM chain.\n\n        ```bash\n        spl-token create-token\n        ```\n\n    7. **Create a token account**: Generate an account to hold the token.\n\n        ```bash\n        spl-token create-account INSERT_TOKEN_ADDRESS\n        ```\n\n    8. **Mint tokens**: Send 1000 tokens to the created account.\n\n        ```bash\n        spl-token mint INSERT_TOKEN_ADDRESS 1000\n        ```\n\n    !!! note\n        NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://www.solana-program.com/docs/transfer-hook-interface){target=\\_blank}.\n???- interface \"Create and Deploy a Sui Token\"\n    This section walks you through setting up a wallet, deploying a Sui Coin contract, and minting tokens on testnet.\n\n    1. **Clone the repository**: Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token-sui){target=\\_blank} to deploy a Sui Coin contract on testnet.\n\n        ```bash\n        git clone https://github.com/wormhole-foundation/example-ntt-token-sui\n        cd example-ntt-token-sui\n        ```\n\n    2. **Set up a new wallet on testnet**: Before building and deploying your token, you'll need to create a new wallet on the Sui testnet and fund it with test tokens.\n\n        1. **Create a new testnet environment**: Configure your Sui client for testnet.\n\n            ```bash\n            sui client new-env --alias testnet --rpc https://fullnode.testnet.sui.io:443\n            ```\n\n        2. **Generate a new address**: Create a new Ed25519 address for your wallet.\n\n            ```bash\n            sui client new-address ed25519\n            ```\n\n        3. **Switch to the new address**: The above command will output a new address. Copy this address and switch to it.\n\n            ```bash\n            sui client switch --address YOUR_ADDRESS_STEP2\n            ```\n\n        4. **Fund your wallet**: Use the faucet to get test tokens.\n\n            ```bash\n            sui client faucet\n            ```\n\n        5. **Verify funding**: Check that your wallet has been funded.\n\n            ```bash\n            sui client balance\n            ```\n\n    3. **Build the project**: Compile the Move contract.\n\n        ```bash\n        sui move build\n        ```\n\n    4. **Deploy the token contract**: Deploy to testnet.\n\n        ```bash\n        sui client publish --gas-budget 20000000\n        ```\n\n    5. **Mint tokens**: Send tokens to your address.\n\n        ```bash\n        sui client call \\\n        --package YOUR_DEPLOYED_PACKAGE_ID_STEP4 \\\n        --module MODULE_NAME_STEP1 \\\n        --function mint \\\n        --args TREASURYCAP_ID_STEP4 AMOUNT_WITH_DECIMALS RECIPIENT_ADDRESS \\\n        --gas-budget 10000000\n        ```\n\n    !!! note\n        This token uses 9 decimals by default. All minting values must be specified with that in mind (1 token = 10^9)."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 3, "depth": 2, "title": "Install NTT CLI", "anchor": "install-ntt-cli", "start_char": 7082, "end_char": 7924, "estimated_token_count": 222, "token_estimator": "heuristic-v1", "text": "## Install NTT CLI\n\nThe NTT CLI is recommended to deploy and manage your cross-chain token configuration.\n\n1. Run the installation commands in your terminal:\n\n    ```bash\n    curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash\n    ```\n2. Verify the NTT CLI is installed:\n\n    ```bash\n    ntt --version\n    ```\n    ??? warning \"Command not found?\"\n        If the `ntt` command is not recognized after installation, ensure that [Bun](https://bun.sh/) v1.2.23 is installed and that its binary directory is included in your shell’s PATH.\n        \n        Append this line to your shell config (e.g., `~/.zshrc` or `~/.bashrc`):\n\n        ```bash\n        echo 'export PATH=\"$HOME/.bun/bin:$PATH\"' >> ~/.zshrc\n        ```\n\n        Then, restart your terminal or run `source ~/.zshrc`."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 4, "depth": 2, "title": "Initialize a New NTT Project", "anchor": "initialize-a-new-ntt-project", "start_char": 7924, "end_char": 8809, "estimated_token_count": 192, "token_estimator": "heuristic-v1", "text": "## Initialize a New NTT Project\n\n1. Once the CLI is installed, scaffold a new project by running:\n\n    ```bash\n    ntt new my-ntt-project\n    cd my-ntt-project\n    ```\n\n2. Initialize a new `deployment.json` file specifying the network:\n\n    === \"Mainnet\"\n        ```bash\n        ntt init Mainnet\n        ```\n\n    === \"Testnet\"\n        ```bash\n        ntt init Testnet\n        ```\n\n    After initialization, the `deployment.json` file contains your NTT configuration and starts with the selected network.\n\n    === \"Mainnet\"\n        ```json\n        {\n            \"network\": \"Mainnet\",\n            \"chains\": {}\n        }\n        ```\n\n    === \"Testnet\"\n        ```json\n        {\n            \"network\": \"Testnet\",\n            \"chains\": {}\n        }\n        ```\n\nIn the deployment steps, you will add your supported chains, their token addresses, deployment modes, and any custom settings."}
{"page_id": "products-token-transfers-native-token-transfers-get-started", "page_title": "Get Started with NTT", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 8809, "end_char": 10035, "estimated_token_count": 333, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nYou 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.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy to EVM Chains**\n\n    ---\n\n    Learn how to deploy NTT on EVM-compatible chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-evm/)\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy to SVM Chains**\n\n    ---\n\n    Follow the guide to deploy and configure NTT for SVM chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-solana/){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy to Sui**\n\n    ---\n\n    Learn how to deploy NTT to Sui.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-sui/){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 662, "end_char": 1056, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore deploying NTT on EVM chains, ensure you have the following prerequisites:\n\n- [Node.js and npm installed](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n- [Bun installed](https://bun.sh/){target=\\_blank}.\n- A wallet private key with tokens on supported chains.\n- ERC-20 tokens already deployed on the source and destination chains."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 1, "depth": 2, "title": "Overview of the Deployment Process", "anchor": "overview-of-the-deployment-process", "start_char": 1056, "end_char": 6632, "estimated_token_count": 1131, "token_estimator": "heuristic-v1", "text": "## Overview of the Deployment Process\n\nDeploying NTT on EVM chains follows a structured process:\n\n1. **Choose your token setup**: Use an existing ERC-20 token or deploy a new one.\n\n    ???- interface \"Deploy an ERC-20 Token on EVM\"\n        Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token-evm){target=\\_blank} to deploy a basic ERC-20 token contract on testnet.\n\n        1. **Install Foundry**: Install the [Forge CLI](https://getfoundry.sh/introduction/installation/){target=\\_blank}.\n\n        2. **Clone the repository**: Fetch the example contract repository.\n\n            ```bash\n            git clone https://github.com/wormhole-foundation/example-ntt-token-evm.git\n            cd example-ntt-token\n            ```\n        3. **Deploy the token contract**: Deploy to testnet with your preferred name, symbol, minter, and owner addresses.\n\n            ```bash\n            forge create --broadcast \\\n                --rpc-url INSERT_RPC_URL \\\n                --private-key INSERT_YOUR_PRIVATE_KEY \\\n                src/PeerToken.sol:PeerToken \\\n                --constructor-args \"INSERT_TOKEN_NAME\" \"INSERT_TOKEN_SYMBOL\" INSERT_MINTER_ADDRESS INSERT_OWNER_ADDRESS\n            ```\n\n        4. **Mint tokens**: Send tokens to your address.\n\n            ```bash\n            cast send INSERT_TOKEN_ADDRESS \\\n                \"mint(address,uint256)\" \\\n                INSERT_RECIPIENT_ADDRESS \\\n                INSERT_AMOUNT_IN_WEI \\\n                --private-key INSERT_YOUR_PRIVATE_KEY \\\n                --rpc-url INSERT_RPC_URL\n            ```\n\n        !!! note\n            This token uses 18 decimals by default. All minting values must be specified in `wei` (1 token = 10^18).\n2. **Choose your deployment model**: Choose a deployment model. The NTT framework supports two [deployment models](/docs/products/token-transfers/native-token-transfers/overview/#deployment-models){target=\\_blank}: burn-and-mint and hub-and-spoke.\n\n    ??? interface \"Burn-and-Mint\"\n\n        Tokens must implement the following non-standard ERC-20 functions:\n\n        - `burn(uint256 amount)`\n        - `mint(address account, uint256 amount)`\n\n        You’ll also need to set mint authority to the relevant `NttManager` contract.\n\n        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 examples of the mentioned functions, as well as optional errors and events.\n\n        ??? interface \"`INttToken` Interface\"\n            ```solidity\n            // SPDX-License-Identifier: Apache 2\n            pragma solidity >=0.8.8 <0.9.0;\n\n            interface INttToken {\n                /// @notice Error when the caller is not the minter.\n                /// @dev Selector 0x5fb5729e.\n                /// @param caller The caller of the function.\n                error CallerNotMinter(address caller);\n\n                /// @notice Error when the minter is the zero address.\n                /// @dev Selector 0x04a208c7.\n                error InvalidMinterZeroAddress();\n\n                /// @notice Error when insufficient balance to burn the amount.\n                /// @dev Selector 0xcf479181.\n                /// @param balance The balance of the account.\n                /// @param amount The amount to burn.\n                error InsufficientBalance(uint256 balance, uint256 amount);\n\n                /// @notice The minter has been changed.\n                /// @dev Topic0\n                ///      0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9.\n                /// @param newMinter The new minter.\n                event NewMinter(address previousMinter, address newMinter);\n\n                // NOTE: the `mint` method is not present in the standard ERC20 interface.\n                function mint(address account, uint256 amount) external;\n\n                // NOTE: the `setMinter` method is not present in the standard ERC20 interface.\n                function setMinter(address newMinter) external;\n\n                // NOTE: NttTokens in `burn` mode require the `burn` method to be present.\n                //       This method is not present in the standard ERC20 interface, but is\n                //       found in the `ERC20Burnable` interface.\n                function burn(uint256 amount) external;\n            }\n            ```\n\n    ??? interface \"Hub-and-Spoke\"\n\n        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:\n\n        - Tokens are locked on Ethereum.\n        - Tokens are minted or burned on Polygon.\n\n        This setup maintains a consistent total supply across all chains.\n\n        To bridge native gas tokens (e.g., ETH) in hub-and-spoke mode, see the [WethUnwrap variant](#wethunwrap-variant) below.\n\n    Example deployment scripts for both models are available in the [`example-ntt-token` GitHub repository](https://github.com/wormhole-foundation/example-ntt-token-evm){target=\\_blank}.\n\n3. **Configure your chains**: Use the NTT CLI to add EVM chains and configure deployment parameters.\n4. **Set Mint Authority**: Set the NTT Manager as a minter for your tokens on the relevant chains.\n    - For burn-and-mint mode, set the NTT Manager as a minter on all chains. \n    - For hub-and-spoke, set the NTT Manager as a minter only on spoke chains."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 2, "depth": 2, "title": "Set Up NTT", "anchor": "set-up-ntt", "start_char": 6632, "end_char": 8051, "estimated_token_count": 308, "token_estimator": "heuristic-v1", "text": "## Set Up NTT\n\nBefore deploying NTT contracts on EVM chains, you need to scaffold a project and initialize your deployment configuration.\n\n!!! note\n    If you already have an NTT deployment to another chain (like Solana), you can skip the `ntt new` and `ntt init` commands. Simply navigate to your existing NTT project directory and proceed directly to the [Deploy and Configure NTT](#deploy-and-configure-ntt) section.\n\nThe [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:\n\n???- interface \"Install the NTT CLI and Scaffold a New Project\"\n    \n    1. Install the NTT CLI:\n\n        ```bash\n        curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash\n        ```\n\n        Verify installation:\n\n        ```bash\n        ntt --version\n        ```\n\n    2. Initialize a new NTT project:\n\n        ```bash\n        ntt new my-ntt-project\n        cd my-ntt-project\n        ```\n\n    3. Create the deployment config using the following command. This will generate a `deployment.json` file where your settings are stored:\n\n        === \"Mainnet\"\n\n            ```bash\n            ntt init Mainnet\n            ```\n        === \"Testnet\"\n\n            ```bash\n            ntt init Testnet\n            ```"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 3, "depth": 2, "title": "Deploy and Configure NTT", "anchor": "deploy-and-configure-ntt", "start_char": 8051, "end_char": 11449, "estimated_token_count": 698, "token_estimator": "heuristic-v1", "text": "## Deploy and Configure NTT\n\nOnce you've set up NTT, proceed with adding your EVM chains and deploying contracts.\n\n1. **Environment Setup**: Ensure you have set up your environment correctly, open your terminal, and run the `export` commands:\n\n    ```bash\n    export ETH_PRIVATE_KEY=INSERT_PRIVATE_KEY\n    export SEPOLIA_SCAN_API_KEY=INSERT_ETHERSCAN_SEPOLIA_API_KEY\n    export ARBITRUMSEPOLIA_SCAN_API_KEY=INSERT_ARBISCAN_SEPOLIA_API_KEY\n    ```\n\n2. **Deploy NTT to EVM**: Add each chain you'll be deploying to using the `ntt add-chain` command. The following example demonstrates configuring NTT in burn-and-mint mode on Ethereum Sepolia and Arbitrum Sepolia:\n\n    ```bash\n\n    # Add each chain\n    # The contracts will be automatically verified using the scanner API keys above\n    ntt add-chain Sepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS\n    ntt add-chain ArbitrumSepolia --latest --mode burning --token INSERT_YOUR_TOKEN_ADDRESS\n    ```\n\n    The `ntt add-chain` command takes the following parameters:\n\n    - Name of each chain.\n    - Version of NTT to deploy (use `--latest` for the latest contract versions).\n    - Mode - either `burning` or `locking`.\n    - Your token contract address.\n\n    For more advanced deployment configuration options, see the [Advanced](#advanced) section below.\n\n    While not recommended, you can pass the `-skip-verify` flag to the `ntt add-chain` command if you want to skip contract verification.\n\n3. **Verify deployment status**: After deployment, check if your `deployment.json` file matches the on-chain configuration using the following command:\n\n    ```bash\n    ntt status\n    ```\n\n    If needed, sync your local configuration with the on-chain configuration:\n\n    ```bash\n    ntt pull\n    ```\n\n4. **Configure rate limits**: Set up inbound and outbound rate limits. By default, limits are set to 0 and must be updated before deployment. For EVM chains, values must be set using 18 decimals.\n\n    Open your `deployment.json` file and adjust the values based on your use case:\n\n    ```json\n    \"outbound\": \"1000.000000000000000000\",\n    \"inbound\": {\n        \"Arbitrum\": \"1000.000000000000000000\"\n    }\n    ```\n\n    - **`outbound`** - a single value that sets the maximum tokens allowed to leave the chain (applies to all destination chains)\n    - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific source chains (e.g., the example above limits tokens received from Arbitrum)\n\n    This configuration ensures your rate limits align with the token's precision on each chain, preventing mismatches that could block or miscalculate transfers. Before setting these values, confirm your token's decimals on each chain by checking the token contract on the relevant block explorer.\n\n    For more details on rate limiting configuration and behavior, see the [Rate Limiting](/docs/products/token-transfers/native-token-transfers/configuration/rate-limiting/){target=\\_blank} page.\n\n5. **Push the final deployment**: Once rate limits are set, sync the on-chain configuration with local changes made to your `deployment.json` file.\n\n    ```bash\n    ntt push \n    ```\n  \nAfter 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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 4, "depth": 2, "title": "Set Mint Authority", "anchor": "set-mint-authority", "start_char": 11449, "end_char": 12368, "estimated_token_count": 213, "token_estimator": "heuristic-v1", "text": "## Set Mint Authority\n\nThe 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.\n\n!!! note\n    The required NTT Manager address can be found in the `deployment.json` file.\n\n- 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.\n    ```json\n    cast send $TOKEN_ADDRESS \"setMinter(address)\" $NTT_MANAGER_ADDRESS --private-key $ETH_PRIVATE_KEY --rpc-url $YOUR_RPC_URL  \n    ```\n\n- 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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 5, "depth": 2, "title": "NTT Manager Deployment Parameters", "anchor": "ntt-manager-deployment-parameters", "start_char": 12368, "end_char": 15056, "estimated_token_count": 591, "token_estimator": "heuristic-v1", "text": "## NTT Manager Deployment Parameters\n\nThis table compares the configuration parameters available when deploying the NTT Manager using the CLI versus those available during a manual deployment with a Forge script. It highlights which options are configurable via each method, whether values are auto-detected or hardcoded, and includes additional comments to help guide deployment decisions.\n\n| <div style=\"width:150px\">Parameter</div> | Forge Script           | CLI                                 | Both   | Comments                                     |\n|-------------------------|------------------------|-------------------------------------|--------|----------------------------------------------|\n| `token`                 | Input                  | `--token <address>`                 | Yes    |                                              |\n| `mode`                  | Input                  | `--mode <locking/burning>`          | Yes    | Key decision: hub-and-spoke or mint-and-burn |\n| `wormhole`              | Input                  | Auto-detected via SDK/`ChainContext`  | Similar|                                              |\n| `wormholeRelayer`       | Input                  | Auto-detected via on-chain query/SDK| Similar|                                              |\n| `specialRelayer`        | Input                  | Not exposed                         | No     | Take into consideration if using custom relaying. Not recommended |\n| `decimals`              | Input, overridable     | Auto-detected via token contract, not overridable  | Similar |                              |\n| `wormholeChainId`       | Queried from Wormhole contract | `--chain` (network param, mapped internally) | Yes     |                              |\n| `rateLimitDuration`     | Hardcoded (`86400`)    | Hardcoded (`86400`)                 | Yes    | Rate limit duration. A day is normal but worth deciding  |\n| `shouldSkipRatelimiter` | Hardcoded (`false`)      | Hardcoded (`false`)                   | Yes    | If rate limit should be disabled (when the manager supports it)         |\n| `consistencyLevel`      | Hardcoded (`202`)      | Hardcoded (`202`)                   | Yes    | `202` (finalized) is the standard — lower is not recommended  |\n| `gasLimit`              | Hardcoded (`500000`)   | Hardcoded (`500000`)                | Yes    |             |\n| `outboundLimit`         | Computed               | Auto-detected/Hardcoded             | Similar| Relative to rate limit             |\n| `managerVariant`        | Input (`MANAGER_VARIANT`)  | `--manager-variant <string>`        | Yes    | Choices: `standard` (default), `noRateLimiting`, `wethUnwrap`. EVM only |"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 6, "depth": 2, "title": "Manager Variants", "anchor": "manager-variants", "start_char": 15056, "end_char": 15647, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "## Manager Variants\n\nThe NTT CLI supports three manager variants for EVM deployments, configured via the `--manager-variant` flag on `ntt add-chain`. The default variant is `standard`.\n\n| Variant | Description |\n|---------|-------------|\n| `standard` | Default NTT Manager with rate limiting enabled. Suitable for most deployments. |\n| `noRateLimiting` | Removes the rate limiter to free contract code space. Use when rate limiting is not required. |\n| `wethUnwrap` | Automatically unwraps WETH to native ETH when tokens are unlocked on the hub chain. Use for bridging native gas tokens. |"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 7, "depth": 3, "title": "WethUnwrap Variant", "anchor": "wethunwrap-variant", "start_char": 15647, "end_char": 16554, "estimated_token_count": 232, "token_estimator": "heuristic-v1", "text": "### WethUnwrap Variant\n\nThe `wethUnwrap` variant enables bridging of native gas tokens (e.g., ETH). On the hub chain, WETH is used as the locked token. When tokens arrive back at the hub via an inbound transfer, the manager automatically unwraps WETH and sends native ETH to the recipient.\n\n**Requirements:**\n\n- **EVM only** — no Solana or Sui equivalent\n- **Locking mode only** — the unwrap occurs during token unlock, which only happens in locking mode\n- **Token must be the WETH contract** — the manager casts the token address to the [IWETH interface](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWETH.sol){target=\\_blank}, so it must implement `deposit()` and `withdraw(uint256)`\n\n**Add the hub chain with the `wethUnwrap` variant:**\n\n```bash\nntt add-chain Ethereum --latest --mode locking \\\n  --token <WETH_ADDRESS> \\\n  --manager-variant wethUnwrap\n```"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 8, "depth": 2, "title": "Advanced", "anchor": "advanced", "start_char": 16554, "end_char": 18545, "estimated_token_count": 440, "token_estimator": "heuristic-v1", "text": "## Advanced\n\nBy default, cross-chain token transfers with NTT wait for full finality on the source chain. On some EVM chains, this can be a few seconds. On other EVM chains, such as Ethereum and L2s, this can be 15-20 minutes. This is the safest option for cross-chain token transfers. For faster cross-chain transfers, we recommend pairing NTT with a fast-transfers product such as [Mayan Swift](/docs/products/settlement/overview/#mayan-swift){target=\\_blank}.\n\nIf you would like to transfer tokens faster than finality natively, you can use the `--unsafe-custom-finality` flag to configure this. **Custom finality is an advanced feature, and Wormhole Contributors recommend using this with caution.** Choosing a level of finality other than `finalized` on EVM chains exposes you to [re-org risk](https://www.alchemy.com/overviews/what-is-a-reorg){target=\\_blank}. This is especially dangerous when moving assets cross-chain, because assets released or minted on the destination chain may not have been burned or locked on the source chain.\n\nTo select a custom finality level on an L1 chain, Wormhole Contributors recommend consulting information on forked blocks in blockchain explorers such as [Etherscan](https://etherscan.io/blocks_forked?p=1){target=\\_blank}, [Polygonscan](https://polygonscan.com/blocks_forked){target=\\_blank}, and others, paying particular attention to the “ReorgDepth” column. Polygon, for instance, has been known to have reorgs with a depth of up to 128 blocks!\n\nTo select a custom finality level on an L2 chain, Wormhole Contributors recommend reviewing L2 block explorers and details on whether the sequencer is centralized and how the L2 RPC node handles finality. Typically, the risks one is exposed to when not waiting for full finality from an L2 are: \n\n1. A centralized (or compromised) sequencer censoring transactions\n2. Re-orgs if sequencing is not centralized\n3. L1 reorg risk and the L2 sequencer not re-submitting the transaction batch to the L1."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-evm", "page_title": "Native Token Transfers EVM Deployment", "index": 9, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 18545, "end_char": 19821, "estimated_token_count": 332, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Test Your Deployment**\n\n    ---\n\n    Follow the NTT Post Deployment Guide for integration examples and testing instructions.\n\n    [:custom-arrow: Test Your NTT deployment](/docs/products/token-transfers/native-token-transfers/guides/post-deployment/)\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy NTT to SVM Chains**\n\n    ---\n\n    Follow the guide to deploy and configure Wormhole's Native Token Transfers (NTT) for SVM chains.\n\n    [:custom-arrow: Deploy NTT to SVM Chains](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-solana/)\n\n-   :octicons-tools-16:{ .lg .middle } **Launch a Multichain Native Memecoin**\n\n    ---\n\n    Learn how to use the NTT framework to launch a multi-chain native Memecoin on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/1bee7446-5ed5-8140-9ec4-e800f40a41bc){target=\\_blank}\n\n-   :octicons-question-16:{ .lg .middle } **View FAQs**\n\n    ---\n\n    Find answers to common questions about NTT.\n\n    [:custom-arrow: View FAQs](/docs/products/token-transfers/native-token-transfers/faqs/)\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 914, "end_char": 1439, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore following this guide, ensure you have:\n\n- An NTT deployment on HyperEVM. If you haven't deployed yet, follow the [Deploy NTT to EVM Chains](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-evm/){target=\\_blank} guide using HyperEVM as your target chain.\n- Your `ETH_PRIVATE_KEY` environment variable set to the deployer wallet private key.\n- The [NTT CLI](/docs/products/token-transfers/native-token-transfers/reference/cli-commands/){target=\\_blank} installed and up to date."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 1, "depth": 2, "title": "Overview of the Deployment Process", "anchor": "overview-of-the-deployment-process", "start_char": 1439, "end_char": 1934, "estimated_token_count": 113, "token_estimator": "heuristic-v1", "text": "## Overview of the Deployment Process\n\nAfter deploying NTT on HyperEVM, integrating with HyperCore follows these steps:\n\n1. **Deploy a spot token on HyperCore** - use the Hyperliquid Deploy Spot UI to register your token and obtain a token index.\n2. **Link HyperCore to HyperEVM** - use `ntt hype link` to connect your HyperCore spot token to its HyperEVM ERC-20 contract.\n3. **Bridge tokens** - use `ntt hype bridge-in` and `ntt hype bridge-out` to move tokens between HyperEVM and HyperCore."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 2, "depth": 2, "title": "Deploy a Spot Token on HyperCore", "anchor": "deploy-a-spot-token-on-hypercore", "start_char": 1934, "end_char": 2779, "estimated_token_count": 206, "token_estimator": "heuristic-v1", "text": "## Deploy a Spot Token on HyperCore\n\nBefore linking your ERC-20 token on HyperEVM to HyperCore, you must first deploy a [HIP-1](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-1-native-token-standard){target=\\_blank} spot token through Hyperliquid's Deploy Spot interface. This is a multi-step process performed directly on the Hyperliquid platform.\n\nNavigate to the Deploy Spot page:\n\n- **Testnet** - [app.hyperliquid-testnet.xyz/deploySpot](https://app.hyperliquid-testnet.xyz/deploySpot){target=\\_blank}\n- **Mainnet** - [app.hyperliquid.xyz/deploySpot](https://app.hyperliquid.xyz/deploySpot){target=\\_blank}\n\n!!! warning\n    Each step is permanent. You cannot change inputs after proceeding to the next step. Hyperliquid recommends testing the exact configuration on testnet before using mainnet."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 3, "depth": 3, "title": "Step 1: Deploy Token", "anchor": "step-1-deploy-token", "start_char": 2779, "end_char": 3546, "estimated_token_count": 194, "token_estimator": "heuristic-v1", "text": "### Step 1: Deploy Token\n\nRegister the token name and configure its decimal precision:\n\n- **`szDecimals`** - tradable precision on the order book. For example, `2` means the minimum order increment is `0.01` tokens.\n- **`weiDecimals`** - smallest indivisible unit. For example, `8` means the smallest unit is `0.00000001` tokens.\n\nThese values must satisfy the constraint: **`szDecimals + 5 <= weiDecimals`** as defined in the [HIP-1 specification](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-1-native-token-standard){target=\\_blank}.\n\n!!! note\n    The HIP-1 token on HyperCore uses `weiDecimals`, which may differ from your ERC-20 token's decimals on HyperEVM. The asset bridge handles the conversion between the two."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 4, "depth": 3, "title": "Step 2: Set Deployer Trading Fee Share", "anchor": "step-2-set-deployer-trading-fee-share", "start_char": 3546, "end_char": 4271, "estimated_token_count": 165, "token_estimator": "heuristic-v1", "text": "### Step 2: Set Deployer Trading Fee Share\n\nConfigure the percentage of trading fees on the spot pair that go to your deployer address. The remainder is burned. This value can only be **decreased** after deployment, never increased.\n\nAfter completing this step, the **Progress So Far** panel on the right side of the screen displays your **Token Index**, the unique integer identifier for your spot token on HyperCore. Save this value as you'll need it for the `ntt hype link` command after completing the Deploy Spot process.\n\n![The Progress So Far panel in the Deploy Spot UI after Step 2, showing Token Index and fee share](/docs/images/products/native-token-transfers/guides/hyperliquid/deploy-spot-progress-step2.jpeg)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 5, "depth": 3, "title": "Step 3: Set Genesis Balances", "anchor": "step-3-set-genesis-balances", "start_char": 4271, "end_char": 5686, "estimated_token_count": 315, "token_estimator": "heuristic-v1", "text": "### Step 3: Set Genesis Balances\n\nThis step allocates the initial HIP-1 token supply. For an NTT bridge token, you must mint the genesis supply to the **asset bridge address** so the bridge has reserves to back bridged tokens.\n\n!!! warning\n    Hyperliquidity (Step 5) reserves a portion of the genesis supply for its automated market making. Account for this when choosing your genesis amount.\n\nThe asset bridge address is deterministic based on your token index. The format is a fixed prefix followed by the token index as a 4-character hex value:\n\n```text\n0x2000000000000000000000000000000000000{tokenIndex as 4-char hex}\n```\n\nFor example, token index `1591` = hex `0637`:\n\n```text\n0x2000000000000000000000000000000000000637\n```\n\nIn the Deploy Spot UI:\n\n1. Enter the **asset bridge address** in the **User** field.\n2. Enter the genesis amount in the **Amount** field. This is a whole number in the smallest unit (wei). For example, with `weiDecimals=8`, an amount of `10000000000000000` equals 100 million tokens.\n3. Click **Register User Genesis** to register the entry.\n4. Click **Complete User Genesis** to finalize (irreversible).\n\n!!! note\n    Why mint to the asset bridge? The bridge credits HIP-1 tokens on HyperCore when ERC-20 deposits arrive on HyperEVM. It can only release tokens it already holds. Minting the genesis supply to the bridge ensures it has reserves to back any deposited ERC-20 tokens."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 6, "depth": 3, "title": "Step 4: Deploy Spot Trading Pair", "anchor": "step-4-deploy-spot-trading-pair", "start_char": 5686, "end_char": 6109, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "### Step 4: Deploy Spot Trading Pair\n\nThis step creates the trading pair between your token and USDC on HyperCore via a `RegisterSpot` action. It requires specifying the base token index (your token) and the quote token index (USDC). The initial pricing is determined through a [Dutch auction](https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/deploying-hip-1-and-hip-2-assets){target=\\_blank} mechanism."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 7, "depth": 3, "title": "Step 5: Deploy Hyperliquidity", "anchor": "step-5-deploy-hyperliquidity", "start_char": 6109, "end_char": 6465, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "### Step 5: Deploy Hyperliquidity\n\n[Hyperliquidity](https://hyperliquid.gitbook.io/hyperliquid-docs/hyperliquid-improvement-proposals-hips/hip-2-hyperliquidity){target=\\_blank} commits permanent on-chain liquidity to the order book. It is not required for the asset bridge to function, but the UI requires you to configure it before proceeding to Step 6."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 8, "depth": 3, "title": "Step 6: Review and Trigger Genesis", "anchor": "step-6-review-and-trigger-genesis", "start_char": 6465, "end_char": 7006, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "### Step 6: Review and Trigger Genesis\n\nReview all inputs and trigger genesis. This step creates the HIP-1 token on HyperCore and is **irreversible**. Without triggering genesis, the token does not exist on HyperCore.\n\nThe **Progress So Far** panel on the right side of the screen summarizes your deployment, including the **Token Index** you'll need for the next step.\n\n![The Progress So Far panel in the Deploy Spot UI showing the Token Index](/docs/images/products/native-token-transfers/guides/hyperliquid/deploy-spot-token-index.jpeg)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 9, "depth": 2, "title": "Link HyperCore to HyperEVM", "anchor": "link-hypercore-to-hyperevm", "start_char": 7006, "end_char": 8456, "estimated_token_count": 361, "token_estimator": "heuristic-v1", "text": "## Link HyperCore to HyperEVM\n\nOnce your spot token is deployed on HyperCore, use the `ntt hype link` command to connect it to your HyperEVM ERC-20 contract. This two-step process registers the EVM contract with HyperCore and finalizes the link.\n\n```bash\nntt hype link --token-index INSERT_TOKEN_INDEX\n```\n\nReplace `INSERT_TOKEN_INDEX` with the token index from the Deploy Spot process (e.g., `1591`).\n\nThe command performs two actions automatically:\n\n1. **Request** - registers the EVM contract address with HyperCore.\n2. **Finalize** - completes the link by confirming the contract deployment nonce.\n\nAfter the command completes, it saves the `tokenIndex` to your `deployment.json` under a `hypercore` key:\n\n```json\n{\n  \"network\": \"Testnet\",\n  \"chains\": {\n    \"HyperEVM\": {\n      \"token\": \"0x...\"\n    }\n  },\n  \"hypercore\": {\n    \"tokenIndex\": 1591\n  }\n}\n```\n\n??? interface \"Additional Options\"\n\n    | Option | Description | Default |\n    |---|---|---|\n    | `--only-finalize` | Skip the request step and only run finalize. Useful if the request was already submitted separately. | `false` |\n    | `--evm-extra-wei-decimals` | Set `evmExtraWeiDecimals` (ERC-20 decimals minus `weiDecimals`). | `10` |\n    | `--deploy-nonce` | Explicitly set the ERC-20 CREATE deploy nonce. Auto-derived from the deployer address if omitted. | Auto |\n    | `--testnet` | Override the network setting from `deployment.json` to use testnet. | From `deployment.json` |"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 10, "depth": 2, "title": "Bridge Tokens Between HyperEVM and HyperCore", "anchor": "bridge-tokens-between-hyperevm-and-hypercore", "start_char": 8456, "end_char": 8693, "estimated_token_count": 40, "token_estimator": "heuristic-v1", "text": "## Bridge Tokens Between HyperEVM and HyperCore\n\nAfter linking, you can move tokens between HyperEVM and HyperCore using the asset bridge. Each HyperCore spot token has a deterministic asset bridge address derived from its token index."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 11, "depth": 3, "title": "Bridge Into HyperCore", "anchor": "bridge-into-hypercore", "start_char": 8693, "end_char": 9055, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "### Bridge Into HyperCore\n\nTransfer tokens from HyperEVM into HyperCore:\n\n```bash\nntt hype bridge-in INSERT_AMOUNT_DECIMAL\n```\n\nReplace `INSERT_AMOUNT_DECIMAL` with the human-readable token amount (e.g., `100`, `0.5`). This sends an ERC-20 `transfer` to the asset bridge address on HyperEVM, which credits the equivalent HIP-1 tokens to your HyperCore account."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 12, "depth": 3, "title": "Bridge Out to HyperEVM", "anchor": "bridge-out-to-hyperevm", "start_char": 9055, "end_char": 9389, "estimated_token_count": 67, "token_estimator": "heuristic-v1", "text": "### Bridge Out to HyperEVM\n\nTransfer tokens from HyperCore back to HyperEVM:\n\n```bash\nntt hype bridge-out INSERT_AMOUNT_DECIMAL\n```\n\nReplace `INSERT_AMOUNT_DECIMAL` with the token amount to withdraw. This performs a `spotSend` on HyperCore to the asset bridge, which releases the tokens as ERC-20 on HyperEVM to your wallet address."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-hyperliquid", "page_title": "Native Token Transfers Hyperliquid Deployment", "index": 13, "depth": 2, "title": "Check Status", "anchor": "check-status", "start_char": 9389, "end_char": 9847, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "## Check Status\n\nAt any point after linking, you can check your HyperCore token configuration:\n\n```bash\nntt hype status\n```\n\nThis displays:\n\n- **Token index** - the HyperCore spot token identifier.\n- **Asset bridge address** - the deterministic bridge address for your token.\n- **Token string** - the HyperCore token identifier (e.g., `WSV:0x7d816f...`).\n- **Network** - testnet or mainnet.\n- **EVM token address** - the linked ERC-20 contract on HyperEVM."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 671, "end_char": 1561, "estimated_token_count": 293, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore deploying NTT on SVM chains, ensure you have the following:\n\n- [Rust](https://rust-lang.org/tools/install/){target=\\_blank} installed.\n- The correct versions of the Solana CLI and Anchor installed, depending on your NTT version:\n\n    === \"v3\"\n        | Dependency | Version |\n        |------------|---------|\n        | [Solana](https://docs.anza.xyz/cli/install/){target=\\_blank} | `v1.18.26` |\n        | [Anchor](https://www.anchor-lang.com/docs/installation){target=\\_blank} | `v0.29.0` |\n\n    === \"v2/v1\"\n        | Dependency | Version |\n        |------------|---------|\n        | [Solana](https://docs.anza.xyz/cli/install/){target=\\_blank} | `v1.18.10` |\n        | [Anchor](https://www.anchor-lang.com/docs/installation){target=\\_blank} | `v0.29.0` |\n\n\nUse the Solana and Anchor versions listed above to avoid compatibility issues while following this guide."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 1, "depth": 2, "title": "Overview of the Deployment Process", "anchor": "overview-of-the-deployment-process", "start_char": 1561, "end_char": 5698, "estimated_token_count": 832, "token_estimator": "heuristic-v1", "text": "## Overview of the Deployment Process\n\nDeploying NTT with the CLI on SVM chains follows a structured process:\n\n1. Choose your token setup:\n\n     - **Use an existing SPL token**: If your token is already deployed on a [supported SVM chain](/docs/products/reference/supported-networks/#ntt){target=\\_blank}, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section.\n     - **Create a new SPL token**: If you don't already have an SPL token deployed, you'll need to deploy and configure it on a supported SVM chain before integrating with Wormhole's NTT.\n\n        ???- interface \"Create and Mint an SPL Token\"\n            This section walks you through generating a Solana wallet, deploying an SPL token, creating a token account, and minting tokens.\n\n            1. **Generate a key pair**: Run the following command to create a new wallet compatible with supported SVM chains.\n\n                ```bash\n                solana-keygen grind --starts-with w:1 --ignore-case\n                ```\n\n            2. **Set CLI keypair configuration**: Configure the Solana CLI to use the generated key pair.\n\n                ```bash\n                solana config set --keypair INSERT_PATH_TO_KEYPAIR_JSON\n                ```\n\n            3. **Select an RPC URL**: Configure the CLI to use the appropriate network using one of the following commands.\n\n                === \"Mainnet\"\n                    ```bash\n                    solana config set -um\n                    ```\n\n                === \"Testnet (Solana's Devnet)\"\n                    ```bash\n                    solana config set -ud\n                    ```\n\n                === \"Fogo Testnet\"\n                    ```bash\n                    solana config set --url INSERT_FOGO_TESTNET_RPC_URL\n                    ```\n                            \n                !!! note\n                    Solana's official testnet cluster is not supported for token creation or deployment with NTT. You must use the Solana devnet instead.\n\n            4. **Fund your wallet**: Ensure your wallet has enough native tokens to cover transaction fees.\n\n                - On Solana Devnet, you can request an airdrop:\n\n                    ```bash\n                    solana airdrop 2\n                    solana balance\n                    ```\n\n            5. **Install SPL Token CLI**: Install or update the required [CLI tool](https://www.solana-program.com/docs/token#setup){target=\\_blank}.\n\n                ```bash\n                cargo install spl-token-cli\n                ```\n\n            6. **Create a new SPL token**: Initialize the token on your connected SVM chain.\n\n                ```bash\n                spl-token create-token\n                ```\n\n            7. **Create a token account**: Generate an account to hold the token.\n\n                ```bash\n                spl-token create-account INSERT_TOKEN_ADDRESS\n                ```\n\n            8. **Mint tokens**: Send 1000 tokens to the created account.\n\n                ```bash\n                spl-token mint INSERT_TOKEN_ADDRESS 1000\n                ```\n\n            !!! note\n                NTT versions `>=v2.0.0+solana` support SPL tokens with [transfer hooks](https://www.solana-program.com/docs/transfer-hook-interface){target=\\_blank}.\n2. **Choose your deployment model**:\n\n    - **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.\n    - **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.\n\n3. **Deploy and configure NTT**: Use the NTT CLI to initialize and deploy the NTT program, specifying your SPL token and deployment mode.\n\n![SVM NTT deployment diagram](/docs/images/products/native-token-transfers/guides/solana/ntt-solana-guide-1.webp)\n\nFollowing this process, your token will fully integrate with NTT, enabling seamless transfers between SVM chains and other chains."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 2, "depth": 2, "title": "Set Up NTT", "anchor": "set-up-ntt", "start_char": 5698, "end_char": 7541, "estimated_token_count": 412, "token_estimator": "heuristic-v1", "text": "## Set Up NTT\n\nTo integrate your token with NTT on a SVM chain, 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.\n\n!!! note\n    If you already have an NTT deployment to another chain (like Ethereum), you can skip the `ntt new` and `ntt init` commands. Simply navigate to your existing NTT project directory and proceed directly to the [Generate an NTT Program Key Pair](#generate-an-ntt-program-key-pair) section.\n\nThe [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:\n\n???- interface \"Install the NTT CLI and Scaffold a New Project\"\n\n    1. Install the NTT CLI:\n\n        ```bash\n        curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash\n        ```\n\n        Verify installation:\n\n        ```bash\n        ntt --version\n        ```\n\n    2. Initialize a new NTT project:\n\n        ```bash\n        ntt new my-ntt-project\n        cd my-ntt-project\n        ```\n\n    3. Create the deployment config using the following command. This will generate a `deployment.json` file where your settings are stored:\n\n        === \"Mainnet\"\n\n            ```bash\n            ntt init Mainnet\n            ```\n        === \"Testnet\"\n\n            ```bash\n            ntt init Testnet\n            ```\n\n!!! note\n    When deploying NTT to Solana in `Testnet` mode, you must use [**Devnet tokens**](https://faucet.solana.com/){target=\\_blank}. Solana's official testnet cluster is not supported for token creation or deployment in NTT."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 3, "depth": 3, "title": "Generate an NTT Program Key Pair", "anchor": "generate-an-ntt-program-key-pair", "start_char": 7541, "end_char": 7693, "estimated_token_count": 43, "token_estimator": "heuristic-v1", "text": "### Generate an NTT Program Key Pair\n\nCreate a unique key pair for the NTT program:\n\n```bash\nsolana-keygen grind --starts-with ntt:1 --ignore-case\n```"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 4, "depth": 3, "title": "Set Mint Authority", "anchor": "set-mint-authority", "start_char": 7693, "end_char": 9999, "estimated_token_count": 537, "token_estimator": "heuristic-v1", "text": "### Set Mint Authority\n\nIf you use burn-and-mint mode, follow these steps to enable the NTT program to mint tokens on a SVM chain. This involves deriving the PDA as the token authority and updating the SPL token's minting permissions.\n\nFor hub-and-spoke and a SVM chain as the hubchain skip this section and proceed to [Deploy and Configure NTT](#deploy-and-configure-ntt), otherwise follow the burn-and-mint instructions below for the SVM chain as a spoke.\n\nBefore 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}.\n\nOptions to set the mint authority for your SPL token:\n\n**For undeployed programs:**\n\n- **Set to token authority PDA:**\n```bash\nntt set-mint-authority --chain INSERT_SVM_CHAIN --token INSERT_TOKEN_ADDRESS --manager INSERT_NTT_PROGRAM_ADDRESS --payer INSERT_KEYPAIR_JSON\n```\n\n- **Set to SPL Multisig:**\n    If you don’t already have one, first [create an SPL Multisig](#create-an-spl-multisig-optional). Then set it:\n    ```bash\n    ntt set-mint-authority --chain INSERT_SVM_CHAIN --token INSERT_TOKEN_ADDRESS --manager INSERT_NTT_PROGRAM_ADDRESS --multisig INSERT_MULTISIG_ADDRESS --payer INSERT_KEYPAIR_JSON\n    ```\n\n**For deployed programs:**\n\n- **Set to token authority PDA:**\n\n```bash\nntt set-mint-authority --chain INSERT_SVM_CHAIN --payer INSERT_KEYPAIR_JSON\n```\n\n- **Set to SPL Multisig**: If you don’t already have one, first [create an SPL Multisig](#create-an-spl-multisig-optional).\n```bash\nntt set-mint-authority --chain INSERT_SVM_CHAIN --multisig INSERT_MULTISIG_ADDRESS --payer INSERT_KEYPAIR_JSON\n```\n\n#### Create an SPL Multisig (optional)\n\nIf you want the mint authority controlled by a multisig, create it once and reuse it across flows:\n\n```bash\nntt solana create-spl-multisig INSERT_MINTER_PUBKEY_1 INSERT_MINTER_PUBKEY_2 ... \\\n  --token INSERT_TOKEN_ADDRESS \\\n  --manager INSERT_NTT_PROGRAM_ADDRESS \\\n  --payer INSERT_KEYPAIR_JSON\n```\n\n!!! note\n    Check out [this utility script](https://github.com/wormhole-foundation/demo-ntt-token-mint-authority-transfer/tree/main){target=\\_blank} for transferring token mint authority out of NTT."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 5, "depth": 2, "title": "Deploy and Configure NTT", "anchor": "deploy-and-configure-ntt", "start_char": 9999, "end_char": 12958, "estimated_token_count": 644, "token_estimator": "heuristic-v1", "text": "## Deploy and Configure NTT\n\n!!! warning\n    If deploying to Solana mainnet, you must use a custom RPC. See how to [set it up in your project](/docs/products/token-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.\n\nAfter setting up your deployment, finalize the configuration and deploy the NTT program on the SVM chain by following these steps:\n\n1. **Deploy NTT to the SVM chain**: Run the appropriate command based on your deployment mode.\n\n    === \"Burn-and-Mint\"\n\n        ```bash\n        ntt add-chain INSERT_SVM_CHAIN --latest --mode burning --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON\n        ```\n\n    === \"Hub-and-Spoke\"\n\n        ```bash\n        ntt add-chain INSERT_SVM_CHAIN --latest --mode locking --token INSERT_TOKEN_ADDRESS --payer INSERT_YOUR_KEYPAIR_JSON --program-key INSERT_YOUR_NTT_PROGRAM_KEYPAIR_JSON\n        ```\n\n    You can optionally add `--solana-priority-fee` to the script to increase the priority fee in microlamports. The default is `50000`.\n\n2. **Verify deployment status**: After deployment, check if your `deployment.json` file matches the on-chain configuration using the following command.\n\n    ```bash\n    ntt status\n    ```\n\n    If needed, sync your local configuration with the on-chain state:\n\n    ```bash\n    ntt pull\n    ```\n\n3. **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 SVM chains use nine decimals.\n\n    Open your `deployment.json` file and adjust the values based on your use case:  \n\n    ```json\n    \"outbound\": \"1000.000000000\",\n    \"inbound\": {\n        \"Sepolia\": \"1000.000000000\"\n    }\n    ```\n\n    - **`outbound`** - a single value that sets the maximum tokens allowed to leave the chain (applies to all destination chains)\n    - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific source chains (e.g., the example above limits tokens received from Sepolia)\n\n    This configuration ensures your rate limits align with the token's precision on each chain, preventing mismatches that could block or miscalculate transfers. Before setting these values, confirm your token's decimals on each chain by checking the token contract on the relevant block explorer.\n    \n    For more details on rate limiting configuration and behavior, see the [Rate Limiting](/docs/products/token-transfers/native-token-transfers/configuration/rate-limiting/){target=\\_blank} page.\n\n4. **Push the final deployment**: Once rate limits are set, push the deployment to the SVM chain using the specified key pair to cover gas fees.\n\n    ```bash\n    ntt push --payer INSERT_YOUR_KEYPAIR_JSON\n    ```"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 6, "depth": 3, "title": "Recovering Rent for Failed SVM Deployments", "anchor": "recovering-rent-for-failed-svm-deployments", "start_char": 12958, "end_char": 13389, "estimated_token_count": 89, "token_estimator": "heuristic-v1", "text": "### Recovering Rent for Failed SVM Deployments\n\nFailed SVM deployments don't result in loss of tokens. Instead, the native tokens 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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-solana", "page_title": "Native Token Transfers SVM Deployment", "index": 7, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 13389, "end_char": 14681, "estimated_token_count": 331, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy on EVM Chains**  \n\n    ---  \n\n    After deploying NTT on SVM chains, deploy and integrate it on EVM chains to enable seamless multichain transfers.  \n\n    [:custom-arrow: Deploy NTT on EVM Chains](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-evm/)\n\n-   :octicons-tools-16:{ .lg .middle } **Test Your Deployment**\n\n    ---\n\n    Follow the NTT Post Deployment Guide for integration examples and testing instructions.\n\n    [:custom-arrow: Test Your NTT deployment](/docs/products/token-transfers/native-token-transfers/guides/post-deployment/)\n\n-   :octicons-tools-16:{ .lg .middle } **Launch a Multichain Native Memecoin**\n\n    ---\n\n    Learn how to use the NTT framework to launch a multi-chain native Memecoin on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/1bee7446-5ed5-8140-9ec4-e800f40a41bc){target=\\_blank}\n\n-   :octicons-question-16:{ .lg .middle } **View FAQs**\n\n    ---\n\n    Find answers to common questions about NTT.\n\n    [:custom-arrow: View FAQs](/docs/products/token-transfers/native-token-transfers/faqs/)\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-sui", "page_title": "Native Token Transfers Sui Deployment", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 526, "end_char": 732, "estimated_token_count": 53, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore deploying NTT on Sui, ensure you have the following prerequisites:\n\n- [Sui Client CLI installed](https://docs.sui.io/guides/developer/getting-started/sui-install){target=\\_blank}."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-sui", "page_title": "Native Token Transfers Sui Deployment", "index": 1, "depth": 2, "title": "Overview of the Deployment Process", "anchor": "overview-of-the-deployment-process", "start_char": 732, "end_char": 4780, "estimated_token_count": 800, "token_estimator": "heuristic-v1", "text": "## Overview of the Deployment Process\n\nDeploying NTT on the Sui network follows a structured process:\n\n1. **Choose your token setup**:\n\n     - **Use an existing Sui token**: If your token is already deployed on the Sui network, you can skip token creation and move directly to the [Set Up NTT](#set-up-ntt) section.\n     - **Create a new Sui token**: If you don't already have a Sui token deployed, you'll need to deploy and configure it on the Sui network before integrating with Wormhole's NTT.\n\n        !!! warning \"Token Compatibility Requirement\"\n            Your Sui token must be created with the legacy `CoinMetadata` type for NTT compatibility, which can be done using the `coin::create_currency` function.\n            Once created, the token can be migrated to the `Currency` standard, but the legacy `CoinMetadata` type must exist initially.\n\n        ???- interface \"Create and Deploy a Sui Token\"\n            This section walks you through setting up a wallet, deploying a Sui Coin contract, and minting tokens on testnet.\n\n            1. **Clone the repository**: Use the [example NTT token repository](https://github.com/wormhole-foundation/example-ntt-token-sui){target=\\_blank} to deploy a Sui Coin contract on testnet.\n\n                ```bash\n                git clone https://github.com/wormhole-foundation/example-ntt-token-sui\n                cd example-ntt-token-sui\n                ```\n\n            2. **Set up a new wallet on testnet**: Before building and deploying your token, you'll need to create a new wallet on the Sui testnet and fund it with test tokens.\n\n                1. **Create a new testnet environment**: Configure your Sui client for testnet.\n\n                    ```bash\n                    sui client new-env --alias testnet --rpc https://fullnode.testnet.sui.io:443\n                    ```\n\n                2. **Generate a new address**: Create a new Ed25519 address for your wallet.\n\n                    ```bash\n                    sui client new-address ed25519\n                    ```\n\n                3. **Switch to the new address**: The above command will output a new address. Copy this address and switch to it.\n\n                    ```bash\n                    sui client switch --address YOUR_ADDRESS_STEP2\n                    ```\n\n                4. **Fund your wallet**: Use the faucet to get test tokens.\n\n                    ```bash\n                    sui client faucet\n                    ```\n\n                5. **Verify funding**: Check that your wallet has been funded.\n\n                    ```bash\n                    sui client balance\n                    ```\n\n            3. **Build the project**: Compile the Move contract.\n\n                ```bash\n                sui move build\n                ```\n\n            4. **Deploy the token contract**: Deploy to testnet.\n\n                ```bash\n                sui client publish --gas-budget 20000000\n                ```\n\n            5. **Mint tokens**: Send tokens to your address.\n\n                ```bash\n                sui client call \\\n                --package YOUR_DEPLOYED_PACKAGE_ID_STEP4 \\\n                --module MODULE_NAME_STEP1 \\\n                --function mint \\\n                --args TREASURYCAP_ID_STEP4 AMOUNT_WITH_DECIMALS RECIPIENT_ADDRESS \\\n                --gas-budget 10000000\n                ```\n\n            !!! note\n                This token uses 9 decimals by default. All minting values must be specified with that in mind (1 token = 10^9).\n2. **Choose your deployment model**:\n\n    - **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.\n    - **Burn-and-mint**: Tokens are burned on the source chain and minted on the destination chain. This requires transferring the Sui Treasury cap object to the NTT manager.\n\n3. **Deploy and configure NTT**: Use the NTT CLI to initialize and deploy the NTT program, specifying your Sui token and deployment mode."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-sui", "page_title": "Native Token Transfers Sui Deployment", "index": 2, "depth": 2, "title": "Set Up NTT", "anchor": "set-up-ntt", "start_char": 4780, "end_char": 6192, "estimated_token_count": 307, "token_estimator": "heuristic-v1", "text": "## Set Up NTT\n\nBefore deploying NTT contracts on Sui, you need to scaffold a project and initialize your deployment configuration.\n\n!!! note\n    If you already have an NTT deployment to another chain (like Solana), you can skip the `ntt new` and `ntt init` commands. Simply navigate to your existing NTT project directory and proceed directly to the [Deploy and Configure NTT](#deploy-and-configure-ntt) section.\n\nThe [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:\n\n???- interface \"Install the NTT CLI and Scaffold a New Project\"\n    \n    1. Install the NTT CLI:\n\n        ```bash\n        curl -fsSL https://raw.githubusercontent.com/wormhole-foundation/native-token-transfers/main/cli/install.sh | bash\n        ```\n\n        Verify installation:\n\n        ```bash\n        ntt --version\n        ```\n\n    2. Initialize a new NTT project:\n\n        ```bash\n        ntt new my-ntt-project\n        cd my-ntt-project\n        ```\n\n    3. Create the deployment config using the following command. This will generate a `deployment.json` file where your settings are stored:\n\n        === \"Mainnet\"\n\n            ```bash\n            ntt init Mainnet\n            ```\n        === \"Testnet\"\n\n            ```bash\n            ntt init Testnet\n            ```"}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-sui", "page_title": "Native Token Transfers Sui Deployment", "index": 3, "depth": 2, "title": "Deploy and Configure NTT", "anchor": "deploy-and-configure-ntt", "start_char": 6192, "end_char": 9956, "estimated_token_count": 817, "token_estimator": "heuristic-v1", "text": "## Deploy and Configure NTT\n\nOnce you've set up NTT, proceed with deploying the contracts.\n\n1. **Environment Setup**: Ensure you have set up your environment correctly, open your terminal, and run the following commands:\n\n    First, list your available key aliases:\n\n    ```bash\n    sui client addresses\n    ```\n    \n    This command displays all available aliases. Note the alias you want to use for your deployment.\n\n    Then, export the private key using your chosen alias:\n\n    ```bash\n    sui keytool export --key-identity goofy\n    ```\n    **Note**: Replace `goofy` with your actual key alias. This command exports the private key in the format required by the NTT add-chain command.\n\n    ```bash\n    export SUI_PRIVATE_KEY=INSERT_PRIVATE_KEY\n    ```\n\n    After setting up your deployment, finalize the configuration and deploy the NTT program onto the Sui network by following the steps below.\n\n2. **Deploy NTT to Sui**: Run the appropriate command based on your deployment mode.\n\n    !!! note\n        The `--token` parameter requires the full Sui coin type in the format `0xADDRESS::module::struct`. \n        For example, `0x2::sui::SUI` for the native SUI token, or `0x1234567890abcdef::my_module::MyToken` for a custom token.\n\n    !!! warning \n        In burning mode, the NTT CLI moves the treasury-cap object during the add-chain command to the NTT manager, enabling the NTT manager to mint tokens. \n        **Important**: Once the treasury-cap object is moved to the NTT manager, you will no longer be able to modify the token's metadata (such as name, symbol, or icon).\n\n    === \"Burn-and-Mint\"\n\n        ```bash\n        ntt add-chain Sui --latest --mode burning --token INSERT_FULL_COIN_TYPE --sui-treasury-cap YOUR_TREASURY_CAP_ID \n        ```\n\n    === \"Hub-and-Spoke\"\n\n        ```bash\n        ntt add-chain Sui --latest --mode locking --token INSERT_FULL_COIN_TYPE\n        ```\n\n3. **Verify deployment status**: After deployment, check if your `deployment.json` file matches the on-chain configuration using the following command.\n\n    ```bash\n    ntt status\n    ```\n\n    If needed, sync your local configuration with the on-chain state:\n\n    ```bash\n    ntt pull\n    ```\n\n4. **Configure inbound and outbound rate limits**: By default, the inbound and outbound limits are set to `0` and must be updated before deployment. \n\n    Open your `deployment.json` file and adjust the values based on your use case:  \n\n    ```json\n    \"outbound\": \"1000.000000000\",\n    \"inbound\": {\n        \"Sepolia\": \"1000.000000000\"\n    }\n    ```\n\n    - **`outbound`** - a single value that sets the maximum tokens allowed to leave the chain (applies to all destination chains)\n    - **`inbound`** - configures per-chain receiving limits for tokens arriving from specific source chains (e.g., the example above limits tokens received from Sepolia)\n\n    This configuration ensures your rate limits align with the token's precision on each chain, preventing mismatches that could block or miscalculate transfers. Before setting these values, confirm your token's decimals on each chain by checking the token contract on the relevant block explorer.\n    \n    For more details on rate limiting configuration and behavior, see the [Rate Limiting](/docs/products/token-transfers/native-token-transfers/configuration/rate-limiting/){target=\\_blank} page.\n\n5. **Push the final deployment**: Once rate limits are set, sync the on-chain configuration with local changes made to your `deployment.json` file.\n\n    ```bash\n    ntt push\n    ```\n  \nAfter 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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-deploy-to-sui", "page_title": "Native Token Transfers Sui Deployment", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 9956, "end_char": 11179, "estimated_token_count": 318, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Test Your Deployment**\n\n    ---\n\n    Follow the NTT Post Deployment Guide for integration examples and testing instructions.\n\n    [:custom-arrow: Test Your NTT deployment](/docs/products/native-token-transfers/guides/post-deployment/)\n\n-   :octicons-tools-16:{ .lg .middle } **Deploy to SVM Chains**\n\n    ---\n\n    Follow the guide to deploy and configure Wormhole's Native Token Transfers (NTT) for SVM chains.\n\n    [:custom-arrow: Deploy NTT to SVM Chains](/docs/products/native-token-transfers/guides/deploy-to-solana/)\n\n-   :octicons-tools-16:{ .lg .middle } **Launch a Multichain Native Memecoin**\n\n    ---\n\n    Learn how to use the NTT framework to launch a multi-chain native Memecoin on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/1bee7446-5ed5-8140-9ec4-e800f40a41bc){target=\\_blank}\n\n-   :octicons-question-16:{ .lg .middle } **View FAQs**\n\n    ---\n\n    Find answers to common questions about NTT.\n\n    [:custom-arrow: View FAQs](/docs/products/native-token-transfers/faqs)\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 648, "end_char": 868, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\n - An EVM-compatible wallet (e.g., [MetaMask](https://metamask.io/){target=\\_blank}, [Phantom](https://phantom.com/){target=\\_blank}, etc.).\n - Minimum ETH (or equivalent) for gas fees per deployment."}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 1, "depth": 2, "title": "Supported Blockchains", "anchor": "supported-blockchains", "start_char": 868, "end_char": 1093, "estimated_token_count": 38, "token_estimator": "heuristic-v1", "text": "## Supported Blockchains\n\nThe NTT Launchpad currently supports deployments on the following mainnet chains:\n\n - Ethereum\n - Arbitrum One\n - Base\n - Berachain\n - Blast\n - BNB Smart Chain\n - Ink\n - Optimism Mainnet\n - Polygon"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 2, "depth": 2, "title": "Choose Your Path", "anchor": "choose-your-path", "start_char": 1093, "end_char": 1538, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "## Choose Your Path\n\nOnce ready, choose an option to proceed:\n\n - **[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.\n - **[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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 3, "depth": 2, "title": "Launch a Cross-Chain Token", "anchor": "launch-a-cross-chain-token", "start_char": 1538, "end_char": 3591, "estimated_token_count": 553, "token_estimator": "heuristic-v1", "text": "## Launch a Cross-Chain Token\n\nDeploy 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:\n\n1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\\_blank}, connect your wallet, and click **Get Started**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp)\n    \n2. Select **Launch a Cross-Chain Token**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-2.webp)\n\n3. Set the token details:\n    1. Select the **home network** from the dropdown menu.\n    2. Enter the **name** for the token.\n    3. Enter the **symbol** of the token. \n    4. Provide the **initial supply**.\n    5. To the token details, click **Next**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-3.webp)\n\n4. Select the deployment chains:\n    1. The home network where your token will be deployed will be populated (e.g., Optimism).\n    2. Choose any additional chains to deploy your token to (e.g., Base).\n    3. To continue, click **Next**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-4.webp)\n\n5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp)\n\n6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp)\n\n7. 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.\n\n8. Once both deployments are completed, proceed to the [**Dashboard**](#explore-the-launchpad-dashboard) to manage your token."}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 4, "depth": 2, "title": "Expand Your Existing Token", "anchor": "expand-your-existing-token", "start_char": 3591, "end_char": 5610, "estimated_token_count": 532, "token_estimator": "heuristic-v1", "text": "## Expand Your Existing Token\n\nExpand 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:\n\n1. Open the [NTT Launchpad](https://ntt.wormhole.com/){target=\\_blank}, connect your wallet, and click **Get Started**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-1.webp)\n\n2. Select **Expand Your Existing Token**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-7.webp)\n\n3. Enter the token details:\n    1. Choose the home network where your token is already deployed (e.g., Optimism).\n    2. Choose any additional chains to deploy your token to (e.g., Base).\n    3. To continue, click **Next**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-8.webp)\n\n4. Select the chains to deploy your token to:\n    1. The home network where your token is already deployed will be populated (e.g., Optimism).\n    2. Choose any additional chains to deploy your token to (e.g., Base).\n    1. Click **Next**.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-9.webp)\n\n5. To deploy on the first chain (Optimism), click on **Deploy**; if prompted, switch your wallet to the correct network and confirm the transaction.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-5.webp)\n\n6. Once deployed, you can view the transaction in a block explorer and add the token to your wallet.\n\n    ![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-6.webp)\n\n7. 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.\n\n8. Now that your token has been deployed on multiple chains click [**Dashboard**](#explore-the-launchpad-dashboard) to review its details."}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 5, "depth": 2, "title": "Explore the Launchpad Dashboard", "anchor": "explore-the-launchpad-dashboard", "start_char": 5610, "end_char": 6368, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## Explore the Launchpad Dashboard\n\nTo 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.\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-10.webp)\n\nThe dashboard provides a high-level view of your token across all deployed chains, including:\n\n - Token addresses for each chain.\n - Supply distribution visualization.\n - List of deployed chains, including inbound and outbound transfer limits, which can be modified in [**Settings**](#settings).\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-11.webp)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 6, "depth": 2, "title": "Settings", "anchor": "settings", "start_char": 6368, "end_char": 6601, "estimated_token_count": 42, "token_estimator": "heuristic-v1", "text": "## Settings\n\nThe **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."}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 7, "depth": 3, "title": "Chain Management", "anchor": "chain-management", "start_char": 6601, "end_char": 7158, "estimated_token_count": 130, "token_estimator": "heuristic-v1", "text": "### Chain Management\n\nUse 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.\n\nFrom this section, you can also:\n\n - **Pause the token**: Temporarily turn off transfers on the selected chain.\n - **Deploy to a new chain**: Expand your token by deploying it to an additional chain.\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-12.webp)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 8, "depth": 3, "title": "Role Management", "anchor": "role-management", "start_char": 7158, "end_char": 7652, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### Role Management\n\nThis section displays key [roles](/docs/products/token-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.\n\n - **Manager’s Owner**: The owner through the `NTTOwner` proxy.\n - **Pauser**: The address authorized to pause transfers.\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-13.webp)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 9, "depth": 3, "title": "Security Threshold", "anchor": "security-threshold", "start_char": 7652, "end_char": 8519, "estimated_token_count": 172, "token_estimator": "heuristic-v1", "text": "### Security Threshold\n\nDetermine and update how transceivers interact with the token. [Transceivers](/docs/products/token-transfers/native-token-transfers/concepts/architecture/#transceivers){target=\\_blank} route NTT transfers between blockchains, ensuring tokens are correctly sent and received across networks.\n\nA 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.  \n\n - **Registered Transceivers**: Displays the number of registered transceivers and their addresses.\n - **Transceivers Threshold**: A configurable value that must be less than or equal to the number of transceivers.\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-14.webp)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-evm-launchpad", "page_title": "Deploy Native Token Transfers with Launchpad", "index": 10, "depth": 3, "title": "Peer Chains Limits", "anchor": "peer-chains-limits", "start_char": 8519, "end_char": 9019, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "### Peer Chains Limits\n\nDefine the transfer restrictions for each connected network. You can adjust:\n\n - **Sending Limits**: The maximum amount of tokens that can be sent from the home chain.\n - **Receiving Limits**: The maximum amount of tokens that can be received for each of the supported peer chains.\n\nEnter a new value to adjust limits and click **Update**. The changes will take effect immediately.\n\n![](/docs/images/products/native-token-transfers/guides/evm-launchpad/ntt-launchpad-15.webp)"}
{"page_id": "products-token-transfers-native-token-transfers-guides-post-deployment", "page_title": "Native Token Transfers Post Deployment", "index": 0, "depth": 2, "title": "Post-Deployment Settings", "anchor": "post-deployment-settings", "start_char": 1455, "end_char": 2379, "estimated_token_count": 205, "token_estimator": "heuristic-v1", "text": "## Post-Deployment Settings\n\nThe following table outlines post-deployment settings available on the NTT Manager contract. These allow you to update roles, pause activity, and adjust transfer limits—useful for upgrades, incident response, or protocol tuning after initial deployment.\n\n| Setting                 | Effect                                   |\n|-------------------------|------------------------------------------|\n| `pause`                 | Pauses the manager.                      |\n| `unpause`               | Unpauses the manager.                    |\n| `setOwner`              | Changes the manager owner.               |\n| `setPauser`             | Changes the pauser role.                 |\n| `setOutboundLimit`      | Sets outbound transfer limit.            |\n| `setInboundLimit`       | Sets inbound transfer limit (per chain). |\n| `setTransceiverPauser ` | Changes pauser for a transceiver.        |"}
{"page_id": "products-token-transfers-native-token-transfers-guides-post-deployment", "page_title": "Native Token Transfers Post Deployment", "index": 1, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 2379, "end_char": 4126, "estimated_token_count": 436, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n- :octicons-tools-16:{ .lg .middle } **Transfer Ownership**\n\n    ---\n\n    Learn how to move ownership of your NTT deployment to a new owner address on EVM, Solana, and Sui with step-by-step instructions.\n\n    [:custom-arrow: Follow the Transfer Ownership guide](/docs/products/token-transfers/native-token-transfers/guides/transfer-ownership/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole NTT Connect Demo**\n\n    ---\n\n    Test a transfer or deployment quickly with a standalone [Connect](/docs/products/connect/overview/){target=\\_blank} implementation with automatic NTT deployment configuration.\n\n    [:custom-arrow: Explore the NTT Connect demo](https://github.com/wormhole-foundation/connect-w/){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole NTT TypeScript SDK Demo**\n\n    ---\n\n    Reference an example project that uses the Wormhole TypeScript SDK to facilitate token transfers between different blockchain networks after deploying the NTT framework.\n\n    [:custom-arrow: Explore the NTT TypeScript SDK demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Query NTT Token and Transfer Data**\n\n    ---\n\n    Learn how to explore NTT by querying token metadata and transfer activity using the Wormholescan API in a TypeScript project.\n\n    [:custom-arrow: Try the NTT Token and Transfers Guide](/docs/products/messaging/guides/wormholescan-api/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-guides-transfer-ownership", "page_title": "Transfer Ownership", "index": 0, "depth": 2, "title": "EVM", "anchor": "evm", "start_char": 226, "end_char": 2513, "estimated_token_count": 620, "token_estimator": "heuristic-v1", "text": "## EVM\n\nThe [NTT CLI](/docs/products/token-transfers/native-token-transfers/get-started/#install-ntt-cli){target=\\_blank} supports transferring ownership on EVM chains. To transfer ownership on the EVM chains, you can do the following:\n\n1. Set the private key used to sign the transaction.\n\n    ```bash\n    export ETH_PRIVATE_KEY=INSERT_EVM_PRIVATE_KEY\n    ```\n\n2. Run the `ntt transfer-ownership` command, specifying the chain and destination address.\n\n    ```bash\n    ntt transfer-ownership INSERT_CHAIN --destination INSERT_DESTINATION_ADDRESS\n    ```\n\n    You’ll see a confirmation prompt. Type `y` to proceed.\n\nIf successful, you will see the following output:\n\n<div id=\"termynal\" data-termynal>\n    <span data-ty=\"input\"><span class=\"file-path\"></span>export ETH_PRIVATE_KEY=INSERT_EVM_PRIVATE_KEY</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span>ntt transfer-ownership ArbitrumSepolia --destination 0xc96CE2a...</span>\n\t<span data-ty></span>\n\t<span data-ty>Transferring ownership on ArbitrumSepolia (Testnet)</span>\n\t<span data-ty>Manager address: 0x00a97bE...</span>\n    <span data-ty>New owner: 0xc96CE2a...</span>\n\t<span data-ty>Current owner: 0x0088DFA...</span>\n    <span data-ty> </span>\n    <span data-ty>⚠️ ⚠️ ⚠️ CRITICAL WARNING ⚠️ ⚠️ ⚠️</span>\n    <span data-ty>This ownership transfer is IRREVERSIBLE!</span>\n    <span data-ty>Please TRIPLE-CHECK that the destination address is correct:</span>\n    <span data-ty>0xc96CE2a...</span>\n    <span data-ty> </span>\n    <span data-ty>Are you absolutely certain you want to transfer ownership to 0xc96CE2a...? [y/N]y</span>\n    <span data-ty>Transaction hash: 0x57da478...</span>\n    <span data-ty>Waiting for 1 confirmation...</span>\n    <span data-ty>Verifying ownership transfer...</span>\n    <span data-ty>✅ Ownership transferred successfully to 0xc96CE2a...</span>\n\t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n</div>\n!!! tip \"Managing NTT from a Safe Multisig?\"\n    If your NTT owner is a Safe multisig, check out the [NTT EVM Safe Multisig Tools](https://github.com/wormhole-foundation/demo-ntt-evm-multisig-tools){target=\\_blank} demo for scripts that generate Safe Transaction Builder JSON files for common operations like peer registration, rate limits, pausing, and ownership transfer."}
{"page_id": "products-token-transfers-native-token-transfers-guides-transfer-ownership", "page_title": "Transfer Ownership", "index": 1, "depth": 2, "title": "Solana", "anchor": "solana", "start_char": 2513, "end_char": 3959, "estimated_token_count": 329, "token_estimator": "heuristic-v1", "text": "## Solana\n\nTransferring ownership of Wormhole's NTT to a multisig on Solana 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#L58){target=\\_blank} to initiate the transfer.\n\n1. **Initiate transfer**: Use the `transfer_ownership` method on the NTT Manager contract to set the new owner (the multisig).\n2. **Claim ownership**: The multisig must then claim ownership via the `claim_ownership` instruction. If not claimed, the current owner can cancel the transfer.\n3. **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)](https://solana.com/docs/core/pda){target=\\_blank}.\n\nFor 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), which provides scripts and guidance for managing an NTT program using Squads' multisig functionality, including procedures for ownership transfer."}
{"page_id": "products-token-transfers-native-token-transfers-guides-transfer-ownership", "page_title": "Transfer Ownership", "index": 2, "depth": 2, "title": "Sui", "anchor": "sui", "start_char": 3959, "end_char": 4957, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "## Sui\n\nThe [Sui CLI](https://docs.sui.io/guides/developer/getting-started/sui-install){target=\\_blank} supports transferring ownership by moving the NTT Manager’s `AdminCap` and `UpgradeCap` to your multisig. You can transfer ownership as follows:\n\n1. Find out the `AdminCap` and `UpgradeCap` for your NTT manager.\n\n    ```bash\n    sui client object INSERT_SUI_NTT_MANAGER_ADDRESS --json 2>/dev/null | jq -r '\"AdminCap ID: \\(.content.fields.admin_cap_id)\\nUpgradeCap ID: \\(.content.fields.upgrade_cap_id)\"'\n    ```\n\n2. Transfer `AdminCap` object over to a multisig.\n\n    ```bash\n    sui client transfer --to INSERT_MULTISIG_ADDRESS --object-id INSERT_ADMIN_CAP_ID_STEP1\n    ```\n\n3. Transfer `UpgradeCap` object over to a multisig.\n\n    ```bash\n    sui client transfer --to INSERT_MULTISIG_ADDRESS --object-id INSERT_UPGRADE_CAP_ID_STEP1\n    ```\n\n4. Check the new owner of the `AdminCap` object.\n\n    ```bash\n    sui client object INSERT_ADMIN_CAP_ID_STEP1 --json \\\n        | jq -r '.owner'\n    ```"}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 0, "depth": 2, "title": "Native Token Transfers Overview", "anchor": "native-token-transfers-overview", "start_char": 0, "end_char": 394, "estimated_token_count": 65, "token_estimator": "heuristic-v1", "text": "## Native Token Transfers Overview\n\nNative 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."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 1, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 394, "end_char": 936, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **Control and customization**: Ensure ownership and configurable access controls, permissions, and thresholds, preventing unauthorized calls.\n- **Advanced rate limiting**: Set rate limits per chain and period to prevent abuse, manage network congestion, and control deployments.\n- **Global accountant**: Ensures the amount burned and transferred on chains never exceeds the amount of tokens minted.\n- **No wrapped tokens**: Tokens are used directly within their native ecosystem, eliminating intermediary transfer steps."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 2, "depth": 2, "title": "Deployment Models", "anchor": "deployment-models", "start_char": 936, "end_char": 1753, "estimated_token_count": 185, "token_estimator": "heuristic-v1", "text": "## Deployment Models\n\nNTT offers two operational modes for your existing tokens: \n\n- **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. A [`wethUnwrap` variant](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-evm/#wethunwrap-variant){target=\\_blank} is available for bridging native gas tokens (e.g., ETH) on EVM chains.\n- **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."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 3, "depth": 2, "title": "Supported Token Standards", "anchor": "supported-token-standards", "start_char": 1753, "end_char": 2542, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "## Supported Token Standards\n\nNative Token Transfers 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 SVM-supported chains for secure cross-chain transfers.\n\nThe 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.\n\nNTT does not currently support non-fungible tokens (NFTs) or multi-token standards like ERC-1155. Support is limited to ERC-20 tokens."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 4, "depth": 2, "title": "Deployment Process", "anchor": "deployment-process", "start_char": 2542, "end_char": 3725, "estimated_token_count": 286, "token_estimator": "heuristic-v1", "text": "## Deployment Process\n\nHere's a breakdown of the key steps involved when deploying NTT:\n\n- **Prepare tokens**: Ensure your ERC-20 or SPL tokens are ready.\n- **Choose deployment model**: Choose your cross-chain token model: either burn-and-mint or hub-and-spoke.\n\n- **Initialization**: Specify target chains and token details, and set up your CLI environment if using it.\n- **Deploy contracts**: Deploy NTT Manager contracts to all selected chains, confirming transactions and covering gas fees.\n- **Finalize configurations**: Grant minting authority, configure rate limits, establish peer manager connections (bilateral via [`setPeer`](/docs/products/token-transfers/native-token-transfers/reference/manager/evm/#setpeer){target=\\_blank} / [`set_peer`](/docs/products/token-transfers/native-token-transfers/reference/manager/solana/#set_peer){target=\\_blank}; local configuration, no cross-chain message), and assign administrative roles.\n- **Monitor and maintain**: Verify deployment, monitor total supply with the [Global Accountant](/docs/products/token-transfers/native-token-transfers/concepts/security/#global-accountant){target=\\_blank}, and adjust configurations as needed."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 5, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 3725, "end_char": 5819, "estimated_token_count": 545, "token_estimator": "heuristic-v1", "text": "## Use Cases \n\n- **Cross-Chain Swaps and Liquidity Aggregation**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Transmits native assets across chains.\n    - **[Connect](/docs/products/connect/overview/)**: Manages user-friendly asset transfers.\n    - **[Queries](/docs/products/queries/overview/)**: Acquires real-time prices for optimal trade execution.\n\n- **Borrowing and Lending Across Chains**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Moves collateral as native assets.\n    - **[Messaging](/docs/products/messaging/overview/)**: Propagates loan requests and liquidations across chains.\n    - **[Queries](/docs/products/queries/overview/)**: Retrieves interest rates and asset prices in real-time.\n\n- **Gas Abstraction**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Facilitates native token conversion for gas payments.\n    - **[Messaging](/docs/products/messaging/overview/)**: Sends gas fee payments across chains.\n\n- **Cross-Chain Payment Widgets**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Ensures direct, native asset transfers.\n    - **[Connect](/docs/products/connect/overview/)**: Facilitates seamless payments in various tokens.\n\n- **Cross-Chain Staking**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Transfers staked assets natively between networks.\n    - **[Messaging](/docs/products/messaging/overview/)**: Moves staking rewards and governance signals across chains.\n\n- **Coordinated Asset Launches**\n\n    - **[Native Token Transfers](/docs/products/token-transfers/native-token-transfers/get-started/)**: Delivers canonical tokens to the destination chain from day one.\n    - **[Sunrise](https://www.sunrisedefi.com/){target=\\_blank}**: Coordinates bridging, liquidity seeding, and DEX integration on top of NTT so assets arrive tradable across major venues immediately."}
{"page_id": "products-token-transfers-native-token-transfers-overview", "page_title": "Native Token Transfers Overview", "index": 6, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 5819, "end_char": 5969, "estimated_token_count": 40, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nFollow these steps to get started with NTT:\n\n[timeline(docs/.snippets/text/products/native-token-transfers/overview/ntt-timeline.json)]"}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 0, "depth": 2, "title": "Table of Commands", "anchor": "table-of-commands", "start_char": 726, "end_char": 1037, "estimated_token_count": 59, "token_estimator": "heuristic-v1", "text": "## Table of Commands\n\nThe following table lists the available NTT CLI commands, descriptions, and examples.\n\nTo 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."}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 1, "depth": 3, "title": "General Commands", "anchor": "general-commands", "start_char": 1037, "end_char": 6954, "estimated_token_count": 917, "token_estimator": "heuristic-v1", "text": "### General Commands\n\n| Command                                 | Description                                                                                                                                                               | Example                                                                                                                                                                                                    |\n|-----------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| `ntt update`                            | Update the NTT CLI.                                                                                                                                                       | `ntt update`                                                                                                                                                                                               |\n| `ntt new <path>`                        | Create a new NTT project.                                                                                                                                                 | `ntt new my-ntt-project`                                                                                                                                                                                   |\n| `ntt add-chain <chain>`                 | Add a chain to the deployment file. Supports `--manager-variant` (`standard`, `noRateLimiting`, `wethUnwrap`) for EVM chains.                                             | `ntt add-chain Ethereum --token 0x1234... --mode burning --latest --manager-variant standard`                                                                                                              |\n| `ntt upgrade <chain>`                   | Upgrade the contract on a specific chain. Supports `--manager-variant` for EVM chains.                                                                                    | `ntt upgrade Solana --ver 1.1.0`                                                                                                                                                                           |\n| `ntt clone <network> <chain> <address>` | Initialize a deployment file from an existing contract.                                                                                                                   | `ntt clone Mainnet Solana Sol5678...`                                                                                                                                                                      |\n| `ntt init <network>`                    | Initialize a deployment file.                                                                                                                                             | `ntt init devnet`                                                                                                                                                                                          |\n| `ntt pull`                              | Pull the remote configuration.                                                                                                                                            | `ntt pull`                                                                                                                                                                                                 |\n| `ntt push`                              | Push the local configuration.                                                                                                                                             | `ntt push`                                                                                                                                                                                                 |\n| `ntt status`                            | Check the status of the deployment.                                                                                                                                       | `ntt status`                                                                                                                                                                                               |\n| `ntt set-mint-authority`                | Set token mint authority to token authority (or valid SPL Multisig if `--multisig` flag is provided).                                                                     | `ntt set-mint-authority --chain Solana --token Sol1234... --manager Sol3456... --payer <SOLANA_KEYPAIR_PATH>`                                                                                              |\n| `ntt transfer-ownership <chain>`        | [Transfer NTT manager ownership](/docs/products/token-transfers/native-token-transfers/guides/transfer-ownership/#evm){target=\\_blank} to a new wallet (EVM chains only). | `ntt transfer-ownership Ethereum --destination 0x1234...`                                                                                                                                                  |\n| `ntt token-transfer`                    | Transfer tokens between chains using the NTT protocol.                                                                                                                    | `ntt token-transfer --network Testnet --source-chain Sepolia --destination-chain Solana --amount 0.5 --destination-address 9yZwWH... --deployment-path ./deployment.json --destination-msg-value 20000000` |"}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 2, "depth": 3, "title": "Advanced Custom Finality", "anchor": "advanced-custom-finality", "start_char": 6954, "end_char": 8090, "estimated_token_count": 221, "token_estimator": "heuristic-v1", "text": "### Advanced Custom Finality\n\n!!! warning \n    Custom finality is an advanced feature. Wormhole Contributors recommend using this with caution. \n\nThe `ntt add-chain` command supports an optional flag that enables custom consistency levels for EVM chains. By default, NTT deployments use the `finalized` consistency level.\n\nChoosing a level of finality other than finalized on EVM chains exposes you to [re-org risk](https://www.alchemy.com/overviews/what-is-a-reorg){target=\\_blank}. This is especially dangerous when moving assets cross-chain, because assets released or minted on the destination chain may not have been burned or locked on the source chain.\n\nTo select a custom finality level, Wormhole Contributors recommend consulting information on forked blocks in blockchain explorers, focusing on the “ReorgDepth” column.\n\nBy proceeding, you affirm that you understand and are comfortable with the risks of setting a custom finality level, and you understand the re-org/rollback risks of Custom finality, accept sole responsibility, and agree that the Wormhole Parties have no liability for losses arising from your selection."}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 3, "depth": 3, "title": "Configuration Commands", "anchor": "configuration-commands", "start_char": 8090, "end_char": 8824, "estimated_token_count": 257, "token_estimator": "heuristic-v1", "text": "### Configuration Commands\n\n| Command                                      | Description                              | Example                                        |\n|----------------------------------------------|------------------------------------------|------------------------------------------------|\n| `ntt config set-chain <chain> <key> <value>` | Set a configuration value for a chain.   | `ntt config set-chain Ethereum scan_api_key`   |\n| `ntt config unset-chain <chain> <key>`       | Unset a configuration value for a chain. | `ntt config unset-chain Ethereum scan_api_key` |\n| `ntt config get-chain <chain> <key>`         | Get a configuration value for a chain.   | `ntt config get-chain Ethereum scan_api_key`   |"}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 4, "depth": 3, "title": "Hyperliquid Commands", "anchor": "hyperliquid-commands", "start_char": 8824, "end_char": 10168, "estimated_token_count": 381, "token_estimator": "heuristic-v1", "text": "### Hyperliquid Commands\n\n| Command                          | Description                                                                                               | Example                                  |\n|----------------------------------|-----------------------------------------------------------------------------------------------------------|------------------------------------------|\n| `ntt hype link`                  | Link a HyperCore spot token to its HyperEVM ERC-20 contract.                                             | `ntt hype link --token-index 1591`       |\n| `ntt hype bridge-in <amount>`    | Bridge tokens from HyperEVM into HyperCore via the asset bridge.                                         | `ntt hype bridge-in 1.0`                 |\n| `ntt hype bridge-out <amount>`   | Bridge tokens from HyperCore back to HyperEVM via spotSend.                                              | `ntt hype bridge-out 1.0`               |\n| `ntt hype status`                | Display HyperCore token index, asset bridge address, and token identifier for the current deployment.     | `ntt hype status`                        |\n\nFor a complete walkthrough on using these commands, see the [Deploy to Hyperliquid](/docs/products/token-transfers/native-token-transfers/guides/deploy-to-hyperliquid/){target=\\_blank} guide."}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 5, "depth": 3, "title": "Solana Commands", "anchor": "solana-commands", "start_char": 10168, "end_char": 10995, "estimated_token_count": 286, "token_estimator": "heuristic-v1", "text": "### Solana Commands\n\n| Command                                        | Description                                               | Example                                         |\n|------------------------------------------------|-----------------------------------------------------------|-------------------------------------------------|\n| `ntt solana key-base58 <keypair>`              | Print private key in base58.                              | `ntt solana key-base58 /path/to/keypair.json`   |\n| `ntt solana token-authority <programId>`       | Print the token authority address for a given program ID. | `ntt solana token-authority Sol1234...`         |\n| `ntt solana ata <mint> <owner> <tokenProgram>` | Print the token authority address for a given program ID. | `ntt solana ata Mint123... Owner123... token22` |"}
{"page_id": "products-token-transfers-native-token-transfers-reference-cli-commands", "page_title": "NTT CLI Commands", "index": 6, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 10995, "end_char": 11720, "estimated_token_count": 176, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n\n-   :octicons-gear-16:{ .lg .middle } **Configure NTT**\n\n    ---\n\n    Find information on configuring NTT, including guidance on setting Owner and Pauser access control roles and management of rate-limiting.\n\n    [:custom-arrow: Configure your NTT deployment](/docs/products/token-transfers/native-token-transfers/configuration/access-control/)\n\n-   :octicons-question-16:{ .lg .middle } **NTT FAQs**\n\n    ---\n\n    Frequently asked questions about Wormhole Native Token Transfers, including cross-chain lending, SDK usage, custom RPCs, and integration challenges.\n\n    [:custom-arrow: Check out the FAQs](/docs/products/token-transfers/native-token-transfers/faqs/)\n\n</div>"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 377, "end_char": 1596, "estimated_token_count": 257, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe NTT Manager system is built using a layered inheritance structure composed of multiple base contracts and interfaces.\n\n```text\nNttManager.sol\n├── INttManager.sol\n├── RateLimiter.sol\n│   ├── IRateLimiter.sol\n│   └── IRateLimiterEvents.sol\n└── ManagerBase.sol\n    ├── IManagerBase.sol\n    ├── TransceiverRegistry.sol\n    ├── PausableOwnable.sol\n    ├── ReentrancyGuardUpgradeable.sol\n    └── Implementation.sol\n```\n\n**Key Components:**\n\n- **`NttManager.sol`**: The main contract that combines all functionality for token transfers with rate limiting.\n- **`ManagerBase.sol`**: Provides core management functionality including message handling, threshold management, and transceiver coordination.\n- **`RateLimiter.sol`**: Adds rate limiting capabilities with queuing mechanisms for both inbound and outbound transfers.\n- **`TransceiverRegistry.sol`**: Manages the registration, enabling, and disabling of transceivers.\n- **`PausableOwnable.sol`**: Provides ownership and emergency pause functionality.\n- **`ReentrancyGuardUpgradeable.sol`**: Protects against reentrancy attacks in an upgradeable context.\n- **`Implementation.sol`**: Handles proxy implementation logic for upgradeable contracts."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 1, "depth": 2, "title": "State Variables", "anchor": "state-variables", "start_char": 1596, "end_char": 1616, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## State Variables"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 2, "depth": 3, "title": "Core Identification", "anchor": "core-identification", "start_char": 1616, "end_char": 2062, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### Core Identification\n\n- `token` ++\"address\"++: Address of the token that this NTT Manager is tied to.\n- `mode` ++\"Mode\"++: Mode of the NTT Manager (LOCKING=0 or BURNING=1).\n- `chainId` ++\"uint16\"++: Wormhole chain ID that the NTT Manager is deployed on.\n- `NTT_MANAGER_VERSION` ++\"string\"++: The version string of the NttManager contract implementation.\n- `rateLimitDuration` ++\"uint64\"++: Duration (in seconds) until limits fully replenish."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 3, "depth": 3, "title": "Cross-chain Peers and Governance Thresholds", "anchor": "cross-chain-peers-and-governance-thresholds", "start_char": 2062, "end_char": 2593, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "### Cross-chain Peers and Governance Thresholds\n\n- `peers` ++\"mapping(uint16 ⇒ NttManagerPeer)\"++: Mapping of peer chain IDs to their peer NTT Manager address and token decimals.\n- `messageAttestations` ++\"mapping(bytes32 ⇒ AttestationInfo)\"++: Tracks whether a message has been executed and the bitmap of transceivers that have attested to it.\n- `THRESHOLD_SLOT` ++\"uint8\"++: Number of attestation approvals required for message execution.\n- `MESSAGE_SEQUENCE_SLOT` ++\"uint64\"++: Monotonic sequence number for outgoing messages."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 4, "depth": 3, "title": "Rate Limiting and Queues", "anchor": "rate-limiting-and-queues", "start_char": 2593, "end_char": 3295, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "### Rate Limiting and Queues\n\n- `rateLimitDuration` ++\"uint64\"++: Duration (in seconds) until limits fully replenish.\n- `outboundLimitParams` ++\"RateLimitParams\"++: Parameters controlling outbound transfer rate limits, including capacity and last transaction timestamp.\n- `inboundLimitParams` ++\"mapping(uint16 ⇒ RateLimitParams)\"++: Parameters controlling inbound transfer rate limits per peer chain.\n- `outboundQueue` ++\"mapping(uint64 ⇒ OutboundQueuedTransfer)\"++: Queue of outbound transfers when rate limits are exceeded, keyed by sequence number.\n- `inboundQueue` ++\"mapping(bytes32 ⇒ InboundQueuedTransfer)\"++: Queue of inbound transfers when rate limits are exceeded, keyed by message digest."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 5, "depth": 2, "title": "Events", "anchor": "events", "start_char": 3295, "end_char": 3306, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Events"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 6, "depth": 3, "title": "InboundTransferLimitUpdated", "anchor": "inboundtransferlimitupdated", "start_char": 3306, "end_char": 3906, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "### InboundTransferLimitUpdated\n\nEmitted when the inbound transfer limit is updated. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nevent InboundTransferLimitUpdated(\n    uint16 chainId,\n    uint256 oldLimit,\n    uint256 newLimit\n)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID for which the limit was updated.\n\n    ---\n\n    `oldLimit` ++\"uint256\"++\n\n    The previous inbound limit.\n\n    ---\n\n    `newLimit` ++\"uint256\"++\n\n    The new inbound limit."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 7, "depth": 3, "title": "InboundTransferQueued", "anchor": "inboundtransferqueued", "start_char": 3906, "end_char": 4307, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### InboundTransferQueued\n\nEmitted when an inbound transfer is queued due to rate limiting. *([Defined in RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nevent InboundTransferQueued(bytes32 digest)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the queued transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 8, "depth": 3, "title": "MessageAlreadyExecuted", "anchor": "messagealreadyexecuted", "start_char": 4307, "end_char": 4872, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "### MessageAlreadyExecuted\n\nEmitted when a message has already been executed to notify client against retries. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nevent MessageAlreadyExecuted(\n    bytes32 indexed sourceNttManager,\n    bytes32 indexed digest\n)\n```\n\n??? interface \"Parameters\"\n\n    `sourceNttManager` ++\"bytes32\"++\n\n    The address of the source NttManager.\n\n    ---\n\n    `digest` ++\"bytes32\"++\n\n    The keccak-256 hash of the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 9, "depth": 3, "title": "MessageAttestedTo", "anchor": "messageattestedto", "start_char": 4872, "end_char": 5482, "estimated_token_count": 154, "token_estimator": "heuristic-v1", "text": "### MessageAttestedTo\n\nEmitted when a message has been attested to by a transceiver. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nevent MessageAttestedTo(bytes32 digest, address transceiver, uint8 index)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the message.\n\n    ---\n\n    `transceiver` ++\"address\"++\n\n    The address of the transceiver that attested to the message.\n\n    ---\n\n    `index` ++\"uint8\"++\n\n    The index of the transceiver in the registry."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 10, "depth": 3, "title": "NotPaused", "anchor": "notpaused", "start_char": 5482, "end_char": 5850, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "### NotPaused\n\nEmitted when the contract is unpaused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent NotPaused(bool notPaused)\n```\n\n??? interface \"Parameters\"\n\n    `notPaused` ++\"bool\"++\n\n    Whether the contract is not paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 11, "depth": 3, "title": "OutboundTransferCancelled", "anchor": "outboundtransfercancelled", "start_char": 5850, "end_char": 6461, "estimated_token_count": 147, "token_estimator": "heuristic-v1", "text": "### OutboundTransferCancelled\n\nEmitted when an outbound transfer has been cancelled. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nevent OutboundTransferCancelled(uint256 sequence, address recipient, uint256 amount)\n```\n\n??? interface \"Parameters\"\n\n    `sequence` ++\"uint256\"++\n\n    The sequence number being cancelled.\n\n    ---\n\n    `recipient` ++\"address\"++\n\n    The canceller and recipient of the funds.\n\n    ---\n\n    `amount` ++\"uint256\"++\n\n    The amount of the transfer being cancelled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 12, "depth": 3, "title": "OutboundTransferLimitUpdated", "anchor": "outboundtransferlimitupdated", "start_char": 6461, "end_char": 6948, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "### OutboundTransferLimitUpdated\n\nEmitted when the outbound transfer limit is updated. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nevent OutboundTransferLimitUpdated(uint256 oldLimit, uint256 newLimit)\n```\n\n??? interface \"Parameters\"\n\n    `oldLimit` ++\"uint256\"++\n\n    The previous outbound limit.\n\n    ---\n\n    `newLimit` ++\"uint256\"++\n\n    The new outbound limit."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 13, "depth": 3, "title": "OutboundTransferQueued", "anchor": "outboundtransferqueued", "start_char": 6948, "end_char": 7363, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "### OutboundTransferQueued\n\nEmitted when an outbound transfer is queued due to rate limiting. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nevent OutboundTransferQueued(uint64 sequence)\n```\n\n??? interface \"Parameters\"\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 14, "depth": 3, "title": "OutboundTransferRateLimited", "anchor": "outboundtransferratelimited", "start_char": 7363, "end_char": 8079, "estimated_token_count": 165, "token_estimator": "heuristic-v1", "text": "### OutboundTransferRateLimited\n\nEmitted when an outbound transfer is rate limited. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nevent OutboundTransferRateLimited(\n    address sender,\n    uint64 sequence,\n    uint256 amount,\n    uint256 currentCapacity\n)\n```\n\n??? interface \"Parameters\"\n\n    `sender` ++\"address\"++\n\n    The address that initiated the transfer.\n\n    ---\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the transfer.\n\n    ---\n\n    `amount` ++\"uint256\"++\n\n    The amount being transferred.\n\n    ---\n\n    `currentCapacity` ++\"uint256\"++\n\n    The current available capacity."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 15, "depth": 3, "title": "OwnershipTransferred", "anchor": "ownershiptransferred", "start_char": 8079, "end_char": 8603, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### OwnershipTransferred\n\nEmitted when ownership of the contract is transferred. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent OwnershipTransferred(address indexed previousOwner, address indexed newOwner)\n```\n\n??? interface \"Parameters\"\n\n    `previousOwner` ++\"address\"++\n\n    The previous owner's address.\n\n    ---\n\n    `newOwner` ++\"address\"++\n\n    The new owner's address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 16, "depth": 3, "title": "Paused", "anchor": "paused", "start_char": 8603, "end_char": 8953, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### Paused\n\nEmitted when the contract is paused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent Paused(bool paused)\n```\n\n??? interface \"Parameters\"\n\n    `paused` ++\"bool\"++\n\n    Whether the contract is paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 17, "depth": 3, "title": "PauserTransferred", "anchor": "pausertransferred", "start_char": 8953, "end_char": 9452, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### PauserTransferred\n\nEmitted when pauser capability is transferred. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent PauserTransferred(address indexed oldPauser, address indexed newPauser)\n```\n\n??? interface \"Parameters\"\n\n    `oldPauser` ++\"address\"++\n\n    The previous pauser's address.\n\n    ---\n\n    `newPauser` ++\"address\"++\n\n    The new pauser's address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 18, "depth": 3, "title": "PeerUpdated", "anchor": "peerupdated", "start_char": 9452, "end_char": 10252, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "### PeerUpdated\n\nEmitted when the peer contract is updated. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nevent PeerUpdated(\n    uint16 indexed chainId_,\n    bytes32 oldPeerContract,\n    uint8 oldPeerDecimals,\n    bytes32 peerContract,\n    uint8 peerDecimals\n)\n```\n\n??? interface \"Parameters\"\n\n    `chainId_` ++\"uint16\"++\n\n    The chain ID of the peer contract.\n\n    ---\n\n    `oldPeerContract` ++\"bytes32\"++\n\n    The old peer contract address.\n\n    ---\n\n    `oldPeerDecimals` ++\"uint8\"++\n\n    The old peer contract decimals.\n\n    ---\n\n    `peerContract` ++\"bytes32\"++\n\n    The new peer contract address.\n\n    ---\n\n    `peerDecimals` ++\"uint8\"++\n\n    The new peer contract decimals."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 19, "depth": 3, "title": "ThresholdChanged", "anchor": "thresholdchanged", "start_char": 10252, "end_char": 10715, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "### ThresholdChanged\n\nEmitted when the threshold required for transceivers is changed. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nevent ThresholdChanged(uint8 oldThreshold, uint8 threshold)\n```\n\n??? interface \"Parameters\"\n\n    `oldThreshold` ++\"uint8\"++\n\n    The old threshold.\n\n    ---\n\n    `threshold` ++\"uint8\"++\n\n    The new threshold."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 20, "depth": 3, "title": "TransceiverAdded", "anchor": "transceiveradded", "start_char": 10715, "end_char": 11315, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "### TransceiverAdded\n\nEmitted when a transceiver is added to the NttManager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nevent TransceiverAdded(address transceiver, uint256 transceiversNum, uint8 threshold)\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The address of the transceiver.\n\n    ---\n\n    `transceiversNum` ++\"uint256\"++\n\n    The current number of transceivers.\n\n    ---\n\n    `threshold` ++\"uint8\"++\n\n    The current threshold of transceivers."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 21, "depth": 3, "title": "TransceiverRemoved", "anchor": "transceiverremoved", "start_char": 11315, "end_char": 11811, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### TransceiverRemoved\n\nEmitted when a transceiver is removed from the NttManager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nevent TransceiverRemoved(address transceiver, uint8 threshold)\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The address of the transceiver.\n\n    ---\n\n    `threshold` ++\"uint8\"++\n\n    The current threshold of transceivers."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 22, "depth": 3, "title": "TransferRedeemed", "anchor": "transferredeemed", "start_char": 11811, "end_char": 12230, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "### TransferRedeemed\n\nEmitted when a transfer has been redeemed (either minted or unlocked on the recipient chain). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nevent TransferRedeemed(bytes32 indexed digest)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 23, "depth": 3, "title": "TransferSent", "anchor": "transfersent", "start_char": 12230, "end_char": 13211, "estimated_token_count": 233, "token_estimator": "heuristic-v1", "text": "### TransferSent\n\nEmitted when a message is sent from the NttManager. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nevent TransferSent(\n    bytes32 indexed recipient,\n    bytes32 indexed refundAddress,\n    uint256 amount,\n    uint256 fee,\n    uint16 recipientChain,\n    uint64 msgSequence\n)\n```\n\n??? interface \"Parameters\"\n\n    `recipient` ++\"bytes32\"++\n\n    The recipient of the message.\n\n    ---\n\n    `refundAddress` ++\"bytes32\"++\n\n    The address on the destination chain to which the refund of unused gas will be paid.\n\n    ---\n\n    `amount` ++\"uint256\"++\n\n    The amount transferred.\n\n    ---\n\n    `fee` ++\"uint256\"++\n\n    The amount of ether sent along with the tx to cover the delivery fee.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++\n\n    The chain ID of the recipient.\n\n    ---\n\n    `msgSequence` ++\"uint64\"++\n\n    The unique sequence ID of the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 24, "depth": 3, "title": "TransferSent (Digest Version)", "anchor": "transfersent-digest-version", "start_char": 13211, "end_char": 13614, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "### TransferSent (Digest Version)\n\nEmitted when a message is sent from the NttManager (digest version). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nevent TransferSent(bytes32 indexed digest)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 25, "depth": 2, "title": "Functions", "anchor": "functions", "start_char": 13614, "end_char": 13628, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Functions"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 26, "depth": 3, "title": "attestationReceived", "anchor": "attestationreceived", "start_char": 13628, "end_char": 14917, "estimated_token_count": 266, "token_estimator": "heuristic-v1", "text": "### attestationReceived\n\nCalled by transceivers when the attestation is received. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction attestationReceived(\n    uint16 sourceChainId,\n    bytes32 sourceNttManagerAddress,\n    TransceiverStructs.NttManagerMessage memory payload\n) external\n```\n\n??? interface \"Parameters\"\n\n    `sourceChainId` ++\"uint16\"++\n\n    The chain ID of the source.\n\n    ---\n\n    `sourceNttManagerAddress` ++\"bytes32\"++\n\n    The address of the source NttManager.\n\n    ---\n\n    `payload` ++\"TransceiverStructs.NttManagerMessage\"++\n\n    The message payload containing transfer details.\n\n    ??? child \"`NttManagerMessage` struct\"\n\n        `id` ++\"bytes32\"++\n\n        Unique message identifier (incrementally assigned on EVM chains).\n        \n        ---\n\n        `sender` ++\"bytes32\"++\n\n        Original message sender address.\n        \n        ---\n\n        `payload` ++\"bytes\"++\n\n        Payload that corresponds to the transfer type.\n\n> **Emits**: `MessageAlreadyExecuted` (if the message was already executed), `OutboundTransferCancelled` or `TransferRedeemed` (if the message execution succeeds), `TransferSent` (if the message execution succeeds)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 27, "depth": 3, "title": "cancelOutboundQueuedTransfer", "anchor": "canceloutboundqueuedtransfer", "start_char": 14917, "end_char": 15424, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "### cancelOutboundQueuedTransfer\n\nCancel an outbound transfer that's been queued due to rate limiting. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction cancelOutboundQueuedTransfer(uint64 messageSequence) external\n```\n\n??? interface \"Parameters\"\n\n    `messageSequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer to cancel.\n\n> **Emits**: `OutboundTransferCancelled`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 28, "depth": 3, "title": "completeInboundQueuedTransfer", "anchor": "completeinboundqueuedtransfer", "start_char": 15424, "end_char": 15890, "estimated_token_count": 116, "token_estimator": "heuristic-v1", "text": "### completeInboundQueuedTransfer\n\nComplete an inbound transfer that's been queued due to rate limiting. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction completeInboundQueuedTransfer(bytes32 digest) external\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the queued transfer.\n\n> **Emits**: `TransferRedeemed`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 29, "depth": 3, "title": "completeOutboundQueuedTransfer", "anchor": "completeoutboundqueuedtransfer", "start_char": 15890, "end_char": 16526, "estimated_token_count": 151, "token_estimator": "heuristic-v1", "text": "### completeOutboundQueuedTransfer\n\nComplete an outbound transfer that's been queued due to rate limiting. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction completeOutboundQueuedTransfer(uint64 messageSequence) external payable returns (uint64)\n```\n\n??? interface \"Parameters\"\n\n    `messageSequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the completed transfer.\n\n> **Emits**: `TransferSent` (two variants)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 30, "depth": 3, "title": "executeMsg", "anchor": "executemsg", "start_char": 16526, "end_char": 17718, "estimated_token_count": 254, "token_estimator": "heuristic-v1", "text": "### executeMsg\n\nExecute a message when the threshold is met. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction executeMsg(\n    uint16 sourceChainId,\n    bytes32 sourceNttManagerAddress,\n    TransceiverStructs.NttManagerMessage memory message\n) external\n```\n\n??? interface \"Parameters\"\n\n    `sourceChainId` ++\"uint16\"++\n\n    The chain ID of the source.\n\n    ---\n\n    `sourceNttManagerAddress` ++\"bytes32\"++\n\n    The address of the source NttManager.\n\n    ---\n\n    `message` ++\"TransceiverStructs.NttManagerMessage\"++\n\n    The message to execute containing transfer details.\n\n    ??? child \"`NttManagerMessage` struct\"\n\n        `id` ++\"bytes32\"++\n\n        Unique message identifier (incrementally assigned on EVM chains).\n        \n        ---\n\n        `sender` ++\"bytes32\"++\n\n        Original message sender address.\n        \n        ---\n\n        `payload` ++\"bytes\"++\n\n        Payload that corresponds to the transfer type.\n\n> **Emits**: `MessageAlreadyExecuted` (if already executed), `OutboundTransferCancelled`, or `TransferRedeemed` (depending on the transfer type)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 31, "depth": 3, "title": "getCurrentInboundCapacity", "anchor": "getcurrentinboundcapacity", "start_char": 17718, "end_char": 18286, "estimated_token_count": 135, "token_estimator": "heuristic-v1", "text": "### getCurrentInboundCapacity\n\nReturns the currently remaining inbound capacity from a chain. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getCurrentInboundCapacity(uint16 chainId) external view returns (uint256)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to check capacity for.\n\n??? interface \"Returns\"\n\n    `capacity` ++\"uint256\"++\n\n    The current available inbound capacity from the specified chain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 32, "depth": 3, "title": "getCurrentOutboundCapacity", "anchor": "getcurrentoutboundcapacity", "start_char": 18286, "end_char": 18707, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### getCurrentOutboundCapacity\n\nReturns the currently remaining outbound capacity. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getCurrentOutboundCapacity() public view returns (uint256)\n```\n\n??? interface \"Returns\"\n\n    `capacity` ++\"uint256\"++\n\n    The current available outbound capacity."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 33, "depth": 3, "title": "getInboundLimitParams", "anchor": "getinboundlimitparams", "start_char": 18707, "end_char": 19623, "estimated_token_count": 201, "token_estimator": "heuristic-v1", "text": "### getInboundLimitParams\n\nReturns the inbound rate limit parameters for a chain. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getInboundLimitParams(uint16 chainId_) external view returns (RateLimitParams memory)\n```\n\n??? interface \"Parameters\"\n\n    `chainId_` ++\"uint16\"++\n\n    The chain ID to get parameters for.\n\n??? interface \"Returns\"\n\n    `params` ++\"RateLimitParams struct\"++\n\n    The inbound rate limit parameters for the specified chain.\n\n    ??? child \"`RateLimitParams` struct\"\n\n        `limit` ++\"TrimmedAmount\"++\n\n        Current rate limit value.\n        \n        ---\n\n        `currentCapacity` ++\"TrimmedAmount\"++\n\n        The current capacity left.\n        \n        ---\n\n        `lastTxTimestamp` ++\"uint64\"++\n\n        Timestamp of when capacity was previously consumed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 34, "depth": 3, "title": "getInboundQueuedTransfer", "anchor": "getinboundqueuedtransfer", "start_char": 19623, "end_char": 20506, "estimated_token_count": 194, "token_estimator": "heuristic-v1", "text": "### getInboundQueuedTransfer\n\nReturns queued transfer details for inbound queue. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getInboundQueuedTransfer(bytes32 digest) external view returns (InboundQueuedTransfer memory)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the queued transfer.\n\n??? interface \"Returns\"\n\n    `transfer` ++\"InboundQueuedTransfer struct\"++\n\n    The queued transfer details.\n\n    ??? child \"`InboundQueuedTransfer` struct\"\n\n        `amount` ++\"TrimmedAmount\"++\n\n        The trimmed amount of the transfer.\n        \n        ---\n\n        `txTimestamp` ++\"uint64\"++\n\n        The timestamp of the transfer.\n        \n        ---\n\n        `recipient` ++\"address\"++\n\n        The recipient of the transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 35, "depth": 3, "title": "getMode", "anchor": "getmode", "start_char": 20506, "end_char": 21187, "estimated_token_count": 177, "token_estimator": "heuristic-v1", "text": "### getMode\n\nReturns the mode (locking or burning) of the NttManager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction getMode() public view returns (uint8)\n```\n\n??? interface \"Returns\"\n\n    `mode` ++\"uint8\"++\n\n    The mode of the NttManager (0 for LOCKING, 1 for BURNING).\n\n    ??? child \"`Mode` enum values\"\n\n        `LOCKING` ++\"0\"++\n\n        Tokens are locked on the source chain and unlocked on the destination chain.\n        \n        ---\n\n        `BURNING` ++\"1\"++\n\n        Tokens are burned on the source chain and minted on the destination chain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 36, "depth": 3, "title": "getMigratesImmutables", "anchor": "getmigratesimmutables", "start_char": 21187, "end_char": 21600, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### getMigratesImmutables\n\nReturns whether the contract migrates immutables. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction getMigratesImmutables() external view returns (bool)\n```\n\n??? interface \"Returns\"\n\n    `migrates` ++\"bool\"++\n\n    Whether the contract migrates immutables."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 37, "depth": 3, "title": "getOutboundLimitParams", "anchor": "getoutboundlimitparams", "start_char": 21600, "end_char": 22377, "estimated_token_count": 168, "token_estimator": "heuristic-v1", "text": "### getOutboundLimitParams\n\nReturns the outbound rate limit parameters. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getOutboundLimitParams() public pure virtual returns (RateLimitParams memory)\n```\n\n??? interface \"Returns\"\n\n    `params` ++\"RateLimitParams struct\"++\n\n    The outbound rate limit parameters.\n\n    ??? child \"`RateLimitParams` struct\"\n\n        `limit` ++\"TrimmedAmount\"++\n\n        Current rate limit value.\n        \n        ---\n\n        `currentCapacity` ++\"TrimmedAmount\"++\n\n        The current capacity left.\n        \n        ---\n\n        `lastTxTimestamp` ++\"uint64\"++\n\n        Timestamp of when capacity was previously consumed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 38, "depth": 3, "title": "getOutboundQueuedTransfer", "anchor": "getoutboundqueuedtransfer", "start_char": 22377, "end_char": 23705, "estimated_token_count": 274, "token_estimator": "heuristic-v1", "text": "### getOutboundQueuedTransfer\n\nReturns queued transfer details for outbound queue. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nfunction getOutboundQueuedTransfer(uint64 queueSequence) external view returns (OutboundQueuedTransfer memory)\n```\n\n??? interface \"Parameters\"\n\n    `queueSequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer.\n\n??? interface \"Returns\"\n\n    `transfer` ++\"OutboundQueuedTransfer struct\"++\n\n    The queued transfer details.\n\n    ??? child \"`OutboundQueuedTransfer` struct\"\n\n        `recipient` ++\"bytes32\"++\n\n        The recipient of the transfer.\n        \n        ---\n\n        `refundAddress` ++\"bytes32\"++\n\n        The refund address for unused gas.\n        \n        ---\n\n        `amount` ++\"TrimmedAmount\"++\n\n        The amount of the transfer, trimmed.\n        \n        ---\n\n        `txTimestamp` ++\"uint64\"++\n\n        The timestamp of the transfer.\n        \n        ---\n\n        `recipientChain` ++\"uint16\"++\n\n        The chain of the recipient.\n        \n        ---\n\n        `sender` ++\"address\"++\n\n        The sender of the transfer.\n        \n        ---\n\n        `transceiverInstructions` ++\"bytes\"++\n\n        Additional instructions for the recipient chain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 39, "depth": 3, "title": "getPeer", "anchor": "getpeer", "start_char": 23705, "end_char": 24467, "estimated_token_count": 187, "token_estimator": "heuristic-v1", "text": "### getPeer\n\nReturns peer information for a given chain ID. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction getPeer(uint16 chainId_) external view returns (NttManagerPeer memory)\n```\n\n??? interface \"Parameters\"\n\n    `chainId_` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n??? interface \"Returns\"\n\n    `peer` ++\"NttManagerPeer struct\"++\n\n    The peer information for the given chain ID.\n\n    ??? child \"`NttManagerPeer` struct\"\n\n        `peerAddress` ++\"bytes32\"++\n\n        The address of the peer contract on the remote chain.\n        \n        ---\n\n        `tokenDecimals` ++\"uint8\"++\n\n        The number of decimals for the peer token."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 40, "depth": 3, "title": "getThreshold", "anchor": "getthreshold", "start_char": 24467, "end_char": 24908, "estimated_token_count": 113, "token_estimator": "heuristic-v1", "text": "### getThreshold\n\nReturns the number of transceivers that must attest to a message. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction getThreshold() external view returns (uint8)\n```\n\n??? interface \"Returns\"\n\n    `threshold` ++\"uint8\"++\n\n    The number of attestations required for a message to be considered valid."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 41, "depth": 3, "title": "getTransceiverInfo", "anchor": "gettransceiverinfo", "start_char": 24908, "end_char": 25668, "estimated_token_count": 172, "token_estimator": "heuristic-v1", "text": "### getTransceiverInfo\n\nReturns the info for all enabled transceivers. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nfunction getTransceiverInfo() external view returns (TransceiverInfo[] memory)\n```\n\n??? interface \"Returns\"\n\n    `info` ++\"TransceiverInfo[] memory\"++\n\n    An array of transceiver information structs.\n\n    ??? child \"`TransceiverInfo` struct\"\n\n        `registered` ++\"bool\"++\n\n        Whether this transceiver is registered.\n        \n        ---\n\n        `enabled` ++\"bool\"++\n\n        Whether this transceiver is enabled.\n        \n        ---\n\n        `index` ++\"uint8\"++\n\n        Index of the transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 42, "depth": 3, "title": "getTransceivers", "anchor": "gettransceivers", "start_char": 25668, "end_char": 26103, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "### getTransceivers\n\nReturns the enabled Transceiver contracts. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nfunction getTransceivers() external pure returns (address[] memory result)\n```\n\n??? interface \"Returns\"\n\n    `result` ++\"address[] memory\"++\n\n    An array of enabled transceiver addresses."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 43, "depth": 3, "title": "initialize", "anchor": "initialize", "start_char": 26103, "end_char": 26359, "estimated_token_count": 71, "token_estimator": "heuristic-v1", "text": "### initialize\n\nInitializes the contract. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction initialize() external payable\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 44, "depth": 3, "title": "isMessageApproved", "anchor": "ismessageapproved", "start_char": 26359, "end_char": 26932, "estimated_token_count": 142, "token_estimator": "heuristic-v1", "text": "### isMessageApproved\n\nChecks if a message has been approved with at least the minimum threshold of attestations from distinct endpoints. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction isMessageApproved(bytes32 digest) external view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The keccak-256 hash of the message.\n\n??? interface \"Returns\"\n\n    `approved` ++\"bool\"++\n\n    Whether the message has been approved."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 45, "depth": 3, "title": "isMessageExecuted", "anchor": "ismessageexecuted", "start_char": 26932, "end_char": 27429, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "### isMessageExecuted\n\nChecks if a message has been executed. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction isMessageExecuted(bytes32 digest) external view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The keccak-256 hash of the message.\n\n??? interface \"Returns\"\n\n    `executed` ++\"bool\"++\n\n    Whether the message has been executed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 46, "depth": 3, "title": "isPaused", "anchor": "ispaused", "start_char": 27429, "end_char": 27825, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "### isPaused\n\nReturns true if the contract is paused, and false otherwise. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction isPaused() external view returns (bool)\n```\n\n??? interface \"Returns\"\n\n    `paused` ++\"bool\"++\n\n    Whether the contract is paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 47, "depth": 3, "title": "messageAttestations", "anchor": "messageattestations", "start_char": 27825, "end_char": 28347, "estimated_token_count": 134, "token_estimator": "heuristic-v1", "text": "### messageAttestations\n\nReturns the number of attestations for a given message. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction messageAttestations(bytes32 digest) external view returns (uint8)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The keccak-256 hash of the message.\n\n??? interface \"Returns\"\n\n    `count` ++\"uint8\"++\n\n    The number of attestations for the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 48, "depth": 3, "title": "migrate", "anchor": "migrate", "start_char": 28347, "end_char": 28616, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### migrate\n\nMigrates the contract state to a new implementation. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction migrate() external\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 49, "depth": 3, "title": "nextMessageSequence", "anchor": "nextmessagesequence", "start_char": 28616, "end_char": 29001, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### nextMessageSequence\n\nReturns the next message sequence. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction nextMessageSequence() external view returns (uint64)\n```\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    The next message sequence number."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 50, "depth": 3, "title": "owner", "anchor": "owner", "start_char": 29001, "end_char": 29386, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### owner\n\nReturns the address of the current owner. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction owner() external view returns (address)\n```\n\n??? interface \"Returns\"\n\n    `owner` ++\"address\"++\n\n    The address of the current owner."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 51, "depth": 3, "title": "pause", "anchor": "pause", "start_char": 29386, "end_char": 29636, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "### pause\n\nPauses the manager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction pause() external\n```\n\n> **Emits**: `Paused`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 52, "depth": 3, "title": "pauser", "anchor": "pauser", "start_char": 29636, "end_char": 30020, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### pauser\n\nReturns the current pauser account address. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction pauser() external view returns (address)\n```\n\n??? interface \"Returns\"\n\n    `pauser` ++\"address\"++\n\n    The address of the current pauser."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 53, "depth": 3, "title": "quoteDeliveryPrice", "anchor": "quotedeliveryprice", "start_char": 30020, "end_char": 30865, "estimated_token_count": 190, "token_estimator": "heuristic-v1", "text": "### quoteDeliveryPrice\n\nFetches the delivery price for a given recipient chain transfer. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction quoteDeliveryPrice(\n    uint16 recipientChain, \n    bytes memory transceiverInstructions\n) public view returns (uint256[] memory, uint256)\n```\n\n??? interface \"Parameters\"\n\n    `recipientChain` ++\"uint16\"++\n\n    The chain ID of the recipient.\n\n    ---\n\n    `transceiverInstructions` ++\"bytes\"++\n\n    The transceiver-specific instructions for the transfer.\n\n??? interface \"Returns\"\n\n    `deliveryQuotes` ++\"uint256[] memory\"++\n\n    An array of delivery quotes from each transceiver.\n\n    ---\n\n    `totalPrice` ++\"uint256\"++\n\n    The total price for delivery across all transceivers."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 54, "depth": 3, "title": "removeTransceiver", "anchor": "removetransceiver", "start_char": 30865, "end_char": 31305, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "### removeTransceiver\n\nRemoves/disables a transceiver address in the registry of a given chain. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction removeTransceiver(address transceiver) external\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The address of the transceiver contract to remove."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 55, "depth": 3, "title": "setInboundLimit", "anchor": "setinboundlimit", "start_char": 31305, "end_char": 31783, "estimated_token_count": 126, "token_estimator": "heuristic-v1", "text": "### setInboundLimit\n\nSet the inbound transfer limit for a specific chain. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction setInboundLimit(uint256 limit, uint16 chainId_) external\n```\n\n??? interface \"Parameters\"\n\n    `limit` ++\"uint256\"++\n\n    The new inbound transfer limit.\n\n    ---\n\n    `chainId_` ++\"uint16\"++\n\n    The chain ID to set the limit for."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 56, "depth": 3, "title": "setOutboundLimit", "anchor": "setoutboundlimit", "start_char": 31783, "end_char": 32149, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### setOutboundLimit\n\nSet the outbound transfer limit. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction setOutboundLimit(uint256 limit) external\n```\n\n??? interface \"Parameters\"\n\n    `limit` ++\"uint256\"++\n\n    The new outbound transfer limit."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 57, "depth": 3, "title": "setPeer", "anchor": "setpeer", "start_char": 32149, "end_char": 33603, "estimated_token_count": 375, "token_estimator": "heuristic-v1", "text": "### setPeer\n\nSet peer contract information for a specific chain; this is local manager configuration (no cross-chain message) and must be called on both chains. If either side is unset or mismatched, inbound verification or amount trimming fails ([`InvalidPeer`](/docs/products/token-transfers/native-token-transfers/reference/manager/evm/#invalidpeer), [`InvalidPeerDecimals`](/docs/products/token-transfers/native-token-transfers/reference/manager/evm/#invalidpeerdecimals)). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n!!! tip \"Example\"\n    - **On Chain A**: Register Chain B as a peer with B’s manager address (`peerContract`), B’s token decimals (`decimals`), and the inbound limit from B → A (`inboundLimit`).\n    - **On Chain B**: Register Chain A the same way (A’s manager, A’s token decimals, inbound limit from A → B).\n\n```sol\nfunction setPeer(\n    uint16 peerChainId,\n    bytes32 peerContract,\n    uint8 decimals,\n    uint256 inboundLimit\n) external\n```\n\n??? interface \"Parameters\"\n\n    `peerChainId` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `peerContract` ++\"bytes32\"++\n\n    The address of the peer contract.\n\n    ---\n\n    `decimals` ++\"uint8\"++\n\n    The number of decimals for the peer token.\n\n    ---\n\n    `inboundLimit` ++\"uint256\"++\n\n    The inbound transfer limit for this peer.\n\n> **Emits**: `PeerUpdated`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 58, "depth": 3, "title": "setThreshold", "anchor": "setthreshold", "start_char": 33603, "end_char": 34068, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "### setThreshold\n\nSets the threshold for the number of attestations required for a message to be considered valid. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction setThreshold(uint8 threshold) external\n```\n\n??? interface \"Parameters\"\n\n    `threshold` ++\"uint8\"++\n\n    The number of attestations required.\n\n> **Emits**: `ThresholdChanged`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 59, "depth": 3, "title": "setTransceiver", "anchor": "settransceiver", "start_char": 34068, "end_char": 34494, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "### setTransceiver\n\nSets the transceiver for the given chain. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction setTransceiver(address transceiver) external\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The address of the transceiver contract.\n\n> **Emits**: `TransceiverAdded`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 60, "depth": 3, "title": "tokenDecimals", "anchor": "tokendecimals", "start_char": 34494, "end_char": 34878, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### tokenDecimals\n\nReturns the number of decimals for the token. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction tokenDecimals() external view returns (uint8)\n```\n\n??? interface \"Returns\"\n\n    `decimals` ++\"uint8\"++\n\n    The number of decimals for the token."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 61, "depth": 3, "title": "transceiverAttestedToMessage", "anchor": "transceiverattestedtomessage", "start_char": 34878, "end_char": 35510, "estimated_token_count": 157, "token_estimator": "heuristic-v1", "text": "### transceiverAttestedToMessage\n\nReturns if the transceiver has attested to the message. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction transceiverAttestedToMessage(bytes32 digest, uint8 index) external view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The keccak-256 hash of the message.\n\n    ---\n\n    `index` ++\"uint8\"++\n\n    The index of the transceiver.\n\n??? interface \"Returns\"\n\n    `attested` ++\"bool\"++\n\n    Whether the transceiver has attested to the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 62, "depth": 3, "title": "transfer (basic)", "anchor": "transfer-basic", "start_char": 35510, "end_char": 36332, "estimated_token_count": 204, "token_estimator": "heuristic-v1", "text": "### transfer (basic)\n\nTransfer tokens (simple version). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction transfer(\n    uint256 amount, \n    uint16 recipientChain, \n    bytes32 recipient\n) external payable returns (uint64)\n```\n\n??? interface \"Parameters\"\n\n    `amount` ++\"uint256\"++\n\n    The amount of tokens to transfer.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++\n\n    The chain ID of the recipient.\n\n    ---\n\n    `recipient` ++\"bytes32\"++\n\n    The recipient address on the destination chain.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the transfer.\n\n> **Emits**: `OutboundTransferRateLimited` (if rate limited), `TransferSent` (two variants, if successful)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 63, "depth": 3, "title": "transfer (advanced)", "anchor": "transfer-advanced", "start_char": 36332, "end_char": 37547, "estimated_token_count": 278, "token_estimator": "heuristic-v1", "text": "### transfer (advanced)\n\nTransfer tokens (full version with additional parameters). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nfunction transfer(\n    uint256 amount,\n    uint16 recipientChain,\n    bytes32 recipient,\n    bytes32 refundAddress,\n    bool shouldQueue,\n    bytes memory transceiverInstructions\n) external payable returns (uint64)\n```\n\n??? interface \"Parameters\"\n\n    `amount` ++\"uint256\"++\n\n    The amount of tokens to transfer.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++\n\n    The chain ID of the recipient.\n\n    ---\n\n    `recipient` ++\"bytes32\"++\n\n    The recipient address on the destination chain.\n\n    ---\n\n    `refundAddress` ++\"bytes32\"++\n\n    The address to refund unused gas to.\n\n    ---\n\n    `shouldQueue` ++\"bool\"++\n\n    Whether to queue the transfer if rate limited.\n\n    ---\n\n    `transceiverInstructions` ++\"bytes\"++\n\n    Additional instructions for transceivers.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n\n    The sequence number of the transfer.\n\n> **Emits**: `OutboundTransferRateLimited` (if rate limited), `TransferSent` (two variants, if successful)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 64, "depth": 3, "title": "transferOwnership", "anchor": "transferownership", "start_char": 37547, "end_char": 38093, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "### transferOwnership\n\n[Transfer ownership](/docs/products/token-transfers/native-token-transfers/guides/transfer-ownership/#evm){target=\\_blank} of the Manager and all Transceiver contracts. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction transferOwnership(address newOwner) external\n```\n\n??? interface \"Parameters\"\n\n    `newOwner` ++\"address\"++\n\n    The address of the new owner.\n\n> **Emits**: `OwnershipTransferred`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 65, "depth": 3, "title": "transferPauserCapability", "anchor": "transferpausercapability", "start_char": 38093, "end_char": 38540, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "### transferPauserCapability\n\nTransfers the ability to pause to a new account. *(Defined in [PausableOwnable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableOwnable.sol){target=\\_blank})*\n\n```sol\nfunction transferPauserCapability(address newPauser) external\n```\n\n??? interface \"Parameters\"\n\n    `newPauser` ++\"address\"++\n\n    The address of the new pauser.\n\n> **Emits**: `PauserTransferred`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 66, "depth": 3, "title": "upgrade", "anchor": "upgrade", "start_char": 38540, "end_char": 38938, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### upgrade\n\nUpgrades to a new manager implementation. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction upgrade(address newImplementation) external\n```\n\n??? interface \"Parameters\"\n\n    `newImplementation` ++\"address\"++\n\n    The address of the new implementation contract."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 67, "depth": 3, "title": "unpause", "anchor": "unpause", "start_char": 38938, "end_char": 39197, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "### unpause\n\nUnpauses the manager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nfunction unpause() external\n```\n\n> **Emits**: `NotPaused`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 68, "depth": 2, "title": "Errors", "anchor": "errors", "start_char": 39197, "end_char": 39208, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Errors"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 69, "depth": 3, "title": "BurnAmountDifferentThanBalanceDiff", "anchor": "burnamountdifferentthanbalancediff", "start_char": 39208, "end_char": 39734, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### BurnAmountDifferentThanBalanceDiff\n\nError when the burn amount differs from the balance difference. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror BurnAmountDifferentThanBalanceDiff(uint256 burnAmount, uint256 balanceDiff);\n```\n\n??? interface \"Parameters\"\n\n    `burnAmount` ++\"uint256\"++\n\n    The amount that was burned.\n\n    ---\n\n    `balanceDiff` ++\"uint256\"++\n\n    The actual balance difference."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 70, "depth": 3, "title": "CallerNotTransceiver", "anchor": "callernottransceiver", "start_char": 39734, "end_char": 40136, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### CallerNotTransceiver\n\nError when the caller is not the transceiver. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror CallerNotTransceiver(address caller);\n```\n\n??? interface \"Parameters\"\n\n    `caller` ++\"address\"++\n\n    The address that is not a transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 71, "depth": 3, "title": "CancellerNotSender", "anchor": "cancellernotsender", "start_char": 40136, "end_char": 40654, "estimated_token_count": 130, "token_estimator": "heuristic-v1", "text": "### CancellerNotSender\n\nError when someone other than the original sender tries to cancel a queued outbound transfer. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror CancellerNotSender(address canceller, address sender);\n```\n\n??? interface \"Parameters\"\n\n    `canceller` ++\"address\"++\n\n    The address attempting to cancel.\n\n    ---\n\n    `sender` ++\"address\"++\n\n    The original sender's address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 72, "depth": 3, "title": "CapacityCannotExceedLimit", "anchor": "capacitycannotexceedlimit", "start_char": 40654, "end_char": 41571, "estimated_token_count": 220, "token_estimator": "heuristic-v1", "text": "### CapacityCannotExceedLimit\n\nThe new capacity cannot exceed the limit. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror CapacityCannotExceedLimit(TrimmedAmount newCurrentCapacity, TrimmedAmount newLimit);\n```\n\n??? interface \"Parameters\"\n\n    `newCurrentCapacity` ++\"TrimmedAmount\"++\n\n    The new current capacity value.\n\n    ??? child \"`TrimmedAmount` type\"\n\n        `amount` ++\"uint64\"++\n\n        The amount value (64 bits).\n        \n        ---\n\n        `decimals` ++\"uint8\"++\n\n        The number of decimals (8 bits).\n\n    ---\n\n    `newLimit` ++\"TrimmedAmount\"++\n\n    The new limit value.\n\n    ??? child \"`TrimmedAmount` type\"\n\n        `amount` ++\"uint64\"++\n\n        The amount value (64 bits).\n        \n        ---\n\n        `decimals` ++\"uint8\"++\n\n        The number of decimals (8 bits)."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 73, "depth": 3, "title": "DeliveryPaymentTooLow", "anchor": "deliverypaymenttoolow", "start_char": 41571, "end_char": 42070, "estimated_token_count": 121, "token_estimator": "heuristic-v1", "text": "### DeliveryPaymentTooLow\n\nPayment for a transfer is too low. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror DeliveryPaymentTooLow(uint256 requiredPayment, uint256 providedPayment);\n```\n\n??? interface \"Parameters\"\n\n    `requiredPayment` ++\"uint256\"++\n\n    The required payment amount.\n\n    ---\n\n    `providedPayment` ++\"uint256\"++\n\n    The payment amount that was provided."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 74, "depth": 3, "title": "DisabledTransceiver", "anchor": "disabledtransceiver", "start_char": 42070, "end_char": 42469, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### DisabledTransceiver\n\nError when the transceiver is disabled. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror DisabledTransceiver(address transceiver);\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The disabled transceiver address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 75, "depth": 3, "title": "InboundQueuedTransferNotFound", "anchor": "inboundqueuedtransfernotfound", "start_char": 42469, "end_char": 42864, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### InboundQueuedTransferNotFound\n\nThe inbound transfer is no longer queued. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror InboundQueuedTransferNotFound(bytes32 digest);\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the queued transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 76, "depth": 3, "title": "InboundQueuedTransferStillQueued", "anchor": "inboundqueuedtransferstillqueued", "start_char": 42864, "end_char": 43364, "estimated_token_count": 120, "token_estimator": "heuristic-v1", "text": "### InboundQueuedTransferStillQueued\n\nThe transfer is still queued. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror InboundQueuedTransferStillQueued(bytes32 digest, uint256 transferTimestamp);\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the queued transfer.\n\n    ---\n\n    `transferTimestamp` ++\"uint256\"++\n\n    The timestamp of the transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 77, "depth": 3, "title": "InvalidInitialization", "anchor": "invalidinitialization", "start_char": 43364, "end_char": 43667, "estimated_token_count": 79, "token_estimator": "heuristic-v1", "text": "### InvalidInitialization\n\nError when the contract is in an invalid initialization state. *(Defined in [Initializable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/Initializable.sol){target=\\_blank})*\n\n```sol\nerror InvalidInitialization();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 78, "depth": 3, "title": "InvalidMode", "anchor": "invalidmode", "start_char": 43667, "end_char": 44015, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### InvalidMode\n\nThe mode is invalid (neither LOCKING nor BURNING). *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidMode(uint8 mode);\n```\n\n??? interface \"Parameters\"\n\n    `mode` ++\"uint8\"++\n\n    The invalid mode value."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 79, "depth": 3, "title": "InvalidPauser", "anchor": "invalidpauser", "start_char": 44015, "end_char": 44408, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### InvalidPauser\n\nError when the pauser is not a valid pauser account. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror InvalidPauser(address account);\n```\n\n??? interface \"Parameters\"\n\n    `account` ++\"address\"++\n\n    The invalid pauser account address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 80, "depth": 3, "title": "InvalidPeer", "anchor": "invalidpeer", "start_char": 44408, "end_char": 44877, "estimated_token_count": 128, "token_estimator": "heuristic-v1", "text": "### InvalidPeer\n\nThe peer for the chain does not match the configuration. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidPeer(uint16 chainId, bytes32 peerAddress);\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `peerAddress` ++\"bytes32\"++\n\n    The peer address that doesn't match."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 81, "depth": 3, "title": "InvalidPeerChainIdZero", "anchor": "invalidpeerchainidzero", "start_char": 44877, "end_char": 45139, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### InvalidPeerChainIdZero\n\nThe peer chain ID cannot be zero. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidPeerChainIdZero();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 82, "depth": 3, "title": "InvalidPeerDecimals", "anchor": "invalidpeerdecimals", "start_char": 45139, "end_char": 45397, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### InvalidPeerDecimals\n\nThe peer cannot have zero decimals. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidPeerDecimals();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 83, "depth": 3, "title": "InvalidPeerSameChainId", "anchor": "invalidpeersamechainid", "start_char": 45397, "end_char": 45663, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### InvalidPeerSameChainId\n\nThe peer cannot be on the same chain. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidPeerSameChainId();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 84, "depth": 3, "title": "InvalidPeerZeroAddress", "anchor": "invalidpeerzeroaddress", "start_char": 45663, "end_char": 45928, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### InvalidPeerZeroAddress\n\nThe peer cannot be the zero address. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidPeerZeroAddress();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 85, "depth": 3, "title": "InvalidRecipient", "anchor": "invalidrecipient", "start_char": 45928, "end_char": 46181, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### InvalidRecipient\n\nError when the recipient is invalid. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidRecipient();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 86, "depth": 3, "title": "InvalidRefundAddress", "anchor": "invalidrefundaddress", "start_char": 46181, "end_char": 46447, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### InvalidRefundAddress\n\nError when the refund address is invalid. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidRefundAddress();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 87, "depth": 3, "title": "InvalidTargetChain", "anchor": "invalidtargetchain", "start_char": 46447, "end_char": 46942, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### InvalidTargetChain\n\nError when trying to execute a message on an unintended target chain. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror InvalidTargetChain(uint16 targetChain, uint16 thisChain);\n```\n\n??? interface \"Parameters\"\n\n    `targetChain` ++\"uint16\"++\n\n    The target chain ID from the message.\n\n    ---\n\n    `thisChain` ++\"uint16\"++\n\n    The current chain ID."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 88, "depth": 3, "title": "InvalidTransceiverZeroAddress", "anchor": "invalidtransceiverzeroaddress", "start_char": 46942, "end_char": 47250, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### InvalidTransceiverZeroAddress\n\nError when the transceiver is the zero address. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror InvalidTransceiverZeroAddress();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 89, "depth": 3, "title": "MessageNotApproved", "anchor": "messagenotapproved", "start_char": 47250, "end_char": 47635, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### MessageNotApproved\n\nError when the message is not approved. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror MessageNotApproved(bytes32 msgHash);\n```\n\n??? interface \"Parameters\"\n\n    `msgHash` ++\"bytes32\"++\n\n    The hash of the message that is not approved."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 90, "depth": 3, "title": "NoEnabledTransceivers", "anchor": "noenabledtransceivers", "start_char": 47635, "end_char": 47915, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### NoEnabledTransceivers\n\nThere are no transceivers enabled with the Manager. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror NoEnabledTransceivers();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 91, "depth": 3, "title": "NonRegisteredTransceiver", "anchor": "nonregisteredtransceiver", "start_char": 47915, "end_char": 48360, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "### NonRegisteredTransceiver\n\nError when attempting to remove a transceiver that is not registered. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror NonRegisteredTransceiver(address transceiver);\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The non-registered transceiver address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 92, "depth": 3, "title": "NotEnoughCapacity", "anchor": "notenoughcapacity", "start_char": 48360, "end_char": 48835, "estimated_token_count": 119, "token_estimator": "heuristic-v1", "text": "### NotEnoughCapacity\n\nNot enough capacity to send the transfer. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror NotEnoughCapacity(uint256 currentCapacity, uint256 amount);\n```\n\n??? interface \"Parameters\"\n\n    `currentCapacity` ++\"uint256\"++\n\n    The current available capacity.\n\n    ---\n\n    `amount` ++\"uint256\"++\n\n    The requested transfer amount."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 93, "depth": 3, "title": "NotInitializing", "anchor": "notinitializing", "start_char": 48835, "end_char": 49127, "estimated_token_count": 79, "token_estimator": "heuristic-v1", "text": "### NotInitializing\n\nError when a function can only be called during initialization. *(Defined in [Initializable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/Initializable.sol){target=\\_blank})*\n\n```sol\nerror NotInitializing();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 94, "depth": 3, "title": "NotMigrating", "anchor": "notmigrating", "start_char": 49127, "end_char": 49401, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "### NotMigrating\n\nError when a function can only be called during migration. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nerror NotMigrating();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 95, "depth": 3, "title": "NotImplemented", "anchor": "notimplemented", "start_char": 49401, "end_char": 49517, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### NotImplemented\n\nFeature is not implemented. *(Defined in INttManager.sol)*\n\n```sol\nerror NotImplemented();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 96, "depth": 3, "title": "OnlyDelegateCall", "anchor": "onlydelegatecall", "start_char": 49517, "end_char": 49800, "estimated_token_count": 78, "token_estimator": "heuristic-v1", "text": "### OnlyDelegateCall\n\nError when a function can only be called via delegate call. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nerror OnlyDelegateCall();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 97, "depth": 3, "title": "OwnableInvalidOwner", "anchor": "ownableinvalidowner", "start_char": 49800, "end_char": 50197, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### OwnableInvalidOwner\n\nError when the owner is not a valid owner account. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror OwnableInvalidOwner(address owner);\n```\n\n??? interface \"Parameters\"\n\n    `owner` ++\"address\"++\n\n    The invalid owner address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 98, "depth": 3, "title": "OwnableUnauthorizedAccount", "anchor": "ownableunauthorizedaccount", "start_char": 50197, "end_char": 50641, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### OwnableUnauthorizedAccount\n\nError when the caller account is not authorized to perform an operation. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror OwnableUnauthorizedAccount(address account);\n```\n\n??? interface \"Parameters\"\n\n    `account` ++\"address\"++\n\n    The unauthorized account address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 99, "depth": 3, "title": "OutboundQueuedTransferNotFound", "anchor": "outboundqueuedtransfernotfound", "start_char": 50641, "end_char": 51056, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### OutboundQueuedTransferNotFound\n\nOutbound transfer is no longer queued. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror OutboundQueuedTransferNotFound(uint64 queueSequence);\n```\n\n??? interface \"Parameters\"\n\n    `queueSequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 100, "depth": 3, "title": "OutboundQueuedTransferStillQueued", "anchor": "outboundqueuedtransferstillqueued", "start_char": 51056, "end_char": 51618, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### OutboundQueuedTransferStillQueued\n\nCannot complete the outbound transfer. The transfer is still queued. *(Defined in [RateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/RateLimiter.sol){target=\\_blank})*\n\n```sol\nerror OutboundQueuedTransferStillQueued(uint64 queueSequence, uint256 transferTimestamp);\n```\n\n??? interface \"Parameters\"\n\n    `queueSequence` ++\"uint64\"++\n\n    The sequence number of the queued transfer.\n\n    ---\n\n    `transferTimestamp` ++\"uint256\"++\n\n    The timestamp of the transfer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 101, "depth": 3, "title": "PeerNotRegistered", "anchor": "peernotregistered", "start_char": 51618, "end_char": 52040, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "### PeerNotRegistered\n\nError when the manager doesn't have a peer registered for the destination chain. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror PeerNotRegistered(uint16 chainId);\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID for which no peer is registered."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 102, "depth": 3, "title": "RefundFailed", "anchor": "refundfailed", "start_char": 52040, "end_char": 52419, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### RefundFailed\n\nError when the refund to the sender fails. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror RefundFailed(uint256 refundAmount);\n```\n\n??? interface \"Parameters\"\n\n    `refundAmount` ++\"uint256\"++\n\n    The amount that failed to be refunded."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 103, "depth": 3, "title": "RequireContractIsNotPaused", "anchor": "requirecontractisnotpaused", "start_char": 52419, "end_char": 52734, "estimated_token_count": 78, "token_estimator": "heuristic-v1", "text": "### RequireContractIsNotPaused\n\nError when a function requires the contract to not be paused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror RequireContractIsNotPaused();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 104, "depth": 3, "title": "RequireContractIsPaused", "anchor": "requirecontractispaused", "start_char": 52734, "end_char": 53039, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "### RequireContractIsPaused\n\nError when a function requires the contract to be paused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror RequireContractIsPaused();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 105, "depth": 3, "title": "RetrievedIncorrectRegisteredTransceivers", "anchor": "retrievedincorrectregisteredtransceivers", "start_char": 53039, "end_char": 53602, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "### RetrievedIncorrectRegisteredTransceivers\n\nRetrieved an incorrect number of registered transceivers. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror RetrievedIncorrectRegisteredTransceivers(uint256 retrieved, uint256 registered);\n```\n\n??? interface \"Parameters\"\n\n    `retrieved` ++\"uint256\"++\n\n    The number of transceivers retrieved.\n\n    ---\n\n    `registered` ++\"uint256\"++\n\n    The number of transceivers that should be registered."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 106, "depth": 3, "title": "StaticcallFailed", "anchor": "staticcallfailed", "start_char": 53602, "end_char": 53839, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "### StaticcallFailed\n\nStaticcall reverted. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror StaticcallFailed();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 107, "depth": 3, "title": "ThresholdTooHigh", "anchor": "thresholdtoohigh", "start_char": 53839, "end_char": 54333, "estimated_token_count": 121, "token_estimator": "heuristic-v1", "text": "### ThresholdTooHigh\n\nThe threshold for transceiver attestations is too high. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror ThresholdTooHigh(uint256 threshold, uint256 transceivers);\n```\n\n??? interface \"Parameters\"\n\n    `threshold` ++\"uint256\"++\n\n    The requested threshold value.\n\n    ---\n\n    `transceivers` ++\"uint256\"++\n\n    The number of available transceivers."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 108, "depth": 3, "title": "TooManyTransceivers", "anchor": "toomanytransceivers", "start_char": 54333, "end_char": 54634, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "### TooManyTransceivers\n\nError when the number of registered transceivers exceeds 64. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror TooManyTransceivers();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 109, "depth": 3, "title": "TransceiverAlreadyAttestedToMessage", "anchor": "transceiveralreadyattestedtomessage", "start_char": 54634, "end_char": 55092, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### TransceiverAlreadyAttestedToMessage\n\nError when the transceiver already attested to the message. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror TransceiverAlreadyAttestedToMessage(bytes32 nttManagerMessageHash);\n```\n\n??? interface \"Parameters\"\n\n    `nttManagerMessageHash` ++\"bytes32\"++\n\n    The hash of the NTT Manager message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 110, "depth": 3, "title": "TransceiverAlreadyEnabled", "anchor": "transceiveralreadyenabled", "start_char": 55092, "end_char": 55541, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### TransceiverAlreadyEnabled\n\nError when attempting to enable a transceiver that is already enabled. *(Defined in [TransceiverRegistry.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/TransceiverRegistry.sol){target=\\_blank})*\n\n```sol\nerror TransceiverAlreadyEnabled(address transceiver);\n```\n\n??? interface \"Parameters\"\n\n    `transceiver` ++\"address\"++\n\n    The already enabled transceiver address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 111, "depth": 3, "title": "TransferAmountHasDust", "anchor": "transferamounthasdust", "start_char": 55541, "end_char": 55962, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "### TransferAmountHasDust\n\nThe transfer has some dust. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror TransferAmountHasDust(uint256 amount, uint256 dust);\n```\n\n??? interface \"Parameters\"\n\n    `amount` ++\"uint256\"++\n\n    The transfer amount.\n\n    ---\n\n    `dust` ++\"uint256\"++\n\n    The dust amount."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 112, "depth": 3, "title": "UndefinedRateLimiting", "anchor": "undefinedratelimiting", "start_char": 55962, "end_char": 56267, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "### UndefinedRateLimiting\n\nIf the rate limiting behavior isn't explicitly defined in the constructor. *(Defined in [IRateLimiter.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IRateLimiter.sol){target=\\_blank})*\n\n```sol\nerror UndefinedRateLimiting();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 113, "depth": 3, "title": "UnexpectedDeployer", "anchor": "unexpecteddeployer", "start_char": 56267, "end_char": 56718, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "### UnexpectedDeployer\n\nThe caller is not the deployer. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror UnexpectedDeployer(address expectedOwner, address owner);\n```\n\n??? interface \"Parameters\"\n\n    `expectedOwner` ++\"address\"++\n\n    The expected owner address.\n\n    ---\n\n    `owner` ++\"address\"++\n\n    The actual owner address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 114, "depth": 3, "title": "UnexpectedMsgValue", "anchor": "unexpectedmsgvalue", "start_char": 56718, "end_char": 56988, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "### UnexpectedMsgValue\n\nAn unexpected msg.value was passed with the call. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror UnexpectedMsgValue();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 115, "depth": 3, "title": "ZeroAmount", "anchor": "zeroamount", "start_char": 56988, "end_char": 57232, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### ZeroAmount\n\nError when the transfer amount is zero. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror ZeroAmount();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 116, "depth": 3, "title": "ZeroThreshold", "anchor": "zerothreshold", "start_char": 57232, "end_char": 57489, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### ZeroThreshold\n\nThe number of thresholds should not be zero. *(Defined in [ManagerBase.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/ManagerBase.sol){target=\\_blank})*\n\n```sol\nerror ZeroThreshold();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 117, "depth": 3, "title": "TransferAlreadyCompleted", "anchor": "transferalreadycompleted", "start_char": 57489, "end_char": 57943, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "### TransferAlreadyCompleted\n\nThrown when trying to complete an inbound transfer that was already processed. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror TransferAlreadyCompleted(bytes32 digest);\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the transfer message that has already been completed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-evm", "page_title": "Native Token Transfers Manager Contract (EVM)", "index": 118, "depth": 3, "title": "UnexpectedRecipientNttManagerAddress", "anchor": "unexpectedrecipientnttmanageraddress", "start_char": 57943, "end_char": 58456, "estimated_token_count": 110, "token_estimator": "heuristic-v1", "text": "### UnexpectedRecipientNttManagerAddress\n\nThrown when the recipient NTT Manager address in the message does not match this contract. *(Defined in [NttManager.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/NttManager/NttManager.sol){target=\\_blank})*\n\n```sol\nerror UnexpectedRecipientNttManagerAddress(bytes32 recipientNttManagerAddress);\n```\n\n??? interface \"Parameters\"\n\n    `recipientNttManagerAddress` ++\"bytes32\"++\n\n    The unexpected NTT Manager address from the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 413, "end_char": 1720, "estimated_token_count": 251, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe NTT Manager system on Solana is implemented as a single Anchor program. The program provides comprehensive token transfer management capabilities, supports both burning and locking modes, integrates with Solana's Token Program (including Token-2022), and provides rate limiting and security features.\n\n```text\nNTT Manager Program\n├── Core Instructions\n├── Administrative Instructions\n├── Rate Limiting\n├── Transceiver Management\n├── Peer Management\n└── Wormhole Integration\n```\n\n**Key Components:**\n\n- **NttManager Program**: The primary Solana program that coordinates token transfers, transceiver interactions, and peer communication for the NTT protocol.\n- **Core Instructions**: Handles token transfer instructions like transfer, redeem, and release.\n- **Administrative Instructions**: Manages ownership, configuration updates, and emergency pause functionality.\n- **Rate Limiting**: Implements configurable inbound and outbound transfer limits with time-based capacity replenishment.\n- **Transceiver Management**: Maintains a registry of enabled transceivers and allows dynamic registration/deregistration.\n- **Peer Management**: Manages authorized cross-chain peers.\n- **Wormhole Integration**: Built-in transceiver that connects the program to Wormhole's messaging layer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 1, "depth": 2, "title": "State Accounts", "anchor": "state-accounts", "start_char": 1720, "end_char": 1739, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## State Accounts"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 2, "depth": 3, "title": "Core Configuration", "anchor": "core-configuration", "start_char": 1739, "end_char": 2065, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "### Core Configuration\n\n- `Config` ++\"account (PDA: 'config')\"++: Primary program configuration: owner/pending_owner, managed `mint`, `token_program` (SPL Token or Token-2022), mode (burn vs. lock), chain_id, `next_transceiver_id`, attestation `threshold`, `enabled_transceivers` bitmap, `paused`, and `custody` (lock mode)."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 3, "depth": 3, "title": "Cross-chain Peers and Governance Thresholds", "anchor": "cross-chain-peers-and-governance-thresholds", "start_char": 2065, "end_char": 2486, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### Cross-chain Peers and Governance Thresholds\n\n- `NttManagerPeer` ++\"account (PDA: 'peer')\"++: Per-chain peer manager metadata—`address` (wormhole-formatted) and `token_decimals`. Stored in a PDA seeded by chain id.\n- `ValidatedTransceiverMessage` ++\"account (PDA: 'transceiver_message')\"++: Validated inbound transceiver message container (`from_chain`, `message`), with helpers for discriminator checks and parsing."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 4, "depth": 3, "title": "Rate Limiting and Queues", "anchor": "rate-limiting-and-queues", "start_char": 2486, "end_char": 3265, "estimated_token_count": 209, "token_estimator": "heuristic-v1", "text": "### Rate Limiting and Queues\n\n- `InboxRateLimit` ++\"account (PDA: 'inbox_rate_limit')\"++: Inbound rate-limit state (per peer chain), wrapping `RateLimitState` (`limit`, `capacity_at_last_tx`, `last_tx_timestamp`).\n- `OutboxRateLimit` ++\"account (PDA: 'outbox_rate_limit')\"++: Global outbound rate-limit state, wrapping `RateLimitState` (`limit`, `capacity_at_last_tx`, `last_tx_timestamp`).\n- `InboxItem` ++\"account (PDA: 'inbox_item')\"++: Per-inbound message item with `amount`, `recipient_address`, `votes` (bitmap), and `release_status` state machine (`NotApproved` → `ReleaseAfter(ts)` → `Released`).\n- `OutboxItem` ++\"account (PDA: 'outbox_item')\"++: Per-outbound transfer item tracking delivery/release state (`amount`, `sender`, `recipient` fields and release metadata)."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 5, "depth": 3, "title": "Authority and Admin Flow", "anchor": "authority-and-admin-flow", "start_char": 3265, "end_char": 3434, "estimated_token_count": 37, "token_estimator": "heuristic-v1", "text": "### Authority and Admin Flow\n\n- `PendingTokenAuthority` ++\"account (PDA: 'pending_token_authority')\"++: Tracks pending mint authority transitions and the `rent_payer`."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 6, "depth": 3, "title": "PDAs", "anchor": "pdas", "start_char": 3434, "end_char": 3830, "estimated_token_count": 108, "token_estimator": "heuristic-v1", "text": "### PDAs\n\n- `TOKEN_AUTHORITY` ++\"PDA (seed: 'token_authority')\"++: Program-derived token authority used by the burn/lock flows. (PDA seed constant in `lib.rs`.)\n- `SESSION_AUTHORITY` ++\"PDA (seed: 'session_authority')\"++: Per-transfer session authority used by `transfer_*` instructions (user approves this PDA to spend, then it burns/locks). (Seed constant and rationale in `lib.rs` comments.)"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 7, "depth": 2, "title": "Instructions", "anchor": "instructions", "start_char": 3830, "end_char": 3847, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Instructions"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 8, "depth": 3, "title": "accept_token_authority", "anchor": "accept_token_authority", "start_char": 3847, "end_char": 4460, "estimated_token_count": 140, "token_estimator": "heuristic-v1", "text": "### accept_token_authority\n\nAccepts token authority from a pending token authority transfer. *(Defined in NTT Manager)*\n\n```rust\npub fn accept_token_authority(ctx: Context<AcceptTokenAuthority>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `token_authority` ++\"Signer\"++\n\n    The new token authority accepting the transfer.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 9, "depth": 3, "title": "accept_token_authority_from_multisig", "anchor": "accept_token_authority_from_multisig", "start_char": 4460, "end_char": 5234, "estimated_token_count": 167, "token_estimator": "heuristic-v1", "text": "### accept_token_authority_from_multisig\n\nAccepts token authority from a multisig pending token authority transfer. *(Defined in NTT Manager)*\n\n```rust\npub fn accept_token_authority_from_multisig(\n    ctx: Context<AcceptTokenAuthorityFromMultisig>\n) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `multisig` ++\"Account<Multisig>\"++\n\n    The multisig account acting as the new token authority.\n\n    ---\n\n    `transaction` ++\"Account<Transaction>\"++\n\n    The multisig transaction account.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 10, "depth": 3, "title": "broadcast_wormhole_id", "anchor": "broadcast_wormhole_id", "start_char": 5234, "end_char": 6432, "estimated_token_count": 286, "token_estimator": "heuristic-v1", "text": "### broadcast_wormhole_id\n\nBroadcasts the NTT Manager ID via Wormhole. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn broadcast_wormhole_id(ctx: Context<BroadcastId>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for transaction fees.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `wormhole_bridge` ++\"mut Account<BridgeData>\"++\n\n    The Wormhole bridge data account.\n\n    ---\n\n    `wormhole_message` ++\"mut Signer\"++\n\n    The Wormhole message account.\n\n    ---\n\n    `wormhole_emitter` ++\"Account<EmitterData>\"++\n\n    The Wormhole emitter account.\n\n    ---\n\n    `wormhole_sequence` ++\"mut Account<SequenceData>\"++\n\n    The Wormhole sequence account.\n\n    ---\n\n    `wormhole_fee_collector` ++\"mut Account<FeeCollectorData>\"++\n\n    The Wormhole fee collector account.\n\n    ---\n\n    `clock` ++\"Sysvar<Clock>\"++\n\n    The clock sysvar.\n\n    ---\n\n    `rent` ++\"Sysvar<Rent>\"++\n\n    The rent sysvar.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program.\n\n    ---\n\n    `wormhole_program` ++\"Program<WormholeCoreBridge>\"++\n\n    The Wormhole core bridge program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 11, "depth": 3, "title": "broadcast_wormhole_peer", "anchor": "broadcast_wormhole_peer", "start_char": 6432, "end_char": 7010, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### broadcast_wormhole_peer\n\nBroadcasts peer information via Wormhole. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn broadcast_wormhole_peer(\n    ctx: Context<BroadcastPeer>,\n    args: BroadcastPeerArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"BroadcastPeerArgs\"++\n\n    The broadcast peer arguments.\n\n    ??? child \"`BroadcastPeerArgs` type\"\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID to broadcast peer information for.\n\n??? interface \"Accounts\"\n\n    Similar to `broadcast_wormhole_id` with additional peer-specific accounts."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 12, "depth": 3, "title": "claim_ownership", "anchor": "claim_ownership", "start_char": 7010, "end_char": 7415, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### claim_ownership\n\nClaims ownership of the NTT Manager after a transfer has been initiated. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn claim_ownership(ctx: Context<ClaimOwnership>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `new_owner` ++\"Signer\"++\n\n    The new owner claiming ownership."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 13, "depth": 3, "title": "claim_token_authority", "anchor": "claim_token_authority", "start_char": 7415, "end_char": 8035, "estimated_token_count": 144, "token_estimator": "heuristic-v1", "text": "### claim_token_authority\n\nClaims token authority after a transfer has been initiated. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn claim_token_authority(ctx: Context<ClaimTokenAuthority>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `token_authority` ++\"Signer\"++\n\n    The new token authority claiming authority.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 14, "depth": 3, "title": "claim_token_authority_to_multisig", "anchor": "claim_token_authority_to_multisig", "start_char": 8035, "end_char": 8688, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "### claim_token_authority_to_multisig\n\nClaims token authority to a multisig account. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn claim_token_authority_to_multisig(\n    ctx: Context<ClaimTokenAuthorityToMultisig>\n) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `multisig` ++\"Account<Multisig>\"++\n\n    The multisig account claiming token authority.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 15, "depth": 3, "title": "deregister_transceiver", "anchor": "deregister_transceiver", "start_char": 8688, "end_char": 9201, "estimated_token_count": 117, "token_estimator": "heuristic-v1", "text": "### deregister_transceiver\n\nRemoves a transceiver from the enabled set. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn deregister_transceiver(ctx: Context<DeregisterTransceiver>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `registered_transceiver` ++\"mut Account<RegisteredTransceiver>\"++\n\n    The registered transceiver account to deregister."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 16, "depth": 3, "title": "initialize", "anchor": "initialize", "start_char": 9201, "end_char": 10805, "estimated_token_count": 371, "token_estimator": "heuristic-v1", "text": "### initialize\n\nInitializes the NTT Manager program with configuration parameters. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn initialize(ctx: Context<Initialize>, args: InitializeArgs) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"InitializeArgs\"++\n\n    The initialization arguments.\n\n    ??? child \"`InitializeArgs` type\"\n\n        `chain_id` ++\"u16\"++\n\n        The chain ID for this deployment.\n        \n        ---\n\n        `limit` ++\"u64\"++\n\n        The initial rate limit for transfers.\n        \n        ---\n\n        `mode` ++\"Mode\"++\n\n        The mode (Burning or Locking) for token handling.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for initialization.\n\n    ---\n\n    `deployer` ++\"Signer\"++\n\n    The program deployer (must be upgrade authority).\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account to initialize.\n\n    ---\n\n    `mint` ++\"InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `rate_limit` ++\"mut Account<OutboxRateLimit>\"++\n\n    The outbound rate limit account.\n\n    ---\n\n    `token_authority` ++\"UncheckedAccount\"++\n\n    The token authority account.\n\n    ---\n\n    `custody` ++\"mut InterfaceAccount<TokenAccount>\"++\n\n    The custody account (for locking mode).\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface.\n\n    ---\n\n    `associated_token_program` ++\"Program<AssociatedToken>\"++\n\n    The associated token program.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 17, "depth": 3, "title": "initialize_lut", "anchor": "initialize_lut", "start_char": 10805, "end_char": 11616, "estimated_token_count": 187, "token_estimator": "heuristic-v1", "text": "### initialize_lut\n\nInitializes a lookup table for the program. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn initialize_lut(ctx: Context<InitializeLUT>, recent_slot: u64) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `recent_slot` ++\"u64\"++\n\n    A recent slot number for lookup table initialization.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for lookup table creation.\n\n    ---\n\n    `lut` ++\"mut UncheckedAccount\"++\n\n    The lookup table account to initialize.\n\n    ---\n\n    `lut_authority` ++\"UncheckedAccount\"++\n\n    The lookup table authority.\n\n    ---\n\n    `address_lookup_table_program` ++\"Program<AddressLookupTableProgram>\"++\n\n    The address lookup table program.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 18, "depth": 3, "title": "mark_outbox_item_as_released", "anchor": "mark_outbox_item_as_released", "start_char": 11616, "end_char": 12384, "estimated_token_count": 170, "token_estimator": "heuristic-v1", "text": "### mark_outbox_item_as_released\n\nMarks an outbox item as released by a specific transceiver. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn mark_outbox_item_as_released(ctx: Context<MarkOutboxItemAsReleased>) -> Result<bool>\n```\n\n??? interface \"Returns\"\n\n    `released` ++\"bool\"++\n\n    Whether the item was successfully marked as released.\n\n??? interface \"Accounts\"\n\n    `transceiver` ++\"Signer\"++\n\n    The transceiver marking the item as released.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `outbox_item` ++\"mut Account<OutboxItem>\"++\n\n    The outbox item to mark as released.\n\n    ---\n\n    `registered_transceiver` ++\"Account<RegisteredTransceiver>\"++\n\n    The registered transceiver account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 19, "depth": 3, "title": "receive_wormhole_message", "anchor": "receive_wormhole_message", "start_char": 12384, "end_char": 13376, "estimated_token_count": 233, "token_estimator": "heuristic-v1", "text": "### receive_wormhole_message\n\nReceives and processes a message from Wormhole. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn receive_wormhole_message(ctx: Context<ReceiveMessage>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for message processing.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `peer` ++\"Account<NttManagerPeer>\"++\n\n    The peer account for the sending chain.\n\n    ---\n\n    `inbox_item` ++\"mut Account<InboxItem>\"++\n\n    The inbox item account to create.\n\n    ---\n\n    `inbox_rate_limit` ++\"mut Account<InboxRateLimit>\"++\n\n    The inbound rate limit account.\n\n    ---\n\n    `vaa` ++\"Account<PostedVaa<TransceiverMessage>>\"++\n\n    The verified VAA containing the message.\n\n    ---\n\n    `transceiver_message` ++\"mut UncheckedAccount\"++\n\n    The transceiver message account.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 20, "depth": 3, "title": "redeem", "anchor": "redeem", "start_char": 13376, "end_char": 14011, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "### redeem\n\nRedeems a transfer by consuming a verified message. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn redeem(ctx: Context<Redeem>, args: RedeemArgs) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"RedeemArgs\"++\n\n    The redeem arguments (currently empty struct).\n\n??? interface \"Accounts\"\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `transceiver_message` ++\"Account<ValidatedTransceiverMessage<NativeTokenTransfer>>\"++\n\n    The validated transceiver message.\n\n    ---\n\n    `inbox_item` ++\"mut Account<InboxItem>\"++\n\n    The inbox item being redeemed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 21, "depth": 3, "title": "register_transceiver", "anchor": "register_transceiver", "start_char": 14011, "end_char": 14772, "estimated_token_count": 177, "token_estimator": "heuristic-v1", "text": "### register_transceiver\n\nRegisters a new transceiver with the NTT Manager. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn register_transceiver(ctx: Context<RegisterTransceiver>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for registration.\n\n    ---\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `registered_transceiver` ++\"mut Account<RegisteredTransceiver>\"++\n\n    The registered transceiver account to create.\n\n    ---\n\n    `transceiver` ++\"UncheckedAccount\"++\n\n    The transceiver program to register.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 22, "depth": 3, "title": "release_inbound_mint", "anchor": "release_inbound_mint", "start_char": 14772, "end_char": 16053, "estimated_token_count": 290, "token_estimator": "heuristic-v1", "text": "### release_inbound_mint\n\nReleases an inbound transfer by minting tokens to the recipient. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn release_inbound_mint(\n    ctx: Context<ReleaseInboundMint>,\n    args: ReleaseInboundArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"ReleaseInboundArgs\"++\n\n    The release arguments.\n\n    ??? child \"`ReleaseInboundArgs` type\"\n\n        `revert_on_delay` ++\"bool\"++\n\n        Whether to revert if the transfer is still in delay.\n\n??? interface \"Accounts\"\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `inbox_item` ++\"mut Account<InboxItem>\"++\n\n    The inbox item to release.\n\n    ---\n\n    `inbox_rate_limit` ++\"mut Account<InboxRateLimit>\"++\n\n    The inbound rate limit account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `recipient_token` ++\"mut InterfaceAccount<TokenAccount>\"++\n\n    The recipient's token account.\n\n    ---\n\n    `token_authority` ++\"UncheckedAccount\"++\n\n    The token authority account.\n\n    ---\n\n    `custody` ++\"mut InterfaceAccount<TokenAccount>\"++\n\n    The custody account.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 23, "depth": 3, "title": "release_inbound_unlock", "anchor": "release_inbound_unlock", "start_char": 16053, "end_char": 16673, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "### release_inbound_unlock\n\nReleases an inbound transfer by unlocking tokens from custody. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn release_inbound_unlock(\n    ctx: Context<ReleaseInboundUnlock>,\n    args: ReleaseInboundArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"ReleaseInboundArgs\"++\n\n    The release arguments.\n\n    ??? child \"`ReleaseInboundArgs` type\"\n\n        `revert_on_delay` ++\"bool\"++\n\n        Whether to revert if the transfer is still in delay.\n\n??? interface \"Accounts\"\n\n    Similar to `release_inbound_mint` but unlocks tokens from custody instead of minting."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 24, "depth": 3, "title": "release_wormhole_outbound", "anchor": "release_wormhole_outbound", "start_char": 16673, "end_char": 18323, "estimated_token_count": 388, "token_estimator": "heuristic-v1", "text": "### release_wormhole_outbound\n\nReleases an outbound transfer via Wormhole. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn release_wormhole_outbound(\n    ctx: Context<ReleaseOutbound>,\n    args: ReleaseOutboundArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"ReleaseOutboundArgs\"++\n\n    The release outbound arguments.\n\n    ??? child \"`ReleaseOutboundArgs` type\"\n\n        `revert_on_delay` ++\"bool\"++\n\n        If `true`, revert when the rate limiter would delay release; if `false`, return early without error.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The fee payer.\n\n    ---\n\n    `config` ++\"NotPausedConfig\"++\n\n    Wrapper enforcing the Manager is not paused; derefs to `Account<Config>`.\n\n    ---\n\n    `outbox_item` ++\"mut Account<OutboxItem>\"++\n\n    The outbound item to release; must not already be marked released by this transceiver.\n\n    ---\n\n    `transceiver` ++\"Account<RegisteredTransceiver>\"++\n\n    Must match this program ID and be enabled in `config`.\n\n    ---\n\n    `wormhole_message` ++\"mut UncheckedAccount\"++\n\n    PDA seeded as `[b\"message\", outbox_item.key()]`; initialized/written by Wormhole Core.\n\n    ---\n\n    `emitter` ++\"UncheckedAccount\"++\n\n    PDA seeded as `[b\"emitter\"]`; used as the Wormhole emitter.\n\n    ---\n\n    `wormhole` ++\"WormholeAccounts\"++\n\n    Bundle of Wormhole Core accounts:\n\n     - `bridge: Account<wormhole::BridgeData>`\n     - `fee_collector: UncheckedAccount`\n     - `sequence: UncheckedAccount`\n     - `program: Program<wormhole::program::Wormhole>`\n     - `system_program: Program<System>`\n     - `clock: Sysvar<Clock>`\n     - `rent: Sysvar<Rent>`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 25, "depth": 3, "title": "revert_token_authority", "anchor": "revert_token_authority", "start_char": 18323, "end_char": 18698, "estimated_token_count": 92, "token_estimator": "heuristic-v1", "text": "### revert_token_authority\n\nReverts a pending token authority change. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn revert_token_authority(ctx: Context<RevertTokenAuthority>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 26, "depth": 3, "title": "set_inbound_limit", "anchor": "set_inbound_limit", "start_char": 18698, "end_char": 19484, "estimated_token_count": 188, "token_estimator": "heuristic-v1", "text": "### set_inbound_limit\n\nSets the inbound transfer rate limit. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_inbound_limit(\n    ctx: Context<SetInboundLimit>,\n    args: SetInboundLimitArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"SetInboundLimitArgs\"++\n\n    The inbound limit arguments.\n\n    ??? child \"`SetInboundLimitArgs` type\"\n\n        `limit` ++\"u64\"++\n\n        The new inbound rate limit.\n\n        ---\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID to set the limit for.\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `rate_limit` ++\"mut Account<InboxRateLimit>\"++\n\n    The inbound rate limit account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 27, "depth": 3, "title": "set_outbound_limit", "anchor": "set_outbound_limit", "start_char": 19484, "end_char": 20190, "estimated_token_count": 166, "token_estimator": "heuristic-v1", "text": "### set_outbound_limit\n\nSets the outbound transfer rate limit. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_outbound_limit(\n    ctx: Context<SetOutboundLimit>,\n    args: SetOutboundLimitArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"SetOutboundLimitArgs\"++\n\n    The outbound limit arguments.\n\n    ??? child \"`SetOutboundLimitArgs` type\"\n\n        `limit` ++\"u64\"++\n\n        The new outbound rate limit.\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `rate_limit` ++\"mut Account<OutboxRateLimit>\"++\n\n    The outbound rate limit account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 28, "depth": 3, "title": "set_paused", "anchor": "set_paused", "start_char": 20190, "end_char": 20636, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### set_paused\n\nSets the pause state of the program. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_paused(ctx: Context<SetPaused>, pause: bool) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `pause` ++\"bool\"++\n\n    Whether to pause or unpause the program.\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 29, "depth": 3, "title": "set_peer", "anchor": "set_peer", "start_char": 20636, "end_char": 22081, "estimated_token_count": 368, "token_estimator": "heuristic-v1", "text": "### set_peer\n\nSets a peer NTT Manager on another chain; this is local program configuration (no cross-chain message) and must be executed on both chains. If either side is unset or mismatched, messages from that peer will fail verification on receive. *(Defined in example-native-token-transfers)*\n\n!!! tip \"Example\"\n    - **On Chain A**: Register Chain B with B’s manager address (address); this creates/updates the peer account (PDA \"peer\") and the inbound rate-limit account for B.\n    - **On Chain B**: Register Chain A the same way.\n\n```rust\npub fn set_peer(ctx: Context<SetPeer>, args: SetPeerArgs) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"SetPeerArgs\"++\n\n    The peer arguments.\n\n    ??? child \"`SetPeerArgs` type\"\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID of the peer.\n\n        ---\n\n        `address` ++\"[u8; 32]\"++\n\n        The address of the peer NTT Manager.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for peer registration.\n\n    ---\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `peer` ++\"mut Account<NttManagerPeer>\"++\n\n    The peer account to create or update.\n\n    ---\n\n    `inbox_rate_limit` ++\"mut Account<InboxRateLimit>\"++\n\n    The inbound rate limit account for the peer.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 30, "depth": 3, "title": "set_threshold", "anchor": "set_threshold", "start_char": 22081, "end_char": 22560, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### set_threshold\n\nSets the threshold number of transceivers required for message approval. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_threshold(ctx: Context<SetThreshold>, threshold: u8) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `threshold` ++\"u8\"++\n\n    The new threshold value.\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 31, "depth": 3, "title": "set_token_authority", "anchor": "set_token_authority", "start_char": 22560, "end_char": 23047, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "### set_token_authority\n\nSets the token authority using a checked transfer process. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_token_authority(ctx: Context<SetTokenAuthorityChecked>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `new_token_authority` ++\"UncheckedAccount\"++\n\n    The new token authority account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 32, "depth": 3, "title": "set_token_authority_one_step_unchecked", "anchor": "set_token_authority_one_step_unchecked", "start_char": 23047, "end_char": 23774, "estimated_token_count": 161, "token_estimator": "heuristic-v1", "text": "### set_token_authority_one_step_unchecked\n\nSets the token authority in a single step without checks. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_token_authority_one_step_unchecked(\n    ctx: Context<SetTokenAuthorityUnchecked>\n) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `new_token_authority` ++\"UncheckedAccount\"++\n\n    The new token authority account.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 33, "depth": 3, "title": "set_wormhole_peer", "anchor": "set_wormhole_peer", "start_char": 23774, "end_char": 24683, "estimated_token_count": 213, "token_estimator": "heuristic-v1", "text": "### set_wormhole_peer\n\nSets a Wormhole transceiver peer on another chain. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn set_wormhole_peer(\n    ctx: Context<SetTransceiverPeer>,\n    args: SetTransceiverPeerArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"SetTransceiverPeerArgs\"++\n\n    The transceiver peer arguments.\n\n    ??? child \"`SetTransceiverPeerArgs` type\"\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID of the peer.\n\n        ---\n\n        `address` ++\"[u8; 32]\"++\n\n        The address of the peer transceiver.\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The program owner.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `peer` ++\"mut Account<WormholeTransceiverPeer>\"++\n\n    The Wormhole transceiver peer account.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 34, "depth": 3, "title": "transfer_burn", "anchor": "transfer_burn", "start_char": 24683, "end_char": 26352, "estimated_token_count": 389, "token_estimator": "heuristic-v1", "text": "### transfer_burn\n\nInitiates an outbound transfer by burning tokens. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn transfer_burn(\n    ctx: Context<TransferBurn>,\n    args: TransferArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"TransferArgs\"++\n\n    The transfer arguments.\n\n    ??? child \"`TransferArgs` type\"\n\n        `amount` ++\"u64\"++\n\n        The amount of tokens to transfer.\n\n        ---\n\n        `recipient_chain` ++\"ChainId\"++\n\n        The recipient chain ID.\n\n        ---\n\n        `recipient_address` ++\"[u8; 32]\"++\n\n        The recipient address on the target chain.\n\n        ---\n\n        `should_queue` ++\"bool\"++\n\n        Whether to queue the transfer if rate limited.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for the transfer.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `from` ++\"mut InterfaceAccount<TokenAccount>\"++\n\n    The sender's token account.\n\n    ---\n\n    `mint` ++\"mut InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `outbox_item` ++\"mut Account<OutboxItem>\"++\n\n    The outbox item account to create.\n\n    ---\n\n    `outbox_rate_limit` ++\"mut Account<OutboxRateLimit>\"++\n\n    The outbound rate limit account.\n\n    ---\n\n    `session_authority` ++\"UncheckedAccount\"++\n\n    The session authority for the transfer.\n\n    ---\n\n    `token_authority` ++\"UncheckedAccount\"++\n\n    The token authority account.\n\n    ---\n\n    `token_program` ++\"Interface<TokenInterface>\"++\n\n    The token program interface.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 35, "depth": 3, "title": "transfer_lock", "anchor": "transfer_lock", "start_char": 26352, "end_char": 27187, "estimated_token_count": 190, "token_estimator": "heuristic-v1", "text": "### transfer_lock\n\nInitiates an outbound transfer by locking tokens in custody. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn transfer_lock(\n    ctx: Context<TransferLock>,\n    args: TransferArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"TransferArgs\"++\n\n    The transfer arguments.\n\n    ??? child \"`TransferArgs` type\"\n\n        `amount` ++\"u64\"++\n\n        The amount of tokens to transfer.\n\n        ---\n\n        `recipient_chain` ++\"ChainId\"++\n\n        The recipient chain ID.\n\n        ---\n\n        `recipient_address` ++\"[u8; 32]\"++\n\n        The recipient address on the target chain.\n\n        ---\n\n        `should_queue` ++\"bool\"++\n\n        Whether to queue the transfer if rate limited.\n\n??? interface \"Accounts\"\n\n    Similar to `transfer_burn` but locks tokens in custody instead of burning."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 36, "depth": 3, "title": "transfer_ownership", "anchor": "transfer_ownership", "start_char": 27187, "end_char": 27751, "estimated_token_count": 146, "token_estimator": "heuristic-v1", "text": "### transfer_ownership\n\nInitiates a two-step [ownership transfer](/docs/products/token-transfers/native-token-transfers/guides/transfer-ownership/#solana){target=\\_blank} process. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn transfer_ownership(ctx: Context<TransferOwnership>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The current program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `new_owner` ++\"UncheckedAccount\"++\n\n    The proposed new owner."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 37, "depth": 3, "title": "transfer_ownership_one_step_unchecked", "anchor": "transfer_ownership_one_step_unchecked", "start_char": 27751, "end_char": 28247, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "### transfer_ownership_one_step_unchecked\n\nTransfers ownership in a single step without verification. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn transfer_ownership_one_step_unchecked(ctx: Context<TransferOwnership>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `owner` ++\"Signer\"++\n\n    The current program owner.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The program configuration account.\n\n    ---\n\n    `new_owner` ++\"UncheckedAccount\"++\n\n    The new owner."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 38, "depth": 3, "title": "version", "anchor": "version", "start_char": 28247, "end_char": 28501, "estimated_token_count": 77, "token_estimator": "heuristic-v1", "text": "### version\n\nReturns the program version string. *(Defined in example-native-token-transfers)*\n\n```rust\npub fn version(_ctx: Context<Version>) -> Result<String>\n```\n\n??? interface \"Returns\"\n\n    `version` ++\"String\"++\n\n    The version string (\"3.0.0\")."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 39, "depth": 2, "title": "Data Structures", "anchor": "data-structures", "start_char": 28501, "end_char": 28521, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## Data Structures"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 40, "depth": 3, "title": "Config", "anchor": "config", "start_char": 28521, "end_char": 30084, "estimated_token_count": 375, "token_estimator": "heuristic-v1", "text": "### Config\n\nThe main program configuration account. *(Defined in config.rs)*\n\n```rust\npub struct Config {\n    pub bump: u8,\n    pub owner: Pubkey,\n    pub pending_owner: Option<Pubkey>,\n    pub mint: Pubkey,\n    pub token_program: Pubkey,\n    pub mode: Mode,\n    pub chain_id: ChainId,\n    pub next_transceiver_id: u8,\n    pub threshold: u8,\n    pub enabled_transceivers: Bitmap,\n    pub paused: bool,\n    pub custody: Pubkey,\n}\n```\n\n??? interface \"Fields\"\n\n    `bump` ++\"u8\"++\n\n    The canonical bump for the config account.\n\n    ---\n\n    `owner` ++\"Pubkey\"++\n\n    The owner of the program.\n\n    ---\n\n    `pending_owner` ++\"Option<Pubkey>\"++\n\n    The pending owner (before claiming ownership).\n\n    ---\n\n    `mint` ++\"Pubkey\"++\n\n    The mint address of the token managed by this program.\n\n    ---\n\n    `token_program` ++\"Pubkey\"++\n\n    The address of the token program (Token or Token-2022).\n\n    ---\n\n    `mode` ++\"Mode\"++\n\n    The mode that this program is running in (Burning or Locking).\n\n    ---\n\n    `chain_id` ++\"ChainId\"++\n\n    The chain ID of the chain that this program is running on.\n\n    ---\n\n    `next_transceiver_id` ++\"u8\"++\n\n    The next transceiver ID to use when registering a transceiver.\n\n    ---\n\n    `threshold` ++\"u8\"++\n\n    The number of transceivers that must attest to a transfer.\n\n    ---\n\n    `enabled_transceivers` ++\"Bitmap\"++\n\n    Bitmap of enabled transceivers.\n\n    ---\n\n    `paused` ++\"bool\"++\n\n    Whether the program is paused.\n\n    ---\n\n    `custody` ++\"Pubkey\"++\n\n    The custody account that holds tokens in locking mode."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 41, "depth": 3, "title": "Mode", "anchor": "mode", "start_char": 30084, "end_char": 30401, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### Mode\n\nThe operating mode of the NTT Manager. *(Defined in ntt-messages)*\n\n```rust\npub enum Mode {\n    Locking,\n    Burning,\n}\n```\n\n??? interface \"Variants\"\n\n    `Locking`\n\n    Tokens are locked in custody and unlocked on release.\n\n    ---\n\n    `Burning`\n\n    Tokens are burned on transfer and minted on release."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 42, "depth": 3, "title": "ChainId", "anchor": "chainid", "start_char": 30401, "end_char": 30596, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "### ChainId\n\nA Wormhole chain identifier. *(Defined in ntt-messages)*\n\n```rust\npub struct ChainId {\n    pub id: u16,\n}\n```\n\n??? interface \"Fields\"\n\n    `id` ++\"u16\"++\n\n    The numeric chain ID."}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 43, "depth": 2, "title": "Errors", "anchor": "errors", "start_char": 30596, "end_char": 30607, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Errors"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 44, "depth": 3, "title": "BadAmountAfterBurn", "anchor": "badamountafterburn", "start_char": 30607, "end_char": 30748, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### BadAmountAfterBurn\n\nError when the amount after burning doesn't match expected. *(Defined in error.rs)*\n\n```rust\nBadAmountAfterBurn\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 45, "depth": 3, "title": "BadAmountAfterTransfer", "anchor": "badamountaftertransfer", "start_char": 30748, "end_char": 30898, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### BadAmountAfterTransfer\n\nError when the amount after transfer doesn't match expected. *(Defined in error.rs)*\n\n```rust\nBadAmountAfterTransfer\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 46, "depth": 3, "title": "BitmapIndexOutOfBounds", "anchor": "bitmapindexoutofbounds", "start_char": 30898, "end_char": 31029, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### BitmapIndexOutOfBounds\n\nError when bitmap index is out of bounds. *(Defined in error.rs)*\n\n```rust\nBitmapIndexOutOfBounds\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 47, "depth": 3, "title": "CantReleaseYet", "anchor": "cantreleaseyet", "start_char": 31029, "end_char": 31166, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "### CantReleaseYet\n\nError when trying to release a transfer that is still in delay. *(Defined in error.rs)*\n\n```rust\nCantReleaseYet\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 48, "depth": 3, "title": "DisabledTransceiver", "anchor": "disabledtransceiver", "start_char": 31166, "end_char": 31302, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### DisabledTransceiver\n\nError when attempting to use a disabled transceiver. *(Defined in error.rs)*\n\n```rust\nDisabledTransceiver\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 49, "depth": 3, "title": "IncorrectRentPayer", "anchor": "incorrectrentpayer", "start_char": 31302, "end_char": 31423, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### IncorrectRentPayer\n\nError when the rent payer is incorrect. *(Defined in error.rs)*\n\n```rust\nIncorrectRentPayer\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 50, "depth": 3, "title": "InvalidChainId", "anchor": "invalidchainid", "start_char": 31423, "end_char": 31540, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### InvalidChainId\n\nError when an invalid chain ID is provided. *(Defined in error.rs)*\n\n```rust\nInvalidChainId\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 51, "depth": 3, "title": "InvalidDeployer", "anchor": "invaliddeployer", "start_char": 31540, "end_char": 31658, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidDeployer\n\nError when the deployer is not authorized. *(Defined in error.rs)*\n\n```rust\nInvalidDeployer\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 52, "depth": 3, "title": "InvalidMintAuthority", "anchor": "invalidmintauthority", "start_char": 31658, "end_char": 31785, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidMintAuthority\n\nError when the mint authority is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidMintAuthority\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 53, "depth": 3, "title": "InvalidMode", "anchor": "invalidmode", "start_char": 31785, "end_char": 31893, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidMode\n\nError when an invalid mode is specified. *(Defined in error.rs)*\n\n```rust\nInvalidMode\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 54, "depth": 3, "title": "InvalidMultisig", "anchor": "invalidmultisig", "start_char": 31893, "end_char": 32010, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidMultisig\n\nError when a multisig account is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidMultisig\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 55, "depth": 3, "title": "InvalidNttManagerPeer", "anchor": "invalidnttmanagerpeer", "start_char": 32010, "end_char": 32141, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### InvalidNttManagerPeer\n\nError when the NTT Manager peer is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidNttManagerPeer\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 56, "depth": 3, "title": "InvalidPendingOwner", "anchor": "invalidpendingowner", "start_char": 32141, "end_char": 32265, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidPendingOwner\n\nError when the pending owner is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidPendingOwner\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 57, "depth": 3, "title": "InvalidPendingTokenAuthority", "anchor": "invalidpendingtokenauthority", "start_char": 32265, "end_char": 32417, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### InvalidPendingTokenAuthority\n\nError when the pending token authority is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidPendingTokenAuthority\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 58, "depth": 3, "title": "InvalidRecipientAddress", "anchor": "invalidrecipientaddress", "start_char": 32417, "end_char": 32553, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidRecipientAddress\n\nError when the recipient address is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidRecipientAddress\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 59, "depth": 3, "title": "InvalidTransceiverPeer", "anchor": "invalidtransceiverpeer", "start_char": 32553, "end_char": 32686, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidTransceiverPeer\n\nError when the transceiver peer is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidTransceiverPeer\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 60, "depth": 3, "title": "InvalidTransceiverProgram", "anchor": "invalidtransceiverprogram", "start_char": 32686, "end_char": 32828, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### InvalidTransceiverProgram\n\nError when the transceiver program is invalid. *(Defined in error.rs)*\n\n```rust\nInvalidTransceiverProgram\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 61, "depth": 3, "title": "MessageAlreadySent", "anchor": "messagealreadysent", "start_char": 32828, "end_char": 32977, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "### MessageAlreadySent\n\nError when attempting to send a message that has already been sent. *(Defined in error.rs)*\n\n```rust\nMessageAlreadySent\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 62, "depth": 3, "title": "NoRegisteredTransceivers", "anchor": "noregisteredtransceivers", "start_char": 32977, "end_char": 33113, "estimated_token_count": 28, "token_estimator": "heuristic-v1", "text": "### NoRegisteredTransceivers\n\nError when no transceivers are registered. *(Defined in error.rs)*\n\n```rust\nNoRegisteredTransceivers\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 63, "depth": 3, "title": "NotPaused", "anchor": "notpaused", "start_char": 33113, "end_char": 33236, "estimated_token_count": 35, "token_estimator": "heuristic-v1", "text": "### NotPaused\n\nError when expecting the program to be paused but it's not. *(Defined in error.rs)*\n\n```rust\nNotPaused\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 64, "depth": 3, "title": "OverflowExponent", "anchor": "overflowexponent", "start_char": 33236, "end_char": 33369, "estimated_token_count": 32, "token_estimator": "heuristic-v1", "text": "### OverflowExponent\n\nError when there's an overflow in exponent calculation. *(Defined in error.rs)*\n\n```rust\nOverflowExponent\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 65, "depth": 3, "title": "OverflowScaledAmount", "anchor": "overflowscaledamount", "start_char": 33369, "end_char": 33515, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### OverflowScaledAmount\n\nError when there's an overflow in scaled amount calculation. *(Defined in error.rs)*\n\n```rust\nOverflowScaledAmount\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 66, "depth": 3, "title": "Paused", "anchor": "paused", "start_char": 33515, "end_char": 33635, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### Paused\n\nError when the program is paused and operation is not allowed. *(Defined in error.rs)*\n\n```rust\nPaused\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 67, "depth": 3, "title": "ThresholdTooHigh", "anchor": "thresholdtoohigh", "start_char": 33635, "end_char": 33754, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### ThresholdTooHigh\n\nError when the threshold is set too high. *(Defined in error.rs)*\n\n```rust\nThresholdTooHigh\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 68, "depth": 3, "title": "TransferAlreadyRedeemed", "anchor": "transferalreadyredeemed", "start_char": 33754, "end_char": 33920, "estimated_token_count": 34, "token_estimator": "heuristic-v1", "text": "### TransferAlreadyRedeemed\n\nError when attempting to redeem a transfer that has already been redeemed. *(Defined in error.rs)*\n\n```rust\nTransferAlreadyRedeemed\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 69, "depth": 3, "title": "TransferCannotBeRedeemed", "anchor": "transfercannotberedeemed", "start_char": 33920, "end_char": 34055, "estimated_token_count": 29, "token_estimator": "heuristic-v1", "text": "### TransferCannotBeRedeemed\n\nError when a transfer cannot be redeemed. *(Defined in error.rs)*\n\n```rust\nTransferCannotBeRedeemed\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 70, "depth": 3, "title": "TransferExceedsRateLimit", "anchor": "transferexceedsratelimit", "start_char": 34055, "end_char": 34194, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### TransferExceedsRateLimit\n\nError when a transfer exceeds the rate limit. *(Defined in error.rs)*\n\n```rust\nTransferExceedsRateLimit\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 71, "depth": 3, "title": "TransferNotApproved", "anchor": "transfernotapproved", "start_char": 34194, "end_char": 34345, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "### TransferNotApproved\n\nError when a transfer has not been approved by enough transceivers. *(Defined in error.rs)*\n\n```rust\nTransferNotApproved\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-manager-solana", "page_title": "Native Token Transfers Manager Program (Solana)", "index": 72, "depth": 3, "title": "ZeroThreshold", "anchor": "zerothreshold", "start_char": 34345, "end_char": 34456, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "### ZeroThreshold\n\nError when the threshold is set to zero. *(Defined in error.rs)*\n\n```rust\nZeroThreshold\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 443, "end_char": 2169, "estimated_token_count": 348, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe NTT Transceiver system is built using a layered inheritance structure with the base [`Transceiver`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank} contract providing common functionality and specific implementations like [`WormholeTransceiver`](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank} adding protocol-specific features.\n\n```text\nWormholeTransceiver.sol\n├── IWormholeTransceiver.sol\n├── IWormholeReceiver.sol\n└── WormholeTransceiverState.sol\n    ├── IWormholeTransceiverState.sol\n    └── Transceiver.sol\n        ├── ITransceiver.sol\n        ├── PausableOwnable.sol\n        ├── ReentrancyGuardUpgradeable.sol\n        └── Implementation.sol\n```\n\n**Key Components:**\n\n- **`Transceiver.sol`**: Base abstract contract providing common transceiver functionality including message transmission, ownership management, and upgrade capabilities.\n- **`WormholeTransceiver.sol`**: Concrete implementation for Wormhole protocol, handling message verification through Wormhole Core and supporting multiple delivery methods (standard relaying, custom relaying, manual).\n- **`WormholeTransceiverState.sol`**: State management contract for Wormhole-specific storage including peer registration, relaying configuration, and VAA consumption tracking.\n- **`PausableOwnable.sol`**: Provides ownership and emergency pause functionality.\n- **`ReentrancyGuardUpgradeable.sol`**: Protects against reentrancy attacks in an upgradeable context.\n- **`Implementation.sol`**: Handles proxy implementation logic for upgradeable contracts."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 1, "depth": 2, "title": "State Variables", "anchor": "state-variables", "start_char": 2169, "end_char": 2189, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## State Variables"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 2, "depth": 3, "title": "Core Identification", "anchor": "core-identification", "start_char": 2189, "end_char": 2490, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "### Core Identification\n\n- `nttManager` ++\"address\"++: Immutable address of the NTT Manager that this transceiver is tied to.\n- `nttManagerToken` ++\"address\"++: Immutable address of the token associated with the NTT deployment.\n- `deployer` ++\"address\"++: Immutable address of the contract deployer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 3, "depth": 3, "title": "Version", "anchor": "version", "start_char": 2490, "end_char": 2609, "estimated_token_count": 23, "token_estimator": "heuristic-v1", "text": "### Version\n\n- `WORMHOLE_TRANSCEIVER_VERSION` ++\"string\"++: Version string of the WormholeTransceiver implementation."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 4, "depth": 3, "title": "Messaging and Relaying Configuration", "anchor": "messaging-and-relaying-configuration", "start_char": 2609, "end_char": 3097, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "### Messaging and Relaying Configuration\n\n- `consistencyLevel` ++\"uint8\"++: Immutable Wormhole consistency level for message finality.\n- `wormhole` ++\"IWormhole\"++: Immutable reference to the Wormhole Core bridge contract.\n- `wormholeRelayer` ++\"IWormholeRelayer\"++: Immutable reference to the relayer contract. \n- `specialRelayer` ++\"ISpecialRelayer\"++: Immutable reference to a custom relayer contract.\n- `gasLimit` ++\"uint256\"++: Immutable gas limit for cross-chain message delivery."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 5, "depth": 3, "title": "Peer Configuration and Replay Protection", "anchor": "peer-configuration-and-replay-protection", "start_char": 3097, "end_char": 3906, "estimated_token_count": 161, "token_estimator": "heuristic-v1", "text": "### Peer Configuration and Replay Protection\n\n- `WORMHOLE_CONSUMED_VAAS_SLOT` ++\"mapping(bytes32 ⇒ bool)\"++: Tracks consumed VAA hashes for replay protection. Exposed via isVAAConsumed.\n- `WORMHOLE_PEERS_SLOT` ++\"mapping(uint16 ⇒ bytes32)\"++: Wormhole chain ID → peer transceiver address. Exposed via getWormholePeer.\n- `WORMHOLE_RELAYING_ENABLED_CHAINS_SLOT` ++\"mapping(uint16 ⇒ BooleanFlag)\"++: Per-chain flag for enabling standard relaying. Exposed via isWormholeRelayingEnabled.\n- `SPECIAL_RELAYING_ENABLED_CHAINS_SLOT` ++\"mapping(uint16 ⇒ BooleanFlag)\"++: Per-chain flag for enabling special relaying. Exposed via isSpecialRelayingEnabled.\n- `WORMHOLE_EVM_CHAIN_IDS` ++\"mapping(uint16 ⇒ BooleanFlag)\"++: Per-chain EVM-compatibility flag used to choose the relaying path. Exposed via isWormholeEvmChain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 6, "depth": 2, "title": "Events", "anchor": "events", "start_char": 3906, "end_char": 3917, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Events"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 7, "depth": 3, "title": "NotPaused", "anchor": "notpaused", "start_char": 3917, "end_char": 4285, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "### NotPaused\n\nEmitted when the contract is unpaused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent NotPaused(bool notPaused)\n```\n\n??? interface \"Parameters\"\n\n    `notPaused` ++\"bool\"++\n\n    Whether the contract is not paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 8, "depth": 3, "title": "OwnershipTransferred", "anchor": "ownershiptransferred", "start_char": 4285, "end_char": 4803, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "### OwnershipTransferred\n\nEmitted when ownership is transferred. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent OwnershipTransferred(address indexed previousOwner, address indexed newOwner)\n```\n\n??? interface \"Parameters\"\n\n    `previousOwner` ++\"address\"++\n\n    The address of the previous owner.\n\n    ---\n\n    `newOwner` ++\"address\"++\n\n    The address of the new owner."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 9, "depth": 3, "title": "Paused", "anchor": "paused", "start_char": 4803, "end_char": 5153, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### Paused\n\nEmitted when the contract is paused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent Paused(bool paused)\n```\n\n??? interface \"Parameters\"\n\n    `paused` ++\"bool\"++\n\n    Whether the contract is paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 10, "depth": 3, "title": "PauserTransferred", "anchor": "pausertransferred", "start_char": 5153, "end_char": 5666, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "### PauserTransferred\n\nEmitted when the pauser capability is transferred. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nevent PauserTransferred(address indexed oldPauser, address indexed newPauser)\n```\n\n??? interface \"Parameters\"\n\n    `oldPauser` ++\"address\"++\n\n    The address of the previous pauser.\n\n    ---\n\n    `newPauser` ++\"address\"++\n\n    The address of the new pauser."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 11, "depth": 3, "title": "ReceivedMessage", "anchor": "receivedmessage", "start_char": 5666, "end_char": 6347, "estimated_token_count": 164, "token_estimator": "heuristic-v1", "text": "### ReceivedMessage\n\nEmitted when a message is received. *(Defined in [IWormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nevent ReceivedMessage(\n    bytes32 digest,\n    uint16 emitterChainId,\n    bytes32 emitterAddress,\n    uint64 sequence\n)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the message.\n\n    ---\n\n    `emitterChainId` ++\"uint16\"++\n\n    The chain ID of the emitter.\n\n    ---\n\n    `emitterAddress` ++\"bytes32\"++\n\n    The address of the emitter.\n\n    ---\n\n    `sequence` ++\"uint64\"++\n\n    The sequence of the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 12, "depth": 3, "title": "ReceivedRelayedMessage", "anchor": "receivedrelayedmessage", "start_char": 6347, "end_char": 6957, "estimated_token_count": 143, "token_estimator": "heuristic-v1", "text": "### ReceivedRelayedMessage\n\nEmitted when a relayed message is received. *(Defined in [IWormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nevent ReceivedRelayedMessage(\n    bytes32 digest,\n    uint16 emitterChainId,\n    bytes32 emitterAddress\n)\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++\n\n    The digest of the message.\n\n    ---\n\n    `emitterChainId` ++\"uint16\"++\n\n    The chain ID of the emitter.\n\n    ---\n\n    `emitterAddress` ++\"bytes32\"++\n\n    The address of the emitter."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 13, "depth": 3, "title": "RelayingInfo", "anchor": "relayinginfo", "start_char": 6957, "end_char": 7619, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "### RelayingInfo\n\nEmitted when a message is sent from the transceiver. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nevent RelayingInfo(\n    uint8 relayingType,\n    bytes32 refundAddress,\n    uint256 deliveryPayment\n)\n```\n\n??? interface \"Parameters\"\n\n    `relayingType` ++\"uint8\"++\n\n    The type of relaying.\n\n    ---\n\n    `refundAddress` ++\"bytes32\"++\n\n    The refund address for unused gas.\n\n    ---\n\n    `deliveryPayment` ++\"uint256\"++\n\n    The amount of ether sent along with the tx to cover the delivery fee."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 14, "depth": 3, "title": "SendTransceiverMessage", "anchor": "sendtransceivermessage", "start_char": 7619, "end_char": 8648, "estimated_token_count": 210, "token_estimator": "heuristic-v1", "text": "### SendTransceiverMessage\n\nEmitted when a message is sent from the transceiver. *(Defined in [IWormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nevent SendTransceiverMessage(\n    uint16 recipientChain,\n    TransceiverStructs.TransceiverMessage message\n)\n```\n\n??? interface \"Parameters\"\n\n    `recipientChain` ++\"uint16\"++\n\n    The chain ID of the recipient.\n\n    ---\n\n    `message` ++\"TransceiverStructs.TransceiverMessage\"++\n\n    The message.\n\n    ??? child \"`TransceiverMessage` type\"\n\n        `sourceNttManagerAddress` ++\"bytes32\"++\n\n        The address of the source NTT Manager.\n        \n        ---\n\n        `recipientNttManagerAddress` ++\"bytes32\"++\n\n        The address of the recipient NTT Manager.\n        \n        ---\n\n        `nttManagerPayload` ++\"bytes\"++\n\n        The NTT Manager payload.\n        \n        ---\n\n        `transceiverPayload` ++\"bytes\"++\n\n        The transceiver-specific payload."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 15, "depth": 3, "title": "SetIsSpecialRelayingEnabled", "anchor": "setisspecialrelayingenabled", "start_char": 8648, "end_char": 9205, "estimated_token_count": 126, "token_estimator": "heuristic-v1", "text": "### SetIsSpecialRelayingEnabled\n\nEmitted when special relaying is enabled for the given chain. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nevent SetIsSpecialRelayingEnabled(uint16 chainId, bool isRelayingEnabled)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to set.\n\n    ---\n\n    `isRelayingEnabled` ++\"bool\"++\n\n    A boolean indicating whether special relaying is enabled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 16, "depth": 3, "title": "SetIsWormholeEvmChain", "anchor": "setiswormholeevmchain", "start_char": 9205, "end_char": 9716, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### SetIsWormholeEvmChain\n\nEmitted when the EVM-compatibility flag is set for a chain. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nevent SetIsWormholeEvmChain(uint16 chainId, bool isEvm)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to set.\n\n    ---\n\n    `isEvm` ++\"bool\"++\n\n    A boolean indicating whether relaying is enabled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 17, "depth": 3, "title": "SetIsWormholeRelayingEnabled", "anchor": "setiswormholerelayingenabled", "start_char": 9716, "end_char": 10259, "estimated_token_count": 124, "token_estimator": "heuristic-v1", "text": "### SetIsWormholeRelayingEnabled\n\nEmitted when relaying is enabled for the given chain. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nevent SetIsWormholeRelayingEnabled(uint16 chainId, bool isRelayingEnabled)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to set.\n\n    ---\n\n    `isRelayingEnabled` ++\"bool\"++\n\n    A boolean indicating whether relaying is enabled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 18, "depth": 3, "title": "SetWormholePeer", "anchor": "setwormholepeer", "start_char": 10259, "end_char": 10747, "estimated_token_count": 122, "token_estimator": "heuristic-v1", "text": "### SetWormholePeer\n\nEmitted when a peer transceiver is set. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nevent SetWormholePeer(uint16 chainId, bytes32 peerContract)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `peerContract` ++\"bytes32\"++\n\n    The address of the peer contract."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 19, "depth": 2, "title": "Functions", "anchor": "functions", "start_char": 10747, "end_char": 10761, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Functions"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 20, "depth": 3, "title": "encodeWormholeTransceiverInstruction", "anchor": "encodewormholetransceiverinstruction", "start_char": 10761, "end_char": 11581, "estimated_token_count": 160, "token_estimator": "heuristic-v1", "text": "### encodeWormholeTransceiverInstruction\n\nEncodes the `WormholeTransceiverInstruction` into a byte array. *(Defined in [WormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nfunction encodeWormholeTransceiverInstruction(\n    WormholeTransceiverInstruction memory instruction\n) public pure returns (bytes memory)\n```\n\n??? interface \"Parameters\"\n\n    `instruction` ++\"WormholeTransceiverInstruction\"++\n\n    The `WormholeTransceiverInstruction` to encode.\n\n    ??? child \"`WormholeTransceiverInstruction` type\"\n\n        `shouldSkipRelayerSend` ++\"bool\"++\n\n        Whether to skip delivery via the relayer.\n\n??? interface \"Returns\"\n\n    `encoded` ++\"bytes\"++\n\n    The encoded instruction."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 21, "depth": 3, "title": "getMigratesImmutables", "anchor": "getmigratesimmutables", "start_char": 11581, "end_char": 12018, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### getMigratesImmutables\n\nReturns whether the contract migrates immutables during upgrades. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction getMigratesImmutables() public view returns (bool)\n```\n\n??? interface \"Returns\"\n\n    `migratesImmutables` ++\"bool\"++\n\n    Whether the contract migrates immutables."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 22, "depth": 3, "title": "getNttManagerOwner", "anchor": "getnttmanagerowner", "start_char": 12018, "end_char": 12450, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "### getNttManagerOwner\n\nReturns the owner address of the NTT Manager that this transceiver is related to. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction getNttManagerOwner() public view returns (address)\n```\n\n??? interface \"Returns\"\n\n    `owner` ++\"address\"++\n\n    The owner address of the NTT Manager."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 23, "depth": 3, "title": "getNttManagerToken", "anchor": "getnttmanagertoken", "start_char": 12450, "end_char": 12866, "estimated_token_count": 107, "token_estimator": "heuristic-v1", "text": "### getNttManagerToken\n\nReturns the address of the token associated with this NTT deployment. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction getNttManagerToken() public view virtual returns (address)\n```\n\n??? interface \"Returns\"\n\n    `token` ++\"address\"++\n\n    The address of the token."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 24, "depth": 3, "title": "getTransceiverType", "anchor": "gettransceivertype", "start_char": 12866, "end_char": 13323, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "### getTransceiverType\n\nReturns the string type of the transceiver. *(Defined in [WormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nfunction getTransceiverType() external pure returns (string memory)\n```\n\n??? interface \"Returns\"\n\n    `transceiverType` ++\"string\"++\n\n    The type of the transceiver (e.g., \"wormhole\")."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 25, "depth": 3, "title": "getWormholePeer", "anchor": "getwormholepeer", "start_char": 13323, "end_char": 13886, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### getWormholePeer\n\nReturns the peer contract address for a given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction getWormholePeer(uint16 chainId) public view returns (bytes32)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to query.\n\n??? interface \"Returns\"\n\n    `peerContract` ++\"bytes32\"++\n\n    The address of the peer contract on the given chain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 26, "depth": 3, "title": "initialize", "anchor": "initialize", "start_char": 13886, "end_char": 14196, "estimated_token_count": 79, "token_estimator": "heuristic-v1", "text": "### initialize\n\nInitializes the contract implementation. Only callable through a delegate call. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction initialize() external payable\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 27, "depth": 3, "title": "isPaused", "anchor": "ispaused", "start_char": 14196, "end_char": 14579, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### isPaused\n\nReturns whether the contract is currently paused. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction isPaused() public view returns (bool)\n```\n\n??? interface \"Returns\"\n\n    `paused` ++\"bool\"++\n\n    Whether the contract is paused."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 28, "depth": 3, "title": "isSpecialRelayingEnabled", "anchor": "isspecialrelayingenabled", "start_char": 14579, "end_char": 15145, "estimated_token_count": 132, "token_estimator": "heuristic-v1", "text": "### isSpecialRelayingEnabled\n\nReturns whether special relaying is enabled for a given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction isSpecialRelayingEnabled(uint16 chainId) public view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to query.\n\n??? interface \"Returns\"\n\n    `isEnabled` ++\"bool\"++\n\n    Whether special relaying is enabled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 29, "depth": 3, "title": "isVAAConsumed", "anchor": "isvaaconsumed", "start_char": 15145, "end_char": 15658, "estimated_token_count": 130, "token_estimator": "heuristic-v1", "text": "### isVAAConsumed\n\nReturns whether a VAA has been consumed. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction isVAAConsumed(bytes32 hash) public view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `hash` ++\"bytes32\"++\n\n    The hash of the VAA.\n\n??? interface \"Returns\"\n\n    `consumed` ++\"bool\"++\n\n    Whether the VAA has been consumed."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 30, "depth": 3, "title": "isWormholeEvmChain", "anchor": "iswormholeevmchain", "start_char": 15658, "end_char": 16188, "estimated_token_count": 130, "token_estimator": "heuristic-v1", "text": "### isWormholeEvmChain\n\nReturns whether a chain is EVM compatible. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction isWormholeEvmChain(uint16 chainId) public view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to query.\n\n??? interface \"Returns\"\n\n    `isEvm` ++\"bool\"++\n\n    Whether the chain is EVM compatible."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 31, "depth": 3, "title": "isWormholeRelayingEnabled", "anchor": "iswormholerelayingenabled", "start_char": 16188, "end_char": 16740, "estimated_token_count": 130, "token_estimator": "heuristic-v1", "text": "### isWormholeRelayingEnabled\n\nReturns whether relaying is enabled for a given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction isWormholeRelayingEnabled(uint16 chainId) public view returns (bool)\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID to query.\n\n??? interface \"Returns\"\n\n    `isEnabled` ++\"bool\"++\n\n    Whether relaying is enabled."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 32, "depth": 3, "title": "migrate", "anchor": "migrate", "start_char": 16740, "end_char": 17058, "estimated_token_count": 83, "token_estimator": "heuristic-v1", "text": "### migrate\n\nMigrates the contract to a new implementation. Only callable during upgrades through a delegate call. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nfunction migrate() external\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 33, "depth": 3, "title": "parseWormholeTransceiverInstruction", "anchor": "parsewormholetransceiverinstruction", "start_char": 17058, "end_char": 17884, "estimated_token_count": 160, "token_estimator": "heuristic-v1", "text": "### parseWormholeTransceiverInstruction\n\nParses the encoded instruction and returns the instruction struct. *(Defined in [WormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nfunction parseWormholeTransceiverInstruction(\n    bytes memory encoded\n) public pure returns (WormholeTransceiverInstruction memory instruction)\n```\n\n??? interface \"Parameters\"\n\n    `encoded` ++\"bytes\"++\n\n    The encoded instruction.\n\n??? interface \"Returns\"\n\n    `instruction` ++\"WormholeTransceiverInstruction\"++\n\n    The parsed `WormholeTransceiverInstruction`.\n\n    ??? child \"`WormholeTransceiverInstruction` type\"\n\n        `shouldSkipRelayerSend` ++\"bool\"++\n\n        Whether to skip delivery via the relayer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 34, "depth": 3, "title": "quoteDeliveryPrice", "anchor": "quotedeliveryprice", "start_char": 17884, "end_char": 18937, "estimated_token_count": 225, "token_estimator": "heuristic-v1", "text": "### quoteDeliveryPrice\n\nFetches the delivery price for a given recipient chain transfer. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction quoteDeliveryPrice(\n    uint16 recipientChain,\n    TransceiverStructs.TransceiverInstruction memory instruction\n) external view returns (uint256)\n```\n\n??? interface \"Parameters\"\n\n    `recipientChain` ++\"uint16\"++\n\n    The Wormhole chain ID of the target chain.\n\n    ---\n\n    `instruction` ++\"TransceiverStructs.TransceiverInstruction\"++\n\n    An additional Instruction provided by the Transceiver to be executed on the recipient chain.\n\n    ??? child \"`TransceiverInstruction` type\"\n\n        `index` ++\"uint8\"++\n\n        The index of the transceiver.\n        \n        ---\n\n        `payload` ++\"bytes\"++\n\n        The instruction payload.\n\n??? interface \"Returns\"\n\n    `deliveryPrice` ++\"uint256\"++\n\n    The cost of delivering a message to the recipient chain, in this chain's native token."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 35, "depth": 3, "title": "owner", "anchor": "owner", "start_char": 18937, "end_char": 19320, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "### owner\n\nReturns the address of the current owner. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction owner() public view returns (address)\n```\n\n??? interface \"Returns\"\n\n    `owner` ++\"address\"++\n\n    The address of the current owner."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 36, "depth": 3, "title": "pauser", "anchor": "pauser", "start_char": 19320, "end_char": 19701, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "### pauser\n\nReturns the address of the current pauser. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction pauser() public view returns (address)\n```\n\n??? interface \"Returns\"\n\n    `pauser` ++\"address\"++\n\n    The address of the current pauser."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 37, "depth": 3, "title": "receiveMessage", "anchor": "receivemessage", "start_char": 19701, "end_char": 20169, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "### receiveMessage\n\nReceives an attested message from the verification layer. *(Defined in [WormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nfunction receiveMessage(bytes memory encodedMessage) external\n```\n\n??? interface \"Parameters\"\n\n    `encodedMessage` ++\"bytes\"++\n\n    The attested message.\n\n> **Emits**: `ReceivedMessage`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 38, "depth": 3, "title": "receiveWormholeMessages", "anchor": "receivewormholemessages", "start_char": 20169, "end_char": 21106, "estimated_token_count": 207, "token_estimator": "heuristic-v1", "text": "### receiveWormholeMessages\n\nReceives and processes Wormhole messages via the relayer. Only callable by the relayer. *(Defined in [WormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nfunction receiveWormholeMessages(\n    bytes memory payload,\n    bytes[] memory additionalMessages,\n    bytes32 sourceAddress,\n    uint16 sourceChain,\n    bytes32 deliveryHash\n) external payable\n```\n\n??? interface \"Parameters\"\n\n    `payload` ++\"bytes\"++\n\n    The message payload.\n\n    ---\n\n    `additionalMessages` ++\"bytes[]\"++\n\n    Additional messages array.\n\n    ---\n\n    `sourceAddress` ++\"bytes32\"++\n\n    The source address of the message.\n\n    ---\n\n    `sourceChain` ++\"uint16\"++\n\n    The source chain ID.\n\n    ---\n\n    `deliveryHash` ++\"bytes32\"++\n\n    The delivery hash.\n\n> **Emits**: `ReceivedRelayedMessage`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 39, "depth": 3, "title": "sendMessage", "anchor": "sendmessage", "start_char": 21106, "end_char": 22462, "estimated_token_count": 279, "token_estimator": "heuristic-v1", "text": "### sendMessage\n\nSends a message to another chain. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction sendMessage(\n    uint16 recipientChain,\n    TransceiverStructs.TransceiverInstruction memory instruction,\n    bytes memory nttManagerMessage,\n    bytes32 recipientNttManagerAddress,\n    bytes32 refundAddress\n) external payable\n```\n\n??? interface \"Parameters\"\n\n    `recipientChain` ++\"uint16\"++\n\n    The Wormhole chain ID of the recipient.\n\n    ---\n\n    `instruction` ++\"TransceiverStructs.TransceiverInstruction\"++\n\n    An additional Instruction provided by the Transceiver to be executed on the recipient chain.\n\n    ??? child \"`TransceiverInstruction` type\"\n\n        `index` ++\"uint8\"++\n\n        The index of the transceiver.\n        \n        ---\n\n        `payload` ++\"bytes\"++\n\n        The instruction payload.\n\n    ---\n\n    `nttManagerMessage` ++\"bytes\"++\n\n    A message to be sent to the nttManager on the recipient chain.\n\n    ---\n\n    `recipientNttManagerAddress` ++\"bytes32\"++\n\n    The Wormhole formatted address of the peer NTT Manager on the recipient chain.\n\n    ---\n\n    `refundAddress` ++\"bytes32\"++\n\n    The Wormhole formatted address of the refund recipient.\n\n> **Emits**: `SendTransceiverMessage`, `RelayingInfo`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 40, "depth": 3, "title": "setIsSpecialRelayingEnabled", "anchor": "setisspecialrelayingenabled-2", "start_char": 22462, "end_char": 23103, "estimated_token_count": 140, "token_estimator": "heuristic-v1", "text": "### setIsSpecialRelayingEnabled\n\nSets whether special relaying is enabled for the given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction setIsSpecialRelayingEnabled(uint16 chainId, bool isRelayingEnabled) external\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The Wormhole chain ID to set.\n\n    ---\n\n    `isRelayingEnabled` ++\"bool\"++\n\n    A boolean indicating whether special relaying is enabled.\n\n> **Emits**: `SetIsSpecialRelayingEnabled`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 41, "depth": 3, "title": "setIsWormholeEvmChain", "anchor": "setiswormholeevmchain-2", "start_char": 23103, "end_char": 23680, "estimated_token_count": 139, "token_estimator": "heuristic-v1", "text": "### setIsWormholeEvmChain\n\nSets whether the chain is EVM compatible. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction setIsWormholeEvmChain(uint16 chainId, bool isEvm) external\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The Wormhole chain ID to set.\n\n    ---\n\n    `isEvm` ++\"bool\"++\n\n    A boolean indicating whether the chain is an EVM chain.\n\n> **Emits**: `SetIsWormholeEvmChain`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 42, "depth": 3, "title": "setIsWormholeRelayingEnabled", "anchor": "setiswormholerelayingenabled-2", "start_char": 23680, "end_char": 24317, "estimated_token_count": 139, "token_estimator": "heuristic-v1", "text": "### setIsWormholeRelayingEnabled\n\nSets whether Wormhole relaying is enabled for the given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction setIsWormholeRelayingEnabled(uint16 chainId, bool isRelayingEnabled) external\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The Wormhole chain ID to set.\n\n    ---\n\n    `isRelayingEnabled` ++\"bool\"++\n\n    A boolean indicating whether relaying is enabled.\n\n> **Emits**: `SetIsWormholeRelayingEnabled`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 43, "depth": 3, "title": "setWormholePeer", "anchor": "setwormholepeer-2", "start_char": 24317, "end_char": 24924, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "### setWormholePeer\n\nSets the Wormhole peer contract for the given chain. *(Defined in [WormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/WormholeTransceiver/WormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nfunction setWormholePeer(uint16 chainId, bytes32 peerContract) external payable\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The Wormhole chain ID of the peer to set.\n\n    ---\n\n    `peerContract` ++\"bytes32\"++\n\n    The address of the peer contract on the given chain.\n\n> **Emits**: `SetWormholePeer`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 44, "depth": 3, "title": "transferOwnership", "anchor": "transferownership", "start_char": 24924, "end_char": 25416, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### transferOwnership\n\nTransfers ownership of the contract to a new account. Can only be called by the current owner. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nfunction transferOwnership(address newOwner) public\n```\n\n??? interface \"Parameters\"\n\n    `newOwner` ++\"address\"++\n\n    The address of the new owner.\n\n> **Emits**: `OwnershipTransferred`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 45, "depth": 3, "title": "transferPauserCapability", "anchor": "transferpausercapability", "start_char": 25416, "end_char": 25861, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "### transferPauserCapability\n\nTransfers the ability to pause to a new account. *(Defined in [PausableOwnable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableOwnable.sol){target=\\_blank})*\n\n```sol\nfunction transferPauserCapability(address newPauser) public\n```\n\n??? interface \"Parameters\"\n\n    `newPauser` ++\"address\"++\n\n    The address of the new pauser.\n\n> **Emits**: `PauserTransferred`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 46, "depth": 3, "title": "transferTransceiverOwnership", "anchor": "transfertransceiverownership", "start_char": 25861, "end_char": 26322, "estimated_token_count": 113, "token_estimator": "heuristic-v1", "text": "### transferTransceiverOwnership\n\nTransfers the ownership of the transceiver to a new address. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction transferTransceiverOwnership(address newOwner) external\n```\n\n??? interface \"Parameters\"\n\n    `newOwner` ++\"address\"++\n\n    The address of the new owner.\n\n> **Emits**: `OwnershipTransferred`"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 47, "depth": 3, "title": "upgrade", "anchor": "upgrade", "start_char": 26322, "end_char": 26729, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### upgrade\n\nUpgrades the transceiver to a new implementation. *(Defined in [Transceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/Transceiver/Transceiver.sol){target=\\_blank})*\n\n```sol\nfunction upgrade(address newImplementation) external\n```\n\n??? interface \"Parameters\"\n\n    `newImplementation` ++\"address\"++\n\n    The address of the new implementation contract."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 48, "depth": 2, "title": "Errors", "anchor": "errors", "start_char": 26729, "end_char": 26740, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Errors"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 49, "depth": 3, "title": "CallerNotNttManager", "anchor": "callernotnttmanager", "start_char": 26740, "end_char": 27102, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "### CallerNotNttManager\n\nThe caller is not the NttManager. *(Defined in [ITransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/ITransceiver.sol){target=\\_blank})*\n\n```sol\nerror CallerNotNttManager(address caller);\n```\n\n??? interface \"Parameters\"\n\n    `caller` ++\"address\"++\n\n    The address of the caller."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 50, "depth": 3, "title": "CallerNotRelayer", "anchor": "callernotrelayer", "start_char": 27102, "end_char": 27466, "estimated_token_count": 95, "token_estimator": "heuristic-v1", "text": "### CallerNotRelayer\n\nThe caller is not the relayer. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror CallerNotRelayer(address caller);\n```\n\n??? interface \"Parameters\"\n\n    `caller` ++\"address\"++\n\n    The caller."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 51, "depth": 3, "title": "CannotRenounceTransceiverOwnership", "anchor": "cannotrenouncetransceiverownership", "start_char": 27466, "end_char": 27897, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "### CannotRenounceTransceiverOwnership\n\nError when trying renounce transceiver ownership. *(Defined in [ITransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/ITransceiver.sol){target=\\_blank})*\n\n```sol\nerror CannotRenounceTransceiverOwnership(address currentOwner);\n```\n\n??? interface \"Parameters\"\n\n    `currentOwner` ++\"address\"++\n\n    The current owner of the transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 52, "depth": 3, "title": "CannotTransferTransceiverOwnership", "anchor": "cannottransfertransceiverownership", "start_char": 27897, "end_char": 28427, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### CannotTransferTransceiverOwnership\n\nError when trying to transfer transceiver ownership. *(Defined in [ITransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/ITransceiver.sol){target=\\_blank})*\n\n```sol\nerror CannotTransferTransceiverOwnership(address currentOwner, address newOwner);\n```\n\n??? interface \"Parameters\"\n\n    `currentOwner` ++\"address\"++\n\n    The current owner of the transceiver.\n\n    ---\n\n    `newOwner` ++\"address\"++\n\n    The new owner of the transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 53, "depth": 3, "title": "InvalidPauser", "anchor": "invalidpauser", "start_char": 28427, "end_char": 28801, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "### InvalidPauser\n\nThe pauser is not a valid pauser account. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror InvalidPauser(address account);\n```\n\n??? interface \"Parameters\"\n\n    `account` ++\"address\"++\n\n    The invalid pauser account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 54, "depth": 3, "title": "InvalidRelayingConfig", "anchor": "invalidrelayingconfig", "start_char": 28801, "end_char": 29202, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### InvalidRelayingConfig\n\nError when the relaying configuration is invalid. *(Defined in [IWormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nerror InvalidRelayingConfig(uint16 chainId);\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID that is invalid."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 55, "depth": 3, "title": "InvalidVaa", "anchor": "invalidvaa", "start_char": 29202, "end_char": 29569, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "### InvalidVaa\n\nError if the VAA is invalid. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror InvalidVaa(string reason);\n```\n\n??? interface \"Parameters\"\n\n    `reason` ++\"string\"++\n\n    The reason the VAA is invalid."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 56, "depth": 3, "title": "InvalidWormholeChainIdZero", "anchor": "invalidwormholechainidzero", "start_char": 29569, "end_char": 29864, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### InvalidWormholeChainIdZero\n\nThe chain ID cannot be zero. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror InvalidWormholeChainIdZero();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 57, "depth": 3, "title": "InvalidWormholePeer", "anchor": "invalidwormholepeer", "start_char": 29864, "end_char": 30352, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### InvalidWormholePeer\n\nError when the peer transceiver is invalid. *(Defined in [IWormholeTransceiver.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiver.sol){target=\\_blank})*\n\n```sol\nerror InvalidWormholePeer(uint16 chainId, bytes32 peerAddress);\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `peerAddress` ++\"bytes32\"++\n\n    The address of the invalid peer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 58, "depth": 3, "title": "InvalidWormholePeerZeroAddress", "anchor": "invalidwormholepeerzeroaddress", "start_char": 30352, "end_char": 30678, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "### InvalidWormholePeerZeroAddress\n\nError the peer contract cannot be the zero address. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror InvalidWormholePeerZeroAddress();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 59, "depth": 3, "title": "NotMigrating", "anchor": "notmigrating", "start_char": 30678, "end_char": 30934, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### NotMigrating\n\nThe contract is not currently migrating. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nerror NotMigrating();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 60, "depth": 3, "title": "OnlyDelegateCall", "anchor": "onlydelegatecall", "start_char": 30934, "end_char": 31208, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### OnlyDelegateCall\n\nFunction can only be called through delegate call. *(Defined in [Implementation.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/Implementation.sol){target=\\_blank})*\n\n```sol\nerror OnlyDelegateCall();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 61, "depth": 3, "title": "OwnableInvalidOwner", "anchor": "ownableinvalidowner", "start_char": 31208, "end_char": 31594, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "### OwnableInvalidOwner\n\nThe owner is not a valid owner account. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror OwnableInvalidOwner(address owner);\n```\n\n??? interface \"Parameters\"\n\n    `owner` ++\"address\"++\n\n    The invalid owner address."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 62, "depth": 3, "title": "OwnableUnauthorizedAccount", "anchor": "ownableunauthorizedaccount", "start_char": 31594, "end_char": 32019, "estimated_token_count": 102, "token_estimator": "heuristic-v1", "text": "### OwnableUnauthorizedAccount\n\nThe caller account is not authorized to perform an operation. *(Defined in [OwnableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/external/OwnableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror OwnableUnauthorizedAccount(address account);\n```\n\n??? interface \"Parameters\"\n\n    `account` ++\"address\"++\n\n    The unauthorized account."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 63, "depth": 3, "title": "RequireContractIsNotPaused", "anchor": "requirecontractisnotpaused", "start_char": 32019, "end_char": 32324, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### RequireContractIsNotPaused\n\nContract is not paused, functionality is unblocked. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror RequireContractIsNotPaused();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 64, "depth": 3, "title": "RequireContractIsPaused", "anchor": "requirecontractispaused", "start_char": 32324, "end_char": 32621, "estimated_token_count": 74, "token_estimator": "heuristic-v1", "text": "### RequireContractIsPaused\n\nContract state is paused, blocking functionality. *(Defined in [PausableUpgradeable.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/libraries/PausableUpgradeable.sol){target=\\_blank})*\n\n```sol\nerror RequireContractIsPaused();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 65, "depth": 3, "title": "PeerAlreadySet", "anchor": "peeralreadyset", "start_char": 32621, "end_char": 33097, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### PeerAlreadySet\n\nError if the peer has already been set. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror PeerAlreadySet(uint16 chainId, bytes32 peerAddress);\n```\n\n??? interface \"Parameters\"\n\n    `chainId` ++\"uint16\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `peerAddress` ++\"bytes32\"++\n\n    The address of the peer."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 66, "depth": 3, "title": "UnexpectedAdditionalMessages", "anchor": "unexpectedadditionalmessages", "start_char": 33097, "end_char": 33404, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "### UnexpectedAdditionalMessages\n\nAdditional messages are not allowed. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror UnexpectedAdditionalMessages();\n```"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 67, "depth": 3, "title": "TransferAlreadyCompleted", "anchor": "transferalreadycompleted", "start_char": 33404, "end_char": 33832, "estimated_token_count": 100, "token_estimator": "heuristic-v1", "text": "### TransferAlreadyCompleted\n\nThe transfer has already been completed. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror TransferAlreadyCompleted(bytes32 digest);\n```\n\n??? interface \"Parameters\"\n\n    `digest` ++\"bytes32\"++  \n\n    The digest of the completed transfer message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 68, "depth": 3, "title": "UnexpectedRecipientNttManagerAddress", "anchor": "unexpectedrecipientnttmanageraddress", "start_char": 33832, "end_char": 34386, "estimated_token_count": 112, "token_estimator": "heuristic-v1", "text": "### UnexpectedRecipientNttManagerAddress\n\nThe recipient NTT Manager address in the message does not match this transceiver’s NTT Manager. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror UnexpectedRecipientNttManagerAddress(bytes32 recipientNttManagerAddress);\n```\n\n??? interface \"Parameters\"\n\n    `recipientNttManagerAddress` ++\"bytes32\"++  \n\n    The unexpected NTT Manager address from the message."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-evm", "page_title": "Native Token Transfers Transceivers Contracts (EVM)", "index": 69, "depth": 3, "title": "InvalidFork", "anchor": "invalidfork", "start_char": 34386, "end_char": 34967, "estimated_token_count": 135, "token_estimator": "heuristic-v1", "text": "### InvalidFork\n\nThe current EVM chain ID does not match the stored chain ID, indicating a possible fork. *(Defined in [IWormholeTransceiverState.sol](https://github.com/wormhole-foundation/native-token-transfers/blob/main/evm/src/interfaces/IWormholeTransceiverState.sol){target=\\_blank})*\n\n```sol\nerror InvalidFork(uint256 expectedChainId, uint256 actualChainId);\n```\n\n??? interface \"Parameters\"\n\n    `expectedChainId` ++\"uint256\"++  \n\n    The chain ID stored at deployment.  \n\n    ---  \n\n    `actualChainId` ++\"uint256\"++  \n\n    The chain ID returned by the current network."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 0, "depth": 2, "title": "Structure Overview", "anchor": "structure-overview", "start_char": 304, "end_char": 1397, "estimated_token_count": 202, "token_estimator": "heuristic-v1", "text": "## Structure Overview\n\nThe NTT Transceiver system on Solana is implemented as a standalone Anchor program that provides Wormhole-based message verification and relay capabilities. The transceiver acts as a bridge between the NTT Manager and the Wormhole protocol, handling cross-chain message transmission and verification.\n\n```text\nNTT Transceiver Program\n├── Wormhole Integration\n│   ├── Message Transmission\n│   ├── Message Reception & Verification  \n│   ├── Peer Management\n│   └── Broadcasting Capabilities\n├── Admin Functions\n└── Message Processing\n```\n\n**Key Components:**\n\n- **NTT Transceiver Program**: Transmits, receives, and verifies NTT messages between chains, integrating with the Wormhole messaging layer.\n- **Wormhole Integration**: Enables native message transmission, reception, and verification using the Wormhole protocol.\n- **Administrative Functions**: Provides interfaces for setting up peer configurations and managing broadcast behavior.\n- **Message Processing**: Automatically processes inbound and outbound messages and forwards valid messages to the NTT Manager."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 1, "depth": 2, "title": "State Accounts", "anchor": "state-accounts", "start_char": 1397, "end_char": 1614, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "## State Accounts\n\n`TransceiverPeer` ++\"account (PDA: 'transceiver_peer')\"++: Per-chain peer entry for the Wormhole transceiver path; stores the peer transceiver `address` (wormhole-formatted `[u8; 32]`) and `bump`."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 2, "depth": 2, "title": "Instructions", "anchor": "instructions", "start_char": 1614, "end_char": 1631, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Instructions"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 3, "depth": 3, "title": "broadcast_wormhole_id", "anchor": "broadcast_wormhole_id", "start_char": 1631, "end_char": 3058, "estimated_token_count": 337, "token_estimator": "heuristic-v1", "text": "### broadcast_wormhole_id\n\nBroadcasts the transceiver ID via Wormhole to announce presence on the network. *(Defined in ntt-transceiver)*\n\n```rust\npub fn broadcast_wormhole_id(ctx: Context<BroadcastId>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for the broadcast transaction.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The NTT Manager configuration account.\n\n    ---\n\n    `mint` ++\"InterfaceAccount<Mint>\"++\n\n    The mint account for the managed token.\n\n    ---\n\n    `wormhole_bridge` ++\"mut Account<BridgeData>\"++\n\n    The Wormhole bridge data account.\n\n    ---\n\n    `wormhole_message` ++\"mut Signer\"++\n\n    The Wormhole message account to create.\n\n    ---\n\n    `wormhole_emitter` ++\"Account<EmitterData>\"++\n\n    The Wormhole emitter account.\n\n    ---\n\n    `wormhole_sequence` ++\"mut Account<SequenceData>\"++\n\n    The Wormhole sequence tracking account.\n\n    ---\n\n    `wormhole_fee_collector` ++\"mut Account<FeeCollectorData>\"++\n\n    The Wormhole fee collector account.\n\n    ---\n\n    `clock` ++\"Sysvar<Clock>\"++\n\n    The clock sysvar.\n\n    ---\n\n    `rent` ++\"Sysvar<Rent>\"++\n\n    The rent sysvar.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program.\n\n    ---\n\n    `ntt_program` ++\"Program<NttProgram>\"++\n\n    The NTT Manager program.\n\n    ---\n\n    `wormhole_program` ++\"Program<WormholeProgram>\"++\n\n    The Wormhole core bridge program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 4, "depth": 3, "title": "broadcast_wormhole_peer", "anchor": "broadcast_wormhole_peer", "start_char": 3058, "end_char": 4752, "estimated_token_count": 386, "token_estimator": "heuristic-v1", "text": "### broadcast_wormhole_peer\n\nBroadcasts peer transceiver information via Wormhole. *(Defined in ntt-transceiver)*\n\n```rust\npub fn broadcast_wormhole_peer(\n    ctx: Context<BroadcastPeer>,\n    args: BroadcastPeerArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"BroadcastPeerArgs\"++\n\n    The broadcast peer arguments.\n\n    ??? child \"`BroadcastPeerArgs` type\"\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID to broadcast peer information for.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for the broadcast transaction.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The NTT Manager configuration account.\n\n    ---\n\n    `peer` ++\"Account<TransceiverPeer>\"++\n\n    The peer transceiver account containing peer information.\n\n    ---\n\n    `wormhole_bridge` ++\"mut Account<BridgeData>\"++\n\n    The Wormhole bridge data account.\n\n    ---\n\n    `wormhole_message` ++\"mut Signer\"++\n\n    The Wormhole message account to create.\n\n    ---\n\n    `wormhole_emitter` ++\"Account<EmitterData>\"++\n\n    The Wormhole emitter account.\n\n    ---\n\n    `wormhole_sequence` ++\"mut Account<SequenceData>\"++\n\n    The Wormhole sequence tracking account.\n\n    ---\n\n    `wormhole_fee_collector` ++\"mut Account<FeeCollectorData>\"++\n\n    The Wormhole fee collector account.\n\n    ---\n\n    `clock` ++\"Sysvar<Clock>\"++\n\n    The clock sysvar.\n\n    ---\n\n    `rent` ++\"Sysvar<Rent>\"++\n\n    The rent sysvar.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program.\n\n    ---\n\n    `ntt_program` ++\"Program<NttProgram>\"++\n\n    The NTT Manager program.\n\n    ---\n\n    `wormhole_program` ++\"Program<WormholeProgram>\"++\n\n    The Wormhole core bridge program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 5, "depth": 3, "title": "receive_wormhole_message", "anchor": "receive_wormhole_message", "start_char": 4752, "end_char": 5674, "estimated_token_count": 211, "token_estimator": "heuristic-v1", "text": "### receive_wormhole_message\n\nReceives and processes an inbound message from Wormhole. *(Defined in ntt-transceiver)*\n\n```rust\npub fn receive_wormhole_message(ctx: Context<ReceiveMessage>) -> Result<()>\n```\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for message processing.\n\n    ---\n\n    `config` ++\"mut Account<Config>\"++\n\n    The NTT Manager configuration account.\n\n    ---\n\n    `peer` ++\"Account<TransceiverPeer>\"++\n\n    The peer transceiver account for verification.\n\n    ---\n\n    `vaa` ++\"Account<PostedVaa<TransceiverMessage>>\"++\n\n    The verified VAA (Verifiable Action Approval) containing the message.\n\n    ---\n\n    `transceiver_message` ++\"mut UncheckedAccount\"++\n\n    The transceiver message account to create.\n\n    ---\n\n    `ntt_program` ++\"Program<NttProgram>\"++\n\n    The NTT Manager program.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 6, "depth": 3, "title": "release_wormhole_outbound", "anchor": "release_wormhole_outbound", "start_char": 5674, "end_char": 7573, "estimated_token_count": 427, "token_estimator": "heuristic-v1", "text": "### release_wormhole_outbound\n\nReleases an outbound message via Wormhole. *(Defined in ntt-transceiver)*\n\n```rust\npub fn release_wormhole_outbound(\n    ctx: Context<ReleaseOutbound>,\n    args: ReleaseOutboundArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"ReleaseOutboundArgs\"++\n\n    The release outbound arguments.\n\n    ??? child \"`ReleaseOutboundArgs` type\"\n\n        `recipient_chain` ++\"ChainId\"++\n\n        The chain ID of the recipient chain.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for the release transaction.\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The NTT Manager configuration account.\n\n    ---\n\n    `outbox_item` ++\"mut Account<OutboxItem>\"++\n\n    The outbox item to be released.\n\n    ---\n\n    `registered_transceiver` ++\"Account<RegisteredTransceiver>\"++\n\n    The registered transceiver account.\n\n    ---\n\n    `transceiver_message` ++\"mut UncheckedAccount\"++\n\n    The transceiver message account to create.\n\n    ---\n\n    `wormhole_bridge` ++\"mut Account<BridgeData>\"++\n\n    The Wormhole bridge data account.\n\n    ---\n\n    `wormhole_message` ++\"mut Signer\"++\n\n    The Wormhole message account to create.\n\n    ---\n\n    `wormhole_emitter` ++\"Account<EmitterData>\"++\n\n    The Wormhole emitter account.\n\n    ---\n\n    `wormhole_sequence` ++\"mut Account<SequenceData>\"++\n\n    The Wormhole sequence tracking account.\n\n    ---\n\n    `wormhole_fee_collector` ++\"mut Account<FeeCollectorData>\"++\n\n    The Wormhole fee collector account.\n\n    ---\n\n    `clock` ++\"Sysvar<Clock>\"++\n\n    The clock sysvar.\n\n    ---\n\n    `rent` ++\"Sysvar<Rent>\"++\n\n    The rent sysvar.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program.\n\n    ---\n\n    `ntt_program` ++\"Program<NttProgram>\"++\n\n    The NTT Manager program.\n\n    ---\n\n    `wormhole_program` ++\"Program<WormholeProgram>\"++\n\n    The Wormhole core bridge program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 7, "depth": 3, "title": "set_wormhole_peer", "anchor": "set_wormhole_peer", "start_char": 7573, "end_char": 8676, "estimated_token_count": 264, "token_estimator": "heuristic-v1", "text": "### set_wormhole_peer\n\nSets or updates a peer transceiver on another chain. *(Defined in ntt-transceiver)*\n\n```rust\npub fn set_wormhole_peer(\n    ctx: Context<SetTransceiverPeer>,\n    args: SetTransceiverPeerArgs\n) -> Result<()>\n```\n\n??? interface \"Parameters\"\n\n    `args` ++\"SetTransceiverPeerArgs\"++\n\n    The transceiver peer arguments.\n\n    ??? child \"`SetTransceiverPeerArgs` type\"\n\n        `chain_id` ++\"ChainId\"++\n\n        The chain ID of the peer.\n\n        ---\n\n        `address` ++\"[u8; 32]\"++\n\n        The address of the peer transceiver.\n\n??? interface \"Accounts\"\n\n    `payer` ++\"mut Signer\"++\n\n    The account paying for peer configuration.\n\n    ---\n\n    `owner` ++\"Signer\"++\n\n    The owner of the NTT Manager (must authorize peer changes).\n\n    ---\n\n    `config` ++\"Account<Config>\"++\n\n    The NTT Manager configuration account.\n\n    ---\n\n    `peer` ++\"mut Account<TransceiverPeer>\"++\n\n    The peer account to create or update.\n\n    ---\n\n    `system_program` ++\"Program<System>\"++\n\n    The system program.\n\n    ---\n\n    `ntt_program` ++\"Program<NttProgram>\"++\n\n    The NTT Manager program."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 8, "depth": 3, "title": "transceiver_type", "anchor": "transceiver_type", "start_char": 8676, "end_char": 9049, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "### transceiver_type\n\nReturns the type identifier for this transceiver. *(Defined in ntt-transceiver)*\n\n```rust\npub fn transceiver_type(_ctx: Context<TransceiverType>) -> Result<String>\n```\n\n??? interface \"Returns\"\n\n    `transceiver_type` ++\"String\"++\n\n    The transceiver type identifier (\"wormhole\").\n\n??? interface \"Accounts\"\n\n    No accounts required (empty context)."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 9, "depth": 2, "title": "Data Structures", "anchor": "data-structures", "start_char": 9049, "end_char": 9069, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## Data Structures"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 10, "depth": 3, "title": "TransceiverPeer", "anchor": "transceiverpeer", "start_char": 9069, "end_char": 9458, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "### TransceiverPeer\n\nStores information about a peer transceiver on another chain. *(Defined in peer.rs)*\n\n```rust\npub struct TransceiverPeer {\n    pub bump: u8,\n    pub address: [u8; 32],\n}\n```\n\n??? interface \"Fields\"\n\n    bump ++\"u8\"++\n    \n    The canonical bump for the peer account.\n\n    ---\n\n    `address` ++\"[u8; 32]\"++\n\n    The wormhole-formatted address of the peer transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 11, "depth": 3, "title": "TransceiverMessage", "anchor": "transceivermessage", "start_char": 9458, "end_char": 10166, "estimated_token_count": 167, "token_estimator": "heuristic-v1", "text": "### TransceiverMessage\n\nThe message format used for cross-chain communication. *(Defined in messages.rs)*\n\n```rust\npub struct TransceiverMessage<P> {\n    pub source_ntt_manager: [u8; 32],\n    pub recipient_ntt_manager: [u8; 32],\n    pub ntt_manager_payload: P,\n    pub transceiver_payload: Vec<u8>,\n}\n```\n\n??? interface \"Fields\"\n\n    `source_ntt_manager` ++\"[u8; 32]\"++\n\n    The address of the source NTT Manager.\n\n    ---\n\n    `recipient_ntt_manager` ++\"[u8; 32]\"++\n\n    The address of the recipient NTT Manager.\n\n    ---\n\n    `ntt_manager_payload` ++\"P\"++\n\n    The payload specific to the NTT Manager.\n\n    ---\n\n    `transceiver_payload` ++\"Vec<u8>\"++\n\n    Additional payload specific to the transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 12, "depth": 3, "title": "ChainId", "anchor": "chainid", "start_char": 10166, "end_char": 10361, "estimated_token_count": 57, "token_estimator": "heuristic-v1", "text": "### ChainId\n\nA Wormhole chain identifier. *(Defined in ntt-messages)*\n\n```rust\npub struct ChainId {\n    pub id: u16,\n}\n```\n\n??? interface \"Fields\"\n\n    `id` ++\"u16\"++\n\n    The numeric chain ID."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 13, "depth": 3, "title": "BroadcastPeerArgs", "anchor": "broadcastpeerargs", "start_char": 10361, "end_char": 10643, "estimated_token_count": 62, "token_estimator": "heuristic-v1", "text": "### BroadcastPeerArgs\n\nArguments for broadcasting peer information. *(Defined in broadcast_peer.rs)*\n\n```rust\npub struct BroadcastPeerArgs {\n    pub chain_id: ChainId,\n}\n```\n\n??? interface \"Fields\"\n\n    `chain_id` ++\"ChainId\"++\n\n    The chain ID to broadcast peer information for."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 14, "depth": 3, "title": "ReleaseOutboundArgs", "anchor": "releaseoutboundargs", "start_char": 10643, "end_char": 10932, "estimated_token_count": 61, "token_estimator": "heuristic-v1", "text": "### ReleaseOutboundArgs\n\nArguments for releasing outbound messages. *(Defined in release_outbound.rs)*\n\n```rust\npub struct ReleaseOutboundArgs {\n    pub recipient_chain: ChainId,\n}\n```\n\n??? interface \"Fields\"\n\n    `recipient_chain` ++\"ChainId\"++\n\n    The chain ID of the recipient chain."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 15, "depth": 3, "title": "SetTransceiverPeerArgs", "anchor": "settransceiverpeerargs", "start_char": 10932, "end_char": 11297, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "### SetTransceiverPeerArgs\n\nArguments for setting transceiver peers. *(Defined in admin.rs)*\n\n```rust\npub struct SetTransceiverPeerArgs {\n    pub chain_id: ChainId,\n    pub address: [u8; 32],\n}\n```\n\n??? interface \"Fields\"\n\n    `chain_id` ++\"ChainId\"++\n\n    The chain ID of the peer.\n\n    ---\n\n    `address` ++\"[u8; 32]\"++\n\n    The address of the peer transceiver."}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 16, "depth": 2, "title": "Constants", "anchor": "constants", "start_char": 11297, "end_char": 11311, "estimated_token_count": 3, "token_estimator": "heuristic-v1", "text": "## Constants"}
{"page_id": "products-token-transfers-native-token-transfers-reference-transceivers-solana", "page_title": "Native Token Transfers Transceiver Program (Solana)", "index": 17, "depth": 3, "title": "TRANSCEIVER_TYPE", "anchor": "transceiver_type-2", "start_char": 11311, "end_char": 11472, "estimated_token_count": 39, "token_estimator": "heuristic-v1", "text": "### TRANSCEIVER_TYPE\n\nThe type identifier for this transceiver implementation. *(Defined in lib.rs)*\n\n```rust\npub const TRANSCEIVER_TYPE: &str = \"wormhole\";\n```"}
{"page_id": "products-token-transfers-overview", "page_title": "Token Transfers Overview", "index": 0, "depth": 2, "title": "Token Transfers Overview", "anchor": "token-transfers-overview", "start_char": 0, "end_char": 637, "estimated_token_count": 148, "token_estimator": "heuristic-v1", "text": "## Token Transfers Overview\n\nWormhole Token Transfers let you move assets seamlessly across chains. Developers can choose between [Native Token Transfers (NTT)](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}, which enable direct movement of native tokens, or [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}, which use a lock-and-mint model for broad compatibility. Both approaches are secured by the Wormhole [Guardians](/docs/protocol/infrastructure/guardians/){target=\\_blank} and integrate with the same cross-chain messaging layer."}
{"page_id": "products-token-transfers-overview", "page_title": "Token Transfers Overview", "index": 1, "depth": 2, "title": "How Token Transfers Work", "anchor": "how-token-transfers-work", "start_char": 637, "end_char": 1603, "estimated_token_count": 260, "token_estimator": "heuristic-v1", "text": "## How Token Transfers Work\n\nBoth NTT and WTT rely on Guardian-signed messages ([VAAs](/docs/protocol/infrastructure/vaas/){target=\\_blank}) to transfer tokens across chains securely. The difference lies in how tokens are represented on the destination chain.\n\nAt a high level, the flow looks like this:\n\n1. A user sends tokens to the Wormhole contract on the source chain.\n2. The contract emits a message, which the Guardians sign as a VAA.\n3. The VAA is submitted to the destination chain.\n4. Depending on the transfer type:\n    - **NTT**: Tokens are minted or released from escrow.\n    - **WTT**: Wrapped tokens are minted to the recipient’s wallet.\n\n```mermaid\nflowchart LR\n    A[User] --> B[Source chain<br/>Wormhole contract]\n    B --> C[Guardians<br/>sign VAA]\n    C --> D[Destination chain<br/>Wormhole contract]\n    D -->|NTT| E[Mint or release<br/>native tokens]\n    D -->|WTT| F[Mint wrapped<br/>tokens]\n    E --> G[Recipient]\n    F --> G[Recipient]\n```"}
{"page_id": "products-token-transfers-overview", "page_title": "Token Transfers Overview", "index": 2, "depth": 2, "title": "Choosing Between NTT and WTT", "anchor": "choosing-between-ntt-and-wtt", "start_char": 1603, "end_char": 7315, "estimated_token_count": 1181, "token_estimator": "heuristic-v1", "text": "## Choosing Between NTT and WTT\n\nWormhole provides two distinct mechanisms for transferring assets cross-chain: [Native Token Transfers (NTT)](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank} and [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}. Both options offer distinct integration paths and feature sets tailored to your requirements, as outlined below.\n\nChoosing between the two models comes down to trade-offs. NTT offers an adaptable, upgradable, and customizable framework that enables teams to retain ownership and define policies across chains. WTT provides the most straightforward and permissionless path, but wrapped token contracts are managed by Wormhole Governance, with no ownership transfer or contract upgradeability possible.\n\n| Feature                | Native Token Transfers                                                                                                                                                               | Wrapped Token Transfers                                                                                                                                                                       |\n|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| **Best for**           | DeFi governance, native assets with multichain liquidity, stablecoins, institutional use cases, and projects that want full control of their cross-chain token                       | Consumer apps, games, wrapped-token use cases, and projects that want a fast, managed bridging solution                                                                                       |\n| **Mechanism**          | Burn-and-mint or hub-and-spoke                                                                                                                                                       | Lock-and-mint                                                                                                                                                                                 |\n| **Security**           | Configurable rate limiting, pausing, access control, threshold attestations. Integrated Global Accountant                                                                            | Preconfigured rate limiting and integrated Global Accountant                                                                                                                                  |\n| **Contract Ownership** | User retains ownership and upgrade authority on each chain                                                                                                                           | Managed via Wormhole Governance; wrapped token contracts are controlled by WTT (ownership is not transferable, and integrators cannot upgrade wrapped contracts)                              |\n| **Token Contracts**    | Native contracts owned by your protocol governance, maintain the same token across chains                                                                                            | Wrapped asset contract owned by the Wormhole WTT contract, creates a new wrapped version on the destination chain                                                                             |\n| **Integration**        | Customizable, flexible framework for advanced deployments                                                                                                                            | Straightforward, permissionless deployment                                                                                                                                                    |\n| **User Experience**    | Seamless, users interact with the same token everywhere                                                                                                                              | Wrapped assets may need [explorer metadata updates](/docs/products/token-transfers/wrapped-token-transfers/faqs/#how-do-i-update-the-metadata-of-a-wrapped-token){target=\\_blank} for clarity |\n| **Examples**           | [NTT Connect](https://github.com/wormhole-foundation/demo-ntt-connect){target=\\_blank}, [NTT TypeScript SDK](https://github.com/wormhole-foundation/demo-ntt-ts-sdk){target=\\_blank} | [Portal Bridge UI](https://portalbridge.com/){target=\\_blank}                                                                                                                                 |\n\n!!! note \"Terminology\"\n    In the SDK and smart contracts, Wrapped Token Transfers (WTT) are referred to as Token Bridge. In documentation, we use WTT for clarity. Both terms describe the same protocol.\n\nIn the following video, Wormhole Foundation DevRel Pauline Barnades walks you through the key differences between Wormhole’s Native Token Transfers (NTT) and Wrapped Token Transfers (WTT) and how to select the best option for your use case:\n\n<style>.embed-container { position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden; max-width: 100%; } .embed-container iframe, .embed-container object, .embed-container embed { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }</style><div class='embed-container'><iframe src='https://www.youtube.com/embed/Mqpu7oWBz2A' frameborder='0' allowfullscreen></iframe></div>"}
{"page_id": "products-token-transfers-overview", "page_title": "Token Transfers Overview", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 7315, "end_char": 7957, "estimated_token_count": 168, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nIf you are looking for more guided practice, take a look at:\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with NTT**\n\n    ---\n\n    Learn how to deploy and register contracts to transfer native tokens across chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/native-token-transfers/get-started/)\n\n-   :octicons-book-16:{ .lg .middle } **Get Started with WTT**\n\n    ---\n\n    Perform token transfers using WTT, including manual and automatic transfers.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/get-started/)\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 0, "depth": 2, "title": "Transfer", "anchor": "transfer", "start_char": 805, "end_char": 2414, "estimated_token_count": 366, "token_estimator": "heuristic-v1", "text": "## Transfer\n\nThe `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.\n\n```text\nPayloadID uint8 = 1\nAmount uint256\nTokenAddress bytes32\nTokenChain uint16\nTo bytes32\nToChain uint16\nFee uint256\n```\n\n??? interface \"Parameters\"\n\n    `PayloadID` ++\"uint8\"++\n\n    Value must be `1`, indicating a `Transfer` operation.\n\n    ---\n\n    `Amount` ++\"uint256\"++\n\n    Amount being transferred, truncated to 8 decimals for consistency across all chains.\n\n    ---\n\n    `TokenAddress` ++\"bytes32\"++\n\n    Address of the token. Left-zero-padded if shorter than 32 bytes.\n    \n    ---\n\n    `TokenChain` ++\"uint16\"++\n\n    Chain ID of the token.\n    \n    ---\n\n    `To` ++\"bytes32\"++\n\n    Address of the recipient. Left-zero-padded if shorter than 32 bytes.\n    \n    ---\n\n    `ToChain` ++\"uint16\"++\n\n    Chain ID of the recipient.\n    \n    ---\n\n    `Fee` ++\"uint256\"++\n\n    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.\n   \n\nTo 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 1, "depth": 2, "title": "AssetMeta", "anchor": "assetmeta", "start_char": 2414, "end_char": 3378, "estimated_token_count": 251, "token_estimator": "heuristic-v1", "text": "## AssetMeta\n\nBefore 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.\n\n```text\nPayloadID uint8 = 2\nTokenAddress [32]uint8\nTokenChain uint16\nDecimals uint8\nSymbol [32]uint8\nName [32]uint8\n```\n\n??? interface \"Parameters\"\n\n    `PayloadID` ++\"uint8\"++\n\n    Value must be `2`, indicating an `AssetMeta` operation.\n\n    ---\n\n    `TokenAddress` ++\"[32]uint8\"++\n\n    Address of the token. Left-zero-padded if shorter than 32 bytes.\n\n    ---\n\n    `TokenChain` ++\"uint16\"++\n\n    Chain ID of the token.\n\n    ---\n\n    `Decimals` ++\"uint8\"++\n\n    Number of decimals the token uses on its native chain (not truncated to 8 decimal places).\n\n    ---\n\n    `Symbol` ++\"[32]uint8\"++\n\n    Symbol of the token, UTF-8 encoded and padded to 32 bytes.\n\n    ---\n\n    `Name` ++\"[32]uint8\"++\n\n    Name of the token, UTF-8 encoded and padded to 32 bytes."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 2, "depth": 2, "title": "TransferWithPayload", "anchor": "transferwithpayload", "start_char": 3378, "end_char": 4841, "estimated_token_count": 316, "token_estimator": "heuristic-v1", "text": "## TransferWithPayload\n\nThe `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.\n\n```text\nPayloadID uint8 = 3\nAmount uint256\nTokenAddress bytes32\nTokenChain uint16\nTo bytes32\nToChain uint16\nFromAddress bytes32\nPayload bytes\n```\n\n??? interface \"Parameters\"\n\n    `PayloadID` ++\"uint8\"++\n\n    Value must be `3`, indicating a `TransferWithPayload` operation.\n\n    ---\n\n    `Amount` ++\"uint256\"++\n\n    Amount being transferred, truncated to 8 decimals.\n\n    ---\n\n    `TokenAddress` ++\"bytes32\"++\n\n    Address of the token. Left-zero-padded if shorter than 32 bytes. \n\n    ---\n\n    `TokenChain` ++\"uint16\"++\n\n    Chain ID of the token.\n\n    ---\n\n    `To` ++\"bytes32\"++\n\n    Address of the recipient. Must be a contract capable of parsing and handling the payload. Left-zero-padded if shorter than 32 bytes.\n\n    ---\n\n    `ToChain` ++\"uint16\"++\n\n    Chain ID of the recipient.\n\n    ---\n\n    `FromAddress` ++\"bytes32\"++\n\n    Address of the sender on the source chain.\n\n    ---\n\n    `Payload` ++\"bytes\"++\n\n    Arbitrary data passed to the recipient contract. Can be used for DeFi operations, authentication, or app-specific logic.\n\n\nUnlike `Transfer`, the `TransferWithPayload` message must be redeemed by the recipient contract since only that contract can handle the custom payload properly."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 3, "depth": 2, "title": "RegisterChain", "anchor": "registerchain", "start_char": 4841, "end_char": 5884, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "## RegisterChain\n\nThe `RegisterChain` governance payload (Action ID = `1`) registers a WTT emitter address for a foreign chain. This ensures the bridge only accepts messages from known peers.\n\n```text\nModule [32]byte\nAction uint8 = 1\nChainId uint16\n\nEmitterChainID uint16\nEmitterAddress [32]uint8\n```\n\n??? interface \"Parameters\"\n\n    `Module` ++\"[32]byte\"++\n\n    Module identifier. Left-padded with `TokenBridge` for WTT.\n\n    ---\n\n    `Action` ++\"uint8\"++\n\n    Value must be `1`, indicating a `RegisterChain` operation.\n\n    ---\n\n    `ChainID` ++\"uint16\"++\n\n    The chain where this governance action should be applied. `0` is a valid value for all chains.\n\n    ---\n\n    `EmitterChainID` ++\"uint16\"++\n\n    Chain ID of the registered emitter.\n\n    ---\n\n    `EmitterAddress` ++\"[32]uint8\"++\n\n    Address of the registered emitter, left-zero-padded if shorter than 32 bytes.\n\nThis 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 4, "depth": 2, "title": "UpgradeContract", "anchor": "upgradecontract", "start_char": 5884, "end_char": 6700, "estimated_token_count": 189, "token_estimator": "heuristic-v1", "text": "## UpgradeContract\n\nThe `UpgradeContract` governance payload (Action ID = `2`) facilitates upgrades to the WTT contract on a specific chain.\n\n```text\nModule [32]byte\nAction uint8 = 2\nChainId uint16\n\nNewContract [32]uint8\n```\n\n??? interface \"Parameters\"\n\n    `Module` ++\"[32]byte\"++\n\n    Module identifier, left-padded with `TokenBridge` for WTT.\n\n    ---\n\n    `Action` ++\"uint8\"++\n\n    Value must be `2`, indicating an `UpgradeContract` operation.\n\n    ---\n\n    `ChainID` ++\"uint16\"++\n\n    The target chain where the governance action should be applied.\n\n    ---\n\n    `NewContract` ++\"[32]uint8\"++\n\n    Address of the new WTT contract, left-zero-padded to 32 bytes.\n\nThis message allows the Wormhole governance system to deploy new versions of the bridge while retaining control over interoperability and security."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-payload-structure", "page_title": "Wrapped Token Transfers (WTT) Payload Structure", "index": 5, "depth": 2, "title": "Summary of Payload Structure", "anchor": "summary-of-payload-structure", "start_char": 6700, "end_char": 7667, "estimated_token_count": 283, "token_estimator": "heuristic-v1", "text": "## Summary of Payload Structure\n\n| Payload Type          | ID            | Purpose                                                                 | Who Emits It          |\n|-----------------------|---------------|-------------------------------------------------------------------------|-----------------------|\n| `Transfer`            | PayloadID `1` | Moves tokens between chains by minting or releasing on the destination. | WTT contract |\n| `AssetMeta`           | PayloadID `2` | Attests token metadata (decimals, symbol, name) before first transfer.  | WTT contract |\n| `TransferWithPayload` | PayloadID `3` | Transfers tokens along with a custom payload for contract execution.    | WTT contract |\n| `RegisterChain`       | Action `1`    | Registers a verified WTT emitter for a foreign chain.          | Wormhole governance   |\n| `UpgradeContract`     | Action `2`    | Upgrades the WTT contract on a specific chain.                 | Wormhole governance   |"}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 0, "depth": 2, "title": "Transfer Flow", "anchor": "transfer-flow", "start_char": 972, "end_char": 5056, "estimated_token_count": 853, "token_estimator": "heuristic-v1", "text": "## Transfer Flow\n\nCross-chain token transfers using WTT follow these steps:\n\n1. **Initiation on the Source Chain**\n\n    The transfer begins when a user calls the WTT contract on the source chain:\n\n    - **Wrapped tokens**: The token is burned.\n    - **Original tokens**: If the token is native to the source chain, the token is locked in the contract.\n\n2. **Transfer Message Publication**\n\n    The WTT contract invokes the Wormhole [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\\_blank}, which emits an on-chain message event describing the transfer.\n\n3. **Message Observation and Signing**\n\n    [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.\n\n    The VAA is then published to the Wormhole network.\n\n4. **VAA Submission to the Destination Chain**\n\n    The VAA must be submitted to the WTT contract on the destination chain to complete the transfer. The WTT contract then verifies the VAA by calling the Core Contract behind the scenes. This step can be handled in two ways:\n\n    - **Automatic**: A relayer service detects the VAA and submits it to the WTT contract.\n    - **Manual**: The user or dApp retrieves the VAA and submits it directly to the WTT contract.\n\n5. **Finalization of the Transfer on the Destination Chain**\n\n    After the VAA is verified on the destination chain, the WTT contract completes the transfer:\n\n    - **Wrapped tokens**: A wrapped representation of the original token is minted.\n    - **Original tokens**: If the token is native to the destination chain, the token is released to the recipient.\n\nConsider this example: Alice wants to send 5 ETH from Ethereum to Solana. The ETH is locked on Ethereum’s WTT, and an equivalent amount of wrapped ETH is minted on Solana. The diagram below illustrates this transfer flow.\n\n```mermaid\nsequenceDiagram\n    participant Alice as Alice\n    participant WTTEth as WTT Ethereum<br>(Source Chain)\n    participant CoreEth as Core Contract Ethereum<br>(Source Chain)\n    participant Guardians\n    participant WTTSol as WTT Solana<br>(Destination Chain)\n    participant CoreSol as Core Contract Solana<br>(Destination Chain)\n\n    Alice->>WTTEth: Initiate ETH transfer<br>(lock ETH)\n    WTTEth->>CoreEth: Publish transfer message\n    CoreEth-->>Guardians: Emit message event\n    Guardians->>Guardians: Sign and publish VAA\n\n    alt Automatic VAA submission\n        Guardians->>WTTSol: Relayer submits VAA\n    else Manual VAA submission\n        Alice->>Guardians: Retrieve VAA\n        Alice->>WTTSol: Submit VAA\n    end\n\n    WTTSol->>CoreSol: Verify VAA\n    CoreSol-->>WTTSol: VAA verified\n    WTTSol-->>Alice: Mint wrapped ETH on Solana (complete transfer)\n```\n\nMaybe Alice wants to transfer her wrapped ETH on Solana back to native ETH on Ethereum. The wrapped ETH is burned on Solana’s WTT, and the equivalent 5 ETH are released on Ethereum. The diagram below illustrates this transfer flow.\n\n```mermaid\nsequenceDiagram\n    participant User as Alice\n    participant WTTSrc as WTT Solana<br>(Source Chain)\n    participant CoreSrc as Core Contract Solana<br>(Source Chain)\n    participant Guardians\n    participant WTTDst as WTT Ethereum<br>(Destination Chain)\n    participant CoreDst as Core Contract Ethereum<br>(Destination Chain)\n\n    User->>WTTSrc: Initiate transfer <br> (burn wrapped ETH)\n    WTTSrc->>CoreSrc: Publish message\n    CoreSrc-->>Guardians: Emit message event\n    Guardians->>Guardians: Sign and publish VAA\n\n    alt Automatic VAA submission\n        Guardians->>WTTDst: Relayer submits VAA\n    else Manual VAA submission\n        User->>Guardians: Retrieve VAA\n        User->>WTTDst: User submits VAA directly\n    end\n\n    WTTDst->>CoreDst: Verify VAA\n    CoreDst-->>WTTDst: VAA verified\n    WTTDst-->>User: Release native ETH on Ethereum (Complete transfer)\n```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 1, "depth": 2, "title": "Automatic vs. Manual Transfers", "anchor": "automatic-vs-manual-transfers", "start_char": 5056, "end_char": 6068, "estimated_token_count": 246, "token_estimator": "heuristic-v1", "text": "## Automatic vs. Manual Transfers\n\nWTT supports two modes of transfer, depending on whether the VAA submission step is handled automatically or manually:\n\n- **Automatic**: A relayer service listens for new VAAs and automatically submits them to the destination chain.\n- **Manual**: The user (or dApp) must retrieve the VAA and manually submit it to the destination chain.\n\nHere's a quick breakdown of the key differences:\n\n| Feature                   | Automatic Transfer          | Manual Transfer                     |\n|---------------------------|-----------------------------|-------------------------------------|\n| Who submits the VAA?      | Relayer                     | User or dApp                        |\n| User Experience           | Seamless, one-step          | Requires manual intervention        |\n| Best for                  | End-users, simple UIs       | Custom dApps, advanced control      |\n| Dependency                | Requires relayer support    | None                                |"}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 2, "depth": 3, "title": "Completing Manual Transfers", "anchor": "completing-manual-transfers", "start_char": 6068, "end_char": 6541, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "### Completing Manual Transfers\n\nThe user who initiated the transfer must complete it 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.\n\nIf this occurs, follow the [Replace Outdated Signatures in VAAs](){target=\\_blank} tutorial to update the VAA with signatures from the current Guardian Set."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 3, "depth": 2, "title": "WTT Relayer (TBR)", "anchor": "wtt-relayer-tbr", "start_char": 6541, "end_char": 6998, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "## WTT Relayer (TBR)\n\nWhen completing an automatic transfer using WTT, 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 WTT Relayer (TBR) manages the interaction with the underlying WTT contracts on [supported chains where the TBR is available](/docs/products/connect/reference/support-matrix/){target=\\_blank}."}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 4, "depth": 3, "title": "Flow of an Automatic Transfer via TBR", "anchor": "flow-of-an-automatic-transfer-via-tbr", "start_char": 6998, "end_char": 9728, "estimated_token_count": 531, "token_estimator": "heuristic-v1", "text": "### Flow of an Automatic Transfer via TBR\n\nThe flow of an automatic transfer using the TBR looks like this:\n\n1. **Initiation on the Source Chain**\n\n    The transfer begins when a user initiates a transfer on the source chain, which results in the TBR contract being called.\n\n2. **Prepare and Forward the Transfer**\n\n    The TBR verifies the token, encodes transfer details (relayer fee, native gas request, recipient), and forwards the transfer to WTT.\n\n3. **Core Messaging Layer Processes the Transfer**  \n\n    WTT emits a message to the Core Contract. Guardians observe the message and produce a signed VAA attesting to the transfer. \n\n4. **Off-Chain Relayer Observes the VAA**\n\n    An off-chain relayer verifies the destination chain and token registration and then prepares to complete the transfer.\n\n5. **Relayer Computes Native Drop-Off and Submits the VAA**\n\n    The relayer queries the destination TBR for the native gas amount, includes it in the transaction, and submits the signed VAA.\n\n6. **TBR Validates and Completes the Transfer**\n    \n    The destination TBR validates the VAA by invoking the WTT contract, confirms it's from a registered TBR, verifies the token and native gas request, and then takes custody of the tokens.\n\n7. **Asset Distribution on the Destination Chain**\n\n    The TBR sends the remaining tokens and native gas to the user, pays the off-chain relayer fee, and refunds any excess native tokens.\n\nThe following diagram illustrates the key steps in the source chain during a transfer:\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant SourceTBR as Source Chain TBR\n    participant SourceWTT as Source Chain WTT\n    participant Messaging as Core Messaging Layer\n\n    User->>SourceTBR: Initiate transfer (token, <br>recipient, fees, native gas)\n    SourceTBR->>SourceWTT: Forward transfer (burn or lock tokens)\n    SourceWTT->>Messaging: Publish transfer message\n```\n\nOnce the core messaging layer processes the transfer, the destination chain handles completion as shown below:\n\n```mermaid\nsequenceDiagram\n    participant Messaging as Core Messaging Layer\n    participant Relayer as Off-chain Relayer\n    participant DestTBR as Destination Chain TBR\n    participant DestWTT as Destination Chain <br> WTT\n    participant DestUser as User <br> (Destination Chain)\n\n    Messaging->>Relayer: Emit signed VAA for transfer\n    Relayer->>Relayer: Verifies destination chain and token registration\n    Relayer->>DestTBR: Query native gas amount\n    Relayer->>DestTBR: Submit signed VAA\n    DestTBR->>DestWTT: Validate VAA\n    DestTBR->>DestTBR: Take custody of tokens\n    DestTBR->>DestUser: Send tokens (after fees & native gas)\n    DestTBR->>Relayer: Pay relayer fee & refund excess\n```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-concepts-transfer-flow", "page_title": "Flow of Wrapped Token Transfers (WTT)", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 9728, "end_char": 10144, "estimated_token_count": 106, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow that you’ve seen how a transfer works, try both types yourself to experience the full process.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with WTT**\n\n    ---\n\n    Perform token transfers using WTT, including manual and automatic transfers.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/get-started/)\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-faqs", "page_title": "Wrapped Token Transfers (WTT) FAQs", "index": 0, "depth": 2, "title": "Can ownership of wrapped tokens be transferred from the WTT?", "anchor": "can-ownership-of-wrapped-tokens-be-transferred-from-the-wtt", "start_char": 38, "end_char": 1323, "estimated_token_count": 312, "token_estimator": "heuristic-v1", "text": "## Can ownership of wrapped tokens be transferred from the WTT?\n\nNo. Ownership of wrapped token contracts cannot be transferred, because [WTT](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank} deploys and retains control of these contracts and tokens.\n\n - **On EVM chains**: When you attest a token, WTT deploys a new ERC-20 contract as a beacon proxy. The upgrade authority for these contracts is the WTT contract itself.\n - **On Solana**: The WTT deploys a new SPL token, where the upgrade authority is a Program Derived Address (PDA) controlled by the WTT contract.\n\nThe logic behind deploying these token contracts involves submitting an attestation VAA, which allows WTT to verify and deploy the wrapped token contract on the destination chain.\n\nRelevant contracts:\n\n - [Ethereum ERC-20](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/token/Token.sol){target=\\_blank}\n - [Solana SPL](https://github.com/wormhole-foundation/wormhole/blob/main/solana/modules/token_bridge/program/src/api/create_wrapped.rs#L128-L145){target=\\_blank}\n - [Attestation VAA and Token Contract Deployment Logic](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol#L385-L431){target=\\_blank}"}
{"page_id": "products-token-transfers-wrapped-token-transfers-faqs", "page_title": "Wrapped Token Transfers (WTT) FAQs", "index": 1, "depth": 2, "title": "How do I update the metadata of a wrapped token?", "anchor": "how-do-i-update-the-metadata-of-a-wrapped-token", "start_char": 1323, "end_char": 1617, "estimated_token_count": 52, "token_estimator": "heuristic-v1", "text": "## How do I update the metadata of a wrapped token?\n\nWrapped tokens are deployed and controlled by the WTT program under Guardian authority. You cannot update their metadata directly. Instead, you must coordinate with the respective block explorer teams to request and apply metadata changes."}
{"page_id": "products-token-transfers-wrapped-token-transfers-faqs", "page_title": "Wrapped Token Transfers (WTT) FAQs", "index": 2, "depth": 2, "title": "How do I calculate the current gas costs for Ethereum Mainnet VAA verification?", "anchor": "how-do-i-calculate-the-current-gas-costs-for-ethereum-mainnet-vaa-verification", "start_char": 1617, "end_char": 2010, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "## How do I calculate the current gas costs for Ethereum Mainnet VAA verification?\n\nYou 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-faqs", "page_title": "Wrapped Token Transfers (WTT) FAQs", "index": 3, "depth": 2, "title": "How can I update my wrapped token image on Solscan?", "anchor": "how-can-i-update-my-wrapped-token-image-on-solscan", "start_char": 2010, "end_char": 2620, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "## How can I update my wrapped token image on Solscan?\n\nUpdating 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 WTT program, not individual developers or projects.\n\nTo request an update, contact Solscan via [support@solscan.io](mailto:support@solscan.io) or their [contact form](https://solscan.io/contactus){target=\\_blank}."}
{"page_id": "products-token-transfers-wrapped-token-transfers-get-started", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 0, "depth": 2, "title": "Introduction", "anchor": "introduction", "start_char": 24, "end_char": 995, "estimated_token_count": 212, "token_estimator": "heuristic-v1", "text": "## Introduction\n\nWormhole's [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/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.\n\nIn 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. \n\n - **Manual transfer**: Where you control each step.\n - **Automatic transfer**: Where a relayer finalizes the transfer for you.\n\nThese examples will help you understand how WTT works across EVM and non-EVM chains.\n\n!!! note \"Terminology\" \n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol."}
{"page_id": "products-token-transfers-wrapped-token-transfers-get-started", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 1, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 995, "end_char": 1828, "estimated_token_count": 241, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, make sure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}.\n - Wallets funded with tokens on two [supported chains](/docs/products/reference/supported-networks/#wtt){target=\\_blank}.\n\nThis 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 [Base Sepolia](https://docs.base.org/docs/tools/network-faucets/){target=\\_blank} wallets funded with testnet tokens for the automatic transfer. You can adapt the examples to match your preferred chains."}
{"page_id": "products-token-transfers-wrapped-token-transfers-get-started", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 2, "depth": 2, "title": "Configure Your Token Transfer Environment", "anchor": "configure-your-token-transfer-environment", "start_char": 1828, "end_char": 2880, "estimated_token_count": 253, "token_estimator": "heuristic-v1", "text": "## Configure Your Token Transfer Environment\n\n1. Create a new directory and initialize a Node.js project:\n\n    ```bash\n    mkdir wh-wtt\n    cd wh-wtt\n    npm init -y\n    ```\n\n2. Install the required dependencies. This example uses the SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1\n    npm install -D tsx typescript\n    ```\n\n3. Create a `transfer.ts` file to handle the multichain transfer logic, and a `helper.ts` file to manage wallet signers and token utilities:\n\n    ```bash\n    touch transfer.ts helper.ts\n    ```\n\n4. 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://getfoundry.sh/cast/reference/wallet/#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-get-started", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 3, "depth": 2, "title": "Perform a Token Transfer", "anchor": "perform-a-token-transfer", "start_char": 2880, "end_char": 11379, "estimated_token_count": 1781, "token_estimator": "heuristic-v1", "text": "## Perform a Token Transfer\n\nThis 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.\n\nIn 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.\n\n1. Open `helper.ts` and define utility functions to load private keys, instantiate signers for Solana and EVM chains, and retrieve token decimals as needed:\n\n    ```ts title=\"helper.ts\"\n    import {\n      ChainAddress,\n      ChainContext,\n      Network,\n      Signer,\n      Wormhole,\n      Chain,\n      isTokenId,\n      TokenId,\n    } from '@wormhole-foundation/sdk';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import evm from '@wormhole-foundation/sdk/evm';\n\n    /**\n     * Returns a signer for the given chain using locally scoped credentials.\n     * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must\n     * be loaded securely beforehand, for example via a keystore, secrets\n     * manager, or environment variables (not recommended).\n     */\n    export async function getSigner<N extends Network, C extends Chain>(\n      chain: ChainContext<N, C>\n    ): Promise<{\n      chain: ChainContext<N, C>;\n      signer: Signer<N, C>;\n      address: ChainAddress<C>;\n    }> {\n      let signer: Signer;\n      const platform = chain.platform.utils()._platform;\n\n      switch (platform) {\n        case 'Evm':\n          signer = await (\n            await evm()\n          ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!);\n          break;\n        case 'Solana':\n          signer = await (\n            await solana()\n          ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!);\n          break;\n        case 'Sui':\n          signer = await (\n            await sui()\n          ).getSigner(await chain.getRpc(), SUI_MNEMONIC!);\n          break;\n        default:\n          throw new Error(`Unsupported platform: ${platform}`);\n      }\n\n      return {\n        chain,\n        signer: signer as Signer<N, C>,\n        address: Wormhole.chainAddress(chain.chain, signer.address()),\n      };\n    }\n\n    /**\n     * Get the number of decimals for the token on the source chain.\n     * This helps convert a user-friendly amount (e.g., '1') into raw units.\n     */\n    export async function getTokenDecimals<N extends Network>(\n      wh: Wormhole<N>,\n      token: TokenId,\n      chain: ChainContext<N, any>\n    ): Promise<number> {\n      return isTokenId(token)\n        ? Number(await wh.getDecimals(token.chain, token.address))\n        : chain.config.nativeTokenDecimals;\n    }\n    ```\n\n2. In `transfer.ts`, choose your transfer mode by selecting the [route](/docs/products/connect/concepts/routes/#wtt-routes){target=\\_blank} you pass to the `tokenTransfer()` object: \n    - `TokenBridge` for manual transfers.\n    - `AutomaticTokenBridge` for automatic transfers.\n\n    === \"Manual Transfer\"\n\n        ```ts title=\"transfer.ts\"\n        import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk';\n        import solana from '@wormhole-foundation/sdk/solana';\n        import sui from '@wormhole-foundation/sdk/sui';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import { getSigner, getTokenDecimals } from './helper';\n\n        (async function () {\n          // Initialize Wormhole SDK for Solana and Sepolia on Testnet\n          const wh = await wormhole('Testnet', [solana, sui, evm]);\n\n          // Define the source and destination chains\n          const sendChain = wh.getChain('Solana');\n          const rcvChain = wh.getChain('Sepolia');\n\n          // Load signers and addresses from helpers\n          const source = await getSigner(sendChain);\n          const destination = await getSigner(rcvChain);\n\n          // Define the token and amount to transfer\n          const tokenId = Wormhole.tokenId('Solana', 'native');\n          const amt = '0.1';\n\n          // Convert to raw units based on token decimals\n          const decimals = await getTokenDecimals(wh, tokenId, sendChain);\n          const transferAmount = amount.units(amount.parse(amt, decimals));\n\n          // Construct the transfer object\n          const xfer = await wh.tokenTransfer(\n            tokenId,\n            transferAmount,\n            source.address,\n            destination.address,\n            'TokenBridge',\n            undefined\n          );\n\n          // Initiate the transfer from Solana\n          console.log('Starting Transfer');\n          const srcTxids = await xfer.initiateTransfer(source.signer);\n          console.log(`Started Transfer: `, srcTxids);\n\n          // Wait for the signed attestation from the Guardian network\n          console.log('Fetching Attestation');\n          const timeout = 5 * 60 * 1000; // 5 minutes\n          await xfer.fetchAttestation(timeout);\n\n          // Redeem the tokens on Sepolia\n          console.log('Completing Transfer');\n          const destTxids = await xfer.completeTransfer(destination.signer);\n          console.log(`Completed Transfer: `, destTxids);\n\n          process.exit(0);\n        })();\n        ```\n    \n    === \"Automatic Transfer\"\n\n        ```ts title=\"transfer.ts\"\n        import { wormhole, amount, Wormhole } from '@wormhole-foundation/sdk';\n        import solana from '@wormhole-foundation/sdk/solana';\n        import sui from '@wormhole-foundation/sdk/sui';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import { getSigner, getTokenDecimals } from './helper';\n\n        (async function () {\n          // Initialize Wormhole SDK for Avalanche and Base Sepolia on Testnet\n          const wh = await wormhole('Testnet', [solana, sui, evm]);\n\n          // Define the source and destination chains\n          const sendChain = wh.getChain('Avalanche');\n          const rcvChain = wh.getChain('BaseSepolia');\n\n          // Load signers and addresses from helpers\n          const source = await getSigner(sendChain);\n          const destination = await getSigner(rcvChain);\n\n          // Define the token and amount to transfer\n          const tokenId = Wormhole.tokenId('Avalanche', 'native');\n          const amt = '0.2';\n\n          // Convert to raw units based on token decimals\n          const decimals = await getTokenDecimals(wh, tokenId, sendChain);\n          const transferAmount = amount.units(amount.parse(amt, decimals));\n\n          // Set to false to require manual approval steps\n          const nativeGas = amount.units(amount.parse('0.0', 6));\n\n          // Construct the transfer object\n          const xfer = await wh.tokenTransfer(\n            tokenId,\n            transferAmount,\n            source.address,\n            destination.address,\n            'AutomaticTokenBridge',\n            nativeGas\n          );\n\n          // Initiate the transfer from Avalanche Fuji\n          console.log('Starting Transfer');\n          const srcTxids = await xfer.initiateTransfer(source.signer);\n          console.log(`Started Transfer: `, srcTxids);\n\n          process.exit(0);\n        })();\n        ```\n\n\n3. Execute the script to initiate and complete the transfer:\n\n    ```bash\n    npx tsx transfer.ts\n    ```\n\n    If successful, the expected output should be similar to this:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n    \t<span data-ty>Starting Transfer</span>\n    \t<span data-ty>Started Transfer:  ['36UwBBh6HH6wt3VBbNNawMd1ijCk28YgFePrBWfE3vGQFHtbMjY5626nqHubmyQWGNh2ZrN1vHKRrSQDNC3gkZgB']</span>\n    \t<span data-ty> </span>\n        <span data-ty>Getting Attestation</span>\n    \t<span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 0/900</span>\n        <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 1/900</span>\n        <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 2/900 </span>\n        <span data-ty> </span>\n        <span data-ty>Completing Transfer</span>\n        <span data-ty>Completed Transfer:  [ '53Nt4mp2KRTk2HFyvUcmP9b6cRXjVAN3wCksoBey9WmT' ]</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\nTo 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}."}
{"page_id": "products-token-transfers-wrapped-token-transfers-get-started", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 11379, "end_char": 12366, "estimated_token_count": 245, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nNow that you've completed a manual multichain token transfer, explore these guides to continue building.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Complete Token Transfer Workflow**\n\n    ---\n\n    Build a reusable application that supports multiple chain combinations and transfer modes (manual and automatic).\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/tutorials/transfer-workflow/)\n\n-   :octicons-tools-16:{ .lg .middle } **Create Multichain Tokens**\n\n    ---\n\n    Learn how to issue tokens that work across chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/tutorials/multichain-token/)\n\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1295, "end_char": 1816, "estimated_token_count": 128, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally.\n- The contract address for the token you wish to register.\n- A wallet setup with the following:\n    - Private keys for your source and destination chains.\n    - A small amount of gas tokens on your source and destination chains."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 1, "depth": 2, "title": "Set Up Your Development Environment", "anchor": "set-up-your-development-environment", "start_char": 1816, "end_char": 5284, "estimated_token_count": 772, "token_estimator": "heuristic-v1", "text": "## Set Up Your Development Environment\n\nFollow these steps to initialize your project, install dependencies, and prepare your developer environment for token attestation.\n\n1. Create a new directory and initialize a Node.js project using the following commands:\n\n    ```bash\n    mkdir attest-token\n    cd attest-token\n    npm init -y\n    ```\n\n2. Install dependencies, including the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\\_blank}. This example uses the SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1 -D tsx typescript\n    ```\n\n3. Set up secure access to your wallets. This guide assumes you are loading your private key values from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://getfoundry.sh/cast/reference/wallet/#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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.\n\n4. Create a new file named `helper.ts` to hold signer functions:\n\n    ```bash\n    touch helper.ts\n    ```\n\n5. Open `helper.ts` and add the following code:\n\n    ```typescript title=\"helper.ts\"\n    import {\n      Chain,\n      ChainAddress,\n      ChainContext,\n      Wormhole,\n      Network,\n      Signer,\n    } from '@wormhole-foundation/sdk';\n    import type { SignAndSendSigner } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n\n    /**\n     * Returns a signer for the given chain using locally scoped credentials.\n     * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must\n     * be loaded securely beforehand, for example via a keystore, secrets\n     * manager, or environment variables (not recommended).\n     */\n    export async function getSigner<N extends Network, C extends Chain>(\n      chain: ChainContext<N, C>\n    ): Promise<{\n      chain: ChainContext<N, C>;\n      signer: SignAndSendSigner<N, C>;\n      address: ChainAddress<C>;\n    }> {\n      let signer: Signer<any, any>;\n      const platform = chain.platform.utils()._platform;\n\n      // Customize the signer by adding or removing platforms as needed. Be sure\n      // to import the necessary packages for the platforms you want to support\n      switch (platform) {\n        case 'Evm':\n          signer = await (\n            await evm()\n          ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!);\n          break;\n        case 'Solana':\n          signer = await (\n            await solana()\n          ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!);\n          break;\n        case 'Sui':\n          signer = await (\n            await sui()\n          ).getSigner(await chain.getRpc(), SUI_MNEMONIC!);\n          break;\n        default:\n          throw new Error(`Unsupported platform: ${platform}`);\n      }\n\n      const typedSigner = signer as SignAndSendSigner<N, C>;\n\n      return {\n        chain,\n        signer: typedSigner,\n        address: Wormhole.chainAddress(chain.chain, signer.address()),\n      };\n    }\n    ```\n\n    You can view the list of [supported platform constants](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/4.14.1/core/base/src/constants/platforms.ts#L6){target=\\_blank} in the Wormhole SDK GitHub repo."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 2, "depth": 2, "title": "Check for a Wrapped Version of a Token", "anchor": "check-for-a-wrapped-version-of-a-token", "start_char": 5284, "end_char": 9732, "estimated_token_count": 1014, "token_estimator": "heuristic-v1", "text": "## Check for a Wrapped Version of a Token\n\nIf you are working with a newly created token that you know has never been transferred to the destination chain, you can continue to the [Create Attestation on the Source Chain](#create-attestation-on-the-source-chain) section.\n\nSince attestation is a one-time process, it is good practice when working with existing tokens to incorporate a check for wrapped versions into your WTT flow. Follow these steps to check for a wrapped version of a token:\n\n1. Create a new file called `attest.ts` to hold the wrapped version check and attestation logic:\n\n    ```bash\n    touch attest.ts\n    ```\n\n2. Open `attest.ts` and add the following code:\n\n    ```typescript title=\"attest.ts\"\n    import {\n      wormhole,\n      Wormhole,\n      TokenId,\n      TokenAddress,\n    } from '@wormhole-foundation/sdk';\n    import { signSendWait, toNative } from '@wormhole-foundation/sdk-connect';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner } from './helper';\n\n    async function attestToken() {\n      // Initialize wormhole instance, define the network, platforms, and chains\n      const wh = await wormhole('Testnet', [evm, solana]);\n      const sourceChain = wh.getChain('Moonbeam');\n      const destinationChain = wh.getChain('Solana');\n\n      // Define the token to check for a wrapped version\n      const tokenId: TokenId = Wormhole.tokenId(\n        sourceChain.chain,\n        'INSERT_TOKEN_CONTRACT_ADDRESS'\n      );\n      // Check if the token is registered with the destination chain WTT (Token Bridge) contract\n      // Registered = returns the wrapped token ID\n      // Not registered = runs the attestation flow to register the token\n      let wrappedToken: TokenId;\n      try {\n        wrappedToken = await wh.getWrappedAsset(destinationChain.chain, tokenId);\n        console.log(\n          '✅ Token already registered on destination:',\n          wrappedToken.address\n        );\n      } catch (e) {\n        // Attestation on the source chain flow code\n        console.log(\n          '⚠️ Token is NOT registered on destination. Running attestation flow...'\n        );\n      }\n    }\n\n    attestToken().catch((e) => {\n      console.error('❌ Error in attestToken', e);\n      process.exit(1);\n    });\n    ```\n\n    After initializing a Wormhole instance and defining the source and destination chains, this code does the following:\n\n    - **Defines the token to check**: Use the contract address on the source chain for this value.\n    - **Calls [`getWrappedAsset`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/4.14.1/connect/src/wormhole.ts#L277){target=\\_blank}**: Part of the `Wormhole` class, the method does the following:\n        - Accepts a [`TokenId`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/4.14.1/platforms/aptos/protocols/tokenBridge/src/types.ts#L12){target=\\_blank} representing a token on the source chain.\n        - Checks for a corresponding wrapped version of the destination chain's WTT contract.\n        - Returns the `TokenId` for the wrapped token on the destination chain if a wrapped version exists.\n\n3. Run the script using the following command:\n\n    ```bash\n    npx tsx attest.ts\n    ```\n\n4. If the token has a wrapped version registered with the destination chain WTT contract, you will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n      <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx attest.ts</span>\n      <span data-ty>✅ Token already registered on destination: SolanaAddress {\n        type: 'Native',\n        address: PublicKey [PublicKey(2qjSAGrpT2eTb673KuGAR5s6AJfQ1X5Sg177Qzuqt7yB)] {\n        _bn: BN: 1b578bb9b7a04a1aab3b5b64b550d8fc4f73ab343c9cf8532d2976b77ec4a8ca\n        }\n        }</span>\n      <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n    You can safely use WTT to transfer this token to the destination chain.\n\n    If a wrapped version isn't found on the destination chain, your terminal output will be similar to the following, and you must attest the token before transfer:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx attest.ts</span>\n    \t<span data-ty>⚠️ Token is NOT registered on destination. Running attestation flow...</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 3, "depth": 2, "title": "Create Attestation on the Source Chain", "anchor": "create-attestation-on-the-source-chain", "start_char": 9732, "end_char": 11739, "estimated_token_count": 420, "token_estimator": "heuristic-v1", "text": "## Create Attestation on the Source Chain\n\nTo create the attestation transaction on the source chain, open `attest.ts` and replace the `// Attestation flow code` comment with the following code:\n\n```typescript title=\"attest.ts\"\n    // Retrieve the WTT (Token Bridge) contract text for the source chain\n    const tb = await sourceChain.getTokenBridge();\n    // Get the signer for the source chain\n    const sourceSigner = await getSigner(sourceChain);\n    // Define the token to attest and a payer address\n    const token: TokenAddress<typeof sourceChain.chain> = toNative(\n      sourceChain.chain,\n      tokenId.address.toString()\n    );\n    const payer = toNative(sourceChain.chain, sourceSigner.signer.address());\n    // Create a new attestation and sign and send the transaction\n    for await (const tx of tb.createAttestation(token, payer)) {\n      const txids = await signSendWait(\n        sourceChain,\n        tb.createAttestation(token),\n        sourceSigner.signer\n      );\n      // Attestation on the destination chain flow code\n      console.log('✅ Attestation transaction sent:', txids);\n      \n```\n\nThis code does the following:\n\n- **Gets the source chain WTT context**: This is where the transaction is sent to create the attestation.\n- Defines the token to attest and the payer.\n- **Calls `createAttestation`**: Defined in the `TokenBridge` interface, the [`createAttestation`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/4.14.1/core/definitions/src/protocols/tokenBridge/tokenBridge.ts#L237){target=\\_blank} method does the following:\n    - Accepts a `TokenAddress` representing the token on its native chain.\n    - Accepts an optional `payer` address to cover the transaction fees for the attestation transaction.\n    - Prepares an attestation for the token, including metadata such as address, symbol, and decimals.\n    - Returns an `AsyncGenerator` that yields unsigned transactions, which are then signed and sent to initiate the attestation process on the source chain."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 4, "depth": 2, "title": "Submit Attestation on Destination Chain", "anchor": "submit-attestation-on-destination-chain", "start_char": 11739, "end_char": 22365, "estimated_token_count": 1921, "token_estimator": "heuristic-v1", "text": "## Submit Attestation on Destination Chain\n\nThe attestation flow finishes with the following: \n\n- Using the transaction ID returned from the `createAttestation` transaction on the source chain to retrieve the associated signed `TokenBridge:AttestMeta` VAA.\n- Submitting the signed VAA to the destination chain to provide Guardian-backed verification of the attestation transaction on the source chain. \n- The destination chain uses the attested metadata to create the wrapped version of the token and register it with its WTT contract.\n\nFollow these steps to complete your attestation flow logic:\n\n1. Add the following code to `attest.ts`:\n\n    ```typescript title=\"attest.ts\"\n          // Parse the transaction to get Wormhole message ID\n          const messages = await sourceChain.parseTransaction(txids[0].txid);\n          console.log('✅ Attestation messages:', messages);\n          // Set a timeout for fetching the VAA, this can take several minutes\n          // depending on the source chain network and finality\n          const timeout = 25 * 60 * 1000;\n          // Fetch the VAA for the attestation message\n          const vaa = await wh.getVaa(\n            messages[0]!,\n            'TokenBridge:AttestMeta',\n            timeout\n          );\n          if (!vaa) throw new Error('❌ VAA not found before timeout.');\n          // Get the WTT (Token Bridge) contract text for the destination chain\n          // and submit the attestation VAA\n          const destTb = await destinationChain.getTokenBridge();\n          // Get the signer for the destination chain\n          const destinationSigner = await getSigner(destinationChain);\n          const payer = toNative(\n            destinationChain.chain,\n            destinationSigner.signer.address()\n          );\n          const destTxids = await signSendWait(\n            destinationChain,\n            destTb.submitAttestation(vaa, payer),\n            destinationSigner.signer\n          );\n          console.log('✅ Attestation submitted on destination:', destTxids);\n        }\n        // Poll for the wrapped token to appear on the destination chain\n        const maxAttempts = 50; // ~5 minutes with 6s interval\n        const interval = 6000;\n        let attempt = 0;\n        let registered = false;\n\n        while (attempt < maxAttempts && !registered) {\n          attempt++;\n          try {\n            const wrapped = await wh.getWrappedAsset(\n              destinationChain.chain,\n              tokenId\n            );\n            console.log(\n              `✅ Wrapped token is now available on ${destinationChain.chain}:`,\n              wrapped.address\n            );\n            registered = true;\n          } catch {\n            console.log(\n              `⏳ Waiting for wrapped token to register on ${destinationChain.chain}...`\n            );\n            await new Promise((res) => setTimeout(res, interval));\n          }\n        }\n        if (!registered) {\n          throw new Error(\n            `❌ Token attestation did not complete in time on ${destinationChain.chain}`\n          );\n        }\n        console.log(\n          `🚀 Token attestation complete! Token registered with ${destinationChain.chain}.`\n        );\n    ```\n\n2. Run the script using the following command:\n\n    ```bash\n    npx tsx attest.ts\n    ```\n\n3. You will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n      <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx attest.ts</span>\n      <span data-ty>⚠️ Token is NOT registered on destination. Running attestation\n        flow...</span>\n      <span data-ty>✅ Attestation transaction sent: [ { chain: 'Moonbeam', txid:\n        '0xbaf7429e1099cac6f39ef7e3c30e38776cfb5b6be837dcd8793374c8ee491799' }\n        ]</span>\n      <span data-ty>✅ Attestation messages: [ { chain: 'Moonbeam', emitter: UniversalAddress {\n        address: [Uint8Array] }, sequence: 1507n } ]</span>\n      <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 0/750</span>\n      <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 1/750</span>\n      <span data-ty>.....</span>\n      <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 10/750</span>\n      <span data-ty>📨 Submitting attestation VAA to Solana...</span>\n      <span data-ty>✅ Attestation submitted on destination: [ { chain: 'Solana', txid:\n        '3R4oF5P85jK3wKgkRs5jmE8BBLoM4wo2hWSgXXL6kA8efbj2Vj9vfuFSb53xALqYZuv3FnXDwJNuJfiKKDwpDH1r'\n        } ]</span>\n      <span data-ty>✅ Wrapped token is now available on Solana: SolanaAddress { type:\n        'Native', address: PublicKey\n        [PublicKey(2qjSAGrpT2eTb673KuGAR5s6AJfQ1X5Sg177Qzuqt7yB)] { _bn: BN:\n        1b578bb9b7a04a1aab3b5b64b550d8fc4f73ab343c9cf8532d2976b77ec4a8ca } }</span>\n      <span data-ty>🚀 Token attestation complete!</span>\n      <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n    ??? example \"View complete script\"\n        ```typescript title=\"attest.ts\"\n        import {\n          wormhole,\n          Wormhole,\n          TokenId,\n          TokenAddress,\n        } from '@wormhole-foundation/sdk';\n        import { signSendWait, toNative } from '@wormhole-foundation/sdk-connect';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import solana from '@wormhole-foundation/sdk/solana';\n        import { getSigner } from './helper';\n\n        async function attestToken() {\n          // Initialize wormhole instance, define the network, platforms, and chains\n          const wh = await wormhole('Testnet', [evm, solana]);\n          const sourceChain = wh.getChain('Moonbeam');\n          const destinationChain = wh.getChain('Solana');\n\n          // Define the token to check for a wrapped version\n          const tokenId: TokenId = Wormhole.tokenId(\n            sourceChain.chain,\n            'INSERT_TOKEN_CONTRACT_ADDRESS'\n          );\n          // Check if the token is registered with the destination chain WTT (Token Bridge) contract\n          // Registered = returns the wrapped token ID\n          // Not registered = runs the attestation flow to register the token\n          let wrappedToken: TokenId;\n          try {\n            wrappedToken = await wh.getWrappedAsset(destinationChain.chain, tokenId);\n            console.log(\n              '✅ Token already registered on destination:',\n              wrappedToken.address\n            );\n          } catch (e) {\n            // Attestation on the source chain flow code\n            console.log(\n              '⚠️ Token is NOT registered on destination. Running attestation flow...'\n            );\n\n            // Retrieve the WTT (Token Bridge) contract text for the source chain\n            const tb = await sourceChain.getTokenBridge();\n            // Get the signer for the source chain\n            const sourceSigner = await getSigner(sourceChain);\n            // Define the token to attest and a payer address\n            const token: TokenAddress<typeof sourceChain.chain> = toNative(\n              sourceChain.chain,\n              tokenId.address.toString()\n            );\n            const payer = toNative(sourceChain.chain, sourceSigner.signer.address());\n            // Create a new attestation and sign and send the transaction\n            for await (const tx of tb.createAttestation(token, payer)) {\n              const txids = await signSendWait(\n                sourceChain,\n                tb.createAttestation(token),\n                sourceSigner.signer\n              );\n              // Attestation on the destination chain flow code\n              console.log('✅ Attestation transaction sent:', txids);\n              \n              // Parse the transaction to get Wormhole message ID\n              const messages = await sourceChain.parseTransaction(txids[0].txid);\n              console.log('✅ Attestation messages:', messages);\n              // Set a timeout for fetching the VAA, this can take several minutes\n              // depending on the source chain network and finality\n              const timeout = 25 * 60 * 1000;\n              // Fetch the VAA for the attestation message\n              const vaa = await wh.getVaa(\n                messages[0]!,\n                'TokenBridge:AttestMeta',\n                timeout\n              );\n              if (!vaa) throw new Error('❌ VAA not found before timeout.');\n              // Get the WTT (Token Bridge) contract text for the destination chain\n              // and submit the attestation VAA\n              const destTb = await destinationChain.getTokenBridge();\n              // Get the signer for the destination chain\n              const destinationSigner = await getSigner(destinationChain);\n              const payer = toNative(\n                destinationChain.chain,\n                destinationSigner.signer.address()\n              );\n              const destTxids = await signSendWait(\n                destinationChain,\n                destTb.submitAttestation(vaa, payer),\n                destinationSigner.signer\n              );\n              console.log('✅ Attestation submitted on destination:', destTxids);\n            }\n            // Poll for the wrapped token to appear on the destination chain\n            const maxAttempts = 50; // ~5 minutes with 6s interval\n            const interval = 6000;\n            let attempt = 0;\n            let registered = false;\n\n            while (attempt < maxAttempts && !registered) {\n              attempt++;\n              try {\n                const wrapped = await wh.getWrappedAsset(\n                  destinationChain.chain,\n                  tokenId\n                );\n                console.log(\n                  `✅ Wrapped token is now available on ${destinationChain.chain}:`,\n                  wrapped.address\n                );\n                registered = true;\n              } catch {\n                console.log(\n                  `⏳ Waiting for wrapped token to register on ${destinationChain.chain}...`\n                );\n                await new Promise((res) => setTimeout(res, interval));\n              }\n            }\n            if (!registered) {\n              throw new Error(\n                `❌ Token attestation did not complete in time on ${destinationChain.chain}`\n              );\n            }\n            console.log(\n              `🚀 Token attestation complete! Token registered with ${destinationChain.chain}.`\n            );\n          }\n        }\n\n        attestToken().catch((e) => {\n          console.error('❌ Error in attestToken', e);\n          process.exit(1);\n        });\n        ```\n\nCongratulations! You've successfully created and submitted an attestation to register a token for transfer via WTT."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-attest-tokens", "page_title": "Token Attestation", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 22365, "end_char": 22713, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Transfer Wrapped Assets**\n\n    ---\n\n    Follow this guide to incorporate token attestation and registration into an end-to-end WTT flow.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/guides/attest-tokens/)\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-fetch-signed-vaa", "page_title": "Fetch a Signed VAA", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 554, "end_char": 830, "estimated_token_count": 81, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following installed:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank}\n- [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} (installed globally)"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-fetch-signed-vaa", "page_title": "Fetch a Signed VAA", "index": 1, "depth": 2, "title": "Set Up Your Developer Environment", "anchor": "set-up-your-developer-environment", "start_char": 830, "end_char": 1410, "estimated_token_count": 138, "token_estimator": "heuristic-v1", "text": "## Set Up Your Developer Environment\n\nFollow these steps to initialize your project, install dependencies, and prepare your developer environment:\n\n1. Create a new directory and initialize a Node.js project using the following commands:\n\n    ```bash\n    mkdir fetch-vaa\n    cd fetch-vaa\n    npm init -y\n    ```\n\n2. Install dependencies, including the [Wormhole TypeScript SDK](https://github.com/wormhole-foundation/wormhole-sdk-ts){target=\\_blank}. This example uses the SDK version `4.14.1`:\n\n    ```bash\n   npm install @wormhole-foundation/sdk@4.14.1 -D tsx typescript\n   ```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-fetch-signed-vaa", "page_title": "Fetch a Signed VAA", "index": 2, "depth": 2, "title": "Fetch VAA via TypeScript SDK", "anchor": "fetch-vaa-via-typescript-sdk", "start_char": 1410, "end_char": 4800, "estimated_token_count": 723, "token_estimator": "heuristic-v1", "text": "## Fetch VAA via TypeScript SDK\n\nFollow these steps to search for and retrieve a VAA using the TypeScript SDK:\n\n1. Create a new file called `fetch-vaa.ts` using the following command:\n\n    ```bash\n    touch fetch-vaa.ts\n    ```\n\n2. Open your `fetch-vaa.ts` file and add the following code:\n\n    ```typescript title=\"fetch-vaa.ts\"\n    import { wormhole } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import { serialize } from '@wormhole-foundation/sdk-definitions';\n    import { toChainId } from '@wormhole-foundation/sdk-base';\n\n    async function main() {\n      // Initialize the Wormhole SDK with the network and platform\n      // to match the source chain for the transaction ID\n      const wh = await wormhole('Testnet', [evm]);\n      // Source chain transaction ID for the VAA you want to fetch\n      const txid =\n        'INSERT_TRANSACTION_ID';\n      // Call getVaa to fetch the VAA associated with the transaction ID\n      // and decode returned data into a human-readable format\n      const vaa = await wh.getVaa(txid, 'Uint8Array', 60000);\n      if (!vaa) {\n        console.error('❌ VAA not found');\n        process.exit(1);\n      }\n      const { emitterChain, emitterAddress, sequence } = vaa;\n      const chainId = toChainId(emitterChain);\n      const emitterHex = emitterAddress.toString();\n\n      const vaaBytes = serialize(vaa);\n      const vaaHex = Buffer.from(vaaBytes).toString('hex');\n\n      console.log('✅ VAA Info');\n      console.log(`Chain: ${chainId}`);\n      console.log(`Emitter: ${emitterHex}`);\n      console.log(`Sequence: ${sequence}`);\n      console.log('---');\n      console.log(`VAA Bytes (hex):\\n${vaaHex}`);\n      // Return the VAA object for further processing if needed\n      return vaa;\n    }\n\n    main().catch(console.error);\n    ```\n\n    This code does the following:\n\n    - Initializes a Wormhole instance with the same `network` and `platform` as the source chain transfer transaction.\n    - Accepts the transaction ID from the source chain transfer transaction.\n    - Prints the associated `chain`, `emitter`, `sequence`, and VAA bytes to the terminal.\n    - Returns the `vaa` object for any further processing.\n\n3. Run the script with the following command:\n\n    ```bash\n    npx tsx fetch-vaa.ts\n    ```\n\n4. You will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx fetch-vaa.ts</span>\n    \t<span data-ty>✅ VAA Info</span>\n    \t<span data-ty>Chain: 16</span>\n    \t<span data-ty>Emitter: 0x000000000000000000000000bc976d4b9d57e57c3ca52e1fd136c45ff7955a96</span>\n        <span data-ty>Sequence: 1512</span>\n    \t<span data-ty>---</span>\n        <span data-ty>VAA Bytes (hex):</span>\n        <span data-ty>010000000001004d34d189b894acf4c16b9f456f908ca8b60aa9b2fa77cfa6ebc18f864818c21a7e18b6c4f72415f441be4d2b666c5b897d354cec0e950b935b15806d002d39670168557fb6000000000010000000000000000000000000bc976d4b9d57e57c3ca52e1fd136c45ff7955a9600000000000005e8010100000000000000000000000000000000000000000000000000000000009896800000000000000000000000009b2ff7b2b5a459853224a3317b786d8e85026660001084b1e2f8a26ddff1a55eed46add73a9b556256f2afda1072f6cfdab1dcb2d53000010000000000000000000000000000000000000000000000000000000000000000</span>\n    \t<span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-fetch-signed-vaa", "page_title": "Fetch a Signed VAA", "index": 3, "depth": 2, "title": "Fetch VAA via Wormholescan", "anchor": "fetch-vaa-via-wormholescan", "start_char": 4800, "end_char": 6093, "estimated_token_count": 300, "token_estimator": "heuristic-v1", "text": "## Fetch VAA via Wormholescan\n\nYou can also use [Wormholescan's](https://wormholescan.io/){target=\\_blank} UI to manually search for a VAA using the source transaction ID, VAA ID, or a wallet address. This type of quick search is helpful during debugging or testing of your integration. Follow these steps to fetch a VAA using Wormholescan:\n\n1. On [Wormholescan](https://wormholescan.io/){target=\\_blank}, use the dropdown menu in the top right corner to select either **Mainnet** or **Testnet**.\n\n2. Enter your transaction ID in the search bar and select \"return\" or \"enter\" to submit your search request. Alternatively, you can enter the wallet address of the transaction signer and return any transactions under that account.\n\n    ![](/docs/images/products/wrapped-token-transfers/guides/fetch-vaa/fetch-vaa-1.webp)\n\n3. Inspect the returned search results. Note that the source transaction ID, current status, transaction details, and the VAA ID are included.\n\n    ![](/docs/images/products/wrapped-token-transfers/guides/fetch-vaa/fetch-vaa-2.webp)\n\nCongratulations! You've now fetched a signed VAA using both the TypeScript SDK and Wormholescan UI. These skills are valuable when developing manual transfer or messaging processes, as well as debugging and testing an integration build."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1149, "end_char": 1808, "estimated_token_count": 161, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n- [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n- [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally.\n- The Wormhole TypeScript SDK version 3.0 or above.\n- The contract address for the ERC-20 token you wish to transfer.\n- A wallet setup with the following:\n    - Private keys for your source and destination chains.\n    - A small amount of gas tokens on your source and destination chains.\n    - A balance on your source chain of the ERC-20 token you want to transfer."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 1, "depth": 2, "title": "Set Up Your Token Transfer Environment", "anchor": "set-up-your-token-transfer-environment", "start_char": 1808, "end_char": 5883, "estimated_token_count": 878, "token_estimator": "heuristic-v1", "text": "## Set Up Your Token Transfer Environment\n\nFollow these steps to initialize your project, install dependencies, and prepare your developer environment for multichain token transfers.\n\n1. Create a new directory and initialize a Node.js project using the following commands:\n   ```bash\n   mkdir wtt-demo\n   cd wtt-demo\n   npm init -y\n   ```\n\n2. Install dependencies, including the Wormhole TypeScript SDK. This example uses the SDK version `4.14.1`:\n\n   ```bash\n   npm install @wormhole-foundation/sdk@4.14.1 -D tsx typescript\n   ```\n\n3. Set up secure access to your wallets. This guide assumes you are loading your private key values from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://getfoundry.sh/cast/reference/wallet#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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.\n\n4. Create a new file named `helpers.ts` to hold signer and decimal functions:\n   ```bash\n   touch helpers.ts\n   ```\n\n5. Open `helpers.ts` and add the following code:\n    ```typescript title=\"helpers.ts\"\n    import {\n      Chain,\n      ChainAddress,\n      ChainContext,\n      isTokenId,\n      Wormhole,\n      Network,\n      Signer,\n      TokenId,\n    } from '@wormhole-foundation/sdk';\n    import type { SignAndSendSigner } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n\n    /**\n     * Returns a signer for the given chain using locally scoped credentials.\n     * The required values (EVM_PRIVATE_KEY, SOL_PRIVATE_KEY, SUI_MNEMONIC) must\n     * be loaded securely beforehand, for example via a keystore, secrets\n     * manager, or environment variables (not recommended).\n     */\n    export async function getSigner<N extends Network, C extends Chain>(\n      chain: ChainContext<N, C>,\n      gasLimit?: bigint\n    ): Promise<{\n      chain: ChainContext<N, C>;\n      signer: SignAndSendSigner<N, C>;\n      address: ChainAddress<C>;\n    }> {\n      let signer: Signer<any, any>;\n      const platform = chain.platform.utils()._platform;\n\n      // Customize the signer by adding or removing platforms as needed\n      // Be sure to import the necessary packages for the platforms you want to support\n      switch (platform) {\n        case 'Evm':\n          const evmSignerOptions = gasLimit ? { gasLimit } : {};\n          (signer = await (\n            await evm()\n          ).getSigner(await chain.getRpc(), EVM_PRIVATE_KEY!)),\n            evmSignerOptions;\n          break;\n        case 'Solana':\n          signer = await (\n            await solana()\n          ).getSigner(await chain.getRpc(), SOL_PRIVATE_KEY!);\n          break;\n        case 'Sui':\n          signer = await (\n            await sui()\n          ).getSigner(await chain.getRpc(), SUI_MNEMONIC!);\n          break;\n        default:\n          throw new Error(`Unsupported platform: ${platform}`);\n      }\n\n      const typedSigner = signer as SignAndSendSigner<N, C>;\n\n      return {\n        chain,\n        signer: typedSigner,\n        address: Wormhole.chainAddress(chain.chain, signer.address()),\n      };\n    }\n\n    /**\n     * Get the number of decimals for the token on the source chain.\n     * This helps convert a user-friendly amount (e.g., '1') into raw units.\n     */\n    export async function getTokenDecimals<N extends Network>(\n      wh: Wormhole<N>,\n      token: TokenId,\n      chain: ChainContext<N, any>\n    ): Promise<number> {\n      return isTokenId(token)\n        ? Number(await wh.getDecimals(token.chain, token.address))\n        : chain.config.nativeTokenDecimals;\n    }\n    ```\n\n    You can view the [constants for platform names](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/3eae2e91fc3a6fec859eb87cfa85a4c92c65466f/core/base/src/constants/platforms.ts#L6){target=\\_blank} in the GitHub repo for a list of supported platforms"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 2, "depth": 2, "title": "Verify Token Registration (Attestation)", "anchor": "verify-token-registration-attestation", "start_char": 5883, "end_char": 18283, "estimated_token_count": 2255, "token_estimator": "heuristic-v1", "text": "## Verify Token Registration (Attestation)\n\nTokens must be registered on the destination chain before they can be bridged. This process involves submitting an attestation with the native token metadata to the destination chain, which enables the destination chain's WTT contract to create a corresponding wrapped version with the same attributes as the native token.\n\nRegistration via attestation is only required the first time a given token is sent to that specific destination chain. Follow these steps to check the registration status of a token:\n\n1. Create a new file named `transfer.ts`:\n   ```bash\n   touch transfer.ts\n   ```\n\n2. Open your `transfer.ts` file and add the following code:\n    ```typescript title=\"transfer.ts\"\n    import { wormhole, Wormhole, TokenId } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner, getTokenDecimals } from './helpers';\n\n    async function transferTokens() {\n      // Initialize wh instance\n      const wh = await wormhole('Testnet', [evm, solana]);\n      // Define sourceChain and destinationChain, get chain contexts\n      const sourceChain = wh.getChain('Moonbeam');\n      const destinationChain = wh.getChain('Solana');\n      // Load signers for both chains\n      const sourceSigner = await getSigner(sourceChain);\n      const destinationSigner = await getSigner(destinationChain);\n\n      // Define token and amount to transfer\n      const tokenId: TokenId = Wormhole.tokenId(\n        sourceChain.chain,\n        'INSERT_TOKEN_CONTRACT_ADDRESS'\n      );\n      // Replace with amount you want to transfer\n      // This is a human-readable number, e.g., 0.2 for 0.2 tokens\n      const amount = INSERT_AMOUNT;\n      // Convert to raw units based on token decimals\n      const decimals = await getTokenDecimals(wh, tokenId, sourceChain);\n      const transferAmount = BigInt(Math.floor(amount * 10 ** decimals));\n\n      // Check if the token is registered with destinationChain WTT (Token Bridge) contract\n      // Registered = returns the wrapped token ID, continues with transfer\n      // Not registered = runs the attestation flow to register the token\n      let wrappedToken: TokenId;\n      try {\n        wrappedToken = await wh.getWrappedAsset(destinationChain.chain, tokenId);\n        console.log(\n          '✅ Token already registered on destination:',\n          wrappedToken.address\n        );\n      } catch (e) {\n        console.log(\n          '⚠️ Token is NOT registered on destination. Attestation required before transfer can proceed...'\n        );\n      }\n      // Insert Initiate Transfer on Source Chain code\n    }\n\n    transferTokens().catch((e) => {\n      console.error('❌ Error in transferTokens', e);\n      process.exit(1);\n    });\n    ```\n\n    This code does the following:\n\n    - Initializes a `wormhole` instance and defines the source and destination chains.\n    - Imports the signer and decimal functions from `helpers.ts`.\n    - Identifies the token and amount to transfer.\n    - Checks to see if a wrapped version of the ERC-20 token to transfer exists on the destination chain.\n\n3. Run the script using the following command:\n\n    ```bash\n    npx tsx transfer.ts\n    ```\n\n    If the token is registered on the destination chain, the address of the existing wrapped asset is returned, and you can continue to [initiate the transfer](#initiate-transfer-on-source-chain) on the source chain. If the token is not registered, you will see a message similar to the following advising the attestation flow will run:\n\n    <div id=\"termynal\" data-termynal>\n      <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n      <span data-ty>⚠️ Token is NOT registered on destination. Running attestation flow...</span>\n      <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n    </div>\n    If you see this message, follow the steps under \"Need to register a token?\" before continuing with the rest of the transfer flow code.\n\n    ??? example \"Need to register a token?\"\n        Token attestation is a one-time process to register a token on a destination chain. You should only follow these steps if your token registration check indicates a wrapped version does not exist on the destination chain.\n\n        1. Create a new file called `attestToken.ts`:\n            ```bash\n            touch attestToken.ts\n            ```\n\n        2. Open `attestToken.ts` and add the following code to create the attestation for token registration:\n            ```typescript title=\"attestToken.ts\"\n            import {\n              wormhole,\n              Wormhole,\n              TokenId,\n              TokenAddress,\n            } from '@wormhole-foundation/sdk';\n            import evm from '@wormhole-foundation/sdk/evm';\n            import solana from '@wormhole-foundation/sdk/solana';\n            import { signSendWait, toNative } from '@wormhole-foundation/sdk-connect';\n            import { getSigner } from './helpers';\n\n            async function attestToken() {\n              // Initialize wh instance\n              const wh = await wormhole('Testnet', [evm, solana]);\n              // Define sourceChain and destinationChain, get chain contexts\n              const sourceChain = wh.getChain('Moonbeam');\n              const destinationChain = wh.getChain('Solana');\n\n              // Define gas limit for EVM chains (optional)\n              const gasLimit = BigInt(2_500_000);\n\n              // Load signers for both chains\n              const sourceSigner = await getSigner(sourceChain);\n              const destinationSigner = await getSigner(destinationChain, gasLimit);\n\n              // Retrieve the WTT (Token Bridge) context for the source chain\n              // This is where you will send the transaction to attest the token\n              const tb = await sourceChain.getTokenBridge();\n              // Define the token to attest\n              const tokenId: TokenId = Wormhole.tokenId(\n                sourceChain.chain,\n                'INSERT_TOKEN_CONTRACT_ADDRESS'\n              );\n              // Define the token to attest and a payer address\n              const token: TokenAddress<typeof sourceChain.chain> = toNative(\n                sourceChain.chain,\n                tokenId.address.toString()\n              );\n              const payer = toNative(sourceChain.chain, sourceSigner.signer.address());\n              // Call the `createAttestation` method to create a new attestation\n              // and sign and send the transaction\n              for await (const tx of tb.createAttestation(token, payer)) {\n                const txids = await signSendWait(\n                  sourceChain,\n                  tb.createAttestation(token),\n                  sourceSigner.signer\n                );\n                console.log('✅ Attestation transaction sent:', txids);\n                // Parse the transaction to get Wormhole message ID\n                const messages = await sourceChain.parseTransaction(txids[0].txid);\n                console.log('✅ Attestation messages:', messages);\n                // Set a timeout for fetching the VAA, this can take several minutes\n                // depending on the source chain network and finality\n                const timeout = 25 * 60 * 1000;\n                // Fetch the VAA for the attestation message\n                const vaa = await wh.getVaa(\n                  messages[0]!,\n                  'TokenBridge:AttestMeta',\n                  timeout\n                );\n                if (!vaa) throw new Error('❌ VAA not found before timeout.');\n                // Get the WTT (Token Bridge) context for the source chaindestination chain\n                // and submit the attestation VAA\n                const destTb = await destinationChain.getTokenBridge();\n                const payer = toNative(\n                  destinationChain.chain,\n                  destinationSigner.signer.address()\n                );\n                const destTxids = await signSendWait(\n                  destinationChain,\n                  destTb.submitAttestation(vaa, payer),\n                  destinationSigner.signer\n                );\n                console.log('✅ Attestation submitted on destination:', destTxids);\n              }\n              // Poll for the wrapped token to appear on the destination chain\n              // before proceeding with the transfer\n              const maxAttempts = 50; // ~5 minutes with 6s interval\n              const interval = 6000;\n              let attempt = 0;\n              let registered = false;\n\n              while (attempt < maxAttempts && !registered) {\n                attempt++;\n                try {\n                  const wrapped = await wh.getWrappedAsset(destinationChain.chain, tokenId);\n                  console.log(\n                    `✅ Wrapped token is now available on ${destinationChain.chain}:`,\n                    wrapped.address\n                  );\n                  registered = true;\n                } catch {\n                  console.log(\n                    `⏳ Waiting for wrapped token to register on ${destinationChain.chain}...`\n                  );\n                  await new Promise((res) => setTimeout(res, interval));\n                }\n              }\n\n              if (!registered) {\n                throw new Error(\n                  `❌ Token attestation did not complete in time on ${destinationChain.chain}`\n                );\n              }\n              console.log('🚀 Token attestation complete! Proceed with transfer...');\n            }\n            ```\n\n            This code does the following:\n        \n            - Gets the WTT protocol for the source chain.\n            - Defines the token to attest for registration on the destination chain and the payer to sign for the transaction.\n            - Calls `createAttestation`, signs, and then sends the transaction.\n            - Waits for the signed VAA confirming the attestation creation.\n            - Sends the VAA to the destination chain to complete registration.\n            - Polls for the wrapped token to be available on the destination chain before continuing the transfer process.\n\n        3. Run the script with the following command:\n            \n            ```bash\n            npx tsx attestToken.ts\n            ```\n\n            When the attestation and registration are complete, you will see terminal output similar to the following:\n\n            <div id=\"termynal\" data-termynal>\n              <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n              <span data-ty>⚠️ Token is NOT registered on destination. Running attestation flow...</span>\n              <span data-ty>✅ Attestation transaction sent: [\n              {\n                chain: 'Moonbeam',\n                txid: '0x2b9878e6d8e92d8ecc96d663904312c18a827ccf0b02380074fdbc0fba7e6b68'\n              }\n            ]</span>\n              <span data-ty>✅ Attestation messages: [\n              {\n                chain: 'Moonbeam',\n                emitter: UniversalAddress { address: [Uint8Array] },\n                sequence: 1505n\n              }\n            ]\n            </span>\n              <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 0/750</span>\n              <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 1/750</span>\n              <span data-ty>....</span>\n              <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 10/750</span>\n              <span data-ty>✅ Attestation submitted on destination: [\n              {\n                chain: 'Solana',\n                txid: '3R4oF5P85jK3wKgkRs5jmE8BBLoM4wo2hWSgXXL6kA8efbj2Vj9vfuFSb53xALqYZuv3FnXDwJNuJfiKKDwpDH1r'\n              }\n            ]</span>\n              <span data-ty>✅ Wrapped token is now available on Solana: SolanaAddress {\n              type: 'Native',\n              address: PublicKey [PublicKey(2qjSAGrpT2eTb673KuGAR5s6AJfQ1X5Sg177Qzuqt7yB)] {\n                _bn: <BN: 1b578bb9b7a04a1aab3b5b64b550d8fc4f73ab343c9cf8532d2976b77ec4a8ca>\n              }\n            }</span>\n              <span data-ty>🚀 Token attestation complete! Proceeding with transfer...</span>\n              <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n            </div>\n        You can now go on to [initiate the transfer](#initiate-transfer-on-source-chain) on the source chain."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 3, "depth": 2, "title": "Initiate Transfer on Source Chain", "anchor": "initiate-transfer-on-source-chain", "start_char": 18283, "end_char": 27010, "estimated_token_count": 1682, "token_estimator": "heuristic-v1", "text": "## Initiate Transfer on Source Chain\n\nBefore initializing the token transfer, decide whether to use an automatic or manual transaction. Refer to the [Automatic vs. Manual Transfers](/docs/products/token-transfers/wrapped-token-transfers/concepts/transfer-flow/#automatic-vs-manual-transfers){target=\\_blank} section for a comparison of both options.\n\nFollow these steps to add the remaining logic to initiate the token transfer on the source chain. Add the below code where the comment says `// Insert Initiate Transfer on Source Chain code` in your `transfer.ts` file:\n\n1. Open your `transfer.ts` file and add the following code:\n\n    === \"Manual Transfer\"\n\n        ```typescript title=\"transfer.ts\"\n          // Build the token transfer object\n          const xfer = await wh.tokenTransfer(\n            tokenId,\n            transferAmount,\n            sourceSigner.address,\n            destinationSigner.address,\n            'TokenBridge',\n            undefined // no payload\n          );\n          console.log('🚀 Built transfer object:', xfer.transfer);\n\n          // Initiate, sign, and send the token transfer\n          const srcTxs = await xfer.initiateTransfer(sourceSigner.signer);\n          console.log('🔗 Source chain tx sent:', srcTxs);\n\n          // For manual transfers, wait for VAA\n          console.log('⏳ Waiting for attestation (VAA) for manual transfer...');\n          const timeout = 10 * 60 * 1000; // 10 minutes timeout\n          const attIds = await xfer.fetchAttestation(timeout);\n          console.log('✅ Got attestation ID(s):', attIds);\n\n          // Complete the manual transfer on the destination chain\n          console.log('↪️ Redeeming transfer on destination...');\n          const destTxs = await xfer.completeTransfer(destinationSigner.signer);\n          console.log('🎉 Destination tx(s) submitted:', destTxs);\n        ```\n                \n    === \"Automatic Transfer\"\n\n        ```ts title=\"transfer.ts\"\n          // Optional native gas amount for automatic transfers only\n          const nativeGasAmount = '0.001'; // 0.001 of native gas in human-readable format\n          // Get the decimals for the source chain\n          const nativeGasDecimals = destinationChain.config.nativeTokenDecimals;\n          // Convert to raw units, otherwise set to 0n\n          const nativeGas = BigInt(Number(nativeGasAmount) * 10 ** nativeGasDecimals);\n\n          // Build the token transfer object\n          const xfer = await wh.tokenTransfer(\n            tokenId,\n            transferAmount,\n            sourceSigner.address,\n            destinationSigner.address,\n            'AutomaticTokenBridge',\n            nativeGas\n          );\n          console.log('🚀 Built transfer object:', xfer.transfer);\n\n          // Initiate, sign, and send the token transfer\n          const srcTxs = await xfer.initiateTransfer(sourceSigner.signer);\n          console.log('🔗 Source chain tx sent:', srcTxs);\n\n          // If automatic, no further action is required. The relayer completes the transfer.\n          console.log('✅ Automatic transfer: relayer is handling redemption.');\n\n          process.exit(0);\n        ```\n\n    This code does the following:\n\n    - Defines the transfer as automatic or manual. For automatic transfers, both the source and destination chain must have an existing `TokenBridgeRelayer` contract, which listens for and completes transfers on your behalf. You can check the list of [deployed `TokenBridgeRelayer` contracts](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/a48c9132015279ca6a2d3e9c238a54502b16fc7e/core/base/src/constants/contracts/tokenBridgeRelayer.ts){target=\\_blank} in the Wormhole SDK repo to see if your desired chains are supported.\n    - Sets an optional amount for [native gas drop-off](/docs/products/token-transfers/wrapped-token-transfers/concepts/transfer-flow/#flow-of-an-automatic-transfer-via-tbr){target=\\_blank}. This option allows you to send a small amount of the destination chain's native token to cover gas fees. Native gas drop-off is currently only supported for automatic transfers.\n    - Builds the transfer object, initiates the transfer, signs the transaction, and sends it.\n    - If the transfer is automatic, the flow ends. Otherwise, the script waits for the signed VAA confirming the transaction on the source chain. The signed VAA is then submitted to the destination chain to claim the tokens and complete the manual transfer.\n\n2. Run the script with the following command:\n    ```bash\n    npx tsx transfer.ts\n    ```\n\n3. You will see terminal output similar to the following:\n\n    === \"Manual Transfer\"\n\n        <div id=\"termynal\" data-termynal>\n          <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n          <span data-ty>✅ Token already registered on destination: SolanaAddress {\n          type: 'Native',\n          address: PublicKey [PublicKey(2qjSAGrpT2eTb673KuGAR5s6AJfQ1X5Sg177Qzuqt7yB)] {\n            _bn: <BN: 1b578bb9b7a04a1aab3b5b64b550d8fc4f73ab343c9cf8532d2976b77ec4a8ca>\n          }\n        }</span>\n          <span data-ty>🚀 Built transfer object: {\n          token: {\n            chain: 'Moonbeam',\n            address: EvmAddress {\n              type: 'Native',\n              address: '0x39F2f26f247CcC223393396755bfde5ecaeb0648'\n            }\n          },\n          amount: 200000000000000000n,\n          from: {\n            chain: 'Moonbeam',\n            address: EvmAddress {\n              type: 'Native',\n              address: '0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12'\n            }\n          },\n          to: {\n            chain: 'Solana',\n            address: SolanaAddress {\n              type: 'Native',\n              address: [PublicKey [PublicKey(21dmEFTFGBEVoUNjmrxumN6A2xFxNBQXTkK7AmMqNmqD)]]\n            }\n          },\n          protocol: 'TokenBridge',\n          payload: undefined\n        }</span>\n          <span data-ty>🔗 Source chain tx sent: [\n          '0xf318a1098a81063ac8acc9ca117eeb41ae9abfd9cb550a976721d2fa978f313a'\n        ]</span>\n          <span data-ty>⏳ Waiting for attestation (VAA) for manual transfer...</span>\n          <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 0/30</span>\n          <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 1/30</span>\n          <span data-ty>.....</span>\n          <span data-ty>Retrying Wormholescan:GetVaaBytes, attempt 15/30</span>\n          <span data-ty>✅ Got attestation ID(s): [\n          {\n            chain: 'Moonbeam',\n            emitter: UniversalAddress { address: [Uint8Array] },\n            sequence: 1506n\n          }\n        ]</span>\n          <span data-ty>↪️ Redeeming transfer on destination...</span>\n          <span data-ty>🎉 Destination tx(s) submitted: [\n          '23NRfFZyKJTDLppJF4GovdegxYAuW2HeXTEFSKKNeA7V82aqTVYTkKeM8sCHCDWe7gWooLAPHARjbAheXoxbbwPk'\n        ]</span>\n          <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\n    === \"Automatic Transfer\"\n\n        <div id=\"termynal\" data-termynal>\n          <span data-ty=\"input\"><span class=\"file-path\"></span>npx tsx transfer.ts</span>\n          <span data-ty>✅ Token already registered on destination: SolanaAddress {\n          type: 'Native',\n          address: PublicKey [PublicKey(2qjSAGrpT2eTb673KuGAR5s6AJfQ1X5Sg177Qzuqt7yB)] {\n            _bn: <BN: 1b578bb9b7a04a1aab3b5b64b550d8fc4f73ab343c9cf8532d2976b77ec4a8ca>\n          }\n        }</span>\n          <span data-ty>🚀 Built transfer object: {\n          token: {\n            chain: 'Moonbeam',\n            address: EvmAddress {\n              type: 'Native',\n              address: '0x39F2f26f247CcC223393396755bfde5ecaeb0648'\n            }\n          },\n          amount: 200000000000000000n,\n          from: {\n            chain: 'Moonbeam',\n            address: EvmAddress {\n              type: 'Native',\n              address: '0xCD8Bcd9A793a7381b3C66C763c3f463f70De4e12'\n            }\n          },\n          to: {\n            chain: 'Solana',\n            address: SolanaAddress {\n              type: 'Native',\n              address: [PublicKey [PublicKey(21dmEFTFGBEVoUNjmrxumN6A2xFxNBQXTkK7AmMqNmqD)]]\n            }\n          },\n          protocol: 'AutomaticTokenBridge',\n          nativeGas: 10000000000000000n\n        }</span>\n          <span data-ty>🔗 Source chain tx sent: [\n          '0xf318a1098a81063ac8acc9ca117eeb41ae9abfd9cb550a976721d2fa978f313a'\n        ]</span>\n          <span data-ty>✅ Automatic transfer: relayer is handling redemption.</span>\n          <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n        </div>\nCongratulations! You've now used WTT to transfer wrapped assets using the Wormhole TypeScript SDK. Consider the following options to build upon what you've achieved."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 27010, "end_char": 27969, "estimated_token_count": 249, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Portal Bridge**\n\n    ---\n\n    Visit this site to interact with Wormhole's Portal Bridge, featuring a working WTT integration.\n\n    [:custom-arrow: Check out the Portal Bridge](https://portalbridge.com/){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Interact with WTT Contracts**\n\n    ---\n\n    This guide explores the Solidity functions used in WTT contracts.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/guides/wtt-contracts/)\n\n-   :octicons-tools-16:{ .lg .middle } **Reference Interfaces**\n\n    ---\n\n    View the source code defining the `TokenBridge` and `AutomaticTokenBridge` interfaces and their associated namespaces.\n\n    [:custom-arrow: See Interfaces](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/tokenBridge/tokenBridge.ts){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 5, "depth": 2, "title": "Recovering Stuck Transfers", "anchor": "recovering-stuck-transfers", "start_char": 27969, "end_char": 28147, "estimated_token_count": 30, "token_estimator": "heuristic-v1", "text": "## Recovering Stuck Transfers\n\nIf your transfer appears stuck or failed to complete automatically, you can recover it manually using the transaction hash from the source chain."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 6, "depth": 3, "title": "Using the Recovery Script", "anchor": "using-the-recovery-script", "start_char": 28147, "end_char": 28586, "estimated_token_count": 115, "token_estimator": "heuristic-v1", "text": "### Using the Recovery Script\n\n1. **Get your source transaction hash**: This is the transaction ID from when you initiated the transfer\n\n2. **Clone the recovery script**:\n\n    ```bash\n    git clone https://github.com/wormhole-foundation/demo-basic-ts-sdk\n    cd demo-basic-ts-sdk\n    ```\n\n3. **Run the recovery**:\n\n    ```bash\n    # Edit src/tx-recover.ts and set recoverTxid to your transaction hash\n    npm run transfer:recover\n    ```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-transfer-wrapped-assets", "page_title": "Transfer Wrapped Assets", "index": 7, "depth": 3, "title": "When Recovery Might Not Work", "anchor": "when-recovery-might-not-work", "start_char": 28586, "end_char": 28810, "estimated_token_count": 50, "token_estimator": "heuristic-v1", "text": "### When Recovery Might Not Work\n\n- **Wrong destination address**: If tokens were sent to a contract that can't release them\n- **Finality not reached**: Wait up to 20 minutes for Ethereum finality before attempting recovery"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1020, "end_char": 1394, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nTo interact with the Wormhole WTT, you'll need the following:\n\n- [The address of the WTT contract](/docs/products/reference/contract-addresses/#wrapped-token-transfers-wtt){target=\\_blank} on the chains you're working with.\n- [The Wormhole chain ID](/docs/products/reference/chain-ids/){target=\\_blank} of the chains you're targeting for token transfers."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 1, "depth": 2, "title": "How to Interact with WTT Contracts", "anchor": "how-to-interact-with-wtt-contracts", "start_char": 1394, "end_char": 1723, "estimated_token_count": 69, "token_estimator": "heuristic-v1", "text": "## How to Interact with WTT Contracts\n\nThe primary functions of the WTT contracts revolve around:\n\n- **Attesting a token**: Registering a new token for cross-chain transfers.\n- **Transferring tokens**: Locking and minting tokens across chains.\n- **Transferring tokens with a payload**: Including additional data with transfers."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 2, "depth": 3, "title": "Attest a Token", "anchor": "attest-a-token", "start_char": 1723, "end_char": 3361, "estimated_token_count": 324, "token_estimator": "heuristic-v1", "text": "### Attest a Token\n\nSuppose a token has never been transferred to the target chain before transferring it cross-chain. In that case, its metadata must be registered so WTT can recognize it and create a wrapped version if necessary.\n\nThe attestation process doesn't require you to manually input token details, such as name, symbol, or decimals. Instead, the WTT contract retrieves these values from the token contract itself when you call the `attestToken()` method.\n\n```solidity\nfunction attestToken(\n    address tokenAddress,\n    uint32 nonce\n) external payable returns (uint64 sequence);\n```\n\n??? interface \"Parameters\"\n\n    `tokenAddress` ++\"address\"++\n        \n    The contract address of the token to be attested.\n\n    ---\n\n    `nonce` ++\"uint32\"++  \n\n    An arbitrary value provided by the caller to ensure uniqueness.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n    \n    A unique identifier for the attestation transaction.\n\n??? interface \"Example\"\n\n    ```solidity\n    IWormhole wormhole = IWormhole(wormholeAddr);\n    ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr);\n\n    uint256 wormholeFee = wormhole.messageFee();\n\n    tokenBridge.attestToken{value: wormholeFee}(\n        address(tokenImpl), // the token contract to attest\n        234                 // nonce for the transfer\n    );\n    ```\n\nWhen `attestToken()` is called, the contract emits a Verifiable Action Approval (VAA) containing the token's metadata, which the Guardians sign and publish.\n\nYou must ensure the token is ERC-20 compliant. If it does not implement the standard functions, the attestation may fail or produce incomplete metadata."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 3, "depth": 3, "title": "Transfer Tokens", "anchor": "transfer-tokens", "start_char": 3361, "end_char": 6177, "estimated_token_count": 565, "token_estimator": "heuristic-v1", "text": "### Transfer Tokens \n\nOnce 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, the VAA is used to mint or release the corresponding amount of wrapped tokens.\n\nCall `transferTokens()` to lock/burn tokens and produce a VAA with transfer details.\n\n```solidity\nfunction transferTokens(\n    address token,\n    uint256 amount,\n    uint16 recipientChain,\n    bytes32 recipient,\n    uint256 arbiterFee,\n    uint32 nonce\n) external payable returns (uint64 sequence);\n```\n\n??? interface \"Parameters\"\n\n    `token` ++\"address\"++\n        \n    The address of the token being transferred.\n\n    ---\n\n    `amount` ++\"uint256\"++\n \n    The amount of tokens to be transferred.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++\n\n    The Wormhole chain ID of the destination chain.\n\n    ---\n\n    `recipient` ++\"bytes32\"++\n\n    The recipient's address on the destination chain.\n\n    ---\n\n    `arbiterFee` ++\"uint256\"++\n\n    Optional fee to be paid to an arbiter for relaying the transfer.\n\n    ---\n\n    `nonce` ++\"uint32\"++\n\n    A unique identifier for the transaction.\n\n??? interface \"Returns\"\n\n    `sequence` ++\"uint64\"++\n    \n    A unique identifier for the transfer transaction.\n\n??? interface \"Example\"\n\n    ```solidity\n    IWormhole wormhole = IWormhole(wormholeAddr);\n    ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr);\n\n    // Get the fee for publishing a message\n    uint256 wormholeFee = wormhole.messageFee();\n\n    tokenBridge.transferTokens{value: wormholeFee}(\n        token,           // address of the ERC-20 token to transfer\n        amount,          // amount of tokens to transfer\n        recipientChain,  // Wormhole chain ID of the destination chain\n        recipient,       // recipient address on the destination chain (as bytes32)\n        arbiterFee,      // fee for relayer\n        nonce            // nonce for this transfer\n    );\n    ```\n\nOnce 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()`.\n\n```solidity\nfunction completeTransfer(bytes memory encodedVm) external;\n```\n\n??? interface \"Parameters\"\n\n    `encodedVm` ++\"bytes memory\"++\n    \n    The signed VAA containing the transfer details.\n\n!!!note\n    - WTT normalizes token amounts to 8 decimals when passing them between chains. Make sure your application accounts for potential decimal truncation.\n    - The VAA ensures the integrity of the message. Only after the Guardians sign the VAA can it be redeemed on the destination chain."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 4, "depth": 3, "title": "Transfer Tokens with Payload", "anchor": "transfer-tokens-with-payload", "start_char": 6177, "end_char": 9233, "estimated_token_count": 588, "token_estimator": "heuristic-v1", "text": "### Transfer Tokens with Payload\n\nWhile 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.\n\nCall `transferTokensWithPayload()` instead of `transferTokens()` to include a custom payload (arbitrary bytes) with the token transfer.\n\n```solidity\nfunction transferTokensWithPayload(\n    address token,\n    uint256 amount,\n    uint16 recipientChain,\n    bytes32 recipient,\n    uint32 nonce,\n    bytes memory payload\n) external payable returns (uint64 sequence);\n```\n\n??? interface \"Parameters\"\n\n    `token` ++\"address\"++\n    \n    The address of the token being transferred.\n\n    ---\n\n    `amount` ++\"uint256\"++\n\n    The amount of tokens to be transferred.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++\n\n    The Wormhole chain ID of the destination chain.\n\n    ---\n\n    `recipient` ++\"bytes32\"++\n\n    The recipient's address on the destination chain.\n\n    ---\n\n    `nonce` ++\"uint32\"++\n\n    A unique identifier for the transaction.\n\n    ---\n\n    `payload` ++\"bytes memory\"++\n\n    Arbitrary data payload attached to the transaction.\n\n??? interface \"Returns\"\n    \n    `sequence` ++\"uint64\"++\n    \n    A unique identifier for the transfer transaction.\n\n??? interface \"Example\"\n\n    ```solidity\n    IWormhole wormhole = IWormhole(wormholeAddr);\n    ITokenBridge tokenBridge = ITokenBridge(tokenBridgeAddr);\n\n    // Get the fee for publishing a message\n    uint256 wormholeFee = wormhole.messageFee();\n\n    tokenBridge.transferTokensWithPayload{value: wormholeFee}(\n        token,           // address of the ERC-20 token to transfer\n        amount,          // amount of tokens to transfer\n        recipientChain,  // Wormhole chain ID of the destination chain\n        recipient,       // recipient address on the destination chain (as bytes32)\n        nonce,           // nonce for this transfer\n        additionalPayload // additional payload data\n    );\n    ```\n\nAfter 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()`.\n\nOnly 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.\n\n```solidity\nfunction completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory);\n```\n\n??? interface \"Parameters\"\n\n    `encodedVm` ++\"bytes memory\"++\n\n    The signed VAA containing the transfer details.\n\n??? interface \"Returns\"\n\n    `bytes memory`\n\n    The extracted payload data."}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 5, "depth": 2, "title": "Source Code References", "anchor": "source-code-references", "start_char": 9233, "end_char": 9653, "estimated_token_count": 109, "token_estimator": "heuristic-v1", "text": "## Source Code References\n\nFor a deeper understanding of WTT implementation and to review the actual source code, please refer to the following links:\n\n- [WTT contract](https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/Bridge.sol){target=\\_blank}\n- [WTT interface](https://github.com/wormhole-foundation/wormhole-solidity-sdk/blob/main/src/interfaces/ITokenBridge.sol){target=\\_blank}"}
{"page_id": "products-token-transfers-wrapped-token-transfers-guides-wtt-contracts", "page_title": "Get Started with Wrapped Token Transfers (WTT)", "index": 6, "depth": 2, "title": "Portal Bridge", "anchor": "portal-bridge", "start_char": 9653, "end_char": 10097, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "## Portal Bridge\n\nA practical implementation of the Wormhole WTT 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-overview", "page_title": "Wrapped Token Transfers (WTT) Overview", "index": 0, "depth": 2, "title": "Wrapped Token Transfers Overview", "anchor": "wrapped-token-transfers-overview", "start_char": 0, "end_char": 439, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "## Wrapped Token Transfers Overview\n\nWrapped Token Transfers (WTT) 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.\n\nThis overview covers WTT's main features, general processes, and possible next steps to begin building a cross-chain application."}
{"page_id": "products-token-transfers-wrapped-token-transfers-overview", "page_title": "Wrapped Token Transfers (WTT) Overview", "index": 1, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 439, "end_char": 1249, "estimated_token_count": 188, "token_estimator": "heuristic-v1", "text": "## Key Features\n\nWTT is built to solve interoperability problems in multichain token transfers. Key features include:\n\n- **Interoperability**: Transfer standards-compliant tokens (e.g., ERC-20, SPL) across over 30 [supported chains](/docs/products/reference/supported-networks/#wtt){target=\\_blank}.\n- **Lock-and-mint mechanism**: Mint wrapped tokens backed 1:1 by locked assets on the source chain.\n- **Preserved metadata**: Ensure that token properties like name, symbol, and decimals persist across chains.\n- **Transfer with payload**: Attach arbitrary data to token transfers, enabling the triggering of specific actions.\n- **Decentralized security**: Verified by the [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\\_blank}, ensuring cross-chain consistency and message authenticity."}
{"page_id": "products-token-transfers-wrapped-token-transfers-overview", "page_title": "Wrapped Token Transfers (WTT) Overview", "index": 2, "depth": 2, "title": "How It Works", "anchor": "how-it-works", "start_char": 1249, "end_char": 2813, "estimated_token_count": 348, "token_estimator": "heuristic-v1", "text": "## How It Works\n\nWTT provides a reliable foundation for multichain interoperability at scale. The transfer process follows these key steps:\n\n1. **Attestation**: The token’s metadata (e.g., symbol, name, decimals) is registered on the destination chain. This step is only required once per token.\n2. **Locking**: On the source chain, the native token is locked in a custody account.\n3. **Message emission**: The [Guardian Network](/docs/protocol/infrastructure/guardians/){target=\\_blank} verifies and emits a [VAA](/docs/protocol/infrastructure/vaas/){target=\\_blank}.\n4. **Verification**: The VAA is submitted and verified on the destination chain to confirm authenticity.\n5. **Minting**: A wrapped version of the token is minted (or the native token is released) to the recipient on the destination chain.\n\nThis diagram showcases a simplified flow of Alice bridging ETH from Ethereum to her account on Solana.\n\n```mermaid\nsequenceDiagram\n    participant Alice\n    participant Ethereum\n    participant GuardianNetwork\n    participant Solana\n\n    Alice->>Ethereum: Lock ETH in WTT contract\n    Ethereum->>GuardianNetwork: Emit transfer message\n    GuardianNetwork->>GuardianNetwork: Verify and sign message\n\n    GuardianNetwork->>Solana: Submit signed message\n    Solana->>Solana: Verify message and mint wrapped ETH (WETH)\n\n    Solana->>Alice: Deliver wrapped ETH on Solana\n```\n\nFor a more in-depth understanding of how WTT works, see the [Flow of a Transfer](/docs/products/token-transfers/wrapped-token-transfers/concepts/transfer-flow/){target=\\_blank} page."}
{"page_id": "products-token-transfers-wrapped-token-transfers-overview", "page_title": "Wrapped Token Transfers (WTT) Overview", "index": 3, "depth": 2, "title": "Use Cases", "anchor": "use-cases", "start_char": 2813, "end_char": 3897, "estimated_token_count": 287, "token_estimator": "heuristic-v1", "text": "## Use Cases\n\nHere are key use cases that highlight the power and versatility of WTT.\n\n- **Multichain Rewards and Token Utility in Decentralized Platforms (e.g., [Chingari](https://chingari.io/){target=\\_blank})** \n\n    - **[WTT](/docs/products/token-transfers/wrapped-token-transfers/get-started/)**: Transfer tokens between chains.\n    - **[Messaging](/docs/products/messaging/overview/)**: Facilitate the distribution and claiming processes of rewards.\n\n- **Tokenized Gaming Rewards**\n\n    - **[WTT](/docs/products/token-transfers/wrapped-token-transfers/get-started/)**: Handle the underlying lock-and-mint logic securely.\n    - **[Connect](/docs/products/connect/overview/)**: Provide a user-friendly way to move game tokens across chains.\n\n- **Multichain DeFi Arbitrage**\n\n    - **[WTT](/docs/products/token-transfers/wrapped-token-transfers/get-started/)**: Enables rapid and secure movement of DeFi assets.\n    - **[Connect](/docs/products/connect/overview/)**: Provides a UI widget to onboard users and facilitate seamless multichain swaps within DeFi aggregator platforms."}
{"page_id": "products-token-transfers-wrapped-token-transfers-overview", "page_title": "Wrapped Token Transfers (WTT) Overview", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3897, "end_char": 4909, "estimated_token_count": 254, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nIf you are looking for more guided practice, take a look at the following guides.\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Get Started with WTT**\n\n    ---\n\n    Perform token transfers using WTT, including manual and automatic transfers.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/get-started/)\n\n\n-   :octicons-tools-16:{ .lg .middle } **Complete Token Transfer Workflow**\n\n    ---\n\n    Build a cross-chain native token transfer app using Wormhole’s TypeScript SDK, supporting native token transfers across EVM and non-EVM chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/tutorials/transfer-workflow/)\n\n-   :octicons-tools-16:{ .lg .middle } **Create Multichain Tokens**\n\n    ---\n\n    Craft a multichain token using Wormhole's Portal Bridge.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/tutorials/multichain-token/)\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-portal-faqs", "page_title": "Portal Bridge FAQs", "index": 0, "depth": 2, "title": "How do I use deep-linking with Portal?", "anchor": "how-do-i-use-deep-linking-with-portal", "start_char": 8, "end_char": 1381, "estimated_token_count": 415, "token_estimator": "heuristic-v1", "text": "## How do I use deep-linking with Portal?\n\nYou can create a direct link to pre-fill chain and asset selections on [Portal Bridge](https://portalbridge.com){target=\\_blank} using URL parameters.\n\n| Parameter     | Description                                                |\n|---------------|------------------------------------------------------------|\n| `sourceChain` | A source chain that will be pre-selected.                   |\n| `targetChain` | A target chain that will be pre-selected.                   |\n| `asset`       | The asset key on the source chain (e.g., SOL, USDC, etc.).  |\n| `targetAsset` | The asset key on the destination chain.                     |\n\nExample:\n\n```bash\nhttps://portalbridge.com/?sourceChain=solana&targetChain=ethereum&asset=SOL&targetAsset=WSOL\n```\n\nThis link will open Portal with:\n \n - **`sourceChain`** pre-selected as `solana`.\n - **`targetChain`** pre-selected as `ethereum`.\n - **`asset`** pre-selected as `SOL`.\n - **`targetAsset`** pre-selected as `WSOL`.\n\n!!! note\n    For [**NTT tokens**](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}, you can define just one asset if the same token exists across chains.\n\n    Example: [https://portalbridge.com/?sourceChain=ethereum&targetChain=solana&asset=W](https://portalbridge.com/?sourceChain=ethereum&targetChain=solana&asset=W){target=\\_blank}"}
{"page_id": "products-token-transfers-wrapped-token-transfers-portal-faqs", "page_title": "Portal Bridge FAQs", "index": 1, "depth": 2, "title": "What does the \"Send to a wallet address\" field do?", "anchor": "what-does-the-send-to-a-wallet-address-field-do", "start_char": 1381, "end_char": 2170, "estimated_token_count": 181, "token_estimator": "heuristic-v1", "text": "## What does the \"Send to a wallet address\" field do?\n\nAfter selecting your tokens and connecting your source wallet on [Portal](https://portalbridge.com/){target=\\_blank}, you'll be prompted to connect your destination wallet. At this step, alongside wallet options like MetaMask or Phantom, you'll also see an option labeled \"Send to a wallet address\".\nThis flexibility allows you to enter any wallet address as the recipient rather than connecting a destination wallet, enabling you to send tokens to a predefined recipient, such as a team wallet, treasury address, or cold storage wallet.\n\n![](/docs/images/products/wrapped-token-transfers/portal-bridge/faqs/portal-wallet-address.webp){.half}\n\nThis field is optional. If left empty, the tokens will be sent to your connected wallet."}
{"page_id": "products-token-transfers-wrapped-token-transfers-portal-faqs", "page_title": "Portal Bridge FAQs", "index": 2, "depth": 2, "title": "Why is the token that I deployed using the WTT / NTT framework not showing up in the Portal Bridge UI?", "anchor": "why-is-the-token-that-i-deployed-using-the-wtt-ntt-framework-not-showing-up-in-the-portal-bridge-ui", "start_char": 2170, "end_char": 2874, "estimated_token_count": 172, "token_estimator": "heuristic-v1", "text": "## Why is the token that I deployed using the WTT / NTT framework not showing up in the Portal Bridge UI?\n\nWhile deploying tokens to new chains via Wormhole is fully permissionless, these tokens do not automatically show up on the [Portal](https://portalbridge.com/){target=\\_blank} UI. Wormhole Contributors maintain discretion in configuring tokens for Portal to prevent abuse. You can quickly spin up your own UI for token transfers using Wormhole Connect. See the demo repositories to get started:\n\n- [**Basic Connect Demo**](https://github.com/wormhole-foundation/demo-basic-connect){target=\\_blank}\n- [**NTT Connect Demo**](https://github.com/wormhole-foundation/demo-ntt-connect){target=\\_blank}"}
{"page_id": "products-token-transfers-wrapped-token-transfers-portal-faqs", "page_title": "Portal Bridge FAQs", "index": 3, "depth": 2, "title": "Why is my CCTP transfer stuck and can't be redeemed?", "anchor": "why-is-my-cctp-transfer-stuck-and-cant-be-redeemed", "start_char": 2874, "end_char": 3611, "estimated_token_count": 157, "token_estimator": "heuristic-v1", "text": "## Why is my CCTP transfer stuck and can't be redeemed?\n\nIf your transfer is stuck and you're unable to complete it through Portal, it may have been initiated through a third-party app or smart contract that reserved the right to finalize it. In that case, Portal is unable to complete the redemption on your behalf. Only the original app can.\n\nTo resolve this, go back to the app or platform you used to start the transfer and look for an option to complete or claim it there.\n\nIf you want to investigate further, check the events of your originating transaction for a `destination_caller` field. If it's set to a non-zero address, that's the address exclusively authorized to redeem the message and the reason Portal can't complete it."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 0, "depth": 2, "title": "Register the Token on the Source Chain", "anchor": "register-the-token-on-the-source-chain", "start_char": 909, "end_char": 1608, "estimated_token_count": 165, "token_estimator": "heuristic-v1", "text": "## Register the Token on the Source Chain\n\nThe 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:\n\n1. Open the [Portal Bridge](https://portalbridge.com/legacy-tools/#/register){target=\\_blank}.\n2. Select the blockchain where your token is currently deployed (source chain).\n3. Connect your wallet by following the on-screen instructions.\n4. Locate the **Asset** field and paste the token contract address.\n5. Click **Next** to proceed.\n\n![Source Chain Registration Screen](/docs/images/products/wrapped-token-transfers/tutorials/multichain-tokens/multichain-token-1.webp)"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 1, "depth": 2, "title": "Register the Token on the Target Chain", "anchor": "register-the-token-on-the-target-chain", "start_char": 1608, "end_char": 2195, "estimated_token_count": 129, "token_estimator": "heuristic-v1", "text": "## Register the Token on the Target Chain\n\nAfter 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.\n\n1. Choose the blockchain where you want the token to be bridged (target chain).\n2. Connect your wallet to the target chain.\n3. Click **Next** to finalize the registration process.\n\n![Target Chain Registration Screen](/docs/images/products/wrapped-token-transfers/tutorials/multichain-tokens/multichain-token-2.webp)"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 2, "depth": 2, "title": "Send an Attestation", "anchor": "send-an-attestation", "start_char": 2195, "end_char": 2930, "estimated_token_count": 165, "token_estimator": "heuristic-v1", "text": "## Send an Attestation\n\nAttestation 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}).\n\n1. Click **Attest** to initiate the attestation process.\n2. Approve the transaction in your wallet when prompted.\n\n![Send Attestation Screen](/docs/images/products/wrapped-token-transfers/tutorials/multichain-tokens/multichain-token-3.webp)\n\n!!! note\n    - Attestation is crucial for token metadata to appear correctly on blockchain explorers like Etherscan, allowing users to identify and trust your token.\n    - Ensure you have sufficient funds to cover transaction fees on the target chain."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 3, "depth": 2, "title": "Create a Wrapped Token", "anchor": "create-a-wrapped-token", "start_char": 2930, "end_char": 3728, "estimated_token_count": 173, "token_estimator": "heuristic-v1", "text": "## Create a Wrapped Token\n\nThe 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.\n\n1. Click **Create** to generate the wrapped token.\n2. Approve the transaction in your wallet when prompted.\n\n![Create Wrapped Token Screen](/docs/images/products/wrapped-token-transfers/tutorials/multichain-tokens/multichain-token-4.webp)\n\nUpon 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:\n\n![Confirmation Screen](/docs/images/products/wrapped-token-transfers/tutorials/multichain-tokens/multichain-token-5.webp)"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 4, "depth": 2, "title": "Additional Steps and Recommendations", "anchor": "additional-steps-and-recommendations", "start_char": 3728, "end_char": 3931, "estimated_token_count": 33, "token_estimator": "heuristic-v1", "text": "## Additional Steps and Recommendations\n\nAfter creating your multichain token, there are a few optional but highly recommended steps to ensure the best experience for users interacting with your token."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 5, "depth": 3, "title": "Update Metadata on Blockchain Explorers", "anchor": "update-metadata-on-blockchain-explorers", "start_char": 3931, "end_char": 5264, "estimated_token_count": 313, "token_estimator": "heuristic-v1", "text": "### Update Metadata on Blockchain Explorers\n\nIt 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.\n\n1. 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).\n2. Copy and paste the wrapped contract address in the **Token Update Application Form**.\n3. 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}.\n4. 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}.\n   - 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.\n5. 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}."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-multichain-token", "page_title": "Create Multichain Tokens", "index": 6, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 5264, "end_char": 5894, "estimated_token_count": 164, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Demo Tutorials Repository**\n\n    ---\n\n    Looking for more hands-on tutorials? Check out the Wormhole Tutorial Demo repository on GitHub for additional examples.\n\n    [:custom-arrow: Explore the Demo Repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 2128, "end_char": 2848, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore you begin, ensure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed on your machine.\n - [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed globally.\n - Native tokens (testnet or mainnet) in Solana and Sui wallets.\n - A wallet with a private key, funded with native tokens (testnet or mainnet) for gas fees.\n - **Sui token compatibility**: If you're working with custom Sui tokens, ensure they are created with the legacy `CoinMetadata` type for WTT. Once created, the token can be migrated to the `Currency` standard, but the legacy `CoinMetadata` type must exist initially."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 1, "depth": 2, "title": "Supported Chains", "anchor": "supported-chains", "start_char": 2848, "end_char": 3233, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "## Supported Chains\n\nThe 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 [Supported Networks](/docs/products/reference/supported-networks/#wtt){target=\\_blank} page, which includes every network where WTT is supported, across both mainnet and testnet."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 2, "depth": 2, "title": "Project Setup", "anchor": "project-setup", "start_char": 3233, "end_char": 7924, "estimated_token_count": 957, "token_estimator": "heuristic-v1", "text": "## Project Setup\n\nIn this section, we’ll guide you through initializing the project, installing dependencies, and preparing your environment for cross-chain transfers.\n\n1. **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.\n\n    ```bash\n    mkdir native-transfers\n    cd native-transfers\n    npm init -y\n    ```\n\n2. **Install dependencies**: Install the required dependencies. This tutorial uses the SDK version `4.14.1`:\n\n    ```bash\n    npm install @wormhole-foundation/sdk@4.14.1 tsx\n    ```\n\n3. **Set up secure access to your wallets**: This guide assumes you are loading your `SOL_PRIVATE_KEY`, `EVM_PRIVATE_KEY` and `SUI_MNEMONIC` from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like [`cast wallet`](https://getfoundry.sh/cast/reference/wallet/#cast-wallet){target=\\_blank}.\n\n    !!! warning\n        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.\n\n4. **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.\n\n    1. Create the helpers file.\n\n        ```bash\n        mkdir -p src/helpers\n        touch src/helpers/helpers.ts\n        ```\n\n    2. Open the `helpers.ts` file and add the following code.\n\n        ```typescript\n        import {\n          ChainAddress,\n          ChainContext,\n          Network,\n          Signer,\n          Wormhole,\n          Chain,\n          TokenId,\n          isTokenId,\n        } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/evm';\n        import solana from '@wormhole-foundation/sdk/solana';\n        import sui from '@wormhole-foundation/sdk/sui';\n        import aptos from '@wormhole-foundation/sdk/aptos';\n        import { config } from 'dotenv';\n        config();\n\n        export interface SignerStuff<N extends Network, C extends Chain> {\n          chain: ChainContext<N, C>;\n          signer: Signer<N, C>;\n          address: ChainAddress<C>;\n        }\n\n        // Signer setup function for different blockchain platforms\n        export async function getSigner<N extends Network, C extends Chain>(\n          chain: ChainContext<N, C>,\n          gasLimit?: bigint\n        ): Promise<{\n          chain: ChainContext<N, C>;\n          signer: Signer<N, C>;\n          address: ChainAddress<C>;\n        }> {\n          let signer: Signer;\n          const platform = chain.platform.utils()._platform;\n\n          switch (platform) {\n            case 'Solana':\n              signer = await (\n                await solana()\n              ).getSigner(await chain.getRpc(), 'SOL_PRIVATE_KEY');\n              break;\n            case 'Evm':\n              const evmSignerOptions = gasLimit ? { gasLimit } : {};\n              signer = await (\n                await evm()\n              ).getSigner(await chain.getRpc(), 'ETH_PRIVATE_KEY', evmSignerOptions);\n              break;\n            case 'Sui':\n              signer = await (\n                await sui()\n              ).getSigner(await chain.getRpc(), 'SUI_MNEMONIC');\n              break;\n            case 'Aptos':\n              signer = await (\n                await aptos()\n              ).getSigner(await chain.getRpc(), 'APTOS_PRIVATE_KEY');\n              break;\n            default:\n              throw new Error('Unsupported platform: ' + platform);\n          }\n\n          return {\n            chain,\n            signer: signer as Signer<N, C>,\n            address: Wormhole.chainAddress(chain.chain, signer.address()),\n          };\n        }\n\n        export async function getTokenDecimals<\n          N extends 'Mainnet' | 'Testnet' | 'Devnet'\n        >(\n          wh: Wormhole<N>,\n          token: TokenId,\n          sendChain: ChainContext<N, any>\n        ): Promise<number> {\n          return isTokenId(token)\n            ? Number(await wh.getDecimals(token.chain, token.address))\n            : sendChain.config.nativeTokenDecimals;\n        }\n        ```\n\n        - **`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.\n        - **`getTokenDecimals`**: Fetches the number of decimals for a token on a specific chain. It helps handle token amounts accurately during transfers."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 3, "depth": 2, "title": "Check and Create Wrapped Tokens", "anchor": "check-and-create-wrapped-tokens", "start_char": 7924, "end_char": 8358, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "## Check and Create Wrapped Tokens\n\nBefore 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.\n\nIn 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 4, "depth": 3, "title": "Configure the Wrapped Token Script", "anchor": "configure-the-wrapped-token-script", "start_char": 8358, "end_char": 17392, "estimated_token_count": 2004, "token_estimator": "heuristic-v1", "text": "### Configure the Wrapped Token Script\n\n1. **Create the `create-wrapped.ts` file**: Set up the script file that will handle checking and wrapping tokens in the `src` directory.\n\n    ```bash\n    mkdir -p src/scripts\n    touch src/scripts/create-wrapped.ts\n    ```\n\n2. **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.\n\n    ```typescript\n    import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import { inspect } from 'util';\n    import { getSigner } from '../helpers/helpers';\n    ```\n\n3. **Initialize the Wormhole SDK**: Initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support.\n\n    ```typescript\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana, sui]);\n    ```\n\n    !!! note\n        You can replace `'Testnet'` with `'Mainnet'` if you want to perform transfers on mainnet.\n\n4. **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).\n\n    ```typescript\n      const srcChain = wh.getChain('ArbitrumSepolia');\n      const destChain = wh.getChain('BaseSepolia');\n      const token = await srcChain.getNativeWrappedTokenId();\n      const gasLimit = BigInt(2_500_000);\n    ```\n\n5. **Set up the destination chain signer**: The signer authorizes transactions, such as submitting the attestation.\n\n    ```typescript\n      const { signer: destSigner } = await getSigner(destChain, gasLimit);\n    ```\n\n6. **Check if the token is wrapped on the destination chain**: Verify if the token already exists as a wrapped asset before creating an attestation.\n\n    ```typescript\n      const tbDest = await destChain.getTokenBridge();\n\n      try {\n        const wrapped = await tbDest.getWrappedAsset(token);\n        console.log(\n          `Token already wrapped on ${destChain.chain}. Skipping attestation.`\n        );\n        return { chain: destChain.chain, address: wrapped };\n      } catch (e) {\n        console.log(\n          `No wrapped token found on ${destChain.chain}. Proceeding with attestation.`\n        );\n      }\n    ```\n\n    If the token is already wrapped, the script exits, and you may proceed to the [next section](/docs/products/token-transfers/wrapped-token-transfers/tutorials/transfer-workflow/#token-transfers). Otherwise, an attestation must be generated.\n\n7. **Set up the source chain signer**: The signer creates and submits the attestation transaction.\n\n    ```typescript\n      const { signer: origSigner } = await getSigner(srcChain);\n    ```\n\n8. **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.\n\n    ```typescript\n      const tbOrig = await srcChain.getTokenBridge();\n      const attestTxns = tbOrig.createAttestation(\n        token.address,\n        Wormhole.parseAddress(origSigner.chain(), origSigner.address())\n      );\n\n      const txids = await signSendWait(srcChain, attestTxns, origSigner);\n      console.log('txids: ', inspect(txids, { depth: null }));\n      const txid = txids[0]!.txid;\n      console.log('Created attestation (save this): ', txid);\n    ```\n\n9. **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.\n\n    ```typescript\n      const msgs = await srcChain.parseTransaction(txid);\n      console.log('Parsed Messages:', msgs);\n\n      const timeout = 25 * 60 * 1000;\n      const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout);\n      if (!vaa) {\n        throw new Error(\n          'VAA not found after retries exhausted. Try extending the timeout.'\n        );\n      }\n    ```\n\n10. **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.\n\n    ```typescript\n      const subAttestation = tbDest.submitAttestation(\n        vaa,\n        Wormhole.parseAddress(destSigner.chain(), destSigner.address())\n      );\n\n      const tsx = await signSendWait(destChain, subAttestation, destSigner);\n    ```\n\n11. **Wait for the wrapped asset to be available**: Poll until the wrapped token is available on the destination chain.\n\n    ```typescript\n      async function waitForIt() {\n        do {\n          try {\n            const wrapped = await tbDest.getWrappedAsset(token);\n            return { chain: destChain.chain, address: wrapped };\n          } catch (e) {\n            console.error('Wrapped asset not found yet. Retrying...');\n          }\n          console.log('Waiting before checking again...');\n          await new Promise((r) => setTimeout(r, 2000));\n        } while (true);\n      }\n\n      console.log('Wrapped Asset: ', await waitForIt());\n    })().catch((e) => console.error(e));\n    ```\n\n    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.\n\n??? code \"Complete script\"\n    ```typescript\n    import { Wormhole, signSendWait, wormhole } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import { inspect } from 'util';\n    import { getSigner } from '../helpers/helpers';\n\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana, sui]);\n\n      // Define the source and destination chains\n      const srcChain = wh.getChain('ArbitrumSepolia');\n      const destChain = wh.getChain('BaseSepolia');\n      const token = await srcChain.getNativeWrappedTokenId();\n      const gasLimit = BigInt(2_500_000);\n\n      // Destination chain signer setup\n      const { signer: destSigner } = await getSigner(destChain, gasLimit);\n      const tbDest = await destChain.getTokenBridge();\n\n      try {\n        const wrapped = await tbDest.getWrappedAsset(token);\n        console.log(\n          `Token already wrapped on ${destChain.chain}. Skipping attestation.`\n        );\n        return { chain: destChain.chain, address: wrapped };\n      } catch (e) {\n        console.log(\n          `No wrapped token found on ${destChain.chain}. Proceeding with attestation.`\n        );\n      }\n\n      // Source chain signer setup\n      const { signer: origSigner } = await getSigner(srcChain);\n\n      // Create an attestation transaction on the source chain\n      const tbOrig = await srcChain.getTokenBridge();\n      const attestTxns = tbOrig.createAttestation(\n        token.address,\n        Wormhole.parseAddress(origSigner.chain(), origSigner.address())\n      );\n\n      const txids = await signSendWait(srcChain, attestTxns, origSigner);\n      console.log('txids: ', inspect(txids, { depth: null }));\n      const txid = txids[0]!.txid;\n      console.log('Created attestation (save this): ', txid);\n\n      // Retrieve the Wormhole message ID from the attestation transaction\n      const msgs = await srcChain.parseTransaction(txid);\n      console.log('Parsed Messages:', msgs);\n\n      const timeout = 25 * 60 * 1000;\n      const vaa = await wh.getVaa(msgs[0]!, 'TokenBridge:AttestMeta', timeout);\n      if (!vaa) {\n        throw new Error(\n          'VAA not found after retries exhausted. Try extending the timeout.'\n        );\n      }\n\n      console.log('Token Address: ', vaa.payload.token.address);\n\n      // Submit the attestation on the destination chain\n      console.log('Attesting asset on destination chain...');\n\n      const subAttestation = tbDest.submitAttestation(\n        vaa,\n        Wormhole.parseAddress(destSigner.chain(), destSigner.address())\n      );\n\n      const tsx = await signSendWait(destChain, subAttestation, destSigner);\n      console.log('Transaction hash: ', tsx);\n\n      // Poll for the wrapped asset until it's available\n      async function waitForIt() {\n        do {\n          try {\n            const wrapped = await tbDest.getWrappedAsset(token);\n            return { chain: destChain.chain, address: wrapped };\n          } catch (e) {\n            console.error('Wrapped asset not found yet. Retrying...');\n          }\n          console.log('Waiting before checking again...');\n          await new Promise((r) => setTimeout(r, 2000));\n        } while (true);\n      }\n\n      console.log('Wrapped Asset: ', await waitForIt());\n    })().catch((e) => console.error(e));\n    ```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 5, "depth": 3, "title": "Run the Wrapped Token Creation", "anchor": "run-the-wrapped-token-creation", "start_char": 17392, "end_char": 17692, "estimated_token_count": 70, "token_estimator": "heuristic-v1", "text": "### Run the Wrapped Token Creation\n\nOnce the script is ready, execute it with:\n\n```bash\nnpx tsx src/scripts/create-wrapped.ts\n```\n\nIf 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 6, "depth": 2, "title": "Token Transfers", "anchor": "token-transfers", "start_char": 17692, "end_char": 18087, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "## Token Transfers\n\nIn this section, you'll create a script to transfer native tokens across chains using Wormhole's WTT protocol. 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 7, "depth": 3, "title": "Configure Transfer Details", "anchor": "configure-transfer-details", "start_char": 18087, "end_char": 21854, "estimated_token_count": 840, "token_estimator": "heuristic-v1", "text": "### Configure Transfer Details\n\nBefore initiating a cross-chain transfer, you must set up the chain context and signers for both the source and destination chains.\n\n1. Create the `native-transfer.ts` file in the `src` directory to hold your script for transferring native tokens across chains.\n\n    ```bash\n    touch src/scripts/native-transfer.ts\n    ```\n\n2. Open the `native-transfer.ts` file and begin by importing the necessary modules from the SDK and helper files.\n\n    ```typescript\n    import {\n      Chain,\n      Network,\n      Wormhole,\n      amount,\n      wormhole,\n      TokenId,\n      TokenTransfer,\n    } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers';\n    ```\n\n3. **Initialize the Wormhole SDK**: Initialize the `wormhole` function for the `Testnet` environment and specify the platforms (EVM, Solana, and Sui) to support.\n\n    ```typescript\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana, sui]);\n    ```\n\n4. **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.\n\n    ```typescript\n      const sendChain = wh.getChain('Sui');\n      const rcvChain = wh.getChain('Solana');\n    ```\n\n5. **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.\n\n    ```typescript\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n    ```\n\n6. **Define the token to transfer**: Specify the native token on the source chain (Sui in this example) by creating a `TokenId` object.\n\n    ```typescript\n      const token = Wormhole.tokenId(sendChain.chain, 'native');\n    ```\n\n7. **Define the transfer amount**: The amount of native tokens to transfer is specified. In this case, we're transferring 1 unit.\n\n    ```typescript\n      const amt = '1';\n    ```\n\n8. **Set transfer mode**: Specify manual or automatic transfer using `route`. Set `route  = 'TokenBridge'` for manual transfers, where you will handle the attestation and finalization steps yourself. To use automatic relaying on EVM chains, set `route = 'AutomaticTokenBridge'`.\n\n    ```typescript\n      const route = 'TokenBridge';\n    ```\n\n    !!! note\n        Automatic transfers are only supported for EVM chains. For non-EVM chains, such as Solana and Sui, you must manually handle the attestation and finalization steps.\n    \n9. **Define decimals**: Fetch the number of decimals for the token on the source chain (Sui) using the `getTokenDecimals` function.\n\n    ```typescript\n      const decimals = await getTokenDecimals(wh, token, sendChain);\n    ```\n\n10. **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`.\n\n    ```typescript\n      const xfer = await tokenTransfer(wh, {\n        token,\n        amount: amount.units(amount.parse(amt, decimals)),\n        source,\n        destination,\n        route,\n      });\n    ```\n\n    Finally, we use `process.exit(0);` to close the script once the transfer completes.\n\n    ```typescript\n      process.exit(0);\n    })();\n    ```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 8, "depth": 3, "title": "Token Transfer Logic", "anchor": "token-transfer-logic", "start_char": 21854, "end_char": 29444, "estimated_token_count": 1590, "token_estimator": "heuristic-v1", "text": "### Token Transfer Logic\n\nThis section defines the `tokenTransfer` function, which manages the core steps for executing cross-chain transfers. This function will handle initiating the transfer on the source chain, retrieving the attestation, and completing the transfer on the destination chain.\n\n#### Defining the Token Transfer Function\n\nThe `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.\n\n```typescript\nasync function tokenTransfer<N extends Network>(\n  wh: Wormhole<N>,\n  route: {\n    token: TokenId;\n    amount: bigint;\n    source: SignerStuff<N, Chain>;\n    destination: SignerStuff<N, Chain>;\n    route: string;\n    payload?: Uint8Array;\n  }\n) {\n  // Token Transfer Logic\n}\n```\n\n#### Steps to Transfer Tokens\n\nThe `tokenTransfer` function comprises several key steps to facilitate cross-chain transfers. Let’s break down each step:\n\n1. **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.\n\n    ```typescript\n      const xfer = await wh.tokenTransfer(\n        route.token,\n        route.amount,\n        route.source.address,\n        route.destination.address,\n        route.route,\n        route.payload\n      );\n    ```\n\n2. **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.\n\n    ```typescript\n      const quote = await TokenTransfer.quoteTransfer(\n        wh,\n        route.source.chain,\n        route.destination.chain,\n        xfer.transfer\n      );\n\n      if (xfer.transfer.route === 'AutomaticTokenBridge' && quote.destinationToken.amount < 0)\n        throw 'The amount requested is too low to cover the fee and any native gas requested.';\n    ```\n\n3. **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.\n\n    ```typescript\n      const srcTxids = await xfer.initiateTransfer(route.source.signer);\n      console.log(`Source Trasaction ID: ${srcTxids[0]}`);\n    ```\n\n     - **`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}.\n\n    ???- note \"How Cross-Chain Transfers Work in the Background\"\n        When `xfer.initiateTransfer(route.source.signer)` is called, it initiates the transfer on the source chain. Here’s what happens in the background:\n\n         - **Token lock or burn**: Tokens are either locked in a smart contract or burned on the source chain, representing the transfer amount.\n         - **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.\n         - **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.\n         - **Redemption on destination**: Once detected, the VAA is used to release or mint the corresponding token amount on the destination chain, completing the transfer.\n\n        This process ensures a secure and verifiable transfer across chains, from locking tokens on the source chain to redeeming them on the destination chain.\n\n4. **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.\n\n    ```typescript\n      await xfer.fetchAttestation(60_000);\n    ```\n\n5. **Complete the transfer on the destination chain**: Redeem the VAA on the destination chain to finalize the transfer.\n\n    ```typescript\n      const destTxids = await xfer.completeTransfer(route.destination.signer);\n      console.log(`Completed Transfer: `, destTxids);\n    ```\n\n??? code \"Complete script\"\n    ```typescript\n    import {\n      Chain,\n      Network,\n      Wormhole,\n      amount,\n      wormhole,\n      TokenId,\n      TokenTransfer,\n    } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import sui from '@wormhole-foundation/sdk/sui';\n    import { SignerStuff, getSigner, getTokenDecimals } from '../helpers/helpers';\n\n    (async function () {\n      const wh = await wormhole('Testnet', [evm, solana, sui]);\n\n      // Set up source and destination chains\n      const sendChain = wh.getChain('Sui');\n      const rcvChain = wh.getChain('Solana');\n\n      // Get signer from local key but anything that implements\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n\n      // Shortcut to allow transferring native gas token\n      const token = Wormhole.tokenId(sendChain.chain, 'native');\n\n      // Define the amount of tokens to transfer\n      const amt = '1';\n\n      // Set route for manual transfers\n      const route = 'TokenBridge';\n\n      // Used to normalize the amount to account for the tokens decimals\n      const decimals = await getTokenDecimals(wh, token, sendChain);\n\n      // Perform the token transfer if no recovery transaction ID is provided\n      const xfer = await tokenTransfer(wh, {\n        token,\n        amount: amount.units(amount.parse(amt, decimals)),\n        source,\n        destination,\n        route,\n      });\n\n      process.exit(0);\n    })();\n\n    async function tokenTransfer<N extends Network>(\n      wh: Wormhole<N>,\n      route: {\n        token: TokenId;\n        amount: bigint;\n        source: SignerStuff<N, Chain>;\n        destination: SignerStuff<N, Chain>;\n        route: string;\n        payload?: Uint8Array;\n      }\n    ) {\n      // Token Transfer Logic\n      // Create a TokenTransfer object to track the state of the transfer over time\n      const xfer = await wh.tokenTransfer(\n        route.token,\n        route.amount,\n        route.source.address,\n        route.destination.address,\n        route.route,\n        route.payload\n      );\n\n      const quote = await TokenTransfer.quoteTransfer(\n        wh,\n        route.source.chain,\n        route.destination.chain,\n        xfer.transfer\n      );\n\n      if (xfer.transfer.route === 'AutomaticTokenBridge' && quote.destinationToken.amount < 0)\n        throw 'The amount requested is too low to cover the fee and any native gas requested.';\n\n      // Submit the transactions to the source chain, passing a signer to sign any txns\n      console.log('Starting transfer');\n      const srcTxids = await xfer.initiateTransfer(route.source.signer);\n      console.log(`Source Trasaction ID: ${srcTxids[0]}`);\n      console.log(`Wormhole Trasaction ID: ${srcTxids[1] ?? srcTxids[0]}`);\n\n      // Wait for the VAA to be signed and ready (not required for auto transfer)\n      console.log('Getting Attestation');\n      await xfer.fetchAttestation(60_000);\n\n      // Redeem the VAA on the dest chain\n      console.log('Completing Transfer');\n      const destTxids = await xfer.completeTransfer(route.destination.signer);\n      console.log(`Completed Transfer: `, destTxids);\n    }\n    ```"}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 9, "depth": 3, "title": "Run the Native Token Transfer", "anchor": "run-the-native-token-transfer", "start_char": 29444, "end_char": 29994, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "### Run the Native Token Transfer\n\nNow 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:\n\n```bash\nnpx tsx src/scripts/native-transfer.ts\n```\n\nThis initiates the native token transfer from the source chain (Sui) and completes it on the destination chain (Solana).\n\nYou can monitor the status of the transaction on the [Wormhole explorer](https://wormholescan.io/#/?network=Testnet){target=\\_blank}."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 10, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 29994, "end_char": 30452, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "## Resources\n\nIf 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."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 11, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 30452, "end_char": 30884, "estimated_token_count": 82, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nYou've successfully built a cross-chain token transfer application using Wormhole's TypeScript SDK and the WTT protocol. This guide walks you through the setup, configuration, and transfer logic required to move native tokens across non-EVM chains, such as Sui and Solana.\n\nThe same transfer logic will apply if you’d like to extend this application to different chain combinations, including EVM-compatible chains."}
{"page_id": "products-token-transfers-wrapped-token-transfers-tutorials-transfer-workflow", "page_title": "Transfer Tokens via Wrapped Token Transfers (WTT) Tutorial", "index": 12, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 30884, "end_char": 31716, "estimated_token_count": 205, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-tools-16:{ .lg .middle } **Build a Staking and Lending Protocol**\n\n    ---\n\n    Master the core features of Wrapped Token Transfers (WTT) by building a real-world staking and lending protocol on the Wormhole Dev Arena, a structured learning hub with hands-on tutorials across the Wormhole ecosystem. \n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/courses/1bee7446-5ed5-8188-92ae-c13ee2f78b1c){target=\\_blank}\n\n-   :octicons-tools-16:{ .lg .middle } **Demo Tutorials Repository**\n\n    ---\n\n    Looking for more hands-on tutorials? Check out the Wormhole Tutorial Demo repository on GitHub for additional examples.\n\n    [:custom-arrow: Explore the Demo Repository](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-architecture", "page_title": "Architecture", "index": 0, "depth": 2, "title": "On-Chain Components", "anchor": "on-chain-components", "start_char": 2299, "end_char": 2965, "estimated_token_count": 139, "token_estimator": "heuristic-v1", "text": "## On-Chain Components\n\n- **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.\n- **[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.\n- **Transaction logs**: Blockchain-specific logs that allow the Guardians to observe messages emitted by the Core Contract."}
{"page_id": "protocol-architecture", "page_title": "Architecture", "index": 1, "depth": 2, "title": "Off-Chain Components", "anchor": "off-chain-components", "start_char": 2965, "end_char": 4576, "estimated_token_count": 365, "token_estimator": "heuristic-v1", "text": "## Off-Chain Components\n\n- **Guardian Network**: Validators that exist in their own P2P network. Guardians observe and validate messages emitted by the Core Contract to produce VAAs. For full Guardian Set chains, all Guardians perform direct on-chain observation. For delegated chains, a delegated subset performs observation and broadcasts signed delegate observations to the rest of the network, after which Canonical Guardians wait for delegate quorum before signing.\n- **[Guardian](/docs/protocol/infrastructure/guardians/){target=\\_blank}**: One of 19 validators in the Guardian Network that contributes to the VAA multisig.\n- **[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.\n- **[API](https://docs.wormholescan.io/){target=\\_blank}**: A REST server to retrieve details for a VAA or the Guardian Network.\n- **[VAAs](/docs/protocol/infrastructure/vaas/){target=\\_blank}**: Verifiable Action Approvals (VAAs) are the signed attestation of an observed message from the Wormhole Core Contract.\n- **[Relayer](/docs/protocol/infrastructure/relayers/relayer/){target=\\_blank}**: Any off-chain process that relays a VAA to the target chain. Wormhole provides the [Executor framework](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank}, a shared execution framework. This framework enables permissionless message delivery through an open marketplace where relay providers compete using a request-and-quote model."}
{"page_id": "protocol-architecture", "page_title": "Architecture", "index": 2, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 4576, "end_char": 5210, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Core Contracts**\n\n    ---\n\n    Discover Wormhole's Core Contracts, enabling multichain communication with message sending, receiving, and multicast features for efficient synchronization.\n\n    [:custom-arrow: Explore Core Contracts](/docs/protocol/infrastructure/core-contracts/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-ecosystem", "page_title": "Ecosystem", "index": 0, "depth": 2, "title": "Ecosystem Overview", "anchor": "ecosystem-overview", "start_char": 939, "end_char": 2520, "estimated_token_count": 416, "token_estimator": "heuristic-v1", "text": "## Ecosystem Overview\n\nThe diagram shows a high-level view of Wormhole’s modular stack, illustrating how different tools are grouped into four layers:\n\n- **Application and user-facing products**: The top layer includes user-centric solutions such as [Connect](/docs/products/connect/overview/){target=\\_blank} (a simple bridging interface).\n- **Asset and data transfer layer**: Below it sits the core bridging and data solutions—[NTT](/docs/products/token-transfers/native-token-transfers/overview/){target=\\_blank}, [WTT](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank}, [Queries](/docs/products/queries/overview/){target=\\_blank}, [Settlement](/docs/products/settlement/overview/){target=\\_blank}, and [MultiGov](/docs/products/multigov/overview/){target=\\_blank}—that handle the movement of tokens, real-time data fetching, advanced cross-chain settlements, and cross-chain governance.\n- **Integration layer**: The [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\\_blank} and [WormholeScan API](https://wormholescan.io/#/){target=\\_blank} provide developer-friendly libraries and APIs to integrate cross-chain capabilities into applications.\n- **Foundation layer**: At the base, the [Wormhole messaging](/docs/products/messaging/overview/){target=\\_blank} system and the [core contracts](/docs/protocol/infrastructure/core-contracts/){target=\\_blank} secure the entire network, providing essential verification and cross-chain message delivery.\n\n![Wormhole ecosystem diagram](/docs/images/protocol/ecosystem/ecosystem-1.webp)"}
{"page_id": "protocol-ecosystem", "page_title": "Ecosystem", "index": 1, "depth": 2, "title": "Bringing It All Together: Interoperability in Action", "anchor": "bringing-it-all-together-interoperability-in-action", "start_char": 2520, "end_char": 3466, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "## Bringing It All Together: Interoperability in Action\n\nWormhole’s modularity makes it easy to adopt just the pieces you need. If you want to quickly add bridging to a dApp, use Connect at the top layer while relying on the Foundation Layer behind the scenes. Or if your app needs to send raw messages between chains, integrate the Messaging layer directly via the Integration Layer (TypeScript or Solidity SDK). You can even layer on additional features—like real-time data calls from Queries or more flexible bridging flows with Native Token Transfers.\n\nUltimately, these components aren’t siloed but designed to be combined. You could, for instance, fetch a balance from one chain using Queries and then perform an on-chain swap on another chain using Settlement. Regardless of your approach, each Wormhole product is powered by the same Guardian-secured messaging backbone, ensuring all cross-chain interactions remain reliable and secure."}
{"page_id": "protocol-ecosystem", "page_title": "Ecosystem", "index": 2, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 3466, "end_char": 4025, "estimated_token_count": 145, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Visit the Product Comparison**\n\n    ---\n\n    Unsure which bridging solution you need? Match your requirements with the right Wormhole tool.\n\n    [:custom-arrow: Compare Products](/docs/products/overview/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 767, "end_char": 2003, "estimated_token_count": 259, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore integrating CCTP with Executor, ensure that:\n\n- Both the source and destination chains are supported.\n- The required CCTP relay type (CCTPv1 `ERC1` or CCTPv2 `ERC2`) is enabled for the destination chain. \n\n!!! note \n    Circle’s Cross-Chain Transfer Protocol supports two versions: CCTPv1 and CCTPv2. These versions differ in how transfers are finalized and how execution can be composed on the destination chain. For a detailed explanation of the differences between CCTPv1 and CCTPv2, see [Circle’s overview](https://www.circle.com/blog/cctp-v2-the-future-of-cross-chain){target=\\_blank}. \n\n??? info \"How to verify chain and relay type support\"\n\n    You can confirm chain and relay type support using the capabilities endpoint:\n\n    ```sh\n    GET https://executor-testnet.labsapis.com/v0/capabilities\n    ```\n    The response includes:\n\n      - Supported source and destination chains\n      - Enabled CCTP relay types (`ERC1` or `ERC2`) for the destination chain\n      - Gas drop-off limits, which define the maximum gas the relay provider can allocate\n\n    The relay provider will only respect the first `GasDropOffInstruction` and will drop off the lesser of the requested amount and the configured limit."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 1, "depth": 2, "title": "References", "anchor": "references", "start_char": 2003, "end_char": 2835, "estimated_token_count": 265, "token_estimator": "heuristic-v1", "text": "## References\n\nUse the following resources throughout this guide:\n\n- [**CCTP with Executor addresses**](/docs/products/messaging/reference/executor-addresses/#cctp-with-executor){target=\\_blank}: List of deployed contracts for CCTP with Executor.\n- **Executor endpoints**: Used for quote requests, transaction status checks, and capability queries.\n\n    | Environment | URL                                                                            |\n    |-------------|--------------------------------------------------------------------------------|\n    | **Mainnet** | <pre>```https://executor.labsapis.com```</pre> |\n    | **Testnet** | <pre>```https://executor-testnet.labsapis.com```</pre> |\n\n    For development and testing, use the testnet endpoint. The mainnet relay provider is reserved for production-ready deployments."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 2, "depth": 2, "title": "Generate Relay Instructions", "anchor": "generate-relay-instructions", "start_char": 2835, "end_char": 5477, "estimated_token_count": 628, "token_estimator": "heuristic-v1", "text": "## Generate Relay Instructions\n\nRelay instructions define how the Executor should perform the relay on the destination chain, including gas limits and optional native token drop-offs. They are serialized into a compact byte format and passed to the Executor contract when submitting a transfer. Before generating relay instructions, install the SDK [Definitions](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/definitions/src/nttWithExecutor.ts){target=\\_blank} package:\n\n```sh\nnpm i @wormhole-foundation/sdk-definitions\n```\n\n[Layouts](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/main/core/definitions/src/protocols/executor/relayInstruction.ts){target=\\_blank} for the Executor `relayInstructions` are provided by the Wormhole TypeScript SDK. Once installed, use the `serializeLayout` helper to construct and encode your relay instructions:\n\n```tsx\nimport {\n  encoding,\n  serializeLayout,\n  UniversalAddress,\n} from \"@wormhole-foundation/sdk-connect\";\nimport { relayInstructionsLayout } from \"@wormhole-foundation/sdk-definitions\";\n\nconst relayInstructions = serializeLayout(relayInstructionsLayout, {\n  requests: [\n    {\n      request: {\n\t      type: \"GasInstruction\",\n\t      gasLimit: 250000n,\n\t      msgValue: 0n,\n\t    },\n\t  }\n  ],\n});\n```\n\n??? interface \"Parameters\"\n\n    `type` ++\"GasInstruction\"++\n\n    Defines the instruction to allocate gas for the relay.\n\n    ---\n\n    `gasLimit` ++\"uint\"++\n\n    Specifies the maximum gas available for executing the redeem transaction on the destination chain.\n\n    ---\n\n    `msgValue` ++\"uint\"++\n\n    Represents the amount of native token (e.g., ETH, SOL) to forward with the transaction; this should typically be set to 0 for NTT transfers.\n\nRelay instructions are encoded using the `relayInstructionsLayout`, which always expects an array of instruction objects. Each array element is a `RelayInstruction` whose `request.type` determines the specific variant:\n\n| Instruction             | Description                                                               | Fields                 |\n| ----------------------- | ------------------------------------------------------------------------- | ---------------------- |\n| `GasInstruction`        | Defines gas allocation for relay execution                                | `gasLimit`, `msgValue` |\n| `GasDropOffInstruction` | Drops native tokens to a wallet on the destination chain                  | `dropOff`, `recipient` |\n\nRelay instructions can include multiple requests (e.g., for gas, value transfer, or drop-off). For most CCTP with Executor flows, a single `GasInstruction` is sufficient."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 3, "depth": 3, "title": "EVM", "anchor": "evm", "start_char": 5477, "end_char": 5837, "estimated_token_count": 75, "token_estimator": "heuristic-v1", "text": "### EVM\n\nFor EVM destinations:\n\n- `gasLimit` is the gas limit set on the redeeming transaction. Actual gas consumption depends on whether a gas drop-off instruction is included (in addition to the normal differences across various EVM chains).\n- `msgValue` is not used by CCTP’s `receiveMessage` entrypoints and should be set to zero for standard CCTP flows."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 4, "depth": 3, "title": "SVM", "anchor": "svm", "start_char": 5837, "end_char": 7182, "estimated_token_count": 278, "token_estimator": "heuristic-v1", "text": "### SVM\n\nFor Solana and other SVM chains:\n\n- `gasLimit` represents the number of compute units to allocate to the transaction.\n- The total relay cost is determined by:\n    - The CUs consumed by the transaction\n    - The [prioritization fee](https://solana.com/docs/core/fees#prioritization-fee){target=\\_blank} used by the relay provider\n- `msgValue` must cover all lamports required for:\n    - Transaction fees\n    - Priority fees\n    - Any rent required for new accounts\n\nCCTP transfers to Solana are redeemed into a USDC token account that must exist before redemption. If the recipient's associated token account (ATA) does not exist, the relayer can create it, but this increases the rent and `msgValue` requirements. To allow the relayer to create the ATA automatically:\n\n1. Target the associated token account for the recipient.\n2. Before sending, check whether the ATA exists.\n3. If it does not exist, include a zero-value `GasDropOffInstruction` for the wallet owner (not the ATA). This gives the relayer enough information to re-derive and create the ATA.\n\n!!!note\n    If a non-zero `GasDropOffInstruction` is used for a new wallet, the drop-off amount must be greater than `getMinimumBalanceForRentExemption` for the token account. Drop-offs below this threshold for new accounts are ignored to avoid guaranteed transaction failure."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 5, "depth": 3, "title": "Sui", "anchor": "sui", "start_char": 7182, "end_char": 7597, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "### Sui\n\nFor Sui:\n\n- `gasLimit` represents the gas budget for the transaction.\n- As with native Sui transactions, the budget often needs to exceed the actual cost to account for variable execution and storage usage.\n- A direct gas budget is used instead of a simulated CU-style model due to the [non-linear gas cost structure](https://docs.sui.io/concepts/tokenomics/gas-in-sui#gas-prices){target=\\_blank} on Sui."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 6, "depth": 2, "title": "Request a Signed Quote", "anchor": "request-a-signed-quote", "start_char": 7597, "end_char": 9066, "estimated_token_count": 251, "token_estimator": "heuristic-v1", "text": "## Request a Signed Quote\n\nOnce you have your relay instructions ready, request a `SignedQuote` from the Executor Relay Provider. The quote authorizes a provider to perform the relay and includes an estimated cost. The example below requests a quote from Sepolia to Base Sepolia:\n\n```ts\nconst EXECUTOR_URL = 'https://executor-testnet.labsapis.com';\nconst { signedQuote: quote, estimatedCost: estimate } = (\n  await axios.post(`${EXECUTOR_URL}/v0/quote`, {\n    srcChain: 10002,\n    dstChain: 10004,\n    relayInstructions,\n  })\n).data;\n```\n\n??? interface \"Parameters\"\n\n    `srcChain` ++\"uint16\"++\n\n    Specify the Wormhole chain IDs for the source networks.\n\n    ---\n\n    `dstChain` ++\"uint16\"++\n\n    Specify the Wormhole chain IDs for the destination networks.\n\n    ---\n\n    `relayInstructions` ++\"Uint8Array\"++\n\n    Encodes the execution parameters you generated in the previous step.\n\n\nExample response:\n\n```bash\n{\n  \"signedQuote\": \"0x455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a271227140000000067dd750f00000000000003e80000000000514b7c000011bbaf716200000011bbaf716200f86edc3960908d257472836d5b1c33c457bf17af67a758d9984356e7166bec8162faa0e07f991d061b93e4f033895c71134a30d9ca369c606fcabba0b742d2431c\",\n  \"estimatedCost\": \"1431935000000\"\n}\n```\n\nSigned Quotes have an expiry time and must be generated for each request. The Executor contract will revert if the quote expires before on-chain submission."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 7, "depth": 2, "title": "Call Sending Contract", "anchor": "call-sending-contract", "start_char": 9066, "end_char": 9313, "estimated_token_count": 42, "token_estimator": "heuristic-v1", "text": "## Call Sending Contract\n\nWith relay instructions and a signed quote, the sending transaction can initiate both the CCTP burn and the Executor request, which instructs the relay provider to redeem and optionally execute on the destination chain."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 8, "depth": 3, "title": "EVM", "anchor": "evm-2", "start_char": 9313, "end_char": 13951, "estimated_token_count": 804, "token_estimator": "heuristic-v1", "text": "### EVM\n\nFor EVM chains, helper contracts wrap the CCTP calls and the Executor request into a single entry point. These helpers perform the CCTP burn via `depositForBurn`, followed by a `requestExecution` through the Executor using the signed quote and relay instructions you generated earlier. A version specific helper contract is used depending on whether your integration relies on CCTPv1 (`CCTPv1WithExecutor`) or CCTPv2 (`CCTPv2WithExecutor`).\n\nBoth versions share the same `ExecutorArgs` and `FeeArgs` structs:\n\n```sol\n// SPDX-License-Identifier: Apache 2\npragma solidity ^0.8.19;\n\nstruct ExecutorArgs {\n    // The refund address used by the Executor.\n    address refundAddress;\n    // The signed quote to be passed into the Executor.\n    bytes signedQuote;\n    // The relay instructions to be passed into the Executor.\n    bytes instructions;\n}\n\nstruct FeeArgs {\n    // The fee in tenths of basis points.\n    uint16 dbps;\n    // To whom the fee should be paid (the \"referrer\").\n    address payee;\n}\n```\n\nThe helper interfaces are as follows:\n\n??? interface \"ICCTPv1WithExecutor\"\n\n    ```sol\n    interface ICCTPv1WithExecutor {\n        /// @notice Deposits and burns tokens from sender to be minted on destination domain using the Executor for relaying.\n        /// @param amount amount of tokens to burn\n        /// @param destinationChain destination chain ID\n        /// @param destinationDomain destination domain (ETH = 0, AVAX = 1)\n        /// @param mintRecipient address of mint recipient on destination domain\n        /// @param burnToken address of contract to burn deposited tokens, on local domain\n        /// @param executorArgs The arguments to be passed into the Executor.\n        /// @param feeArgs The arguments used to compute and pay the referrer fee.\n        /// @return nonce Circle nonce reserved by message\n        ///\n        function depositForBurn(\n            uint256 amount,\n            uint16 destinationChain,\n            uint32 destinationDomain,\n            bytes32 mintRecipient,\n            address burnToken,\n            ExecutorArgs calldata executorArgs,\n            FeeArgs calldata feeArgs\n        ) external payable returns (uint64 nonce);\n    }\n    ```\n\n??? interface \"ICCTPv2WithExecutor\"\n\n    ```sol\n    interface ICCTPv2WithExecutor {\n        /**\n         * @notice Deposits and burns tokens from sender to be minted on destination domain.\n         * Emits a `DepositForBurn` event.\n         * @dev reverts if:\n         * - given burnToken is not supported\n         * - given destinationDomain has no TokenMessenger registered\n         * - transferFrom() reverts. For example, if sender's burnToken balance or approved allowance\n         * to this contract is less than `amount`.\n         * - burn() reverts. For example, if `amount` is 0.\n         * - maxFee is greater than or equal to `amount`.\n         * - MessageTransmitterV2#sendMessage reverts.\n         * @param amount amount of tokens to burn\n         * @param destinationChain destination chain ID\n         * @param destinationDomain destination domain to receive message on\n         * @param mintRecipient address of mint recipient on destination domain\n         * @param burnToken token to burn `amount` of, on local domain\n         * @param destinationCaller authorized caller on the destination domain, as bytes32. If equal to bytes32(0),\n         * any address can broadcast the message.\n         * @param maxFee maximum fee to pay on the destination domain, specified in units of burnToken\n         * @param minFinalityThreshold the minimum finality at which a burn message will be attested to.\n         * @param executorArgs The arguments to be passed into the Executor.\n         * @param feeArgs The arguments used to compute and pay the referrer fee.\n         */\n        function depositForBurn(\n            uint256 amount,\n            uint16 destinationChain,\n            uint32 destinationDomain,\n            bytes32 mintRecipient,\n            address burnToken,\n            bytes32 destinationCaller,\n            uint256 maxFee,\n            uint32 minFinalityThreshold,\n            ExecutorArgs calldata executorArgs,\n            FeeArgs calldata feeArgs\n        ) external payable;\n    }\n    ```\n\nIn both cases, you pass:\n\n- `executorArgs.signedQuote`: The `signedQuote` returned by the Executor `/v0/quote` endpoint.\n- `executorArgs.instructions`: The serialized relay instructions from the previous step.\n- `executorArgs.refundAddress`: The address that should receive any unused funds refunded by the Executor.\n- `feeArgs`: Optional referrer fee configuration, if your integration charges a fee on transfers."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 9, "depth": 3, "title": "SVM with CCTPv1", "anchor": "svm-with-cctpv1", "start_char": 13951, "end_char": 23498, "estimated_token_count": 1657, "token_estimator": "heuristic-v1", "text": "### SVM with CCTPv1\n\nFor CCTPv1, an `ExampleCCTPExecutor` program is available to help compose a full CCTP Executor request directly on-chain. The program reads the latest nonce published by the CCTP `MessageTransmitter` and issues a relay request using that value.\n\n??? interface \"ExampleCCTPExecutor.json\"\n\n    ```json\n    {\n      \"address\": \"CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs\",\n      \"metadata\": {\n        \"name\": \"example_cctp_with_executor\",\n        \"version\": \"0.1.0\",\n        \"spec\": \"0.1.0\",\n        \"description\": \"Created with Anchor\"\n      },\n      \"instructions\": [\n        {\n          \"name\": \"relay_last_message\",\n          \"discriminator\": [\n            68,\n            157,\n            251,\n            90,\n            201,\n            66,\n            40,\n            60\n          ],\n          \"accounts\": [\n            {\n              \"name\": \"payer\",\n              \"docs\": [\n                \"Payer will pay the Executor\"\n              ],\n              \"writable\": true,\n              \"signer\": true\n            },\n            {\n              \"name\": \"payee\",\n              \"writable\": true\n            },\n            {\n              \"name\": \"message_transmitter\"\n            },\n            {\n              \"name\": \"executor_program\",\n              \"address\": \"Ax7mtQPbNPQmghd7C3BHrMdwwmkAXBDq7kNGfXNcc7dg\"\n            },\n            {\n              \"name\": \"system_program\",\n              \"address\": \"11111111111111111111111111111111\"\n            }\n          ],\n          \"args\": [\n            {\n              \"name\": \"args\",\n              \"type\": {\n                \"defined\": {\n                  \"name\": \"RelayLastMessageArgs\"\n                }\n              }\n            }\n          ]\n        }\n      ],\n      \"accounts\": [\n        {\n          \"name\": \"MessageTransmitter\",\n          \"discriminator\": [\n            71,\n            40,\n            180,\n            142,\n            19,\n            203,\n            35,\n            252\n          ]\n        }\n      ],\n      \"types\": [\n        {\n          \"name\": \"MessageTransmitter\",\n          \"docs\": [\n            \"Main state of the MessageTransmitter program\"\n          ],\n          \"type\": {\n            \"kind\": \"struct\",\n            \"fields\": [\n              {\n                \"name\": \"owner\",\n                \"type\": \"pubkey\"\n              },\n              {\n                \"name\": \"pending_owner\",\n                \"type\": \"pubkey\"\n              },\n              {\n                \"name\": \"attester_manager\",\n                \"type\": \"pubkey\"\n              },\n              {\n                \"name\": \"pauser\",\n                \"type\": \"pubkey\"\n              },\n              {\n                \"name\": \"paused\",\n                \"type\": \"bool\"\n              },\n              {\n                \"name\": \"local_domain\",\n                \"type\": \"u32\"\n              },\n              {\n                \"name\": \"version\",\n                \"type\": \"u32\"\n              },\n              {\n                \"name\": \"signature_threshold\",\n                \"type\": \"u32\"\n              },\n              {\n                \"name\": \"enabled_attesters\",\n                \"type\": {\n                  \"vec\": \"pubkey\"\n                }\n              },\n              {\n                \"name\": \"max_message_body_size\",\n                \"type\": \"u64\"\n              },\n              {\n                \"name\": \"next_available_nonce\",\n                \"type\": \"u64\"\n              }\n            ]\n          }\n        },\n        {\n          \"name\": \"RelayLastMessageArgs\",\n          \"type\": {\n            \"kind\": \"struct\",\n            \"fields\": [\n              {\n                \"name\": \"recipient_chain\",\n                \"type\": \"u16\"\n              },\n              {\n                \"name\": \"exec_amount\",\n                \"type\": \"u64\"\n              },\n              {\n                \"name\": \"signed_quote_bytes\",\n                \"type\": \"bytes\"\n              },\n              {\n                \"name\": \"relay_instructions\",\n                \"type\": \"bytes\"\n              }\n            ]\n          }\n        }\n      ]\n    }\n    ```\n\n??? interface \"ExampleCCTPExecutor.ts\"\n\n    ```tsx\n    /**\n     * Program IDL in camelCase format in order to be used in JS/TS.\n     *\n     * Note that this is only a type helper and is not the actual IDL. The original\n     * IDL can be found at `target/idl/example_cctp_with_executor.json`.\n     */\n    export type ExampleCctpWithExecutor = {\n      address: 'CXGRA5SCc8jxDbaQPZrmmZNu2JV34DP7gFW4m31uC1zs';\n      metadata: {\n        name: 'exampleCctpWithExecutor';\n        version: '0.1.0';\n        spec: '0.1.0';\n        description: 'Created with Anchor';\n      };\n      instructions: [\n        {\n          name: 'relayLastMessage';\n          discriminator: [68, 157, 251, 90, 201, 66, 40, 60];\n          accounts: [\n            {\n              name: 'payer';\n              docs: ['Payer will pay the Executor'];\n              writable: true;\n              signer: true;\n            },\n            {\n              name: 'payee';\n              writable: true;\n            },\n            {\n              name: 'messageTransmitter';\n            },\n            {\n              name: 'executorProgram';\n              address: 'Ax7mtQPbNPQmghd7C3BHrMdwwmkAXBDq7kNGfXNcc7dg';\n            },\n            {\n              name: 'systemProgram';\n              address: '11111111111111111111111111111111';\n            }\n          ];\n          args: [\n            {\n              name: 'args';\n              type: {\n                defined: {\n                  name: 'relayLastMessageArgs';\n                };\n              };\n            }\n          ];\n        }\n      ];\n      accounts: [\n        {\n          name: 'messageTransmitter';\n          discriminator: [71, 40, 180, 142, 19, 203, 35, 252];\n        }\n      ];\n      types: [\n        {\n          name: 'messageTransmitter';\n          docs: ['Main state of the MessageTransmitter program'];\n          type: {\n            kind: 'struct';\n            fields: [\n              {\n                name: 'owner';\n                type: 'pubkey';\n              },\n              {\n                name: 'pendingOwner';\n                type: 'pubkey';\n              },\n              {\n                name: 'attesterManager';\n                type: 'pubkey';\n              },\n              {\n                name: 'pauser';\n                type: 'pubkey';\n              },\n              {\n                name: 'paused';\n                type: 'bool';\n              },\n              {\n                name: 'localDomain';\n                type: 'u32';\n              },\n              {\n                name: 'version';\n                type: 'u32';\n              },\n              {\n                name: 'signatureThreshold';\n                type: 'u32';\n              },\n              {\n                name: 'enabledAttesters';\n                type: {\n                  vec: 'pubkey';\n                };\n              },\n              {\n                name: 'maxMessageBodySize';\n                type: 'u64';\n              },\n              {\n                name: 'nextAvailableNonce';\n                type: 'u64';\n              }\n            ];\n          };\n        },\n        {\n          name: 'relayLastMessageArgs';\n          type: {\n            kind: 'struct';\n            fields: [\n              {\n                name: 'recipientChain';\n                type: 'u16';\n              },\n              {\n                name: 'execAmount';\n                type: 'u64';\n              },\n              {\n                name: 'signedQuoteBytes';\n                type: 'bytes';\n              },\n              {\n                name: 'relayInstructions';\n                type: 'bytes';\n              }\n            ];\n          };\n        }\n      ];\n    };\n    ```\n    \nTo integrate this with your existing CCTP `depositForBurn` transaction, add `relayLastMessage` as a `postInstruction`:\n\n```tsx\nconst shimProgram = new Program<ExampleCctpWithExecutor>(\n  ExampleCctpWithExecutorIdl,\n  provider\n);\n\n// ... your CCTP depositForBurn builder ...\n\n.postInstructions([\n  await shimProgram.methods\n    .relayLastMessage({\n      execAmount: new BN(estimate),\n      recipientChain: dstChain,\n      signedQuoteBytes,\n      relayInstructions: Buffer.from(relayInstructions.substring(2), \"hex\"),\n    })\n    .accounts({\n      messageTransmitter: new web3.PublicKey(\n        \"BWrwSWjbikT3H7qHAkUEbLmwDQoB4ZDJ4wcSEhSPTZCu\"\n      ),\n      payee: new web3.PublicKey(signedQuoteBytes.subarray(24, 56)),\n    })\n    .instruction(),\n])\n...\n```\n\n??? interface \"Parameters\"\n\n    `execAmount` ++\"u64\"++  \n\n    The execution budget passed to the Executor. This should be set to the `estimatedCost` returned by the `/v0/quote` endpoint.\n\n    ---\n\n    `recipientChain` ++\"uint16\"++  \n\n    The Wormhole chain ID of the destination chain where the USDC redemption should occur.\n\n    ---\n\n    `signedQuoteBytes` ++\"bytes\"++  \n\n    The signed quote returned from the Executor `/v0/quote` endpoint. Must be passed as raw bytes (without the `0x` prefix).\n\n    ---\n\n    `relayInstructions` ++\"bytes\"++  \n\n    The serialized relay instructions generated earlier, typically created by converting the hex string into a byte buffer.\n\n    ---\n\n    `messageTransmitter` ++\"pubkey\"++  \n\n    The CCTP `MessageTransmitter` program account on Solana.\n\n    ---\n\n    `payee` ++\"pubkey\"++  \n\n    The address extracted from the signed quote that receives refunds or drop-offs.\n\n\nThis combines the CCTP burn and the Executor request atomically in a single Solana transaction."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 10, "depth": 3, "title": "SVM with CCTPv2", "anchor": "svm-with-cctpv2", "start_char": 23498, "end_char": 24326, "estimated_token_count": 161, "token_estimator": "heuristic-v1", "text": "### SVM with CCTPv2\n\nCCTPv2 on Solana does not require a dedicated helper program. The integration can be implemented entirely client-side:\n\n1. Call `depositForBurn` or `depositForBurnWithHook`.\n2. Follow by calling `requestForExecution` with `requestBytes: Buffer.from(\"4552433201\", \"hex\")`\n3. Pass `requestBytes`, the `signedQuote` from the quote endpoint, the serialized `relayInstructions`, and the estimated cost (as lamports) as `execAmount`.\n\nIf needed, you can fetch the on-chain IDLs for both programs:\n\n```bash\nanchor idl --provider.cluster m fetch CCTPV2Sm4AdWt5296sk4P66VBZ7bEhcARwFaaS9YPbeC\nanchor idl --provider.cluster m fetch execXUrAsMnqMmTHj5m7N1YQgsDz3cwGLYCYyuDRciV\n```\n\nThis allows CCTPv2 with Executor to be composed entirely in your client transaction builder without additional on-chain infrastructure."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 11, "depth": 3, "title": "Sui", "anchor": "sui-2", "start_char": 24326, "end_char": 26200, "estimated_token_count": 492, "token_estimator": "heuristic-v1", "text": "### Sui\n\nOn Sui, an `executor_requests` helper module is deployed so that, using [Programmable Transaction Blocks (PTB)](https://docs.sui.io/develop/transactions/ptbs/prog-txn-blocks){target=\\_blank}, no integration-specific Move module is required. You can extend an existing `deposit_for_burn` PTB by deriving the CCTP message fields and then issuing an Executor request.\n\nThe following example shows how to:\n\n1. Call `deposit_for_burn` and capture the returned CCTP message.\n2. Read the `source_domain` and `nonce` from the message.\n3. Build CCTPv1 request bytes via `executor_requests::make_cctp_v1_request`.\n4. Split off a coin to pay the Executor using the `estimatedCost` from the quote.\n5. Call `executor::request_execution` with the quote, request bytes, and relay instructions.\n\n```tsx\n// grab the message NestedResult\nconst [_, message] = tx.moveCall({\n  target: `${tokenMessengerId}::deposit_for_burn::deposit_for_burn`,\n  // ... existing CCTP args ...\n});\n\nconst [source_domain] = tx.moveCall({\n  target: `${messageTransmitterId}::message::source_domain`,\n  arguments: [message],\n});\n\nconst [nonce] = tx.moveCall({\n  target: `${messageTransmitterId}::message::nonce`,\n  arguments: [message],\n});\n\nconst [requestBytes] = tx.moveCall({\n  target: `${executorRequestsId}::executor_requests::make_cctp_v1_request`,\n  arguments: [source_domain, nonce],\n});\n\nconst [executorCoin] = tx.splitCoins(tx.gas, [tx.pure.u64(BigInt(estimate))]);\n\ntx.moveCall({\n  target: `${executorId}::executor::request_execution`,\n  arguments: [\n    executorCoin,\n    tx.object(SUI_CLOCK_OBJECT_ID),\n    tx.pure.u16(dstChain),\n    tx.pure.address('0x0'),\n    tx.pure.address(signer.getPublicKey().toSuiAddress()),\n    tx.pure.vector('u8', Buffer.from(quote.substring(2), 'hex')),\n    requestBytes,\n    tx.pure.vector('u8', Buffer.from(relayInstructions.substring(2), 'hex')),\n  ],\n});\n```"}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 12, "depth": 2, "title": "Check the Transaction Status", "anchor": "check-the-transaction-status", "start_char": 26200, "end_char": 26737, "estimated_token_count": 138, "token_estimator": "heuristic-v1", "text": "## Check the Transaction Status\n\nAfter submitting your transaction, you can query the relay provider to check its execution status. This allows you to confirm whether the transfer has been processed and finalized by the Executor.\n\n```ts\nconst res = await axios.post(`${EXECUTOR_URL}/v0/status/tx`, {\n  txHash,\n  chainId,\n});\n```\n\nYou can also link directly to the transaction in the explorer:\n\n```ts\n`https://wormholelabs-xyz.github.io/executor-explorer/#/chain/${chainId}tx/${txHash}?endpoint=${encodeURIComponent(EXECUTOR_URL)}`;\n```"}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 13, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 26737, "end_char": 27391, "estimated_token_count": 121, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nIntegrating CCTP with Executor enables permissionless, quote-based relaying and execution for USDC across EVM, SVM, and Sui. CCTP continues to provide the canonical burn-and-mint flow for USDC, while Executor coordinates cross-chain execution through a network of relay providers rather than a single dedicated relayer.\n\nApplications can build end-to-end CCTP transfers, with redeem and any follow-up logic handled automatically on the destination chain. This pattern lets you keep CCTP as the source of truth for USDC movement, while using Executor to flexibly manage gas, drop-offs, and execution behavior across multiple environments."}
{"page_id": "protocol-infrastructure-guides-cctp-executor", "page_title": "Integrate CCTP with Executor", "index": 14, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 27391, "end_char": 27703, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Circle CCTP Documentation**\n\n    ---\n\n    Learn how USDC cross-chain transfers work and explore advanced CCTP features.\n\n    [:custom-arrow: See the Circle Docs](https://developers.circle.com/cctp){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 0, "depth": 2, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 1413, "end_char": 2568, "estimated_token_count": 248, "token_estimator": "heuristic-v1", "text": "## Prerequisites\n\nBefore starting, ensure you have:\n\n- [NTT deployed](/docs/products/token-transfers/native-token-transfers/get-started/){target=\\_blank} on both the source and destination chains.\n- Verified that both source and destination chains are supported and that NTT with Executor (`ERN1`) is enabled on the destination chain. \n\n??? info \"How to verify chain and relay type support\"\n\n    You can confirm chain and relay type support using the capabilities endpoint:\n\n    ```sh\n    GET https://executor-testnet.labsapis.com/v0/capabilities\n    ```\n    The response includes:\n\n      - Supported source and destination chains\n      - Available relay types (e.g., `wormhole` or `ERN1`).\n      - Gas drop-off limits, which define the maximum gas the relay provider can allocate.\n\n    Chain identifiers returned by this endpoint use Wormhole chain IDs. A complete list of supported Wormhole chain IDs is available in the [Chain IDs reference](/docs/products/reference/chain-ids/){target=\\_blank}.\n\n    The relay provider will only respect the first `GasDropOffInstruction` and will drop off the lesser of the requested amount and the configured limit."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 1, "depth": 2, "title": "References", "anchor": "references", "start_char": 2568, "end_char": 3383, "estimated_token_count": 259, "token_estimator": "heuristic-v1", "text": "## References\n\nUse the following resources throughout this guide:\n\n- [**NTT With Executor addresses**](/docs/products/reference/executor-addresses/#ntt-with-executor){target=\\_blank}: List of deployed contracts for NTT with Executor.\n- **Executor endpoints**: Used for quote requests, transaction status checks, and capability queries.\n\n    | Environment | URL                                                                            |\n    | ----------- | ------------------------------------------------------------------------------ |\n    | **Mainnet** | <pre>```https://executor.labsapis.com```</pre> |\n    | **Testnet** | <pre>```https://executor-testnet.labsapis.com```</pre> |\n\nFor development and testing, use the testnet endpoint. The mainnet relay provider is reserved for production-ready deployments."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 2, "depth": 2, "title": "Generate Relay Instructions", "anchor": "generate-relay-instructions", "start_char": 3383, "end_char": 6102, "estimated_token_count": 634, "token_estimator": "heuristic-v1", "text": "## Generate Relay Instructions\n\nRelay instructions define how the Executor should perform the relay on the destination chain, including parameters such as gas limits, message value, and additional execution options. They are serialized into a compact byte format and passed to the Executor contract when a transfer is submitted. Before generating relay instructions, install the SDK [Definitions](https://github.com/wormhole-foundation/native-token-transfers/blob/main/sdk/definitions/src/nttWithExecutor.ts){target=\\_blank} package:\n\n```sh\nnpm i @wormhole-foundation/sdk-definitions\n```\n\n[Layouts](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/b9035ad835d70bb19df366662682d3510461d72b/core/definitions/src/protocols/executor/relayInstruction.ts){target=\\_blank} for the Executor `RelayInstructions` are provided by the Wormhole TypeScript SDK. Once installed, use the `serializeLayout` helper to construct and encode your relay instructions:\n\n```ts\nimport {\n  encoding,\n  serializeLayout,\n  UniversalAddress,\n} from \"@wormhole-foundation/sdk-connect\";\nimport { relayInstructionsLayout } from \"@wormhole-foundation/sdk-definitions\";\n\nconst relayInstructions = serializeLayout(relayInstructionsLayout, {\n  requests: [\n    {\n      request: {\n        type: \"GasInstruction\",\n        gasLimit: 500000n,\n        msgValue: 0n,\n      },\n    },\n  ],\n});\n```\n\n??? interface \"Parameters\"\n\n    `type` ++\"GasInstruction\"++\n\n    Defines the instruction to allocate gas for the relay.\n\n    ---\n\n    `gasLimit` ++\"uint\"++\n\n    Specifies the maximum gas available for executing the redeem transaction on the destination chain.\n\n    ---\n\n    `msgValue` ++\"uint\"++\n\n    Represents the amount of native token (e.g., ETH, SOL) to forward with the transaction. This parameter is typically set to 0 for NTT transfers.\n\nRelay instructions are encoded using the `relayInstructionsLayout`, which always expects an array of instruction objects. Each array element is a `RelayInstruction` whose `request.type` determines the specific variant:\n\n| Instruction             | Description                                                               | Fields                 |\n| ----------------------- | ------------------------------------------------------------------------- | ---------------------- |\n| `GasInstruction`        | Defines gas allocation for relay execution                                | `gasLimit`, `msgValue` |\n| `GasDropOffInstruction` | Drops native tokens to a wallet on the destination chain                  | `dropOff`, `recipient` |\n\nRelay instructions can include multiple requests (e.g., for gas, value transfer, or drop-off). For most NTT with Executor flows, a single `GasInstruction` is sufficient."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 3, "depth": 3, "title": "EVM", "anchor": "evm", "start_char": 6102, "end_char": 6416, "estimated_token_count": 64, "token_estimator": "heuristic-v1", "text": "### EVM\n\nFor EVM-based destination chains:\n\n- `gasLimit` defines the redeeming transaction gas limit on the destination chain. Actual gas usage depends on the token configuration, manager setup, and chain parameters.\n- `msgValue` is not used by NTT Transceivers’ `receiveMessage` function and should be set to 0."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 4, "depth": 3, "title": "SVM", "anchor": "svm", "start_char": 6416, "end_char": 7721, "estimated_token_count": 274, "token_estimator": "heuristic-v1", "text": "### SVM\n\nFor Solana and other SVM chains:\n\n- `gasLimit` represents the total compute units required across all transactions, plus a 20% buffer.\n- The relayer estimates required compute units using logic similar to [`determineComputeBudget`](https://github.com/wormhole-foundation/wormhole-sdk-ts/blob/2cf3749f01c09e97693fc8872180db442c09c778/platforms/solana/src/signer.ts#L357){target=\\_blank}, which simulates the transaction and sets the budget to 120% of the simulated `unitsConsumed`. This logic allows the relayer to automatically determine the budget required for each transaction in the series needed to perform an NTT redeem.\n- `msgValue` must cover the lamports required for the transaction, including priority fees and rent. Transfers to Solana are redeemed to an [associated token account (ATA)](https://www.solana-program.com/docs/associated-token-account){target=\\_blank}, which must exist before redemption. If missing, the relayer will automatically create the ATA, increasing rent cost and required `msgValue`.\n- When using a non-zero `GasDropOffInstruction` for a new wallet, the drop-off amount must be greater than the `getMinimumBalanceForRentExemption` lamports. Wormhole's relayer will ignore drop-offs to new accounts if they are below the minimum, as the transaction would fail."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 5, "depth": 2, "title": "Request a Signed Quote", "anchor": "request-a-signed-quote", "start_char": 7721, "end_char": 9611, "estimated_token_count": 353, "token_estimator": "heuristic-v1", "text": "## Request a Signed Quote\n\nOnce your relay instructions are generated, request a `SignedQuote` from the Executor Relay Provider. A signed quote authorizes the relay provider to execute the transfer and includes the estimated cost of execution. The following is an example of a quote request from Sepolia to Base Sepolia. See the complete list of supported [chain IDs](/docs/products/reference/chain-ids/){target=\\_blank}.\n\n```ts\nconst EXECUTOR_URL = 'https://executor-testnet.labsapis.com';\nconst { signedQuote: quote, estimatedCost: estimate } = (\n  await axios.post(`${EXECUTOR_URL}/v0/quote`, {\n    srcChain: 10002,\n    dstChain: 10004,\n    relayInstructions,\n  })\n).data;\n```\n\n??? interface \"Parameters\"\n\n    `srcChain` ++\"uint16\"++\n\n    Specify the Wormhole chain IDs for the source networks.\n\n    ---\n\n    `dstChain` ++\"uint16\"++\n\n    Specify the Wormhole chain IDs for the destination networks.\n\n    ---\n\n    `relayInstructions` ++\"Uint8Array\"++\n\n    Encodes the execution parameters you generated in the previous step.\n\nExample response:\n\n```sh\n{\n  \"signedQuote\": \"0x455130315241c9276698439fef2780dbab76fec90b633fbd000000000000000000000000f7122c001b3e07d7fafd8be3670545135859954a271227140000000067dd750f00000000000003e80000000000514b7c000011bbaf716200000011bbaf716200f86edc3960908d257472836d5b1c33c457bf17af67a758d9984356e7166bec8162faa0e07f991d061b93e4f033895c71134a30d9ca369c606fcabba0b742d2431c\",\n  \"estimatedCost\": \"1431935000000\"\n}\n```\n\n??? interface \"Returns\"\n\n    `signedQuote` ++\"string\"++\n\n    A signed authorization used in the on-chain call to the Executor. Includes quote data and a 65-byte ECDSA signature.\n\n    ---\n\n    `estimatedCost` ++\"string\"++\n\n    The total estimated gas or lamport cost for the relay.\n\nSigned quotes have an expiry time and must be generated for each request. The Executor contract will revert if the quote expires before on-chain submission."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 6, "depth": 2, "title": "Call Sending Contract", "anchor": "call-sending-contract", "start_char": 9611, "end_char": 9940, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## Call Sending Contract\n\nOnce you have generated your relay instructions and received a signed quote, use them to call your sending-side contract. Refer to the [NTT With Executor Addresses](/docs/products/reference/executor-addresses/#ntt-with-executor){target=\\_blank} page for the complete list of deployed helper contracts."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 7, "depth": 3, "title": "EVM", "anchor": "evm-2", "start_char": 9940, "end_char": 12503, "estimated_token_count": 469, "token_estimator": "heuristic-v1", "text": "### EVM\n\nFor EVM-based transfers, an `NttManagerWithExecutor` contract combines the standard NTT `transfer` and the Executor’s `requestExecution` into a single call. The `INttManagerWithExecutor` interface is defined as follows:\n\n```ts\n// SPDX-License-Identifier: Apache 2\npragma solidity ^0.8.19;\n\nstruct ExecutorArgs {\n    // The msg value to be passed into the Executor.\n    uint256 value;\n    // The refund address used by the Executor.\n    address refundAddress;\n    // The signed quote to be passed into the Executor.\n    bytes signedQuote;\n    // The relay instructions to be passed into the Executor.\n    bytes instructions;\n}\n\nstruct FeeArgs {\n    // The fee in tenths of basis points.\n    uint16 dbps;\n    // To whom the fee should be paid (the \"referrer\").\n    address payee;\n}\n\ninterface INttManagerWithExecutor {\n    /// @notice Error when the refund to the sender fails.\n    error RefundFailed(uint256 refundAmount);\n\n    /// @notice Transfer tokens using the Executor for relaying.\n    /// @param nttManager The NTT manager used for the transfer.\n    /// @param amount The amount to transfer.\n    /// @param recipientChain The Wormhole chain ID for the destination.\n    /// @param recipientAddress The recipient address.\n    /// @param refundAddress The address to which unused gas is refunded.\n    /// @param shouldQueue Whether the transfer should be queued if the outbound limit is hit.\n    /// @param encodedInstructions Additional instructions for the destination chain.\n    /// @param executorArgs The arguments to be passed into the Executor.\n    /// @param feeArgs The arguments used to compute and pay the referrer fee.\n    /// @return msgId The resulting message ID of the transfer.\n    function transfer(\n        address nttManager,\n        uint256 amount,\n        uint16 recipientChain,\n        bytes32 recipientAddress,\n        bytes32 refundAddress,\n        bool shouldQueue,\n        bytes memory encodedInstructions,\n        ExecutorArgs calldata executorArgs,\n        FeeArgs calldata feeArgs\n    ) external payable returns (uint64 msgId);\n}\n```\n\nIf the NTT Manager is configured with a Transceiver that supports the Legacy Standard Relayer, the automated relaying must be disabled when using the Executor. The `encodedInstructions` parameter contains serialized NTT instructions that control transceiver behavior. When Standard Relayer instructions are included, set the `automatic` flag to `false` so that delivery is handled exclusively by the Executor. This ensures the transfer follows the intended Executor integration path."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 8, "depth": 3, "title": "SVM", "anchor": "svm-2", "start_char": 12503, "end_char": 17505, "estimated_token_count": 1018, "token_estimator": "heuristic-v1", "text": "### SVM\n\nFor Solana and other SVM-based chains, two helper programs are available to assist with generating and submitting NTT execution requests:\n\n- [example-ntt-svm-lut](https://github.com/wormholelabs-xyz/example-ntt-svm-lut){target=\\_blank}: Manages Lookup Tables for NTT programs without canonical LUTs.\n- [example-ntt-with-executor-svm](https://github.com/wormholelabs-xyz/example-ntt-with-executor-svm){target=\\_blank}: Generates and attaches Executor relay instructions on-chain to reduce transaction size.\n\nTogether, these helpers allow you to compose and send a full NTT with Executor transaction using the Wormhole TypeScript SDK. Below is a simplified example adapted from the SDK implementation:\n\n```ts\nconst ntt = await s.getProtocol(\"Ntt\", {\n  ntt: {\n    chain: \"Solana\",\n    manager: ...,\n    token: ...,\n    transceiver: { wormhole: ... },\n  },\n});\n...\n// as of this writing, there's only one tx on Solana\nconst txs = ntt.transfer(\n  new SolanaAddress(payer.publicKey),\n  1n,\n  {\n    chain: \"Sepolia\",\n    address: new UniversalAddress(\n      recipientWallet,\n      \"hex\"\n    ),\n  },\n  { queue: false, automatic: false }\n);\nfor await (const tx of txs) {\n\t// https://github.com/wormhole-foundation/native-token-transfers/blob/b4aa0e34755f735fca40e4566e07c17ac6b2b812/solana/ts/sdk/ntt.ts#L970C8-L970C20\n\tif (tx.description === \"Ntt.Transfer\") {\n\t\t// Not sure if the first signer will always be the outbox\n\t  const outboxKeypair = tx.transaction.signers[0];\n\t  // Get the lookup tables configured on the NTT manager\n\t  const luts: AddressLookupTableAccount[] = [];\n\t  try {\n\t    // @ts-ignore\n\t    luts.push(await ntt.getAddressLookupTable());\n\t  } catch (e) {\n\t    console.log(e.message);\n\t  }\n\t  // Decompile the message\n\t  const message = TransactionMessage.decompile(\n\t    tx.transaction.transaction.message,\n\t    { addressLookupTableAccounts: luts }\n\t  );\n\t  // Add the execution request to the message\n\t  const exampleNttWithExecutorProgram = new Program<ExampleNttWithExecutor>(\n      ExampleNttWithExecutorIdl as ExampleNttWithExecutor,\n      provider\n    );\n    message.instructions.push(\n      await exampleNttWithExecutorProgram.methods\n        .relayNttMesage({\n          execAmount: new BN(estimate.toString()),\n          recipientChain: chainToChainId(\"Sepolia\"),\n          signedQuoteBytes,\n          relayInstructions: Buffer.from(relayInstructions.substring(2), \"hex\"),\n        })\n        .accounts({\n          payee: new web3.PublicKey(signedQuoteBytes.subarray(24, 56)),\n          nttProgramId,\n          nttPeer: web3.PublicKey.findProgramAddressSync(\n            [\n              Buffer.from(\"peer\"),\n              encoding.bignum.toBytes(chainToChainId(\"Sepolia\")),\n            ],\n            nttProgramId\n          )[0],\n          nttMessage: outboxKeypair.publicKey,\n        })\n        .instruction()\n    );\n    // If the canonical NTT manager lookup table did not exist\n    if (luts.length === 0) {\n      // This should probably check the program version and only do this for versions without the canonical lookup table\n      // Otherwise, it should call `initializeLut` on the manager(?)\n      // I'm not sure if that is already checked somewhere in the SDK\n      console.log(\"no manager lookup table found, checking helper program\");\n      const exampleNttSvmLutProgram = new Program<ExampleNttSvmLut>(\n        ExampleNttSvmLutIdl as ExampleNttSvmLut,\n        provider\n      );\n      const lutPointerAddress = web3.PublicKey.findProgramAddressSync(\n        [Buffer.from(\"lut\"), nttProgramId.toBuffer()],\n        exampleNttSvmLutProgram.programId\n      )[0];\n      let lutPointer = await exampleNttSvmLutProgram.account.lut.fetchNullable(\n        lutPointerAddress\n      );\n      if (!lutPointer) {\n        console.log(\"no helper program lookup table found, initializing...\");\n        const recentSlot =\n          (await exampleNttSvmLutProgram.provider.connection.getSlot()) - 1;\n        const tx = await exampleNttSvmLutProgram.methods\n          .initializeLut(new BN(recentSlot))\n          .accounts({\n            nttProgramId,\n          })\n          .rpc();\n        console.log(`initialized lookup table: ${tx}`);\n        while (!lutPointer) {\n          // wait for lut to warm up\n          await new Promise((resolve) => setTimeout(resolve, 2000));\n          lutPointer = await exampleNttSvmLutProgram.account.lut.fetchNullable(\n            lutPointerAddress\n          );\n        }\n      }\n      const response = await connection.getAddressLookupTable(\n        lutPointer.address\n      );\n      if (!response.value) {\n        throw new Error(\"unable to fetch lookup table\");\n      }\n      luts.push(response.value);\n    }\n    // Recompile the message with the lookup table (whether manager or helper)\n    tx.transaction.transaction.message = message.compileToV0Message(luts);\n    // Broadcast\n    const hash = await provider.sendAndConfirm(\n      tx.transaction.transaction,\n      tx.transaction.signers,\n      { commitment: \"confirmed\" }\n    );\n  }\n}\n```"}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 9, "depth": 2, "title": "Check the Transaction Status", "anchor": "check-the-transaction-status", "start_char": 17505, "end_char": 18030, "estimated_token_count": 134, "token_estimator": "heuristic-v1", "text": "## Check the Transaction Status\n\nAfter submitting your transaction, you can query the relay provider to check its execution status and confirm whether the transfer has been processed and finalized by the Executor.\n\n```ts\nconst res = await axios.post(`${EXECUTOR_URL}/v0/status/tx`, {\n  txHash,\n  chainId,\n});\n```\n\nYou can also link directly to the transaction in the Explorer:\n\n```ts\n`https://wormholelabs-xyz.github.io/executor-explorer/#/chain/${chainId}tx/${txHash}?endpoint=${encodeURIComponent(\n  EXECUTOR_URL\n)}`;\n```"}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 10, "depth": 2, "title": "Conclusion", "anchor": "conclusion", "start_char": 18030, "end_char": 18357, "estimated_token_count": 58, "token_estimator": "heuristic-v1", "text": "## Conclusion\n\nIntegrating Executor with NTT enables permissionless, quote-based execution of cross-chain transfers. By combining NTT’s native transfer mechanism with Executor’s open relay network, applications can achieve automated, end-to-end redemption across EVM and Solana chains without relying on centralized relayers."}
{"page_id": "protocol-infrastructure-guides-ntt-executor", "page_title": "Integrate Native Token Transfers with Executor", "index": 11, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 18357, "end_char": 18701, "estimated_token_count": 98, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **NTT Executor Integration Demo**\n\n    ---\n\n    For a working reference implementation, see the NTT with Executor TypeScript demo.\n\n    [:custom-arrow: See the Demo](https://github.com/wormhole-foundation/demo-ntt-ts-sdk/tree/main){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-guides-run-spy", "page_title": "Run a Spy", "index": 0, "depth": 2, "title": "How to Start a Spy", "anchor": "how-to-start-a-spy", "start_char": 555, "end_char": 1836, "estimated_token_count": 323, "token_estimator": "heuristic-v1", "text": "## How to Start a Spy\n\nTo start a Spy locally, run the following Docker command:\n\n=== \"Mainnet\"\n\n    ```sh\n    docker run --pull=always --platform=linux/amd64 \\\n        -p 7073:7073 \\\n        --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \\\n        spy \\\n        --nodeKey /node.key \\\n        --spyRPC \"[::]:7073\" \\\n        --env mainnet\n    ```\n\n=== \"Testnet\"\n\n    ```sh\n    docker run --pull=always --platform=linux/amd64 \\\n        -p 7073:7073 \\\n        --entrypoint /guardiand ghcr.io/wormhole-foundation/guardiand:latest \\\n        spy \\\n        --nodeKey /node.key \\\n        --spyRPC \"[::]:7073\" \\\n        --env testnet\n    ```\n\nIf you want to run the Spy built from source, change `ghcr.io/wormhole-foundation/guardiand:latest` to `guardian` after building the `guardian` image.\n\nOptionally, add the following flags to skip any VAAs with invalid signatures:\n\n=== \"Mainnet\"\n\n    ```sh\n    --ethRPC https://eth.drpc.org\n    --ethContract 0x98f3c9e6E3fAce36bAAd05FE09d375Ef1464288B\n    ```\n\n=== \"Testnet\"\n\n    ```sh\n    --ethRPC https://sepolia.drpc.org/\n    --ethContract 0x4a8bc80Ed5a4067f1CCf107057b8270E0cC11A78    \n    ```\n\nOptionally, add the following flags to prevent unbounded log growth:\n\n```sh\n--log-opt max-size=10m \\\n--log-opt max-file=3\n```"}
{"page_id": "protocol-infrastructure-guides-run-spy", "page_title": "Run a Spy", "index": 1, "depth": 2, "title": "Subscribe to Filtered VAAs", "anchor": "subscribe-to-filtered-vaas", "start_char": 1836, "end_char": 2177, "estimated_token_count": 103, "token_estimator": "heuristic-v1", "text": "## Subscribe to Filtered VAAs\n\nOnce running, a [gRPC](https://grpc.io/){target=\\_blank} client (i.e., your program) can subscribe to a filtered stream of messages (VAAs).\n\nUse 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."}
{"page_id": "protocol-infrastructure-guides-run-spy", "page_title": "Run a Spy", "index": 2, "depth": 2, "title": "Data Persistence", "anchor": "data-persistence", "start_char": 2177, "end_char": 2718, "estimated_token_count": 116, "token_estimator": "heuristic-v1", "text": "## Data Persistence\n\nThe 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.\n\nThe 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."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 0, "depth": 2, "title": "Key Functions", "anchor": "key-functions", "start_char": 485, "end_char": 1537, "estimated_token_count": 178, "token_estimator": "heuristic-v1", "text": "## Key Functions \n\nKey functions of the Wormhole Core Contract include the following:\n\n- **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.\n- **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.\n- **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.\n- **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."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 1, "depth": 2, "title": "How the Core Contract Works", "anchor": "how-the-core-contract-works", "start_char": 1537, "end_char": 3220, "estimated_token_count": 294, "token_estimator": "heuristic-v1", "text": "## How the Core Contract Works\n\nThe 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.\n\nThe following describes the role of the Wormhole Core Contract in message transfers:\n\n1. **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.\n2. **Guardian verification**: Guardians independently observe and sign the message. On chains where all Guardians perform direct on-chain observation, each Guardian signs based on its own verification of the event. On delegated chains, a delegated subset signs and broadcasts signed delegate observations to the rest of the network. Canonical Guardians wait for delegate quorum before contributing their signatures. Once a supermajority of 13 out of 19 Guardians have signed, the signatures are combined with the message and metadata to produce a VAA.\n3. **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.\n\nFor 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."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 2, "depth": 3, "title": "Message Submission", "anchor": "message-submission", "start_char": 3220, "end_char": 4431, "estimated_token_count": 245, "token_estimator": "heuristic-v1", "text": "### Message Submission\n\nYou 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:\n\n- **`emitterAddress`**: The contract which made the call to publish the message.\n- **`sequenceNumber`**: A unique number that increments for every message for a given emitter (and implicitly chain).\n- **`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.\n\nThere are no fees to publish a message except when publishing on Solana, but this is subject to change in the future."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 3, "depth": 3, "title": "Message Reception", "anchor": "message-reception", "start_char": 4431, "end_char": 4997, "estimated_token_count": 111, "token_estimator": "heuristic-v1", "text": "### Message Reception\n\nWhen 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. The Core Contract does not distinguish between chains with direct observation and delegated chains; it verifies only that a valid 13-of-19 VAA has been produced."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 4, "depth": 2, "title": "Multicast", "anchor": "multicast", "start_char": 4997, "end_char": 6302, "estimated_token_count": 262, "token_estimator": "heuristic-v1", "text": "## Multicast\n\nMulticast 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.\n\nThis 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.\n\nThis doesn't mean an application _cannot_ specify a destination address or chain. For example, the [Wrapped Token Transfers (WTT)](/docs/products/token-transfers/wrapped-token-transfers/overview/){target=\\_blank} and [Executor](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank} contracts require that some destination details be passed and verified on the destination chain.\n\nBecause 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."}
{"page_id": "protocol-infrastructure-core-contracts", "page_title": "Core Contracts", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 6302, "end_char": 7250, "estimated_token_count": 235, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Verified Action Approvals (VAA)**\n\n    ---\n\n    Learn about Verified Action Approvals (VAAs) in Wormhole, their structure, validation, and their role in multichain communication.\n\n    [:custom-arrow: Learn About VAAs](/docs/protocol/infrastructure/vaas/)\n\n- :octicons-tools-16:{ .lg .middle } **Get Started with Core Contracts**\n\n    ---\n\n    This guide walks through the key methods of the Core Contracts, providing you with the knowledge needed to integrate them into your multichain contracts.\n\n    [:custom-arrow: Build with Core Contracts](/docs/products/messaging/guides/core-contracts/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 0, "depth": 2, "title": "Guardian Sets and Delegation", "anchor": "guardian-sets-and-delegation", "start_char": 1419, "end_char": 2352, "estimated_token_count": 161, "token_estimator": "heuristic-v1", "text": "## Guardian Sets and Delegation\n\nThe Guardian network comprises 19 Guardians. However, some chains may utilize delegated subsets. Some chains (such as Ethereum and Solana) are secured by all 19 Guardians. Each Guardian runs a full node and independently observes on-chain events. Other chains may be secured by a delegated subset of Guardians based on chain activity. Chains that are not explicitly delegated, default to full Guardian Set observation, meaning all 19 Guardians observe directly.\n\nFor these chains:\n\n- A configured delegated subset of the 19 Guardians performs direct on-chain observation.\n- Delegated Guardians broadcast a `SignedDelegateObservation` gossip message.\n- Canonical Guardians wait until a delegate quorum is reached before signing.\n- A standard 13-of-19 VAA is ultimately produced.\n\nThis design provides operational flexibility while maintaining compatibility with the existing Wormhole contract stack."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 1, "depth": 3, "title": "Delegated Observation Flow", "anchor": "delegated-observation-flow", "start_char": 2352, "end_char": 3387, "estimated_token_count": 188, "token_estimator": "heuristic-v1", "text": "### Delegated Observation Flow\n\nThe following flow shows how a subset of Guardians directly observes events on those chains and broadcasts a `SignedDelegateObservation` message over the Guardian gossip network. Canonical Guardians wait until the configured delegate quorum is reached before proceeding with the normal signing process. The final result is still a standard 13-of-19 VAA, fully compatible with existing smart contracts and integrations.\n\n```mermaid\nsequenceDiagram\n\nparticipant CB as CoreBridge\nparticipant DG as DelegatedGuardian\nparticipant G as Gossip network\nparticipant CG as CanonicalGuardian 1\nparticipant CG2 as CanonicalGuardian 2\n\nCB-->>DG: LogMessagePublished\nDG->>DG: Watch & verify\n\nalt DelegatedSet chain\n  DG-->>G: Broadcast SignedDelegateObservation\n  G-->>CG: Receive SignedDelegateObservation\n  G-->>CG2: Receive SignedDelegateObservation\n  loop Wait for delegate quorum\n    CG->>CG: Mark message valid\n    CG2->>CG2: Mark message valid\n  end\nend\n\nnote over CG,CG2: Standard signing flow continues\n```"}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 2, "depth": 3, "title": "Delegate Quorum Safeguards", "anchor": "delegate-quorum-safeguards", "start_char": 3387, "end_char": 3882, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "### Delegate Quorum Safeguards\n\nOn delegated chains, Canonical Guardians will not sign a message until a delegate quorum has been reached. This prevents a minority of Delegated Guardians from lowering the effective security threshold of a chain. For example, if a chain is configured as 7-of-9 Delegated Guardians, Canonical Guardians will only sign after at least 7 delegate observations agree. Once a delegate quorum is satisfied, Canonical Guardians sign to produce a standard 13-of-19 VAA."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 3, "depth": 2, "title": "Guardian Network", "anchor": "guardian-network", "start_char": 3882, "end_char": 4808, "estimated_token_count": 173, "token_estimator": "heuristic-v1", "text": "## Guardian Network\n\nThe 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.\n\nThe Guardian Network is designed to help Wormhole deliver on five key principles:\n\n- **Decentralization**: Control of the network is distributed across many parties.\n- **Modularity**: Independent components (e.g., oracle, relayer, applications) ensure flexibility and upgradeability.\n- **Chain agnosticism**: Supports EVM, Solana, and other blockchains without relying on a single network.\n- **Scalability**: Can handle large transaction volumes and high-value transfers.\n- **Upgradeable**: Can change the implementation of its existing modules without breaking integrators to adapt to changes in decentralized computing.\n\nThe following sections explore each principle in detail."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 4, "depth": 3, "title": "Decentralization", "anchor": "decentralization", "start_char": 4808, "end_char": 8099, "estimated_token_count": 619, "token_estimator": "heuristic-v1", "text": "### Decentralization\n\nDecentralization 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.\n\nTwo common approaches to decentralization have notable limitations:\n\n- **Proof-of-Stake (PoS)**: While PoS is often seen as a go-to model for decentralization, it is not well-suited for a network that verifies many blockchains and does not run its own smart contracts. Its security in this context is unproven, and it introduces complexities that make other design goals harder to achieve.\n- **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.\n\nIn the current DeFi 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.\n\nIf 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?\n\nTo answer that, consider these key constraints and design decisions:\n\n- **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.\n- **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 deliberately specified.\n- **19 Guardians form the canonical set**: A set of 19 participants presents ample opportunity for both decentralization and efficiency. A quorum of 13 signatures is required to produce a valid VAA.\n- **Per-chain delegated thresholds**: On delegated chains, a delegated subset of Guardians may be configured with an optimized observation threshold. Canonical Guardians wait for delegate quorum before contributing their signatures, ensuring that the effective security threshold for a chain cannot be reduced below its configured level.\n- **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.\n\nThis 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."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 5, "depth": 3, "title": "Modularity", "anchor": "modularity", "start_char": 8099, "end_char": 8451, "estimated_token_count": 70, "token_estimator": "heuristic-v1", "text": "### Modularity\n\nWormhole is designed with simple components that are very good at a single function. Separating security and consensus (Guardians) from message delivery ([Executor](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank}) allows for the flexibility to change or upgrade one component without disrupting the others."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 6, "depth": 3, "title": "Chain Agnosticism", "anchor": "chain-agnosticism", "start_char": 8451, "end_char": 8880, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "### Chain Agnosticism\n\nToday, 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."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 7, "depth": 3, "title": "Scalability", "anchor": "scalability", "start_char": 8880, "end_char": 9764, "estimated_token_count": 148, "token_estimator": "heuristic-v1", "text": "### Scalability\n\nWormhole scales well, as demonstrated by its ability to handle substantial total value locked (TVL) and transaction volume even during tumultuous events.\n\nOn chains where all Guardians perform direct on-chain observation, each Guardian runs a full node and independently observes events. 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.\n\nOn delegated chains, only the delegated subset of Guardians runs full nodes. Canonical Guardians rely on delegate observations broadcast through the gossip network and wait for delegate quorum before signing.\n\nThis reduces operational overhead while preserving the security model of the network. Performance is generally limited by the speed of the underlying blockchains, not the Guardian Network itself."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 8, "depth": 3, "title": "Upgradeable", "anchor": "upgradeable", "start_char": 9764, "end_char": 10487, "estimated_token_count": 127, "token_estimator": "heuristic-v1", "text": "### Upgradeable\n\nWormhole is designed to adapt and evolve in the following ways:\n\n- **Per-chain security configuration**: The Delegated Guardian configuration is managed via governance through the `WormholeDelegatedGuardians` contract, allowing per-chain threshold adjustments without requiring upgrades to existing Core contracts.\n- **Guardian Set expansion**: Future updates may introduce threshold signatures to allow for more Guardians in the set.\n- **ZKP integration**: As Zero-Knowledge Proofs become more widely supported, the network can transition to a fully trustless model.\n\nThese principles combine to create a clear pathway towards a fully trustless interoperability layer that spans decentralized computing."}
{"page_id": "protocol-infrastructure-guardians", "page_title": "Guardians", "index": 9, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 10487, "end_char": 11455, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Executor**\n\n    ---\n\n    Learn about the Executor framework - a shared, permissionless system for executing cross-chain messages using standardized contracts and quotes.\n\n    [:custom-arrow: Learn About Executor](/docs/protocol/infrastructure/relayers/executor-framework/)\n\n-   :octicons-tools-16:{ .lg .middle } **Query Guardian Data**\n\n    ---\n\n    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.\n\n    [:custom-arrow: Build with Queries](/docs/products/queries/overview/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n\n</div>"}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 0, "depth": 2, "title": "Architecture and Components", "anchor": "architecture-and-components", "start_char": 1024, "end_char": 2883, "estimated_token_count": 431, "token_estimator": "heuristic-v1", "text": "## Architecture and Components\n\nThe Executor framework separates responsibilities between three independent participants:\n\n| Actor\t            | Responsibility                                                              | \n|-------------------|-----------------------------------------------------------------------------| \n| Integrator        | Creates and submits execution requests using valid quotes.                  | \n| Executor Contract | Publishes requests, transfers payment, and emits observable events.         | \n| Relay Provider\t| Monitors events, issues and validates signed quotes, and executes messages. | \n\nThis modular structure enables permissionless, verifiable, and cost-efficient message execution across multiple blockchains — without persistent on-chain state or protocol-specific relayers.\n\nThe Executor framework comprises a small set of on-chain and off-chain components that work together to request, quote, and execute cross-chain messages. The following components define the roles, interfaces, and data structures involved in the execution process.\n\n- **Relay Provider**: An off-chain party responsible for performing message execution between chains. \n- **[Executor contract](/docs/products/reference/executor-addresses/){target=\\_blank}**: The shared on-chain contract or program used to make execution requests. \n- **Execution quote**: A signed quote defining cost and parameters for execution between a source and destination chain. \n- **Execution request**: A request generated on-chain or off-chain for a given message (e.g., NTT, VAA v1, etc.) to be executed on another chain. \n- **Quoter**: An off-chain service that produces signed quotes. It's Quoter’s EVM public key that identifies each Relay Provider.\n- **Payee**: The wallet address designated by the Quoter to receive payment once the execution is completed."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 1, "depth": 2, "title": "Execution Lifecycle", "anchor": "execution-lifecycle", "start_char": 2883, "end_char": 3111, "estimated_token_count": 37, "token_estimator": "heuristic-v1", "text": "## Execution Lifecycle\n\nThe execution lifecycle defines the sequence of interactions between integrators, the Executor contract, and Relay Providers that result in a cross-chain message being executed on the destination chain."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 2, "depth": 3, "title": "Request Flow", "anchor": "request-flow", "start_char": 3111, "end_char": 4244, "estimated_token_count": 233, "token_estimator": "heuristic-v1", "text": "### Request Flow\n\nMessage execution starts on the source chain, where an integrator creates an execution request. The request includes a signed quote from a Quoter, along with message data and delivery instructions.\n\n1. A client requests a quote from a Quoter, specifying source and destination chains.  \n2. The Quoter returns a signed quote with pricing and parameters.  \n3. The client sends a message through an integrator contract, including the signed quote.  \n4. The integrator publishes the message via the [Wormhole Core contract](/docs/protocol/infrastructure/core-contracts/){target=\\_blank}.  \n5. The integrator then calls the Executor contract to register the execution request.\n\n```mermaid\n---\ntitle: v1 VAA Execution Request\n---\nsequenceDiagram\n\t\tparticipant C as Client\n\t\tparticipant Q as Quoter\n\t\tbox Source Chain\n\t\tparticipant I as Integrator Contract\n\t\tparticipant W as Wormhole Core\n\t\tparticipant E as Executor Contract\n\t\tend\n    C->>Q: srcChain, dstChain\n    Q-->>C: signedQuote\n    C->>I: sendMessage(signedQuote, relayInstructions)\n    I->>W: publishMessage\n    W-->>I: sequence\n    I->>E: requestExecution\n```"}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 3, "depth": 3, "title": "Result Flow", "anchor": "result-flow", "start_char": 4244, "end_char": 5242, "estimated_token_count": 201, "token_estimator": "heuristic-v1", "text": "### Result Flow\n\nOnce the request is recorded on-chain, off-chain Relay Providers monitor the Executor contract for events that match their signed quotes. When a valid request is detected, the provider retrieves the message from the Guardians and executes it on the destination chain.\n\n1. The Executor contract emits an event with the request and payment details.\n2. A Relay Provider verifies the quote and fetches the associated message (e.g., a VAA).\n3. The provider delivers the message to the destination chain’s integrator contract.\n4. The integrator verifies the message with the Wormhole Core contract and performs the specified logic.\n\n```mermaid\n---\ntitle: v1 VAA Execution Result\n---\nsequenceDiagram\n\t\tbox Source Chain\n\t\tparticipant EC as Executor Contract\n\t\tend\n\t\tparticipant RP as Relay Provider (Off-Chain)\n\t\tbox Destination Chain\n\t\tparticipant I as Integrator Contract\n\t\tparticipant W as Wormhole Core\n\t\tend\n\t\tEC-->>RP: event\n    RP->>I: executeVaaV1\n    I->>W: parseAndVerifyVM\n```"}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 4, "depth": 2, "title": "On-Chain Quote Resolution", "anchor": "on-chain-quote-resolution", "start_char": 5242, "end_char": 8165, "estimated_token_count": 591, "token_estimator": "heuristic-v1", "text": "## On-Chain Quote Resolution\n\nWhile the default execution flow relies on off-chain signed quotes, the Executor framework also supports fully on-chain execution pricing. This mechanism is designed for integrators who cannot modify their off-chain flow or must rely strictly on on-chain state to determine pricing. Instead of passing a signed quote to the Executor contract, the integrator specifies a Quoter public key, and the quote is constructed on-chain through a routing contract.\n\nOn-chain quote resolution is appropriate when:\n\n- The integrator must follow a view → payable contract pattern.\n- Execution pricing must be deterministically derived from on-chain logic.\n- The integration comprises protocols that cannot pass arbitrary off-chain signatures.\n\nFor most SDK-based integrations, off-chain signed quotes remain the recommended and more efficient approach.\n\n```mermaid\n---\ntitle: On-Chain Quote Resolution (EQ02)\n---\nsequenceDiagram\n    actor Client\n    participant I as Integrator\n    participant R as ExecutorQuoterRouter\n    participant Q as ExecutorQuoter\n    participant E as Executor\n\n    Client->>I: quote(...)\n    I->>R: quoteExecution(quoterAddr,...)\n    R->>Q: requestQuote(...)\n    Q-->>R: requiredPayment\n    R-->>I: requiredPayment\n\n    Client->>I: execute{value}(...)\n    I->>R: requestExecution(quoterAddr,...)\n    R->>Q: requestExecutionQuote(...)\n    Q-->>R: payee, quoteBody\n    R->>E: requestExecution(EQ02)\n```\n\nOn EVM chains, on-chain quoting introduces two additional contracts:\n\n- `ExecutorQuoter`: Implements the pricing logic for a specific Relay Provider.\n- `ExecutorQuoterRouter`: Acts as the canonical entrypoint for integrators requesting on-chain quotes.\n\nThe [Quoter public key](/docs/products/reference/executor-addresses/#on-chain-quoter){target=\\_blank} identifies a Relay Provider and is used to select which provider’s pricing logic will be applied during execution. This allows multiple providers to register independent pricing logic, permissionless participation, and on-chain formation of execution quotes without requiring signatures.\n\nThe Router constructs an unsigned `EQ02` quote on-chain and forwards the execution request to the Executor contract. `EQ02` contains the same pricing fields as the signed `EQ01` quote. Still, it is constructed on-chain, it does not contain a signature, and Relay Providers verify it by checking for an `OnChainQuote` event emitted by the canonical Router. This preserves compatibility with existing Executor tooling and off-chain validation logic.\n\nMost applications do not need to interact directly with `ExecutorQuoter`, `ExecutorQuoterRouter`, or `EQ02` formatting. The Wormhole SDK abstracts quote resolution, relay instruction formatting, execution request construction, and payment handling. Unless building a low-level contract integration, developers should rely on the SDK to manage quote construction and execution flows."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 5, "depth": 3, "title": "Quoter Governance", "anchor": "quoter-governance", "start_char": 8165, "end_char": 8707, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "### Quoter Governance\n\nRelay Providers register their `ExecutorQuoter` implementation through a signed governance message submitted to the `ExecutorQuoterRouter`.\n\nThe governance message:\n\n- Associates a Quoter public key with a specific implementation contract\n- Includes an expiry to prevent replay\n- Is validated by the `ExecutorQuoterRouter`\n\nThis ensures that providers can update pricing logic, the Router remains immutable and permissionless, and off-chain infrastructure can verify that a quote originated from the canonical Router."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 6, "depth": 2, "title": "Executor Contract", "anchor": "executor-contract", "start_char": 8707, "end_char": 10902, "estimated_token_count": 492, "token_estimator": "heuristic-v1", "text": "## Executor Contract\n\nEach supported chain hosts a stateless, permissionless [Executor contract](/docs/products/reference/executor-addresses/){target=\\_blank}. The contract provides an interface for submitting execution requests and emitting observable events for off-chain providers. It maintains no persistent state; all requests exist as events that off-chain agents can detect.\n\nWhen called, the Executor contract:\n\n- Accepts execution requests from integrators or clients.\n- Verifies basic parameters (source/destination chain IDs, expiry time).\n- Transfers payment to the designated [`payeeAddress`](https://github.com/wormholelabs-xyz/example-messaging-executor/blob/main/evm/src/Executor.sol#L59){target=\\_blank}.\n- Emits events containing request details for off-chain consumption. \n\nThe Executor contract exposes the [`requestExecution`](https://github.com/wormholelabs-xyz/example-messaging-executor/blob/main/evm/src/Executor.sol#L22){target=\\_blank} function, used by both on-chain and off-chain integrations to create an execution request. When `requestExecution` is called, the contract checks that:\n\n- The quote’s source chain matches the chain of deployment.\n- The destination matches the provided destination chain.\n- The quote has not expired.\n\nIf all checks pass, payment is transferred to the [`payeeAddress`](https://github.com/wormholelabs-xyz/example-messaging-executor/blob/main/evm/src/Executor.sol#L59){target=\\_blank} defined in the quote, and a [`RequestForExecution`](https://github.com/wormholelabs-xyz/example-messaging-executor/blob/main/evm/src/Executor.sol#L61){target=\\_blank} event is emitted.\n\nTo remain lightweight and chain-agnostic, the Executor contract performs only minimal validation:\n\n- **No signature verification**: The client is responsible for verifying the quote before submission.\n- **No message inspection**: The contract does not parse or validate the message payload.\n- **No payment enforcement**: The contract does not check that the payment matches the quoted fee; providers enforce this off-chain.\n\nThis minimal design keeps the contract generic, inexpensive, and compatible with multiple message formats and future Wormhole protocols."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 7, "depth": 2, "title": "Relay Provider", "anchor": "relay-provider", "start_char": 10902, "end_char": 13348, "estimated_token_count": 426, "token_estimator": "heuristic-v1", "text": "## Relay Provider\n\nA Relay Provider is an off-chain service that executes messages between chains and operates a Quoter service to issue signed execution quotes. Providers compete in a permissionless marketplace by offering signed execution quotes that define their pricing and delivery terms. This system decentralizes message delivery, allowing integrators to choose providers or run their own, rather than relying on a single relayer service. \n\nEach provider runs infrastructure that listens for execution requests emitted by the Executor contract on supported chains. When a request matches one of their quotes, the provider retrieves the associated VAA from the Guardians and performs the message execution on the destination chain.  \n\nEach Relay Provider operates a Quoter service that issues signed quotes and defines execution terms. \n\nEach quote specifies: \n\n- The source and destination chains\n- Pricing\n- An expiry time before which the Executor contract can accept the quote\n\nShort expiry windows reduce the risk of stale quotes but must be long enough for users to submit transactions on the source chain. \n\nBecause the network is open, multiple providers may compete to fulfill the same request. Each quote defines the conditions under which a provider is willing to execute, enabling competitive pricing and redundancy across the system. Message validity is enforced through the Wormhole VAA and Guardian verification process, preventing providers from altering or forging the message and ensuring all executions remain trust-minimized.\n\nRelay Providers may operate multiple wallets, each capable of performing execution or receiving payment. They can choose whether payments are collected per-wallet or directed to a central [`payeeAddress`](https://github.com/wormholelabs-xyz/example-messaging-executor/blob/main/evm/src/Executor.sol#L59){target=\\_blank} defined by the Quoter.\n\nProviders should provide a public API for integrators to track the status of the request such as: \n\n- Request creation\n- Added gas fees\n- Transaction executes\n- Any issued refunds\n\nTo improve transparency, providers may also publish a Service-Level Agreement (SLA) describing the types of executions they support, their retry and refund policies, and their expected behavior during execution.\n\n!!!warning\n    The framework does not prevent repeated execution attempts. Providers should implement their own safeguards to avoid duplicate deliveries."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 8, "depth": 2, "title": "Security Considerations", "anchor": "security-considerations", "start_char": 13348, "end_char": 13768, "estimated_token_count": 72, "token_estimator": "heuristic-v1", "text": "## Security Considerations\n\nThe Executor contract is explicitly designed to be immutable and sit outside an integrator's security stack. Executor is intended to be used as a mechanism to permissionlessly deliver cross-chain data that includes an independent attestation source, such as Wormhole VAAs. The Executor does not change Wormhole’s security model; it changes how delivery requests are initiated and fulfilled."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 9, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 13768, "end_char": 14197, "estimated_token_count": 101, "token_estimator": "heuristic-v1", "text": "## Resources\n\n- [demo-hello-executor](https://github.com/wormhole-foundation/demo-hello-executor){target=\\_blank} — Minimal end-to-end example demonstrating quote requests and `requestExecution` flows.\n- [Executor Addresses Reference](/docs/products/reference/executor-addresses/){target=\\_blank} — Deployed Executor contracts, On-chain Quoter contracts, Wormhole Labs’ Quoter implementations, and published Quoter public keys."}
{"page_id": "protocol-infrastructure-relayers-executor-framework", "page_title": "Executor Framework", "index": 10, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 14197, "end_char": 14870, "estimated_token_count": 171, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Migrate to Executor**\n\n    ---\n\n    Understand the key differences between the Executor framework and the Standard Relayer, and find guidance for migrating existing integrations.\n\n    [:custom-arrow: Migrate to Executor](/docs/protocol/infrastructure/relayers/executor-vs-sr/)\n\n-   :octicons-tools-16:{ .lg .middle } **Executor Demo**\n\n    ---\n\n    Check out a minimal end-to-end Executor demo showing quoting, request calls, and replay protection.\n\n    [:custom-arrow: See the Hello Executor Demo](https://github.com/wormhole-foundation/demo-hello-executor){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 0, "depth": 2, "title": "Quoting, Payment, and Refunds", "anchor": "quoting-payment-and-refunds", "start_char": 1347, "end_char": 2720, "estimated_token_count": 306, "token_estimator": "heuristic-v1", "text": "## Quoting, Payment, and Refunds \n\nBoth models rely on a quote to determine execution cost, but they differ in how the quote is obtained and how payment and refunds are handled.\n\n**Standard Relayer**\n\n- **Quoting**: On-chain via `IDeliveryProvider.quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`, which returns `(nativePriceQuote, refundPerGasUnused)`.\n- **Payment**: Supplied to `sendPayloadToEvm` alongside `nativePriceQuote`.\n- **Refunds**: Managed on-chain by the relayer contract through its refund/value-forwarding logic and surfaced via events and explicit error types.\n\n**Executor**\n\n- **Quoting**: Off-chain via a signed quote returned by a [Quoter](/docs/protocol/infrastructure/relayers/executor-framework/#relay-provider){target=\\_blank} operated by a Relay Provider. The quote encodes the relay instructions and delivery terms.\n- **Request**: The application calls `Executor.requestExecution(...)` (or the SDK helper `_publishAndRelay`), passing the signed quote and relay instructions.\n- **Payment**: The payment is transferred to the provider’s designated `payee` when the request is registered. The Executor contract is stateless and performs minimal checks (chain match, expiry).\n- **Refunds**: Determined entirely by the provider’s off-chain policy. The Executor contract does not handle refund mechanics, gas accounting, or delivery logic."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 1, "depth": 2, "title": "VAA Verification", "anchor": "vaa-verification", "start_char": 2720, "end_char": 3524, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "## VAA Verification\n\nThe two systems differ in where VAA verification occurs and how the message reaches your application.\n\n**Standard Relayer**  \n\nThe Relayer contract (together with the [Core Contract](/docs/protocol/infrastructure/core-contracts/){target=\\_blank}) fetches and verifies the VAA before delivery. Your contract implements `receiveWormholeMessages` and typically only validates the expected sender, source chain, and its own application-level invariants.\n\n**Executor**  \n\nYour contract verifies the VAA directly. Using the SDK base, it calls Core’s `parseAndVerifyVM`, applies replay protection, and then dispatches to `_executeVaa` with the payload and VAA metadata. Verification becomes explicit in your contract’s execution flow, while the on-chain Executor contract remains minimal."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 2, "depth": 2, "title": "Replay Protection and Finality", "anchor": "replay-protection-and-finality", "start_char": 3524, "end_char": 4727, "estimated_token_count": 249, "token_estimator": "heuristic-v1", "text": "## Replay Protection and Finality\n\nReplay protection works very differently between the two models, especially depending on the VAA’s consistency level.\n\n**Standard Relayer**\n\nThe Standard Relayer enforces an “execute only once” guarantee at the delivery layer. Applications do not implement custom replay protection - the relayer ensures each request is executed exactly once.\n\n**Executor**\n\nExecutor integrations must implement their own replay-protection scheme. Two options are available:\n\n- **Sequence-based**: Recommended for finalized VAAs. It tracks `(emitterChain, emitterAddress, sequence)` and is the lowest-cost approach, but cannot safely handle non-finalized (e.g., instant) consistency levels.\n- **Hash-based**: Works for all consistency levels, including instant. It uses the VAA hash to guarantee unique identification and prevent replays.\n\nThe [Hello Executor demo](https://github.com/wormhole-foundation/demo-hello-executor){target=\\_blank} includes examples of both approaches and explains how they map to consistency levels (e.g., `200` for finalized, `1` for instant). Use `SequenceReplayProtectionLib` for finalized messages or `HashReplayProtectionLib` for non-finalized flows."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 3, "depth": 2, "title": "Delivery Behavior", "anchor": "delivery-behavior", "start_char": 4727, "end_char": 5890, "estimated_token_count": 221, "token_estimator": "heuristic-v1", "text": "## Delivery Behavior\n\nThe two models differ in how delivery is handled, what is enforced on-chain, and what guarantees are provided by the infrastructure versus the provider.\n\n**Standard Relayer**\n\nThe Standard Relayer provides a managed delivery flow with on-chain pricing, refund logic, and detailed error handling. It offers:\n\n- Delivery to the target contract with gas limit, receiver value, refund mechanics, and delivery status events.\n- A dedicated `DeliveryProvider` contract for on-chain pricing and supported chains.\n- A broad error surface for misquotes, overrides, and budget violations.\n\n**Executor**\n\nThe Executor contract is intentionally minimal. It registers execution requests and forwards payment to the provider, leaving all delivery semantics to the off-chain provider. It offers:\n\n- A stateless executor contract that accepts requests, transfers payment to the provider’s designated payee, and emits request events.\n- Minimal validation (chain match, expiry), with no price enforcement on-chain, no gas accounting, and no message inspection.\n- An open provider marketplace, where any provider can fulfill the request by submitting the VAA."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 4, "depth": 2, "title": "Migration Notes", "anchor": "migration-notes", "start_char": 5890, "end_char": 7323, "estimated_token_count": 285, "token_estimator": "heuristic-v1", "text": "## Migration Notes\n\nMoving from the Standard Relayer to the Executor model involves changes to how messages are published, how delivery requests are issued, and how peers and replay protection are handled. The steps below outline the core updates required in a typical integration.\n\n- **Sending**: Replace `quoteEVMDeliveryPrice` + `sendPayloadToEvm` with two calls: `Core.publishMessage` and `Executor.requestExecution` (or the SDK helper `_publishAndRelay`). Fetch a signed quote from your chosen provider off-chain.\n- **Receiving**: Replace `IWormholeReceiver.receiveWormholeMessages` with the Executor base pattern: implement `_executeVaa`, `_replayProtect`, and `_getPeer` when using the SDK, or `executeVAA` if implementing the flow manually.\n- **Access control and addressing**: Migrate registered senders to a `peers` registry keyed by Wormhole chain ID (universal `bytes32` address). SDK helpers are available for converting and validating peer addresses. \n- **Finality and replay protection**: If delivery semantics were previously used for replay safety, choose either sequence-based (finalized consistency only), or hash-based replay protection (any consistency level) and wire `_replayProtect` according to your chosen consistency level.\n- **Fees and refunds**: Refunds, retries, and SLAs are provider policy in the Executor model. Use the provider’s API and signed-quote metadata for observability and error handling."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 5, "depth": 2, "title": "Migration for Wormhole Connect Integrators", "anchor": "migration-for-wormhole-connect-integrators", "start_char": 7323, "end_char": 8540, "estimated_token_count": 301, "token_estimator": "heuristic-v1", "text": "## Migration for Wormhole Connect Integrators\n\n!!! note\n    If you are using [Wormhole Connect](/docs/products/connect/overview/){target=\\_blank} and currently configure NTT routes with `nttRoutes()`, you should migrate to `nttExecutorRoute()`. The `nttRoutes()` helper bundles both the Manual route and the Executor route, but since the Standard Relayer is being deprecated, the recommended path forward is to use the Executor route explicitly.\n\n**Before** - using `nttRoutes()`:\n\n```typescript\nimport { nttRoutes } from '@wormhole-foundation/wormhole-connect';\n\nconst config = {\n  routes: [\n    ...nttRoutes({\n      tokens: { /* your token config */ },\n    }),\n  ],\n};\n```\n\n**After** - using `nttExecutorRoute()`:\n\n```typescript\nimport { nttExecutorRoute } from '@wormhole-foundation/wormhole-connect/ntt';\n\nconst config = {\n  routes: [\n    nttExecutorRoute({\n      ntt: {\n        tokens: { /* your token config */ },\n      },\n    }),\n  ],\n};\n```\n\nThe `nttExecutorRoute` provides one-click transfers powered by the Executor, with support for native gas drop-off and referrer fees. For a complete working example, see the [NTT Connect demo](https://github.com/wormhole-foundation/demo-ntt-connect){target=\\_blank}."}
{"page_id": "protocol-infrastructure-relayers-executor-vs-sr", "page_title": "Standard Relayer to Executor Migration", "index": 6, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 8540, "end_char": 9459, "estimated_token_count": 231, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\nThe resources below provide deeper technical detail and example implementations. \n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Executor Framework Overview**\n\n    ---\n\n    Learn about the Executor model, components, and request flow.\n\n    [:custom-arrow: Learn About the Framework](/docs/protocol/infrastructure/relayers/executor-framework/#relay-provider)\n\n-   :octicons-book-16:{ .lg .middle } **Executor Addresses**\n\n    ---\n\n    See the chain-specific deployed addresses.\n\n    [:custom-arrow: See Addresses](/docs/products/messaging/reference/executor-addresses/)\n\n-   :octicons-tools-16:{ .lg .middle } **Executor Demo**\n\n    ---\n\n    Check out a minimal end-to-end Executor demo showing quoting, request calls, and replay protection.\n\n    [:custom-arrow: See the Hello Executor Demo](https://github.com/wormhole-foundation/demo-hello-executor){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-relayers-relayer", "page_title": "Relayers Overview", "index": 0, "depth": 2, "title": "Fundamentals", "anchor": "fundamentals", "start_char": 1033, "end_char": 2343, "estimated_token_count": 229, "token_estimator": "heuristic-v1", "text": "## Fundamentals\n\nRelayers act as delivery mechanisms for cross-chain messages. Their responsibility is to observe signed VAAs and submit them to destination chain contracts for on-chain verification and execution. Guardian signatures and on-chain verification logic define what is executed, while relayers provide availability and automation by ensuring messages reach their destination.\n\n- **Anyone can relay a message**: The Guardian Network broadcasts signed VAAs publicly, allowing any entity to submit them to destination chain contracts. Guardian signatures provide universal verifiability, ensuring relaying is permissionless. If one relayer is unavailable, another party can submit the same VAA to complete delivery.\n- **Security is in the VAA**: Guardian signatures authenticate message contents and execution parameters. Contracts should rely only on signed VAAs and on-chain state, not on off-chain data supplied by relayers. As a result, relayers can affect delivery timing, but not message correctness or security, making relaying trustless.\n- **User experience vs. infrastructure**: Relayers automate cross-chain delivery to improve user experience, but introduce considerations around fees. Developers can choose between client-side relaying or the Executor framework depending on their needs."}
{"page_id": "protocol-infrastructure-relayers-relayer", "page_title": "Relayers Overview", "index": 1, "depth": 2, "title": "Manual vs. Automated Relaying", "anchor": "manual-vs-automated-relaying", "start_char": 2343, "end_char": 4017, "estimated_token_count": 319, "token_estimator": "heuristic-v1", "text": "## Manual vs. Automated Relaying\n\nWhen integrating Wormhole messaging, applications can use either manual (client-side) relaying or automated relaying. The difference lies in who is responsible for delivering the VAA to the destination chain.\n\n- **Manual relaying (client-side)**: The user or client application (e.g., a dApp or wallet) is responsible for carrying out all cross-chain steps. After an action on the source chain produces a VAA, the user must fetch the VAA (e.g., via a Wormhole API or explorer) and submit it in a transaction on the destination chain. No backend infrastructure is required, and costs are limited to destination-chain transaction fees. However, this approach requires multiple user interactions and funds on each chain involved, making it best suited for testing, demos, and MVPs rather than production applications.\n- **Automated relaying**: Cross-chain delivery is handled automatically by a relayer service or network instead of the end user. From the user's perspective, the message is delivered to the destination chain without manual intervention, enabling a smoother, one-step experience. With the [Executor framework](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank}, applications can leverage Wormhole's decentralized relayer infrastructure to request automated delivery, without running a backend service. This reduces operational complexity at the cost of service fees, while significantly improving user experience.\n\nChoosing between manual and automated relaying depends on the application's requirements. If the integrator prioritizes convenience, automated relaying provides a superior experience."}
{"page_id": "protocol-infrastructure-relayers-relayer", "page_title": "Relayers Overview", "index": 2, "depth": 2, "title": "Executor", "anchor": "executor", "start_char": 4017, "end_char": 5306, "estimated_token_count": 236, "token_estimator": "heuristic-v1", "text": "## Executor\n\nThe Executor is a permissionless, next-generation relaying framework that enables anyone to act as a relayer through a request-and-quote model, with support for multichain delivery and flexible pricing.\n\nAt a high level, the Executor consists of:\n\n- A lightweight, stateless [Executor contract](/docs/protocol/infrastructure/relayers/executor-framework/#executor-contract){target=\\_blank} deployed by Wormhole on supported chains\n- A permissionless network of off-chain [relay providers](/docs/protocol/infrastructure/relayers/executor-framework/#relay-provider){target=\\_blank} that fulfill delivery requests\n\nApplications request automated delivery by submitting an execution request to the Executor contract, along with a signed fee quote obtained off-chain from a relay provider. Relay providers monitor these requests and deliver the corresponding VAAs to destination chains for on-chain execution, extending relaying functionality beyond EVM-only environments.\n\nThe Executor does not change Wormhole’s security model. Guardian signatures and on-chain verification enforce message integrity and execution correctness, while relay providers compete on pricing and availability. This creates a decentralized marketplace for relaying rather than a single relayer service."}
{"page_id": "protocol-infrastructure-relayers-relayer", "page_title": "Relayers Overview", "index": 3, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 5306, "end_char": 5939, "estimated_token_count": 158, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Migrate to Executor**\n\n    ---\n\n    Understand the key differences between the Executor framework and the Standard Relayer, and find guidance for migrating existing integrations.\n\n    [:custom-arrow: Migrate to Executor](/docs/protocol/infrastructure/relayers/executor-vs-sr/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-spy", "page_title": "Spy", "index": 0, "depth": 2, "title": "Key Features", "anchor": "key-features", "start_char": 785, "end_char": 1700, "estimated_token_count": 183, "token_estimator": "heuristic-v1", "text": "## Key Features\n\n- **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.\n- **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.\n- **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.\n- **Support for multiple message protocols**: It can observe messages from different Wormhole messaging protocols (WTT, CCTP, NTT, etc.), providing broad coverage of cross-chain activity.\n- **Lightweight and infrastructure-ready**: The Spy is designed to run as part of indexing or backend services, not requiring validator-level infrastructure."}
{"page_id": "protocol-infrastructure-spy", "page_title": "Spy", "index": 1, "depth": 2, "title": "Integrator Use Case", "anchor": "integrator-use-case", "start_char": 1700, "end_char": 2455, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "## Integrator Use Case\n\nThe 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.\n\nThis 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."}
{"page_id": "protocol-infrastructure-spy", "page_title": "Spy", "index": 2, "depth": 2, "title": "Observable Message Categories", "anchor": "observable-message-categories", "start_char": 2455, "end_char": 3433, "estimated_token_count": 208, "token_estimator": "heuristic-v1", "text": "## Observable Message Categories\n\nA Spy can access the following categories of messages shared over the gossip protocol:\n\n- **[Verifiable Action Approvals (VAAs)](/docs/protocol/infrastructure/vaas/){target=\\_blank}**: Packets of multichain data.\n\n    - 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.\n\n- **[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.\n\n    - A Spy allow users to monitor these messages, adding transparency and insight into blockchain events.\n\n- **[Guardian heartbeats](/docs/products/reference/glossary/#heartbeat){target=\\_blank}**: Heartbeat messages represent Guardian node status.\n\n    - By monitoring heartbeats, a Spy can signal the liveness and connectivity of Guardians in the network."}
{"page_id": "protocol-infrastructure-spy", "page_title": "Spy", "index": 3, "depth": 2, "title": "Additional Resources", "anchor": "additional-resources", "start_char": 3433, "end_char": 4476, "estimated_token_count": 265, "token_estimator": "heuristic-v1", "text": "## Additional Resources\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-code-16:{ .lg .middle } **Spy Source Code**\n\n    ---\n\n    To see the source code for the Go implementation of the Spy, visit the `wormhole` repository on GitHub.\n\n    [:custom-arrow: View the Source Code](https://github.com/wormhole-foundation/wormhole/blob/main/node/cmd/spy/spy.go){target=\\_blank}\n\n-   :octicons-code-16:{ .lg .middle } **Alternative Implementation**\n\n    ---\n\n    Visit the `beacon` repository on GitHub to learn more about Beacon, an alternative highly available, reduced-latency version of the Wormhole Spy.\n\n    [:custom-arrow: Get Started with Pyth Beacon](https://github.com/pyth-network/beacon)\n\n-   :octicons-book-16:{ .lg .middle } **Discover Wormhole Queries**\n\n    ---\n\n    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. \n\n    [:custom-arrow: Explore Queries](/docs/products/queries/overview/)\n\n</div>"}
{"page_id": "protocol-infrastructure-spy", "page_title": "Spy", "index": 4, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 4476, "end_char": 5413, "estimated_token_count": 245, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-code-16:{ .lg .middle } **Run a Spy**\n\n    ---\n\n    Learn how to run the needed infrastructure to spin up a Spy daemon locally and subscribe to a stream of Verifiable Action Approvals (VAAs).\n\n    [:custom-arrow: Spin Up a Spy](/docs/protocol/infrastructure-guides/run-spy/)\n\n-   :octicons-code-16:{ .lg .middle } **Use Queries**\n\n    ---\n\n    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.\n\n    [:custom-arrow: Get Started with Queries](/docs/products/queries/guides/use-queries/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 0, "depth": 2, "title": "VAA Format", "anchor": "vaa-format", "start_char": 1481, "end_char": 4080, "estimated_token_count": 615, "token_estimator": "heuristic-v1", "text": "## VAA Format\n\nThe basic VAA consists of header and body components described as follows:\n\n- **Header**: Holds metadata about the current VAA, the Guardian set that is currently active, and the list of signatures gathered so far.\n    - **`version` ++\"byte\"++**: The VAA Version.\n    - **`guardian_set_index` ++\"u32\"++**: Indicates which Guardian set is signing.\n    - **`len_signatures` ++\"u8\"++**: The number of signatures stored.\n    - **`signatures` ++\"[]signature\"++**: The collection of Guardian signatures.\n\n    Where each `signature` is:\n\n    - **`index` ++\"u8\"++**: The index of this Guardian in the Guardian set.\n    - **`signature` ++\"[65]byte\"++**: The ECDSA signature.\n\n- **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.\n    - **`timestamp` ++\"u32\"++**: The timestamp of the block this message was published in.\n    - **`nonce` ++\"u32\"++**: The nonce associated with this message.\n    - **`emitter_chain` ++\"u16\"++**: The id of the chain that emitted the message.\n    - **`emitter_address` ++\"[32]byte\"++**: The contract address (Wormhole formatted) that called the Core Contract.\n    - **`sequence` ++\"u64\"++**: The auto-incrementing integer that represents the number of messages published by this emitter.\n    - **`consistency_level` ++\"u8\"++**: The consistency level (finality) required by this emitter.\n    - **`payload` ++\"[]byte\"++**: Arbitrary bytes containing the data to be acted on.\n\nThe 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 depending on the consistency level.\n\nThe 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.\n\nBecause 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."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 1, "depth": 2, "title": "Consistency and Finality", "anchor": "consistency-and-finality", "start_char": 4080, "end_char": 4930, "estimated_token_count": 142, "token_estimator": "heuristic-v1", "text": "## Consistency and Finality\n\nThe 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.\n\nGuardian 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."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 2, "depth": 2, "title": "Signatures", "anchor": "signatures", "start_char": 4930, "end_char": 5633, "estimated_token_count": 164, "token_estimator": "heuristic-v1", "text": "## Signatures\n\nThe body of the VAA is hashed twice with `keccak256` to produce the signed digest message.\n\n```js\n// hash the bytes of the body twice\ndigest = keccak256(keccak256(body))\n// sign the result \nsignature = ecdsa_sign(digest, key)\n```\n\n!!!tip \"Hash vs. double hash\"\n    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.\n\n    For example, the [Solana secp256k1 program](https://solana.com/docs/core/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."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 3, "depth": 2, "title": "Payload Types", "anchor": "payload-types", "start_char": 5633, "end_char": 5885, "estimated_token_count": 50, "token_estimator": "heuristic-v1", "text": "## Payload Types\n\nDifferent 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)."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 4, "depth": 3, "title": "Token Transfer", "anchor": "token-transfer", "start_char": 5885, "end_char": 7648, "estimated_token_count": 415, "token_estimator": "heuristic-v1", "text": "### Token Transfer\n\nMany 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 Wrapped Token Transfer (WTT) is chain-agnostic and can be rapidly integrated into any network with a Wormhole contract.\n\nTransferring tokens from the sending chain to the destination chain requires the following steps:\n\n1. Lock the token on the sending chain.\n2. The sending chain emits a message as proof the token lockup is complete.\n3. The destination chain receives the message confirming the lockup event on the sending chain.\n4. The token is minted on the destination chain.\n\nThe message the sending chain emits to verify the lockup is referred to as a transfer message and has the following structure:\n\n- **`payload_id` ++\"u8\"++**: The ID of the payload. This should be set to `1` for a token transfer.\n- **`amount` ++\"u256\"++**: Amount of tokens being transferred.\n- **`token_address` ++\"u8[32]\"++**: Address on the source chain.\n- **`token_chain` ++\"u16\"++**: Numeric ID for the source chain.\n- **`to` ++\"u8[32]\"++**: Address on the destination chain.\n- **`to_chain` ++\"u16\"++**: Numeric ID for the destination chain.\n- **`fee` ++\"u256\"++**: Portion of amount paid to a relayer.\n\nThis 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.\n\nNote 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."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 5, "depth": 3, "title": "Attestation", "anchor": "attestation", "start_char": 7648, "end_char": 9552, "estimated_token_count": 436, "token_estimator": "heuristic-v1", "text": "### Attestation\n\nWhile 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, WTT supports token attestation.\n\nTo 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.\n\nThe message format for token attestation is as follows:\n\n- **`payload_id` ++\"u8\"++**: The ID of the payload. This should be set to `2` for an attestation.\n- **`token_address` ++\"[32]byte\"++**: Address of the originating token contract.\n- **`token_chain` ++\"u16\"++**: Chain ID of the originating token.\n- **`decimals` ++\"u8\"++**: Number of decimals this token should have.\n- **`symbol` ++\"[32]byte\"++**: Short name of asset.\n- **`name` ++\"[32]byte\"++**: Full name of asset.\n\n#### Attestation Tips\n\nBe aware of the following considerations when working with attestations:\n\n- 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.\n\n- 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.\n\n- 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.\n\n- 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.\n\n- Without knowing a token's decimal precision, the destination chain cannot correctly mint the number of tokens when processing a transfer. For this reason, WTT requires an attestation for each token transfer."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 6, "depth": 3, "title": "Token Transfer with Message", "anchor": "token-transfer-with-message", "start_char": 9552, "end_char": 10706, "estimated_token_count": 326, "token_estimator": "heuristic-v1", "text": "### Token Transfer with Message\n\nThe Token Transfer with Message data structure is identical to the token-only data structure, except for the following:\n\n- **`fee` field**: Replaced with the `from_address` field.\n- **`payload` field**: Is added containing arbitrary bytes. A dApp may include additional data in this arbitrary byte field to inform some application-specific behavior.\n\nThis 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 structure is as follows:\n\n- **`payload_id` ++\"u8\"++**: The ID of the payload. This should be set to `3` for a token transfer with message.\n- **`amount` ++\"u256\"++**: Amount of tokens being transferred.\n- **`token_address` ++\"u8[32]\"++**: Address on the source chain.\n- **`token_chain` ++\"u16\"++**: Numeric ID for the source chain.\n- **`to` ++\"u8[32]\"++**: Address on the destination chain.\n- **`to_chain` ++\"u16\"++**: Numeric ID for the destination chain.\n- **`from_address` ++\"u8[32]\"++**: Address that called WTT on the source chain.\n- **`payload` ++\"[]byte\"++**: Message, arbitrary bytes, app-specific."}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 7, "depth": 3, "title": "Governance", "anchor": "governance", "start_char": 10706, "end_char": 12255, "estimated_token_count": 349, "token_estimator": "heuristic-v1", "text": "### Governance\n\nGovernance 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).\n\n#### Action Structure\n\nGovernance messages contain pre-defined actions, which can target the various Wormhole modules currently deployed on-chain. The structure includes the following fields:\n\n- **`module` ++\"u8[32]\"++**: Contains a right-aligned module identifier.\n- **`action` ++\"u8\"++**: Predefined governance action to execute.\n- **`chain`  ++\"u16\"++**: Chain the action is targeting. This should be set to `0` for all chains.\n- **`args`  ++\"any\"++**: Arguments to the action.\n\nBelow 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.\n\n```js\nmodule:       0x0000000000000000000000000000000000000000000000000000436f7265\naction:       1\nchain:        1\nnew_contract: 0x348567293758957162374959376192374884562522281937446234828323\n```\n\n#### Actions\n\nThe 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:\n\n- [Core governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md){target=\\_blank}\n- [WTT governance actions](https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0003_token_bridge.md){target=\\_blank}"}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 8, "depth": 2, "title": "Lifetime of a Message", "anchor": "lifetime-of-a-message", "start_char": 12255, "end_char": 14172, "estimated_token_count": 367, "token_estimator": "heuristic-v1", "text": "## Lifetime of a Message\n\nAnyone 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.\n\nWith 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.\n\n1. **A message is emitted by a contract running on Chain A**: Any contract can emit messages, and the Guardian Network observes supported chains for these events. For full Guardian Set chains, all 19 Guardians directly observe on-chain messages. For delegated chains, a delegated subset performs direct observation and broadcasts signed delegate observations to the rest of the network. In the diagram, Guardians are represented as a single entity for simplicity, but observation and signing are performed independently by each participating Guardian.\n2. **Signatures are aggregated**: Guardians independently observe and sign the message. For full Guardian Set chains, all Guardians perform on-chain observation. For delegated chains, a delegated subset observes and broadcasts `SignedDelegateObservation` messages to the rest of the network. Canonical Guardians wait for delegate quorum before contributing their signatures. Once a two-thirds majority (13 out of 19) have signed, the signatures are combined with the message and metadata to produce a VAA.\n3. **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.\n\n![Lifetime of a message diagram](/docs/images/protocol/infrastructure/vaas/lifetime-vaa-diagram.webp)"}
{"page_id": "protocol-infrastructure-vaas", "page_title": "VAAs", "index": 9, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 14172, "end_char": 14783, "estimated_token_count": 152, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Guardians**\n\n    ---\n\n    Explore Wormhole's Guardian Network, a decentralized system for secure, scalable cross-chain communication across various blockchain ecosystems.\n\n    [:custom-arrow: Learn About Guardians](/docs/protocol/infrastructure/guardians/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/ecosystem){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 0, "depth": 2, "title": "What Problems Does Wormhole Solve?", "anchor": "what-problems-does-wormhole-solve", "start_char": 1855, "end_char": 2877, "estimated_token_count": 164, "token_estimator": "heuristic-v1", "text": "## What Problems Does Wormhole Solve?\n\nInteroperability 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.\n\nCritical problems Wormhole addresses include:\n\n- **Blockchain isolation**: Wormhole connects disparate blockchains, enabling the transfer of assets, data, and governance actions across networks.\n- **Cross-chain complexity**: By abstracting the complexities of cross-chain communication, Wormhole makes it easier for developers to build and deploy cross-chain applications.\n- **Security and decentralization**: Wormhole prioritizes security through a decentralized Guardian network that validates and signs messages, ensuring the integrity of cross-chain interactions."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 1, "depth": 2, "title": "What Does Wormhole Offer?", "anchor": "what-does-wormhole-offer", "start_char": 2877, "end_char": 3691, "estimated_token_count": 198, "token_estimator": "heuristic-v1", "text": "## What Does Wormhole Offer?\n\nWormhole provides a suite of tools and protocols that support a wide range of use cases:\n\n- **Cross-chain messaging**: Securely transfer arbitrary data between blockchains, enabling the development of cross-chain decentralized applications.\n- **Asset transfers**: Facilitate the movement of tokens across supported chains with ease, powered by protocols built on Wormhole like [Portal](https://portalbridge.com/){target=\\_blank}.\n- **Developer tools**: Leverage Wormhole’s [TypeScript SDK](/docs/tools/typescript-sdk/get-started/){target=\\_blank}, [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."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 2, "depth": 2, "title": "What Isn't Wormhole?", "anchor": "what-isnt-wormhole", "start_char": 3691, "end_char": 4082, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "## What Isn't Wormhole?\n\n- **Wormhole is _not_ a blockchain**: It acts as a communication layer that connects different blockchains, enabling them to interact without being a blockchain itself.\n- **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."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 3, "depth": 2, "title": "Use Cases of Wormhole", "anchor": "use-cases-of-wormhole", "start_char": 4082, "end_char": 4870, "estimated_token_count": 169, "token_estimator": "heuristic-v1", "text": "## Use Cases of Wormhole\n\nConsider the following examples of potential applications enabled by Wormhole:\n\n- **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.\n- [**Cross-chain governance**](https://wormhole.com/blog/stake-for-governance-guide){target=\\_blank}: Projects with communities spread across multiple blockchains can use Wormhole to relay votes from each chain to a designated governance chain, enabling unified decision-making through combined proposals.\n- **Cross-chain game**: Games can be developed on a performant network like Solana, with rewards issued on another network, such as Ethereum."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 4, "depth": 2, "title": "Explore", "anchor": "explore", "start_char": 4870, "end_char": 5235, "estimated_token_count": 93, "token_estimator": "heuristic-v1", "text": "## Explore\n\nDiscover more about the Wormhole ecosystem, components, and protocols:\n\n- **[Architecture](/docs/protocol/architecture/){target=\\_blank}**: Explore the components of the protocol.\n- **[Protocol Specifications](https://github.com/wormhole-foundation/wormhole/tree/main/whitepapers){target=\\_blank}**: Learn about the protocols built on top of Wormhole."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 5, "depth": 2, "title": "Demos", "anchor": "demos", "start_char": 5235, "end_char": 5940, "estimated_token_count": 168, "token_estimator": "heuristic-v1", "text": "## Demos\n\nDemos offer more realistic implementations than tutorials:\n\n- **[Wormhole Scaffolding](https://github.com/wormhole-foundation/wormhole-scaffolding){target=\\_blank}**: Quickly set up a project with the Scaffolding repository.\n- **[Demo Tutorials](https://github.com/wormhole-foundation/demo-tutorials){target=\\_blank}**: Explore various demos that showcase Wormhole's capabilities across different blockchains.\n\n!!! note\n    Wormhole Integration Complete?\n\n    Let us know so we can list your project in our ecosystem directory and introduce you to our global, multichain community!\n\n    **[Reach out now!](https://forms.clickup.com/45049775/f/1aytxf-10244/JKYWRUQ70AUI99F32Q){target=\\_blank}**"}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 6, "depth": 2, "title": "Supported Networks by Product", "anchor": "supported-networks-by-product", "start_char": 5940, "end_char": 6202, "estimated_token_count": 54, "token_estimator": "heuristic-v1", "text": "## Supported Networks by Product\n\nWormhole supports a growing number of blockchains. Check out the [Supported Networks by Product](/docs/products/reference/supported-networks/){target=\\_blank} page to see which networks are supported for each Wormhole product."}
{"page_id": "protocol-introduction", "page_title": "Introduction to Wormhole", "index": 7, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 6202, "end_char": 6796, "estimated_token_count": 156, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **Architecture Overview**\n\n    ---\n\n    Get an overview of Wormhole's architecture, detailing key on-chain and off-chain components like the Core Contract, Guardian Network, and relayers.\n\n    [:custom-arrow: Learn More](/docs/protocol/architecture/)\n\n-   :octicons-tools-16:{ .lg .middle } **Wormhole Dev Arena**\n\n    ---\n\n    A structured learning hub with hands-on tutorials across the Wormhole ecosystem.\n\n    [:custom-arrow: Explore the Dev Arena](https://arena.wormhole.com/){target=\\_blank}\n\n</div>"}
{"page_id": "protocol-security", "page_title": "Security", "index": 0, "depth": 2, "title": "Core Security Assumptions", "anchor": "core-security-assumptions", "start_char": 12, "end_char": 2004, "estimated_token_count": 422, "token_estimator": "heuristic-v1", "text": "## Core Security Assumptions\n\nAt 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.\n\n- Wormhole's core security primitive is its signed messages (signed [VAAs](/docs/protocol/infrastructure/vaas/){target=\\_blank}).\n- 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}.\n- Guardians produce signed state attestations (signed VAAs) when requested by a Core Contract integrator.\n- 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.\n- Any Signed VAA can be verified as authentic by the Core Contract of any other chain.\n- The [Executor](/docs/protocol/infrastructure/relayers/executor-framework/){target=\\_blank} is considered untrusted in the Wormhole ecosystem. It can affect message availability (timing of delivery) but cannot alter or forge VAAs, as validity is enforced by Guardian signatures.\n\nIn summary:\n\n- **Core integrators are not exposed to risk from chains and contracts they do not integrate with**.\n- By default, you only trust Wormhole's signing process and the core contracts of the chains you're on.\n- You can expand your contract and chain dependencies as you see fit.\n\nCore 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."}
{"page_id": "protocol-security", "page_title": "Security", "index": 1, "depth": 2, "title": "Guardian Network", "anchor": "guardian-network", "start_char": 2004, "end_char": 2801, "estimated_token_count": 137, "token_estimator": "heuristic-v1", "text": "## Guardian Network\n\nWormhole is an evolving platform. While the canonical Guardian set consists of 19 members, not all chains require all 19 Guardians to perform direct on-chain observation. For delegated chains, a delegated subset of Guardians performs direct on-chain observation while the final VAA signature threshold remains 13-of-19.\n\nDelegated Guardian Sets introduces a per-chain trust assumption: the delegate quorum threshold determines how many Delegated Guardians must independently agree before Canonical Guardians sign. This model does not weaken the final 13-of-19 VAA requirement, but it means the observation layer for that chain depends on fewer nodes. The `WormholeDelegatedGuardians` governance contract allows these thresholds to be adjusted as network requirements evolve."}
{"page_id": "protocol-security", "page_title": "Security", "index": 2, "depth": 3, "title": "Governance", "anchor": "governance", "start_char": 2801, "end_char": 4101, "estimated_token_count": 234, "token_estimator": "heuristic-v1", "text": "### Governance\n\nGovernance 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.\n\nThis 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.\n\nGovernance messages can target any of the various wormhole modules, including the core contracts and all currently deployed Wrapped Token Transfers (WTT) 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.\n\nAll governance actions and contract upgrades have been managed via Wormhole's on-chain governance system.\n\nVia governance, the Guardians can:\n\n- Change the current Guardian set.\n- Expand the Guardian set.\n- Upgrade ecosystem contract implementations.\n- Configure per-chain Delegated Guardian sets and security thresholds via the `WormholeDelegatedGuardians` contract.\n\nThe governance system is fully open source in the core repository. See the [Open Source section](#open-source){target=\\_blank} for contract source."}
{"page_id": "protocol-security", "page_title": "Security", "index": 3, "depth": 2, "title": "Monitoring", "anchor": "monitoring", "start_char": 4101, "end_char": 5328, "estimated_token_count": 208, "token_estimator": "heuristic-v1", "text": "## Monitoring\n\nA 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.\n\nFor full Guardian Set chains, all Guardians run full nodes and independently monitor block production and contract activity. For delegated chains, Delegated Guardians perform direct on-chain monitoring while Canonical Guardians monitor delegate observations and enforce quorum safeguards.\n\nGuardians monitor:\n\n- **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.\n- **Smart contract level data**: Via processes like the Governor, Guardians constantly monitor the circulating supply and token movements across all supported blockchains.\n- **Guardian level activity**: The Guardian Network functions as an autonomous decentralized computing network, ensuring independent security measures across its validators."}
{"page_id": "protocol-security", "page_title": "Security", "index": 4, "depth": 2, "title": "Asset Layer Protections", "anchor": "asset-layer-protections", "start_char": 5328, "end_char": 6332, "estimated_token_count": 182, "token_estimator": "heuristic-v1", "text": "## Asset Layer Protections\n\nOne key strength of the Wormhole ecosystem is the Guardians' ability to validate and protect the integrity of assets across multiple blockchains.\n\nTo 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.\n\nFor delegated chains, delegate quorum must be reached before Canonical Guardians contribute signatures, ensuring that per-chain delegate thresholds are respected without altering the Global Accountant's 13-of-19 security model.\n\nIn 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."}
{"page_id": "protocol-security", "page_title": "Security", "index": 5, "depth": 2, "title": "Open Source", "anchor": "open-source", "start_char": 6332, "end_char": 6708, "estimated_token_count": 105, "token_estimator": "heuristic-v1", "text": "## Open Source\n\nWormhole builds in the open and is always open source.\n\n- **[Wormhole core repository](https://github.com/wormhole-foundation/wormhole){target=\\_blank}**\n- **[Wormhole Foundation GitHub organization](https://github.com/wormhole-foundation){target=\\_blank}**\n- **[Wormhole contract deployments](/docs/protocol/infrastructure/core-contracts/){target=\\_blank}**"}
{"page_id": "protocol-security", "page_title": "Security", "index": 6, "depth": 2, "title": "Audits", "anchor": "audits", "start_char": 6708, "end_char": 7601, "estimated_token_count": 299, "token_estimator": "heuristic-v1", "text": "## Audits\n\nWormhole has been heavily audited, with _29 third-party audits completed_ and more started. Audits have been performed by the following firms:\n\n- [Trail of Bits](https://www.trailofbits.com/){target=\\_blank}\n- [Neodyme](https://neodyme.io/en/){target=\\_blank}\n- [Kudelski](https://kudelskisecurity.com/){target=\\_blank}\n- [OtterSec](https://osec.io/){target=\\_blank}\n- [Certik](https://www.certik.com/){target=\\_blank}\n- [Hacken](https://hacken.io/){target=\\_blank}\n- [Zellic](https://www.zellic.io/){target=\\_blank}\n- [Coinspect](https://www.coinspect.com/){target=\\_blank}\n- [Halborn](https://www.halborn.com/){target=\\_blank}\n- [Cantina](https://cantina.xyz/welcome){target=\\_blank}\n\nAll 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}."}
{"page_id": "protocol-security", "page_title": "Security", "index": 7, "depth": 2, "title": "Bug Bounties", "anchor": "bug-bounties", "start_char": 7601, "end_char": 8478, "estimated_token_count": 216, "token_estimator": "heuristic-v1", "text": "## Bug Bounties\n\nWormhole has one of the largest bug bounty programs in software development and has repeatedly shown commitment to engaging with the white hat community.\n\nWormhole runs a bug bounty program through [Immunefi](https://immunefi.com/bug-bounty/wormhole/){target=\\_blank} program, with a top payout of **5 million dollars**.\n\nIf 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}.\n\nFor more information about submitting to the bug bounty programs, refer to the [Wormhole Immunefi page](https://immunefi.com/bug-bounty/wormhole/){target=\\_blank}."}
{"page_id": "protocol-security", "page_title": "Security", "index": 8, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 8478, "end_char": 8859, "estimated_token_count": 104, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **View Latest Security Policies**\n\n    ---\n\n    The `SECURITY.md` from the official Wormhole repository on GitHub has the latest security policies and updates.\n\n    [:custom-arrow: See SECURITY.md](https://github.com/wormhole-foundation/wormhole/blob/main/SECURITY.md){target=\\_blank}\n\n</div>"}
{"page_id": "tools-cli-get-started", "page_title": "Wormhole CLI", "index": 0, "depth": 2, "title": "Installation", "anchor": "installation", "start_char": 180, "end_char": 617, "estimated_token_count": 118, "token_estimator": "heuristic-v1", "text": "## Installation\n\nClone the repository and change directories to the appropriate directory:\n\n```bash\ngit clone https://github.com/wormhole-foundation/wormhole &&\ncd wormhole/clients/js\n```\n\nBuild and install the CLI tool:\n\n```bash\nmake install\n```\n\nThis 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."}
{"page_id": "tools-cli-get-started", "page_title": "Wormhole CLI", "index": 1, "depth": 2, "title": "Usage", "anchor": "usage", "start_char": 617, "end_char": 4623, "estimated_token_count": 536, "token_estimator": "heuristic-v1", "text": "## Usage\n\nYou can interact with the Wormhole CLI by typing `worm` and including the `command` and any necessary subcommands and parameters.  \n\n| Command                                                                                                                  | Description                                                                                                      |\n|--------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|\n| `worm aptos INSERT_COMMAND`                                                                                              | Aptos utilities.                                                                                                 |\n| `worm edit-vaa INSERT_COMMAND`                                                                                           | Edits or generates a VAA.                                                                                        |\n| `worm evm INSERT_COMMAND`                                                                                                | EVM utilities.                                                                                                   |\n| `worm generate INSERT_COMMAND`                                                                                           | Generate VAAs (devnet and testnet only).                                                                         |\n| `worm info INSERT_COMMAND`                                                                                               | Contract, chain, RPC, and address information utilities.                                                         |\n| `worm near INSERT_NETWORK, INSERT_ACCOUNT`                                                                               | NEAR utilities.                                                                                                  |\n| `worm parse INSERT_VAA`                                                                                                  | Parse a VAA (can be in either hex or base64 format).                                                             |\n| `worm recover INSERT_DIGEST INSERT_SIGNATURE`                                                                            | Recover an address from a signature.                                                                             |\n| `worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH`                                                              | Prints information about the automatic delivery initiated on the specified network, chain, and transaction hash. |\n| `worm submit INSERT_VAA`                                                                                                 | Execute a VAA.                                                                                                   |\n| `worm sui INSERT_COMMAND`                                                                                                | Sui utilities.                                                                                                   |\n| `worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK` | Transfers a token.                                                                                               |\n| `worm verify-vaa INSERT_VAA, INSERT_NETWORK`                                                                             | Verifies a VAA by querying the Core Contract on Ethereum.                                                        |\n\nYou can also refer to the below options, available with all `worm` commands:\n\n```bash\nOptions:\n  --help     Show help                                                 [boolean]\n  --version  Show version number                                       [boolean]\n```"}
{"page_id": "tools-cli-get-started", "page_title": "Wormhole CLI", "index": 2, "depth": 3, "title": "Subcommands", "anchor": "subcommands", "start_char": 4623, "end_char": 21533, "estimated_token_count": 2717, "token_estimator": "heuristic-v1", "text": "### Subcommands\n\n??? interface \"Aptos\"\n    ```bash\n    worm aptos INSERT_COMMAND\n\n    Commands:\n      worm aptos init-token-bridge              Init token bridge contract\n      worm aptos init-wormhole                  Init Wormhole core contract\n      worm aptos deploy <package-dir>           Deploy an Aptos package\n      worm aptos deploy-resource <seed>         Deploy an Aptos package using a\n      <package-dir>                             resource account\n      worm aptos send-example-message           Send example message\n      <message>\n      worm aptos derive-resource-account        Derive resource account address\n      <account> <seed>\n      worm aptos derive-wrapped-address         Derive wrapped coin type\n      <chain> <origin-address>\n      worm aptos hash-contracts <package-dir>   Hash contract bytecodes for upgrade\n      worm aptos upgrade <package-dir>          Perform upgrade after VAA has been\n                                                submitted\n      worm aptos migrate                        Perform migration after contract\n                                                upgrade\n      worm aptos faucet                         Request money from the faucet for a\n                                                given account\n      worm aptos start-validator                Start a local aptos validator\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"Edit VAA\"\n    ```bash\n    worm edit-vaa INSERT_COMMAND\n\n    Options:\n          --help                       Show help                           [boolean]\n          --version                    Show version number                 [boolean]\n      -v, --vaa                        vaa in hex format         [string] [required]\n      -n, --network                    Network\n                                [required] [choices: \"mainnet\", \"testnet\", \"devnet\"]\n          --guardian-set-index, --gsi  guardian set index                   [number]\n          --signatures, --sigs         comma separated list of signatures   [string]\n          --wormscanurl, --wsu         url to wormscan entry for the vaa that\n                                       includes signatures                  [string]\n          --wormscan, --ws             if specified, will query the wormscan entry\n                                       for the vaa to get the signatures   [boolean]\n          --emitter-chain-id, --ec     emitter chain id to be used in the vaa\n                                                                            [number]\n          --emitter-address, --ea      emitter address to be used in the vaa[string]\n          --nonce, --no                nonce to be used in the vaa          [number]\n          --sequence, --seq            sequence number to be used in the vaa[string]\n          --consistency-level, --cl    consistency level to be used in the vaa\n                                                                            [number]\n          --timestamp, --ts            timestamp to be used in the vaa in unix\n                                       seconds                              [number]\n      -p, --payload                    payload in hex format                [string]\n          --guardian-secret, --gs      Guardian's secret key                [string]\n    ```\n\n??? interface \"EVM\"\n    ```bash\n    worm evm INSERT_COMMAND\n\n    Commands:\n      worm evm address-from-secret <secret>  Compute a 20 byte eth address from a 32\n                                             byte private key\n      worm evm storage-update                Update a storage slot on an EVM fork\n                                             during testing (anvil or hardhat)\n      worm evm chains                        Return all EVM chains\n      worm evm info                          Query info about the on-chain state of\n                                             the contract\n      worm evm hijack                        Override the guardian set of the core\n                                             bridge contract during testing (anvil\n                                             or hardhat)\n      worm evm start-validator               Start a local EVM validator\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n      --rpc      RPC endpoint                                               [string]\n    ```\n\n??? interface \"Generate\"\n    ```bash\n    worm generate INSERT_COMMAND\n\n    Commands:\n      worm generate registration                Generate registration VAA\n      worm generate upgrade                     Generate contract upgrade VAA\n      worm generate attestation                 Generate a token attestation VAA\n      worm generate recover-chain-id            Generate a recover chain ID VAA\n      worm generate                             Sets the default delivery provider\n      set-default-delivery-provider             for the Wormhole Relayer contract\n\n    Options:\n          --help             Show help                                     [boolean]\n          --version          Show version number                           [boolean]\n      -g, --guardian-secret  Guardians' secret keys (CSV)        [string] [required]\n    ```\n\n??? interface \"Info\"\n    ```bash\n    worm info INSERT_COMMAND\n\n    Commands:\n      worm info chain-id <chain>                Print the wormhole chain ID integer\n                                                associated with the specified chain\n                                                name\n      worm info contract <network> <chain>      Print contract address\n      <module>\n      worm info emitter <chain> <address>       Print address in emitter address\n                                                format\n      worm info origin <chain> <address>        Print the origin chain and address\n                                                of the asset that corresponds to the\n                                                given chain and address.\n      worm info registrations <network>         Print chain registrations\n      <chain> <module>\n      worm info rpc <network> <chain>           Print RPC address\n      worm info wrapped <origin-chain>          Print the wrapped address on the\n      <origin-address> <target-chain>           target chain that corresponds with\n                                                the specified origin chain and\n                                                address.\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"NEAR\"\n    ```bash\n    worm near INSERT_COMMAND\n\n    Commands:\n      worm near contract-update <file>  Submit a contract update using our specific\n                                        APIs\n      worm near deploy <file>           Submit a contract update using near APIs\n\n    Options:\n          --help      Show help                                            [boolean]\n          --version   Show version number                                  [boolean]\n      -m, --module    Module to query  [choices: \"Core\", \"TokenBridge\"]\n      -n, --network   Network   [required] [choices: \"mainnet\", \"testnet\", \"devnet\"]\n          --account   Near deployment account                    [string] [required]\n          --attach    Attach some near                                      [string]\n          --target    Near account to upgrade                               [string]\n          --mnemonic  Near private keys                                     [string]\n          --key       Near private key                                      [string]\n      -r, --rpc       Override default rpc endpoint url                     [string]\n    ```\n\n??? interface \"Parse\"\n    ```bash\n    worm parse INSERT_VAA\n\n    Positionals:\n      vaa  vaa                                                              [string]\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"Recover\"\n    ```bash\n    worm recover INSERT_DIGEST INSERT_SIGNATURE\n\n    Positionals:\n      digest     digest                                                     [string]\n      signature  signature                                                  [string]\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"Status\"\n    ```bash\n    worm status INSERT_NETWORK, INSERT_CHAIN, INSERT_TXN_HASH\n\n    Positionals:\n      network  Network                     [choices: \n      'mainnet', \n      'testnet', \n      'devnet']\n      chain    Source chain\n                 [choices: \n      'unset',\n      'solana',\n      'ethereum',\n      'terra',\n      'bsc',\n      'polygon',\n      'avalanche',\n      'oasis',\n      'algorand',\n      'aurora',\n      'fantom',\n      'karura',\n      'acala',\n      'klaytn',\n      'celo',\n      'near',\n      'moonbeam',\n      'neon',\n      'terra2',\n      'injective',\n      'osmosis',\n      'sui',\n      'aptos',\n      'arbitrum',\n      'optimism',\n      'gnosis',\n      'pythnet',\n      'xpla',\n      'btc',\n      'base',\n      'sei',\n      'rootstock',\n      'scroll',\n      'mantle',\n      'blast',\n      'xlayer',\n      'linea',\n      'berachain',\n      'seievm',\n      'wormchain',\n      'cosmoshub',\n      'evmos',\n      'kujira',\n      'neutron',\n      'celestia',\n      'stargaze',\n      'seda',\n      'dymension',\n      'provenance',\n      'sepolia',\n      'arbitrum_sepolia',\n      'base_sepolia',\n      'optimism_sepolia',\n      'holesky',\n      'polygon_sepolia']\n      tx       Source transaction hash                                      [string]\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"Submit\"\n    ```bash\n    worm submit INSERT_VAA\n\n    Positionals:\n      vaa  vaa                                                              [string]\n\n    Options:\n          --help              Show help                                    [boolean]\n          --version           Show version number                          [boolean]\n      -c, --chain             chain name\n    [choices: 'unset',\n      'solana',\n      'ethereum',\n      'terra',\n      'bsc',\n      'polygon',\n      'avalanche',\n      'oasis',\n      'algorand',\n      'aurora',\n      'fantom',\n      'karura',\n      'acala',\n      'klaytn',\n      'celo',\n      'near',\n      'moonbeam',\n      'neon',\n      'terra2',\n      'injective',\n      'osmosis',\n      'sui',\n      'aptos',\n      'arbitrum',\n      'optimism',\n      'gnosis',\n      'pythnet',\n      'xpla',\n      'btc',\n      'base',\n      'sei',\n      'rootstock',\n      'scroll',\n      'mantle',\n      'blast',\n      'xlayer',\n      'linea',\n      'berachain',\n      'seievm',\n      'wormchain',\n      'cosmoshub',\n      'evmos',\n      'kujira',\n      'neutron',\n      'celestia',\n      'stargaze',\n      'seda',\n      'dymension',\n      'provenance',\n      'sepolia',\n      'arbitrum_sepolia',\n      'base_sepolia',\n      'optimism_sepolia',\n      'holesky',\n      'polygon_sepolia']\n      -n, --network           Network\n                                [required] \n      [choices: \n      'mainnet', \n      'testnet', \n      'devnet']\n      -a, --contract-address  Contract to submit VAA to (override config)   [string]\n          --rpc               RPC endpoint                                  [string]\n          --all-chains, --ac  Submit the VAA to all chains except for the origin\n                              chain specified in the payload\n                                                          [boolean] [default: false]\n    ```\n\n??? interface \"Sui\"\n    ```bash\n    worm sui INSERT_COMMAND\n\n    Commands:\n      worm sui build-coin                    Build wrapped coin and dump bytecode.\n\n                                             Example:\n                                             worm sui build-coin -d 8 -v V__0_1_1 -n\n                                             testnet -r\n                                             \"https://fullnode.testnet.sui.io:443\"\n      worm sui deploy <package-dir>          Deploy a Sui package\n      worm sui init-example-message-app      Initialize example core message app\n      worm sui init-token-bridge             Initialize token bridge contract\n      worm sui init-wormhole                 Initialize wormhole core contract\n      worm sui publish-example-message       Publish message from example app via\n                                             core bridge\n      worm sui setup-devnet                  Setup devnet by deploying and\n                                             initializing core and token bridges and\n                                             submitting chain registrations.\n      worm sui objects <owner>               Get owned objects by owner\n      worm sui package-id <state-object-id>  Get package ID from State object ID\n      worm sui tx <transaction-digest>       Get transaction details\n\n    Options:\n      --help     Show help                                                 [boolean]\n      --version  Show version number                                       [boolean]\n    ```\n\n??? interface \"Transfer\"\n    ```bash\n    worm transfer INSERT_SOURCE_CHAIN, INSERT_DESTINATION_CHAIN, INSERT_DESTINATION_ADDRESS, INSERT_AMOUNT, INSERT_NETWORK\n\n    Options:\n          --help        Show help                                          [boolean]\n          --version     Show version number                                [boolean]\n          --src-chain   source chain [required] [choices:\n      'solana',\n      'ethereum',\n      'terra',\n      'bsc',\n      'polygon',\n      'avalanche',\n      'oasis',\n      'algorand',\n      'aurora',\n      'fantom',\n      'karura',\n      'acala',\n      'klaytn',\n      'celo',\n      'near',\n      'moonbeam',\n      'neon',\n      'terra2',\n      'injective',\n      'osmosis',\n      'sui',\n      'aptos',\n      'arbitrum',\n      'optimism',\n      'gnosis',\n      'pythnet',\n      'xpla',\n      'btc',\n      'base',\n      'sei',\n      'rootstock',\n      'scroll',\n      'mantle',\n      'blast',\n      'xlayer',\n      'linea',\n      'berachain',\n      'seievm',\n      'wormchain',\n      'cosmoshub',\n      'evmos',\n      'kujira',\n      'neutron',\n      'celestia',\n      'stargaze',\n      'seda',\n      'dymension',\n      'provenance',\n      'sepolia',\n      'arbitrum_sepolia',\n      'base_sepolia',\n      'optimism_sepolia',\n      'holesky',\n      'polygon_sepolia']\n      --dst-chain   destination chain\n               [required] [choices: \n      'solana',\n      'ethereum',\n      'terra',\n      'bsc',\n      'polygon',\n      'avalanche',\n      'oasis',\n      'algorand',\n      'aurora',\n      'fantom',\n      'karura',\n      'acala',\n      'klaytn',\n      'celo',\n      'near',\n      'moonbeam',\n      'neon',\n      'terra2',\n      'injective',\n      'osmosis',\n      'sui',\n      'aptos',\n      'arbitrum',\n      'optimism',\n      'gnosis',\n      'pythnet',\n      'xpla',\n      'btc',\n      'base',\n      'sei',\n      'rootstock',\n      'scroll',\n      'mantle',\n      'blast',\n      'xlayer',\n      'linea',\n      'berachain',\n      'seievm',\n      'wormchain',\n      'cosmoshub',\n      'evmos',\n      'kujira',\n      'neutron',\n      'celestia',\n      'stargaze',\n      'seda',\n      'dymension',\n      'provenance',\n      'sepolia',\n      'arbitrum_sepolia',\n      'base_sepolia',\n      'optimism_sepolia',\n      'holesky',\n      'polygon_sepolia']\n          --dst-addr    destination address                      [string] [required]\n          --token-addr  token address               [string] [default: native token]\n          --amount      token amount                             [string] [required]\n      -n, --network     Network [required] [choices: \"mainnet\", \"testnet\", \"devnet\"]\n          --rpc         RPC endpoint                                        [string]\n    ```\n\n??? interface \"Verify VAA\"\n    ```bash\n    worm verify-vaa INSERT_VAA, INSERT_NETWORK\n\n    Options:\n          --help     Show help                                             [boolean]\n          --version  Show version number                                   [boolean]\n      -v, --vaa      vaa in hex format                           [string] [required]\n      -n, --network  Network    [required] [choices: \"mainnet\", \"testnet\", \"devnet\"]\n    ```"}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 0, "depth": 2, "title": "Tooling Installation", "anchor": "tooling-installation", "start_char": 212, "end_char": 594, "estimated_token_count": 87, "token_estimator": "heuristic-v1", "text": "## Tooling Installation\n\nThe [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}."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 1, "depth": 2, "title": "Development Stages", "anchor": "development-stages", "start_char": 594, "end_char": 728, "estimated_token_count": 19, "token_estimator": "heuristic-v1", "text": "## Development Stages\n\nDifferent approaches to development and testing are recommended at various stages of application development."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 2, "depth": 3, "title": "Initial Development", "anchor": "initial-development", "start_char": 728, "end_char": 1672, "estimated_token_count": 228, "token_estimator": "heuristic-v1", "text": "### Initial Development\n\nDuring 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:\n\n- **[Environment](https://github.com/wormhole-foundation/wormhole){target=\\_blank}**: Select the folder for the desired network to learn about the recommended native toolset.\n- **[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 VAAs for any program methods that require some message be sent or received.\n- **[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.\n\nRelying on native tools when possible allows for more rapid prototyping and iteration."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 3, "depth": 3, "title": "Integration", "anchor": "integration", "start_char": 1672, "end_char": 2629, "estimated_token_count": 194, "token_estimator": "heuristic-v1", "text": "### Integration\n\nFor 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.\n\n!!! note\n    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."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 4, "depth": 3, "title": "Prepare for Deployment", "anchor": "prepare-for-deployment", "start_char": 2629, "end_char": 2969, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "### Prepare for Deployment\n\nOnce 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."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 5, "depth": 2, "title": "Validator Setup with Tilt", "anchor": "validator-setup-with-tilt", "start_char": 2969, "end_char": 2999, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## Validator Setup with Tilt"}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 6, "depth": 3, "title": "Tilt", "anchor": "tilt", "start_char": 2999, "end_char": 3475, "estimated_token_count": 114, "token_estimator": "heuristic-v1", "text": "### Tilt\nIf 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."}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 7, "depth": 2, "title": "Deploying to Public Networks", "anchor": "deploying-to-public-networks", "start_char": 3475, "end_char": 3508, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## Deploying to Public Networks"}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 8, "depth": 3, "title": "Testnet", "anchor": "testnet", "start_char": 3508, "end_char": 4184, "estimated_token_count": 149, "token_estimator": "heuristic-v1", "text": "### Testnet\n\nWhen 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:\n\n```text\nhttps://api.testnet.wormholescan.io\n```"}
{"page_id": "tools-dev-env", "page_title": "Local Dev Environment", "index": 9, "depth": 3, "title": "Mainnet", "anchor": "mainnet", "start_char": 4184, "end_char": 4509, "estimated_token_count": 84, "token_estimator": "heuristic-v1", "text": "### Mainnet\n\nThe 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:\n\n```text\nhttps://api.wormholescan.io\n```"}
{"page_id": "tools-faqs", "page_title": "Toolkit FAQs", "index": 0, "depth": 2, "title": "Why does the `toNative` function in the TypeScript SDK return an error?", "anchor": "why-does-the-tonative-function-in-the-typescript-sdk-return-an-error", "start_char": 16, "end_char": 619, "estimated_token_count": 131, "token_estimator": "heuristic-v1", "text": "## Why does the `toNative` function in the TypeScript SDK return an error?\n\nThe `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.\n\nTo 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:\n\n```typescript\nimport solana from '@wormhole-foundation/sdk/solana';\nconst wh = await wormhole('Testnet', [solana]);\n```"}
{"page_id": "tools-faqs", "page_title": "Toolkit FAQs", "index": 1, "depth": 2, "title": "How can I retrieve the history of previously bridged transactions?", "anchor": "how-can-i-retrieve-the-history-of-previously-bridged-transactions", "start_char": 619, "end_char": 1349, "estimated_token_count": 153, "token_estimator": "heuristic-v1", "text": "## How can I retrieve the history of previously bridged transactions?\n\nTo 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:\n\n```bash\nhttps://api.wormholescan.io/api/v1/operations?address=INSERT_ADDRESS\n```\n\nSimply replace `INSERT_ADDRESS` with the address you want to query. The API will return a list of operations, including details about previously bridged transactions.\n\n???- example \"Fetch transaction history for a specific address\"\n    ```bash\n    curl -X GET \"https://api.wormholescan.io/api/v1/operations?address=0x05c009C4C1F1983d4B915C145F4E782de23d3A38\" -H \"accept: application/json\"\n    ```"}
{"page_id": "tools-faqs", "page_title": "Toolkit FAQs", "index": 2, "depth": 2, "title": "How can I manually submit a VAA to a destination chain in the correct format?", "anchor": "how-can-i-manually-submit-a-vaa-to-a-destination-chain-in-the-correct-format", "start_char": 1349, "end_char": 2929, "estimated_token_count": 377, "token_estimator": "heuristic-v1", "text": "## How can I manually submit a VAA to a destination chain in the correct format?\n\nTo manually submit a VAA (Verifiable Action Approval) to a destination chain, follow these steps:\n\n1. **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.\n\n    ```bash\n    https://wormholescan.io/#/tx/INSERT_TX_HASH?view=advanced\n    ```\n\n2. **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.\n\n3. **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`).\n\n    - The `TokenBridge` contract addresses for each chain are available in the [Wormhole contract addresses](/docs/products/reference/contract-addresses/){target=\\_blank} section.\n\n    - Interact with the smart contract through the Etherscan UI by pasting the hex-encoded VAA into the appropriate field.\n\nFollowing these steps, you can manually submit a VAA in the proper format to a destination chain."}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 0, "depth": 2, "title": "Install the SDK", "anchor": "install-the-sdk", "start_char": 842, "end_char": 2793, "estimated_token_count": 472, "token_estimator": "heuristic-v1", "text": "## Install the SDK\n\nTo install the Wormhole TypeScript SDK, use the following command:\n\n```bash\nnpm install @wormhole-foundation/sdk\n```\n\nThis package combines all the individual packages to make setup easier.\n\nYou can choose to install a specific set of packages as needed. For example, to install EVM-specific utilities, you can run:\n\n```bash\nnpm install @wormhole-foundation/sdk-evm\n```\n\n??? example \"Complete list of individually published packages\"\n\n    Platform-Specific Packages\n\n    - `@wormhole-foundation/sdk-evm`\n    - `@wormhole-foundation/sdk-solana`\n    - `@wormhole-foundation/sdk-algorand`\n    - `@wormhole-foundation/sdk-aptos`\n    - `@wormhole-foundation/sdk-cosmwasm`\n    - `@wormhole-foundation/sdk-sui`\n\n    ---\n\n    Protocol-Specific Packages\n\n    - Core Protocol\n        - `@wormhole-foundation/sdk-evm-core`\n        - `@wormhole-foundation/sdk-solana-core`\n        - `@wormhole-foundation/sdk-algorand-core`\n        - `@wormhole-foundation/sdk-aptos-core`\n        - `@wormhole-foundation/sdk-cosmwasm-core`\n        - `@wormhole-foundation/sdk-sui-core`\n\n    - WTT\n        - `@wormhole-foundation/sdk-evm-tokenbridge`\n        - `@wormhole-foundation/sdk-solana-tokenbridge`\n        - `@wormhole-foundation/sdk-algorand-tokenbridge`\n        - `@wormhole-foundation/sdk-aptos-tokenbridge`\n        - `@wormhole-foundation/sdk-cosmwasm-tokenbridge`\n        - `@wormhole-foundation/sdk-sui-tokenbridge`\n\n    - CCTP\n        - `@wormhole-foundation/sdk-evm-cctp`\n        - `@wormhole-foundation/sdk-solana-cctp`\n        - `@wormhole-foundation/sdk-aptos-cctp`\n        - `@wormhole-foundation/sdk-sui-cctp`\n\n    - Other Protocols\n        - `@wormhole-foundation/sdk-evm-portico`\n        - `@wormhole-foundation/sdk-evm-tbtc`\n        - `@wormhole-foundation/sdk-solana-tbtc`\n\n    ---\n\n    Utility Packages\n    \n    - `@wormhole-foundation/sdk-base`\n    - `@wormhole-foundation/sdk-definitions`\n    - `@wormhole-foundation/sdk-connect`"}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 1, "depth": 2, "title": "Initialize the SDK", "anchor": "initialize-the-sdk", "start_char": 2793, "end_char": 3844, "estimated_token_count": 270, "token_estimator": "heuristic-v1", "text": "## Initialize the SDK\n\nGetting your integration started is simple. First, import Wormhole:\n\n```ts\nimport { wormhole } from '@wormhole-foundation/sdk';\n```\n\nThen, import each of the ecosystem [platforms](/docs/tools/typescript-sdk/sdk-reference/#platforms) that you wish to support:\n\n```ts\nimport algorand from '@wormhole-foundation/sdk/algorand';\nimport aptos from '@wormhole-foundation/sdk/aptos';\nimport cosmwasm from '@wormhole-foundation/sdk/cosmwasm';\nimport evm from '@wormhole-foundation/sdk/evm';\nimport solana from '@wormhole-foundation/sdk/solana';\nimport sui from '@wormhole-foundation/sdk/sui';\n```\n\nTo 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:\n\n```ts\n  const wh = await wormhole('Testnet', [\n    evm,\n    solana,\n    aptos,\n    algorand,\n    cosmwasm,\n    sui,\n  ]);\n```\n\nWith a configured `Wormhole` object, you can begin to interact with these chains."}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 2, "depth": 2, "title": "Example Usage", "anchor": "example-usage", "start_char": 3844, "end_char": 3993, "estimated_token_count": 26, "token_estimator": "heuristic-v1", "text": "## Example Usage\n\nFollow these steps to confirm that the SDK is initialized correctly and can fetch basic chain information for your target chains."}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 3, "depth": 3, "title": "Prerequisites", "anchor": "prerequisites", "start_char": 3993, "end_char": 6837, "estimated_token_count": 625, "token_estimator": "heuristic-v1", "text": "### Prerequisites\n\nBefore you begin, make sure you have the following:\n\n - [Node.js and npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm){target=\\_blank} installed.\n - [TypeScript](https://www.typescriptlang.org/download/){target=\\_blank} installed.\n\n??? example \"Project setup instructions\"\n \n    Use the following commands to create a TypeScript project:\n\n    1. Create a directory and initialize a Node.js project:\n\n        ```bash\n        mkdir wh-ts-demo\n        cd wh-ts-demo\n        npm init -y\n        ```\n\n    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:\n\n        ```bash\n        npm install --save-dev tsx typescript @types/node @wormhole-foundation/sdk @wormhole-foundation/sdk-evm @wormhole-foundation/sdk-solana\n        ```\n\n    3. Create a `tsconfig.json` if you don't have one. You can generate a basic one using the following command:\n\n        ```bash\n        npx tsc --init\n        ```\n\n        Make sure your `tsconfig.json` includes the following settings:\n\n        ```json \n        {\n            \"compilerOptions\": {\n                // es2020 or newer\n                \"target\": \"es2020\",\n                // Use esnext if you configured your package.json with type: \"module\"\n                \"module\": \"commonjs\",\n                \"esModuleInterop\": true,\n                \"forceConsistentCasingInFileNames\": true,\n                \"strict\": true,\n                \"skipLibCheck\": true,\n                \"resolveJsonModule\": true\n            }\n        }\n        ```\n\n    4. Initialize the main `Wormhole` class to use the SDK. Create a new TypeScript file named `src/main.ts` in your project directory:\n\n        ```bash\n        mkdir src\n        touch src/main.ts\n        ```\n\n    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:\n\n        ```ts title=\"src/main.ts\"\n        import { wormhole } from '@wormhole-foundation/sdk';\n        // Import specific platform modules for the chains you intend to use\n        import evm from '@wormhole-foundation/sdk/evm';\n        import solana from '@wormhole-foundation/sdk/solana';\n\n        async function main() {\n          console.log('Initializing Wormhole SDK...');\n\n          // Determine the network: \"Mainnet\", \"Testnet\", or \"Devnet\"\n          const network = 'Testnet';\n\n          // Initialize the SDK with the chosen network and platform contexts\n          const wh = await wormhole(network, [evm, solana]);\n\n          console.log('Wormhole SDK Initialized!');\n        }\n\n        main().catch((e) => {\n          console.error('Error initializing Wormhole SDK', e);\n          process.exit(1);\n        });\n        ```"}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 4, "depth": 3, "title": "Fetch Chain Information", "anchor": "fetch-chain-information", "start_char": 6837, "end_char": 9142, "estimated_token_count": 581, "token_estimator": "heuristic-v1", "text": "### Fetch Chain Information\n\n1. Update the `main` function as follows to retrieve the chain ID and RPC for the chains your project supports:\n\n    ```ts title=\"src/main.ts\"\n    import { wormhole } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n\n    async function main() {\n      console.log('Initializing Wormhole SDK...');\n\n      const network = 'Testnet';\n      const wh = await wormhole(network, [evm, solana]);\n\n      console.log('Wormhole SDK Initialized!');\n\n      // Example: Get a chain ID and RPC for Solana\n      const solanaDevnetChain = wh.getChain('Solana');\n      console.log(\n        `Chain ID for Solana Testnet: ${solanaDevnetChain.config.chainId}`\n      );\n      console.log(`RPC for Solana Testnet: ${solanaDevnetChain.config.rpc}`);\n\n      // Example: Get a chain ID for Sepolia (EVM Testnet)\n      const sepoliaChain = wh.getChain('Sepolia');\n      console.log(`Chain ID for Sepolia: ${sepoliaChain.config.chainId}`);\n      console.log(`RPC for Sepolia: ${sepoliaChain.config.rpc}`);\n    }\n\n    main().catch((e) => {\n      console.error(\n        'Error initializing Wormhole SDK or fetching chain information:',\n        e\n      );\n      process.exit(1);\n    });\n    ```\n\n2. Run the script with the following command, replacing `INSERT_FILE_NAME` with your file name:\n\n    ```bash\n    npx tsx INSERT_FILE_NAME\n    ```\n\n    You will see terminal output similar to the following:\n\n    <div id=\"termynal\" data-termynal>\n        <span data-ty=\"input\"\n          ><span class=\"file-path\"></span>npx tsx src/main.ts</span\n        >\n        <span data-ty>Initializing Wormhole SDK...</span>\n        <span data-ty>Wormhole SDK Initialized!</span>\n        <span data-ty>Chain ID for Solana Testnet: 1</span>\n        <span data-ty>RPC for Solana Testnet: https://api.devnet.solana.com</span>\n        <span data-ty>Chain ID for Sepolia: 10002</span>\n        <span data-ty>RPC for Sepolia: https://ethereum-sepolia.publicnode.com</span>\n        <span data-ty=\"input\"><span class=\"file-path\"></span></span>\n      </div>\nCongratulations! You’ve successfully installed the Wormhole TypeScript SDK and initialized a `Wormhole` instance. Consider the following options to build on what you've accomplished."}
{"page_id": "tools-typescript-sdk-get-started", "page_title": "Get Started with the TypeScript SDK", "index": 5, "depth": 2, "title": "Next Steps", "anchor": "next-steps", "start_char": 9142, "end_char": 10381, "estimated_token_count": 313, "token_estimator": "heuristic-v1", "text": "## Next Steps\n\n<div class=\"grid cards\" markdown>\n\n-   :octicons-book-16:{ .lg .middle } **TypeScript SDK Reference**\n\n    ---\n\n    Explore Wormhole's TypeScript SDK and learn how to perform different types of transfers, including native, token, and USDC.\n    \n\n    [:custom-arrow: Get Familiar with the SDK](/docs/tools/typescript-sdk/sdk-reference/)\n\n-   :octicons-tools-16:{ .lg .middle } **Send a Multichain Message**\n\n    ---\n\n    Use Wormhole's core protocol to publish a multichain message and return transaction information with VAA identifiers.\n\n    [:custom-arrow: Get Started](/docs/products/messaging/get-started/)\n\n-   :octicons-tools-16:{ .lg .middle } **Transfer Assets via WTT**\n\n    ---\n\n    Build a cross-chain native token transfer app using the TypeScript SDK, supporting native token transfers across EVM and non-EVM chains.\n\n    [:custom-arrow: Get Started](/docs/products/token-transfers/wrapped-token-transfers/tutorials/transfer-workflow/)\n\n-   :octicons-tools-16:{ .lg .middle } **Transfer USDC via the CCTP Bridge**\n\n    ---\n\n    Perform USDC cross-chain transfers using the TypeScript SDK and Circle's CCTP.\n\n    [:custom-arrow: Get Started](/docs/products/cctp-bridge/tutorials/complete-usdc-transfer/)\n\n</div>"}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 0, "depth": 2, "title": "What is a Protocol?", "anchor": "what-is-a-protocol", "start_char": 1016, "end_char": 1928, "estimated_token_count": 188, "token_estimator": "heuristic-v1", "text": "## What is a Protocol?\n\nIn 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 in a consistent and standardized way.\n\nExamples of Protocols:\n\n - **`TokenBridge`**: Enables cross-chain token transfers, including operations like transferring tokens and relaying payloads.\n - **`NTT (Native Token Transfers)`**: Manages native token movements across chains.\n\nProtocols are defined by:\n\n - **A `name`**: A string identifier (e.g., `TokenBridge`, `Ntt`).\n - **A set of `payloads`**: These represent the specific actions or messages supported by the protocol, such as `Transfer` or `TransferWithPayload`.\n\nEach protocol is registered in the Wormhole SDK, allowing developers to leverage its predefined features or extend it with custom payloads."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 1, "depth": 2, "title": "What is a Payload?", "anchor": "what-is-a-payload", "start_char": 1928, "end_char": 2599, "estimated_token_count": 137, "token_estimator": "heuristic-v1", "text": "## What is a Payload?\n\nA 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.\n\nEach payload is defined as:\n\n - **A `layout`**: Describes the binary format of the payload fields.\n - **A `literal`**: Combines the protocol name and payload name into a unique identifier (e.g., `TokenBridge:Transfer`).\n\nBy registering payloads, developers can enforce type safety and enable serialization and deserialization for specific protocol operations."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 2, "depth": 2, "title": "Register Protocols and Payloads", "anchor": "register-protocols-and-payloads", "start_char": 2599, "end_char": 3073, "estimated_token_count": 83, "token_estimator": "heuristic-v1", "text": "## Register Protocols and Payloads\n\nProtocols and payloads work together to enable cross-chain communication with precise type safety. For instance, in the `TokenBridge` protocol:\n\n - The protocol is registered under the `TokenBridge` namespace.\n - Payloads like `Transfer` or `AttestMeta` are linked to the protocol to handle specific operations.\n\nUnderstanding the connection between these components is important for customizing or extending the SDK to suit your needs."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 3, "depth": 3, "title": "Register Protocols", "anchor": "register-protocols", "start_char": 3073, "end_char": 5249, "estimated_token_count": 448, "token_estimator": "heuristic-v1", "text": "### Register Protocols\n\nRegistering a protocol establishes its connection to Wormhole's infrastructure, ensuring it interacts seamlessly with payloads and platforms while maintaining type safety and consistency.\n\n#### How Protocol Registration Works\n\nProtocol registration involves two key tasks:\n\n - **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.\n - **Linking protocols to platforms**: Specify platform-specific implementations if needed, or use default mappings for platform-agnostic protocols.\n\nFor example, here's the `TokenBridge` protocol registration:\n\n```typescript\ndeclare module '../../registry.js' {\n  export namespace WormholeRegistry {\n    interface ProtocolToInterfaceMapping<N, C> {\n      TokenBridge: TokenBridge<N, C>;\n    }\n    interface ProtocolToPlatformMapping {\n      TokenBridge: EmptyPlatformMap<'TokenBridge'>;\n    }\n  }\n}\n```\n\nThis code snippet:\n\n - Maps the `TokenBridge` protocol to its interface to define how it operates.\n - Links the protocol to a default platform mapping via `EmptyPlatformMap`.\n\nYou 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}.\n\n#### Platform-Specific Protocols\n\nSome protocols require platform-specific behavior. For instance, the EVM-compatible Wormhole Registry maps native addresses for Ethereum-based chains:\n\n```typescript\ndeclare module '@wormhole-foundation/sdk-connect' {\n  export namespace WormholeRegistry {\n    interface PlatformToNativeAddressMapping {\n      Evm: EvmAddress;\n    }\n  }\n}\n\nregisterNative(_platform, EvmAddress);\n```\n\nThis 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."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 4, "depth": 3, "title": "Register Payloads", "anchor": "register-payloads", "start_char": 5249, "end_char": 8750, "estimated_token_count": 713, "token_estimator": "heuristic-v1", "text": "### Register Payloads\n\n[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.\n\nThis process ties a protocol to its payloads using a combination of:\n\n - **Payload literals**: Unique identifiers in the format `<ProtocolName>:<PayloadName>`. These literals map each payload to a layout.\n - **Payload layouts**: Structures that define the binary representation of payload data.\n - **The payload factory**: A centralized runtime registry that maps payload literals to layouts for dynamic resolution and serialization.\n\nThese components work together to streamline the definition and management of protocol payloads.\n\n#### How Payload Registration Works\n\nPayload registration involves:\n\n1. **Define payload layouts**: Create layouts to structure your payloads. For instance, a protocol might use a `TransferWithPayload` layout.\n\n    ```typescript\n    export const transferWithPayloadLayout = <\n      const P extends CustomizableBytes = undefined\n    >(\n      customPayload?: P\n    ) =>\n      [\n        payloadIdItem(3),\n        ...transferCommonLayout,\n        { name: 'from', ...universalAddressItem },\n        customizableBytes({ name: 'payload' }, customPayload),\n      ] as const;\n    ```\n\n2. **Register payloads**: Use `registerPayloadTypes` to map payload literals to their layouts.\n\n    ```typescript\n    registerPayloadTypes('ProtocolName', protocolNamedPayloads);\n    ```\n\n3. **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.\n\n    ```typescript\n    const layout = getPayloadLayout('ProtocolName:PayloadName');\n    ```\n\nThese steps link payload literals and their layouts, enabling seamless runtime handling.\n\n#### The Payload Factory\n\nAt the core of the payload registration process is the `payloadFactory`, a registry that manages the mapping between payload literals and layouts:\n\n```typescript\nexport const payloadFactory = new Map<LayoutLiteral, Layout>();\n\nexport function registerPayloadType(\n  protocol: ProtocolName,\n  name: string,\n  layout: Layout\n) {\n  const payloadLiteral = composeLiteral(protocol, name);\n  if (payloadFactory.has(payloadLiteral)) {\n    throw new Error(`Payload type ${payloadLiteral} already registered`);\n  }\n  payloadFactory.set(payloadLiteral, layout);\n}\n```\n\n - The `payloadFactory` ensures each payload literal maps to its layout uniquely.\n - 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.\n\nThis implementation ensures dynamic, efficient handling of payloads at runtime."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 5, "depth": 2, "title": "Integrate Protocols with Payloads", "anchor": "integrate-protocols-with-payloads", "start_char": 8750, "end_char": 9115, "estimated_token_count": 68, "token_estimator": "heuristic-v1", "text": "## Integrate Protocols with Payloads\n\nIntegrating 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}."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 6, "depth": 3, "title": "Payload Discriminators", "anchor": "payload-discriminators", "start_char": 9115, "end_char": 11209, "estimated_token_count": 392, "token_estimator": "heuristic-v1", "text": "### Payload Discriminators\n\nPayload 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.\n\n#### How Discriminators Work\n\nDiscriminators 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`).\n\nThis system ensures:\n\n - **Dynamic runtime identification**: Payloads are parsed based on their content, even if a single protocol handles multiple payload types.\n - **Strict type enforcement**: Discriminators leverage layout mappings to prevent invalid payloads from being processed.\n\nBelow is an example of how the Wormhole SDK builds a discriminator to distinguish between payload layouts:\n\n```typescript\nexport function layoutDiscriminator<B extends boolean = false>(\n  layouts: readonly Layout[],\n  allowAmbiguous?: B\n): Discriminator<B> {\n  // Internal logic to determine distinguishable layouts\n  const [distinguishable, discriminator] = internalBuildDiscriminator(layouts);\n  if (!distinguishable && !allowAmbiguous) {\n    throw new Error('Cannot uniquely distinguish the given layouts');\n  }\n\n  return (\n    !allowAmbiguous\n      ? (encoded: BytesType) => {\n          const layout = discriminator(encoded);\n          return layout.length === 0 ? null : layout[0];\n        }\n      : discriminator\n  ) as Discriminator<B>;\n}\n```\n\n - [`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.\n - The `allowAmbiguous` parameter determines whether layouts with overlapping characteristics are permitted."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 7, "depth": 3, "title": "Real-World Example: Wrapped Token Transfers (WTT) Protocol", "anchor": "real-world-example-wrapped-token-transfers-wtt-protocol", "start_char": 11209, "end_char": 15426, "estimated_token_count": 864, "token_estimator": "heuristic-v1", "text": "### Real-World Example: Wrapped Token Transfers (WTT) Protocol\n\nIntegrating 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.\n\n!!! note \"Terminology\" \n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol.\n\n#### WTT Protocol and Payloads\n\nThe `TokenBridge` protocol enables cross-chain token transfers through its payloads. Key payloads include:\n\n - **`Transfer`**: Handles basic token transfer operations.\n - **`TransferWithPayload`**: Extends the `Transfer` payload to include custom data, enhancing functionality.\n\nPayloads are registered to the `TokenBridge` protocol via the `PayloadLiteralToLayoutMapping` interface, which links payload literals (e.g., `TokenBridge:Transfer`) to their layouts.\n\nAdditionally, 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}:\n\n```typescript\nexport const transferWithPayloadLayout = <\n  const P extends CustomizableBytes = undefined\n>(\n  customPayload?: P\n) =>\n  [\n    payloadIdItem(3),\n    ...transferCommonLayout,\n    { name: 'from', ...universalAddressItem },\n    customizableBytes({ name: 'payload' }, customPayload),\n  ] as const;\n```\n\nThis layout includes:\n\n - A `payloadIdItem` to identify the payload type.\n - Common fields for token and recipient details.\n - A customizable `payload` field for additional data.\n\n#### Use the Discriminator\n\nTo manage multiple payloads, the `TokenBridge` protocol utilizes a discriminator to distinguish between payload types dynamically. For example:\n\n```typescript\nconst tokenBridgePayloads = ['Transfer', 'TransferWithPayload'] as const;\n\nexport const getTransferDiscriminator = lazyInstantiate(() =>\n  payloadDiscriminator([_protocol, tokenBridgePayloads])\n);\n```\n\n - 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.\n - This ensures that each payload type is processed according to its unique structure and type-safe layout.\n\n#### Register Payloads to Protocols\n\nHere’s how the `TokenBridge` protocol connects its payloads to the Wormhole SDK:\n\n```typescript\ndeclare module '../../registry.js' {\n  export namespace WormholeRegistry {\n    interface PayloadLiteralToLayoutMapping\n      extends RegisterPayloadTypes<\n        'TokenBridge',\n        typeof tokenBridgeNamedPayloads\n      > {}\n  }\n}\n\nregisterPayloadTypes('TokenBridge', tokenBridgeNamedPayloads);\n```\n\nThis registration links the `TokenBridge` payload literals to their respective layouts, enabling serialization and deserialization at runtime.\n\nYou 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}.\n\n#### WTT Payloads\n\nThe following payloads are registered for the `TokenBridge` protocol:\n\n - **`AttestMeta`**: Used for token metadata attestation.\n - **`Transfer`**: Facilitates token transfers.\n - **`TransferWithPayload`**: Adds a custom payload to token transfers.\n\nThese 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}."}
{"page_id": "tools-typescript-sdk-guides-protocols-payloads", "page_title": "Building Protocols and Payloads", "index": 8, "depth": 3, "title": "Other Protocols: Native Token Transfers (NTT)", "anchor": "other-protocols-native-token-transfers-ntt", "start_char": 15426, "end_char": 16171, "estimated_token_count": 147, "token_estimator": "heuristic-v1", "text": "### Other Protocols: Native Token Transfers (NTT)\n\nWhile this guide focuses on the `TokenBridge` protocol, other protocols, like NTT, follow a similar structure.\n\n - NTT manages the transfer of native tokens across chains.\n - Payloads such as `WormholeTransfer` and `WormholeTransferStandardRelayer` are registered to the protocol using the same patterns for payload literals and layouts.\n - The same mechanisms for type-safe registration and payload discriminators apply, ensuring reliability and extensibility.\n\nFor 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}."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 0, "depth": 2, "title": "Key Concepts", "anchor": "key-concepts", "start_char": 852, "end_char": 869, "estimated_token_count": 4, "token_estimator": "heuristic-v1", "text": "## Key Concepts"}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 1, "depth": 3, "title": "Layout Items", "anchor": "layout-items", "start_char": 869, "end_char": 2648, "estimated_token_count": 430, "token_estimator": "heuristic-v1", "text": "### Layout Items\n\nA 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.\n\nLayouts 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:\n\n - **`name`**: Name of the field.\n - **`binary`**: Type of data (e.g., `uint`, `bytes`).\n - **`size`**: Byte length for fixed-size fields within uint and bytes items only.\n\nLayout items can represent:\n\n - **Primitive types**: Basic data types like unsigned integers (`uint`) or byte arrays (`bytes`).\n - **Composite types**: More complex structures, such as arrays or nested objects.\n\nBelow is an example of a layout that might be used to serialize a message across the Wormhole protocol:\n\n```typescript\nconst exampleLayout = [\n  { name: 'sourceChain', binary: 'uint', size: 2 },\n  { name: 'orderSender', binary: 'bytes', size: 32 },\n  { name: 'redeemer', binary: 'bytes', size: 32 },\n  { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 },\n] as const;\n```\n\nIn this example:\n\n - `sourceChain` is a 2-byte unsigned integer (`uint`) identifying the source blockchain.\n - `orderSender` is a fixed-length 32-byte array representing the sender's address.\n - `redeemer` is another 32-byte array used for the redeemer’s address.\n - `redeemerMessage` is a variable-length byte sequence, with its length specified by a 4-byte integer.\n\nThis layout definition ensures that all necessary data fields are consistently encoded and can be correctly interpreted when they are deserialized."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 2, "depth": 3, "title": "Serialization and Deserialization", "anchor": "serialization-and-deserialization", "start_char": 2648, "end_char": 3141, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "### Serialization and Deserialization\n\nSerialization converts structured data into binary format; deserialization reverses this, reconstructing the original objects.\n\nYou can serialize data using the `serializeLayout` function:\n\n```typescript\nconst serialized = serializeLayout(fillLayout, exampleFill);\n```\n\nTo deserialize the binary data back into a structured object, use the `deserializeLayout` function:\n\n```typescript\nconst deserialized = deserializeLayout(fillLayout, serialized);\n```"}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 3, "depth": 3, "title": "Custom Conversions", "anchor": "custom-conversions", "start_char": 3141, "end_char": 3802, "estimated_token_count": 136, "token_estimator": "heuristic-v1", "text": "### Custom Conversions\n\nLayouts 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.\n\nFor example, consider a custom conversion for a chain ID:\n\n```typescript\nconst chainCustomConversion = {\n  to: (chainId: number) => toChain(chainId),\n  from: (chain: Chain) => chainToChainId(chain),\n} satisfies CustomConversion<number, Chain>;\n```\n\nThis setup allows Wormhole to convert between human-readable formats and binary-encoded data used in payloads."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 4, "depth": 3, "title": "Error Handling", "anchor": "error-handling", "start_char": 3802, "end_char": 4163, "estimated_token_count": 76, "token_estimator": "heuristic-v1", "text": "### Error Handling\n\nThe 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 example below:\n\n```typescript\ntry {\n  deserializeLayout(fillLayout, corruptedData);\n} catch (error) {\n  console.error('Error during deserialization:', error.message);\n}\n```"}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 5, "depth": 2, "title": "Application of Layouts", "anchor": "application-of-layouts", "start_char": 4163, "end_char": 4417, "estimated_token_count": 41, "token_estimator": "heuristic-v1", "text": "## Application of Layouts\n\nThis 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 6, "depth": 3, "title": "Defining Layouts", "anchor": "defining-layouts", "start_char": 4417, "end_char": 5218, "estimated_token_count": 205, "token_estimator": "heuristic-v1", "text": "### Defining Layouts\n\nTo 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.\n\nConsider the following layout for a payload:\n\n```typescript\nconst exampleLayout = [\n  { name: 'sourceChain', binary: 'uint', size: 2 },\n  { name: 'orderSender', binary: 'bytes', size: 32 },\n  { name: 'redeemer', binary: 'bytes', size: 32 },\n  { name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 },\n] as const;\n```\n\nIn this example:\n\n - `sourceChain` is an unsigned integer (uint) of 2 bytes.\n - `orderSender` is a 32-byte fixed-length byte array.\n - `redeemer` is another 32-byte byte array.\n - `redeemerMessage` is a length-prefixed byte array, with the length specified by a 4-byte integer."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 7, "depth": 3, "title": "Serialize Data", "anchor": "serialize-data", "start_char": 5218, "end_char": 5874, "estimated_token_count": 135, "token_estimator": "heuristic-v1", "text": "### Serialize Data\n\nOnce 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.\n\n```typescript\nconst examplePayload = {\n  sourceChain: 6,\n  orderSender: new Uint8Array(32),\n  redeemer: new Uint8Array(32),\n  redeemerMessage: new Uint8Array([0x01, 0x02, 0x03]),\n};\n\nconst serializedData = serializeLayout(exampleLayout, examplePayload);\n```\n\nThis 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 8, "depth": 3, "title": "Deserialize Data", "anchor": "deserialize-data", "start_char": 5874, "end_char": 6285, "estimated_token_count": 73, "token_estimator": "heuristic-v1", "text": "### Deserialize Data\n\nDeserialization is the reverse of serialization. Given a serialized `Uint8Array`, we can convert it back into its original structure using the `deserializeLayout` function.\n\n```typescript\nconst deserializedPayload = deserializeLayout(exampleLayout, serializedData);\n```\n\nThis will output the structured object, making it easy to work with data transmitted or received from another chain."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 9, "depth": 3, "title": "Handling Variable-Length Fields", "anchor": "handling-variable-length-fields", "start_char": 6285, "end_char": 6823, "estimated_token_count": 123, "token_estimator": "heuristic-v1", "text": "### Handling Variable-Length Fields\n\nOne relevant aspect of Wormhole SDK's layout system is the ability to handle variable-length fields, such as arrays and length-prefixed byte sequences.\n\nFor 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.\n\n```typescript\n{ name: 'message', binary: 'bytes', lengthSize: 4 }\n```\n\nThis tells the SDK to read or write the message's length (in 4 bytes) and then handle the content."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 10, "depth": 2, "title": "Nested Layouts and Strong Typing", "anchor": "nested-layouts-and-strong-typing", "start_char": 6823, "end_char": 7092, "estimated_token_count": 40, "token_estimator": "heuristic-v1", "text": "## Nested Layouts and Strong Typing\n\nThe 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 11, "depth": 3, "title": "Nested Layout", "anchor": "nested-layout", "start_char": 7092, "end_char": 8019, "estimated_token_count": 238, "token_estimator": "heuristic-v1", "text": "### Nested Layout\n\nIn 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.\n\nRefer to the following nested layout where a message contains nested fields:\n\n```typescript\nconst nestedLayout = [\n  {\n    name: 'source',\n    binary: 'bytes',\n    layout: [\n      { name: 'chainId', binary: 'uint', size: 2 },\n      { name: 'sender', binary: 'bytes', size: 32 },\n    ],\n  },\n  {\n    name: 'redeemer',\n    binary: 'bytes',\n    layout: [\n      { name: 'address', binary: 'bytes', size: 32 },\n      { name: 'message', binary: 'bytes', lengthSize: 4 },\n    ],\n  },\n] as const satisfies Layout;\n```\n\nIn this layout:\n\n - **`source` is an object with two fields**: `chainId` and `sender`.\n - **`redeemer` is another object with two fields**: `address` and a length-prefixed `message`."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 12, "depth": 3, "title": "Strong Typing", "anchor": "strong-typing", "start_char": 8019, "end_char": 9016, "estimated_token_count": 196, "token_estimator": "heuristic-v1", "text": "### Strong Typing\n\nOne 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.\n\nUsing TypeScript, the `LayoutToType` utility provided by the SDK automatically generates a strongly typed structure based on the layout:\n\n```typescript\ntype NestedMessage = LayoutToType<typeof nestedLayout>;\n```\n\nThis ensures that when you serialize or deserialize data, it matches the expected structure.\n\n```typescript\nconst message: NestedMessage = {\n  source: {\n    chainId: 6,\n    sender: new Uint8Array(32),\n  },\n  redeemer: {\n    address: new Uint8Array(32),\n    message: new Uint8Array([0x01, 0x02, 0x03]),\n  },\n};\n```\n\nAttempting 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 13, "depth": 3, "title": "Serialization and Deserialization with Nested Layouts", "anchor": "serialization-and-deserialization-with-nested-layouts", "start_char": 9016, "end_char": 9506, "estimated_token_count": 80, "token_estimator": "heuristic-v1", "text": "### Serialization and Deserialization with Nested Layouts\n\nYou can serialize and deserialize nested structures in the same way as simpler layouts:\n\n```typescript\nconst serializedNested = serializeLayout(nestedLayout, message);\nconst deserializedNested = deserializeLayout(nestedLayout, serializedNested);\n```\n\nStrong 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 14, "depth": 2, "title": "Commonly Used Layouts", "anchor": "commonly-used-layouts", "start_char": 9506, "end_char": 9940, "estimated_token_count": 99, "token_estimator": "heuristic-v1", "text": "## Commonly Used Layouts\n\nThe 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 15, "depth": 3, "title": "Chain ID Layouts", "anchor": "chain-id-layouts", "start_char": 9940, "end_char": 12214, "estimated_token_count": 555, "token_estimator": "heuristic-v1", "text": "### Chain ID Layouts\n\nChain 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.\n\n#### Base Structure\n\nThis simple structure is the blueprint for more specific layouts by standardizing the binary format and size.\n\n```typescript\nconst chainItemBase = { binary: 'uint', size: 2 } as const;\n```\n\n#### Dynamic Chain ID Layout\n\nThe 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.\n\n```typescript\nexport const chainItem = <\n  const C extends readonly Chain[] = typeof chains,\n  const N extends boolean = false,\n>(opts?: {\n  allowedChains?: C;\n  allowNull?: N;\n}) =>\n  ({\n    ...chainItemBase, // Builds on the base structure\n    custom: {\n      to: (val: number): AllowNull<C[number], N> => { ... },\n      from: (val: AllowNull<C[number], N>): number => { ... },\n    },\n  });\n```\n\nThis 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.\n\n#### Fixed Chain ID Layout\n\nThe 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.\n\n```typescript\nexport const fixedChainItem = <const C extends Chain>(chain: C) => ({\n  ...chainItemBase, // Builds on the base structure\n  custom: {\n    to: chain,\n    from: chainToChainId(chain),\n  },\n});\n```\n\nThis layout allows developers to efficiently serialize and deserialize messages involving a single, fixed chain ID."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 16, "depth": 3, "title": "Address Layout", "anchor": "address-layout", "start_char": 12214, "end_char": 13517, "estimated_token_count": 273, "token_estimator": "heuristic-v1", "text": "### Address Layout\n\nThe 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.\n\n#### Base Structure\n\nThe [`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.\n\n```typescript\nexport const universalAddressItem = {\n  binary: 'bytes',\n  size: 32,\n  custom: {\n    to: (val: Uint8Array): UniversalAddress => new UniversalAddress(val),\n    from: (val: UniversalAddress): Uint8Array => val.toUint8Array(),\n  } satisfies CustomConversion<Uint8Array, UniversalAddress>,\n} as const satisfies LayoutItem;\n```\n\nThis layout ensures consistent address handling by defining the following:\n\n - **Serialization**: Converts a high-level `UniversalAddress` object into raw binary (32 bytes) for efficient storage or transmission.\n - **Deserialization**: Converts raw binary back into a `UniversalAddress` object, enabling further interaction in a human-readable or programmatic format."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 17, "depth": 3, "title": "Signature Layout", "anchor": "signature-layout", "start_char": 13517, "end_char": 15131, "estimated_token_count": 380, "token_estimator": "heuristic-v1", "text": "### Signature Layout\n\nIn 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.\n\n#### Base Structure\n\nThe `signatureLayout` specifies the binary structure of a secp256k1 signature. It divides the signature into three components:\n\n```typescript\nconst signatureLayout = [\n  { name: 'r', binary: 'uint', size: 32 },\n  { name: 's', binary: 'uint', size: 32 },\n  { name: 'v', binary: 'uint', size: 1 },\n] as const satisfies Layout;\n```\n\nThis layout provides a clear binary format for the secp256k1 signature, making it efficient to process within the Wormhole protocol.\n\n#### Layout with Custom Conversion\n\nThe [`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.\n\n```typescript\nexport const signatureItem = {\n  binary: 'bytes',\n  layout: signatureLayout,\n  custom: {\n    to: (val: LayoutToType<typeof signatureLayout>) =>\n      new Signature(val.r, val.s, val.v),\n    from: (val: Signature) => ({ r: val.r, s: val.s, v: val.v }),\n  } satisfies CustomConversion<LayoutToType<typeof signatureLayout>, Signature>,\n} as const satisfies BytesLayoutItem;\n```\n\nThe `custom` field ensures seamless integration of raw binary data with the `Signature` class, encapsulating signature-specific logic."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 18, "depth": 2, "title": "Advanced Use Cases", "anchor": "advanced-use-cases", "start_char": 15131, "end_char": 18040, "estimated_token_count": 561, "token_estimator": "heuristic-v1", "text": "## Advanced Use Cases\n\nThe 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.\n\n???- code \"Switch Statements for Conditional Layouts\"\n\n    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.\n\n    For example, different message types can be identified using a payload ID, and the layout for each message can be determined at runtime:\n\n    ```typescript\n    const switchLayout = {\n      binary: 'switch',\n      idSize: 1, // size of the payload ID\n      idTag: 'messageType', // tag to identify the type of message\n      layouts: [\n        [[1, 'messageType1'], fillLayout], // layout for type 1\n        [[2, 'messageType2'], fastFillLayout], // layout for type 2\n      ],\n    } as const satisfies Layout;\n    ```\n\n    The switch statement helps developers parse multiple payload types using the same structure, depending on a control field like an ID.\n\n???- code \"Fixed Conversions and Omitted Fields\"\n\n    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.\n\n    **Example: Fixed Conversion**\n\n    In some cases, a field may always contain a predefined value. The layout system supports fixed conversions, allowing developers to “hard-code” these values:\n\n    ```typescript\n    const fixedConversionLayout = {\n      binary: 'uint',\n      size: 2,\n      custom: {\n        to: 'Ethereum',\n        from: chainToChainId('Ethereum'),\n      },\n    } as const satisfies Layout;\n    ```\n\n    **Example: Omitted Fields**\n\n    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:\n\n    ```typescript\n    const omittedFieldLayout = [\n      { name: 'reserved', binary: 'uint', size: 2, omit: true },\n    ] as const satisfies Layout;\n    ```\n\n    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.\n\n    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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 19, "depth": 2, "title": "Integration with Wormhole Protocol", "anchor": "integration-with-wormhole-protocol", "start_char": 18040, "end_char": 18337, "estimated_token_count": 46, "token_estimator": "heuristic-v1", "text": "## Integration with Wormhole Protocol\n\nThe 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 20, "depth": 3, "title": "VAAs and Layouts", "anchor": "vaas-and-layouts", "start_char": 18337, "end_char": 25452, "estimated_token_count": 1576, "token_estimator": "heuristic-v1", "text": "### VAAs and Layouts\n\nVAAs 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.\n\n#### Base VAA Structure\n\nThe Wormhole SDK organizes the VAA structure into three key components:\n\n - **[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.\n - **[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}.\n - **Payload**: Provides application-specific data, such as the actual message or operation being performed.\n\n**Header layout:**\n\n```typescript\nconst guardianSignatureLayout = [\n  { name: 'guardianIndex', binary: 'uint', size: 1 },\n  { name: 'signature', ...signatureItem },\n] as const satisfies Layout;\n\nexport const headerLayout = [\n  { name: 'version', binary: 'uint', size: 1, custom: 1, omit: true },\n  { name: 'guardianSet', ...guardianSetItem },\n  {\n    name: 'signatures',\n    binary: 'array',\n    lengthSize: 1,\n    layout: guardianSignatureLayout,\n  },\n] as const satisfies Layout;\n```\n\nThe 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.\n\n!!! note \"Signature Standard Compliance\"\n\n    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.\n\n**Envelope layout:**\n\n```typescript\nexport const envelopeLayout = [\n  { name: 'timestamp', binary: 'uint', size: 4 },\n  { name: 'nonce', binary: 'uint', size: 4 },\n  { name: 'emitterChain', ...chainItem() },\n  { name: 'emitterAddress', ...universalAddressItem },\n  { name: 'sequence', ...sequenceItem },\n  { name: 'consistencyLevel', binary: 'uint', size: 1 },\n] as const satisfies Layout;\n```\n\nThe 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.\n\n**Payload Layout:**\n\nThe 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.\n\n```typescript\nconst examplePayloadLayout = [\n  { name: 'type', binary: 'uint', size: 1 },\n  { name: 'data', binary: 'bytes', lengthSize: 2 },\n] as const satisfies Layout;\n```\n\nThis example demonstrates a payload containing:\n\n - A type field specifying the operation type (e.g., transfer or governance action).\n - A data field that is length-prefixed and can store operation-specific information.\n\nDynamic payload layouts are selected at runtime using the `payloadLiteral` field, which maps to a predefined layout in the Wormhole SDK.\n\n**Combined Base Layout:**\n\nThe base VAA layout combines the header, envelope, and dynamically selected payload layout:\n\n```typescript\nexport const baseLayout = [...headerLayout, ...envelopeLayout] as const;\n```\n\nAt runtime, the payload layout is appended to the `baseLayout` to form the complete structure.\n\n#### Serializing VAA Data\n\nThe 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.\n\n```typescript\nimport { serialize } from '@wormhole-foundation/sdk-core/vaa/functions';\n\nconst vaaData = {\n  guardianSet: 1,\n  signatures: [{ guardianIndex: 0, signature: new Uint8Array(65).fill(0) }],\n  timestamp: 1633000000,\n  nonce: 42,\n  emitterChain: 2, // Ethereum\n  emitterAddress: new Uint8Array(32).fill(0),\n  sequence: BigInt(1),\n  consistencyLevel: 1,\n  payloadLiteral: 'SomePayloadType',\n  payload: { key: 'value' },\n};\n\nconst serializedVAA = serialize(vaaData);\n```\n\n???- note \"How does it work?\"\n\n    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.\n\n    ```typescript\n    const layout = [\n      ...baseLayout, // Header and envelope layout\n      payloadLiteralToPayloadItemLayout(vaa.payloadLiteral), // Payload layout\n    ] as const;\n\n    return serializeLayout(layout, vaa as LayoutToType<typeof layout>);\n    ```\n\n#### Deserializing VAA Data\n\nThe 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.\n\n```typescript\nimport { deserialize } from '@wormhole-foundation/sdk-core/vaa/functions';\n\nconst serializedVAA = new Uint8Array([\n  /* Serialized VAA binary data */\n]);\n\nconst vaaPayloadType = 'SomePayloadType'; // The payload type expected for this VAA\nconst deserializedVAA = deserialize(vaaPayloadType, serializedVAA);\n```\n\n???- note \"How does it work?\"\n\n    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.\n\n    ```typescript\n    const [header, envelopeOffset] = deserializeLayout(headerLayout, data, {\n      consumeAll: false,\n    });\n\n    const [envelope, payloadOffset] = deserializeLayout(envelopeLayout, data, {\n      offset: envelopeOffset,\n      consumeAll: false,\n    });\n\n    const [payloadLiteral, payload] =\n      typeof payloadDet === 'string'\n        ? [\n            payloadDet as PayloadLiteral,\n            deserializePayload(payloadDet as PayloadLiteral, data, payloadOffset),\n          ]\n        : deserializePayload(\n            payloadDet as PayloadDiscriminator,\n            data,\n            payloadOffset\n          );\n\n    return {\n      ...header,\n      ...envelope,\n      payloadLiteral,\n      payload,\n    } satisfies VAA;\n    ```"}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 21, "depth": 3, "title": "Registering Custom Payloads", "anchor": "registering-custom-payloads", "start_char": 25452, "end_char": 25948, "estimated_token_count": 97, "token_estimator": "heuristic-v1", "text": "### Registering Custom Payloads\n\nIn 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.\n\nTo 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 22, "depth": 2, "title": "Common Pitfalls & Best Practices", "anchor": "common-pitfalls-best-practices", "start_char": 25948, "end_char": 26184, "estimated_token_count": 46, "token_estimator": "heuristic-v1", "text": "## Common Pitfalls & Best Practices\n\nWhen 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 23, "depth": 3, "title": "Pitfalls to Avoid", "anchor": "pitfalls-to-avoid", "start_char": 26184, "end_char": 27561, "estimated_token_count": 323, "token_estimator": "heuristic-v1", "text": "### Pitfalls to Avoid\n\n#### Defining Sizes for Data Types\n\nWhen defining sizes for each data type, make sure to match the actual data length to the specified size to prevent serialization and deserialization errors:\n\n - **`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.\n - **`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.\n\n```typescript\n// Pitfall: Mismatch between the size of data and the defined size in the layout\n{ name: 'orderSender', binary: 'bytes', size: 32 }\n// If the provided data is not exactly 32 bytes, this will fail\n```\n\n#### Incorrectly Defined Arrays\n\nArrays 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.\n\n```typescript\n// Pitfall: Array length does not match the expected size\n{ name: 'redeemerMessage', binary: 'bytes', lengthSize: 4 }\n```"}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 24, "depth": 3, "title": "Best Practices", "anchor": "best-practices", "start_char": 27561, "end_char": 30459, "estimated_token_count": 587, "token_estimator": "heuristic-v1", "text": "### Best Practices\n\nThese best practices and common pitfalls can help prevent bugs and improve the reliability of your implementation when working with layouts in the Wormhole SDK.\n\n#### Reuse Predefined Layout Items\n\nRather 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.\n\nFor instance, use the `chainItem` layout for chain IDs or `universalAddressItem` for blockchain addresses:\n\n```typescript\nimport {\n  chainItem,\n  universalAddressItem,\n} from '@wormhole-foundation/sdk-core/layout-items';\n\nconst exampleLayout = [\n  { name: 'sourceChain', ...chainItem() }, // Use predefined chain ID layout\n  { name: 'senderAddress', ...universalAddressItem }, // Use universal address layout\n] as const;\n```\n\nBy leveraging predefined layout items, you reduce redundancy, maintain consistency, and ensure compatibility with Wormhole’s standards.\n\n#### Use Class Instances\n\nWhenever 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:\n\n```typescript\nimport { UniversalAddress } from '@wormhole-foundation/sdk-core';\n\nconst deserializedAddress = new UniversalAddress(someBinaryData);\n```\n\nFocusing on reusing predefined layout items and converting deserialized data into higher-level abstractions can ensure a more robust and maintainable implementation.\n\n#### Consistent Error Handling\n\nAlways 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.\n\n```typescript\ntry {\n  const deserialized = deserializeLayout(fillLayout, data);\n} catch (error) {\n  console.error('Deserialization failed:', error);\n}\n```\n\n#### Leverage Reusable Layouts\n\nCreating 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.\n\nFor example, define a reusable layout for chain IDs and addresses:\n\n```typescript\nconst commonLayout = [\n  { name: 'chainId', binary: 'uint', size: 2 },\n  { name: 'address', binary: 'bytes', size: 32 },\n] as const satisfies Layout;\n\n// Reuse the common layout in different contexts\nconst exampleLayout = [\n  ...commonLayout,\n  { name: 'sequence', binary: 'uint', size: 8 },\n];\n```\n\nBy abstracting common elements into a single layout, you ensure consistency across different parts of your application and simplify future updates."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 25, "depth": 2, "title": "Performance Considerations", "anchor": "performance-considerations", "start_char": 30459, "end_char": 30704, "estimated_token_count": 37, "token_estimator": "heuristic-v1", "text": "## Performance Considerations\n\nEfficient 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."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 26, "depth": 3, "title": "Lazy Instantiation", "anchor": "lazy-instantiation", "start_char": 30704, "end_char": 31206, "estimated_token_count": 86, "token_estimator": "heuristic-v1", "text": "### Lazy Instantiation\n\nBuilding 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.\n\n```typescript\nconst lazyDiscriminator = lazyInstantiate(() => layoutDiscriminator(layouts));\n```\n\nThis approach ensures that discriminators are only built when required, helping to optimize performance, especially for complex or conditional layouts."}
{"page_id": "tools-typescript-sdk-guides-sdk-layout", "page_title": "Data Layouts", "index": 27, "depth": 2, "title": "Resources", "anchor": "resources", "start_char": 31206, "end_char": 31992, "estimated_token_count": 163, "token_estimator": "heuristic-v1", "text": "## Resources\n\nFor further learning and practical experience, explore the following resources:\n\n - **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`.\n\n - **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."}
{"page_id": "tools-typescript-sdk-guides-vaas-protocols", "page_title": "VAAs and Protocols", "index": 0, "depth": 2, "title": "VAA Structure", "anchor": "vaa-structure", "start_char": 1033, "end_char": 2417, "estimated_token_count": 350, "token_estimator": "heuristic-v1", "text": "## VAA Structure\n\nUnderstanding 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:\n\n| Section  | Description                                                                                            |\n|----------|--------------------------------------------------------------------------------------------------------|\n| Header   | Includes the version and guardian signature information required to verify the VAA.                     |\n| Envelope | Contains metadata about the emitted message, such as the emitter chain, emitter address, and timestamp. |\n| Payload  | Represents the actual message, in raw bytes, without a length prefix.                                   |\n\nThe 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.\n\nWhen integrating protocols like Wrapped Token Transfers (WTT) or Wormhole Relayer:\n\n- The TypeScript SDK handles VAAs off-chain, focusing on deserialization, validation, and payload extraction before submission.\n- 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."}
{"page_id": "tools-typescript-sdk-guides-vaas-protocols", "page_title": "VAAs and Protocols", "index": 1, "depth": 2, "title": "VAAs in Protocol Contexts", "anchor": "vaas-in-protocol-contexts", "start_char": 2417, "end_char": 2447, "estimated_token_count": 6, "token_estimator": "heuristic-v1", "text": "## VAAs in Protocol Contexts"}
{"page_id": "tools-typescript-sdk-guides-vaas-protocols", "page_title": "VAAs and Protocols", "index": 2, "depth": 3, "title": "How VAAs Enable Protocol-Specific Messaging", "anchor": "how-vaas-enable-protocol-specific-messaging", "start_char": 2447, "end_char": 3918, "estimated_token_count": 391, "token_estimator": "heuristic-v1", "text": "### How VAAs Enable Protocol-Specific Messaging\n\nVAAs are the backbone of Wormhole's cross-chain communication, encapsulating critical protocol payloads that drive actions on different blockchains. Each protocol—such as [WTT](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.\n\nExamples of mapping protocols to VAAs:\n\n| Protocol         | Payload Purpose                                           | Example                            |\n|------------------|-----------------------------------------------------------|------------------------------------|\n| WTT              | Transfers token data and metadata.                        | Token transfer or redemption.      |\n| Wormhole Relayer | Manages delivery instructions for messages across chains. | Delivery fee or refund handling.   |\n| Circle CCTP      | Facilitates stablecoin mint-and-burn operations.          | Circle-issued stablecoin transfer. |\n\nEach protocol integrates its payload format into the VAA structure, ensuring consistent message validation and execution across the ecosystem."}
{"page_id": "tools-typescript-sdk-guides-vaas-protocols", "page_title": "VAAs and Protocols", "index": 3, "depth": 3, "title": "TypeScript SDK: Off-Chain Handling of VAAs", "anchor": "typescript-sdk-off-chain-handling-of-vaas", "start_char": 3918, "end_char": 5599, "estimated_token_count": 405, "token_estimator": "heuristic-v1", "text": "### TypeScript SDK: Off-Chain Handling of VAAs\n\nThe 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.\n\nIn 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}:\n\n```typescript\nimport { deserializeLayout } from '@wormhole-foundation/sdk-base';\nimport {\n  universalAddressItem,\n  sequenceItem,\n} from '@wormhole-foundation/core/layout-items/index.js';\n\nexport const envelopeLayout = [\n  { name: 'timestamp', binary: 'uint', size: 4 },\n  { name: 'nonce', binary: 'uint', size: 4 },\n  { name: 'emitterChain', binary: 'uint', size: 2 },\n  { name: 'emitterAddress', ...universalAddressItem },\n  { name: 'sequence', ...sequenceItem },\n  { name: 'consistencyLevel', binary: 'uint', size: 1 },\n] as const satisfies Layout;\n\nconst encodedEnvelope = new Uint8Array([\n  /* binary envelope data */\n]);\nconst deserializedEnvelope = deserializeLayout(envelopeLayout, encodedEnvelope);\n```\n\nFor 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."}
{"page_id": "tools-typescript-sdk-guides-vaas-protocols", "page_title": "VAAs and Protocols", "index": 4, "depth": 3, "title": "Solidity SDK: On-Chain Handling of VAAs", "anchor": "solidity-sdk-on-chain-handling-of-vaas", "start_char": 5599, "end_char": 6929, "estimated_token_count": 244, "token_estimator": "heuristic-v1", "text": "### Solidity SDK: On-Chain Handling of VAAs\n\nThe 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.\n\nBelow is an example of parsing an envelope on-chain using the Solidity SDK:\n\n```solidity\n// SPDX-License-Identifier: Apache 2\npragma solidity ^0.8.19;\n\nimport {VaaLib} from \"wormhole-sdk/libraries/VaaLib.sol\";\n\ncontract EnvelopeParser {\n    using VaaLib for bytes;\n\n    function parseEnvelope(\n        bytes memory encodedVaa\n    )\n        public\n        pure\n        returns (\n            uint32 timestamp,\n            uint32 nonce,\n            uint16 emitterChainId,\n            bytes32 emitterAddress,\n            uint64 sequence,\n            uint8 consistencyLevel\n        )\n    {\n        // Skip the header and decode the envelope\n        uint offset = VaaLib.skipVaaHeaderMemUnchecked(encodedVaa, 0);\n        return VaaLib.decodeVaaEnvelopeMemUnchecked(encodedVaa, offset);\n    }\n}\n```"}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 0, "depth": 2, "title": "Concepts", "anchor": "concepts", "start_char": 1280, "end_char": 1579, "estimated_token_count": 54, "token_estimator": "heuristic-v1", "text": "## Concepts\n\nUnderstanding 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."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 1, "depth": 3, "title": "Platforms", "anchor": "platforms", "start_char": 1579, "end_char": 3000, "estimated_token_count": 393, "token_estimator": "heuristic-v1", "text": "### Platforms\n\nThe 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:\n\n- [Protocols](#protocols) preconfigured to suit the selected platform.\n- Definitions and configurations for types, signers, addresses, and chains.\n- Helpers configured for dealing with unsigned transactions on the selected platform.\n\nThese modules expose key functions and types from the native ecosystem, reducing the need for full packages and keeping dependencies lightweight.\n\n??? interface \"Supported platform modules\"\n\n    | Platform | Installation Command                               |\n    |----------|----------------------------------------------------|\n    | EVM      | <pre>```@wormhole-foundation/sdk-evm```</pre>      |\n    | Solana   | <pre>```@wormhole-foundation/sdk-solana```</pre>   |\n    | Algorand | <pre>```@wormhole-foundation/sdk-algorand```</pre> |\n    | Aptos    | <pre>```@wormhole-foundation/sdk-aptos```</pre>    |\n    | Cosmos   | <pre>```@wormhole-foundation/sdk-cosmwasm```</pre> |\n    | Sui      | <pre>```@wormhole-foundation/sdk-sui```</pre>      |\n\n    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."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 2, "depth": 3, "title": "Chain Context", "anchor": "chain-context", "start_char": 3000, "end_char": 3764, "estimated_token_count": 180, "token_estimator": "heuristic-v1", "text": "### Chain Context\n\n`ChainContext` (from the `@wormhole-foundation/sdk-definitions` package) provides a unified interface for interacting with connected chains. It:\n\n- Holds network, chain, and platform configurations.\n- Caches RPC and protocol clients.\n- Exposes both platform-inherited and chain-specific methods.\n- Defines the core types used across the SDK such as the `Network`, `Chain`, and `Platform`.\n\n```ts\n// Get the chain context for the source and destination chains\n// This is useful to grab direct clients for the protocols\nconst srcChain = wh.getChain(senderAddress.chain);\nconst dstChain = wh.getChain(receiverAddress.chain);\n\nconst tb = await srcChain.getTokenBridge(); // => TokenBridge<'Evm'>\nsrcChain.getRpcClient(); // => RpcClient<'Evm'>\n```"}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 3, "depth": 3, "title": "Addresses", "anchor": "addresses", "start_char": 3764, "end_char": 4868, "estimated_token_count": 241, "token_estimator": "heuristic-v1", "text": "### Addresses\n\nThe 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.\n\n```ts\n// It's possible to convert a string address to its Native address\nconst ethAddr: NativeAddress<'Evm'> = toNative('Ethereum', '0xbeef...');\n\n// A common type in the SDK is the `ChainAddress` which provides\n// the additional context of the `Chain` this address is relevant for\nconst senderAddress: ChainAddress = Wormhole.chainAddress(\n  'Ethereum',\n  '0xbeef...'\n);\nconst receiverAddress: ChainAddress = Wormhole.chainAddress(\n  'Solana',\n  'Sol1111...'\n);\n\n// Convert the ChainAddress back to its canonical string address format\nconst strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...'\n\n// Or if the ethAddr above is for an emitter and you need the UniversalAddress\nconst emitterAddr = ethAddr.toUniversalAddress().toString();\n```"}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 4, "depth": 3, "title": "Tokens", "anchor": "tokens", "start_char": 4868, "end_char": 5480, "estimated_token_count": 155, "token_estimator": "heuristic-v1", "text": "### Tokens\n\nThe `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.\n\n```ts\n// Get the TokenId for an ERC-20 token\nconst sourceToken: TokenId = Wormhole.tokenId('Ethereum', '0xbeef...');\n// Get the TokenId for native ETH\nconst gasToken: TokenId = Wormhole.tokenId('Ethereum', 'native');\n// Convert a TokenId back to a string\nconst strAddress = Wormhole.canonicalAddress(senderAddress); // => '0xbeef...'\n```"}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 5, "depth": 3, "title": "Signers", "anchor": "signers", "start_char": 5480, "end_char": 8305, "estimated_token_count": 655, "token_estimator": "heuristic-v1", "text": "### Signers\n\nThe SDK's `Signer` interface can be implemented as either a `SignOnlySigner` or a `SignAndSendSigner`, created by wrapping an offline or web wallet:\n\n- **`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.\n- **`SignAndSendSigner`**: Signs and broadcasts transactions, returning their transaction IDs in order.\n\n```ts\nexport type Signer = SignOnlySigner | SignAndSendSigner;\n\nexport interface SignOnlySigner {\n  chain(): ChainName;\n  address(): string;\n  // Accept an array of unsigned transactions and return\n  // an array of signed and serialized transactions.\n  // The transactions may be inspected or altered before\n  // signing.\n  sign(tx: UnsignedTransaction[]): Promise<SignedTx[]>;\n}\n\nexport interface SignAndSendSigner {\n  chain(): ChainName;\n  address(): string;\n  // Accept an array of unsigned transactions and return\n  // an array of transaction ids in the same order as the\n  // unsignedTransactions array.\n  signAndSend(tx: UnsignedTransaction[]): Promise<TxHash[]>;\n}\n```\n\n#### Set Up a Signer with Ethers.js\n\nTo sign transactions programmatically with the Wormhole SDK, you can use [Ethers.js](https://docs.ethers.org/v6/){target=\\_blank} to manage private keys and handle signing. Here's an example of setting up a signer using Ethers.js:\n\n```javascript\nimport { ethers } from 'ethers';\n\n// Update the following variables\nconst rpcUrl = 'INSERT_RPC_URL';\nconst privateKey = 'INSERT_PRIVATE_KEY';\nconst toAddress = 'INSERT_RECIPIENT_ADDRESS';\n\n// Set up a provider and signer\nconst provider = new ethers.JsonRpcProvider(rpcUrl);\nconst signer = new ethers.Wallet(privateKey, provider);\n\n// Example: Signing and sending a transaction\nasync function sendTransaction() {\n  const tx = {\n    to: toAddress,\n    value: ethers.parseUnits('0.1'), // Sending 0.1 ETH\n    gasPrice: await provider.getGasPrice(),\n    gasLimit: ethers.toBeHex(21000),\n  };\n\n  const transaction = await signer.sendTransaction(tx);\n  console.log('Transaction hash:', transaction.hash);\n}\nsendTransaction();\n```\n\nThese components work together to create, sign, and submit a transaction to the blockchain:\n\n- **`provider`**: Connects to the Ethereum or EVM-compatible network, enabling data access and transaction submission.\n- **`signer`**: Represents the account that signs transactions using a private key.\n- **`Wallet`**: Combines provider and signer to create, sign, and send transactions programmatically."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 6, "depth": 3, "title": "Protocols", "anchor": "protocols", "start_char": 8305, "end_char": 14616, "estimated_token_count": 1554, "token_estimator": "heuristic-v1", "text": "### Protocols\n\nWormhole 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.\n\n??? interface \"Supported protocol modules\"\n\n    | Protocol              | Installation Command                                           |\n    |-----------------------|----------------------------------------------------------------|\n    | EVM Core              | <pre>```@wormhole-foundation/sdk-evm-core```</pre>             |\n    | EVM WTT               | <pre>```@wormhole-foundation/sdk-evm-tokenbridge```</pre>      |\n    | EVM CCTP              | <pre>```@wormhole-foundation/sdk-evm-cctp```</pre>             |\n    | EVM Portico           | <pre>```@wormhole-foundation/sdk-evm-portico```</pre>          |\n    | EVM TBTC              | <pre>```@wormhole-foundation/sdk-evm-tbtc```</pre>             |\n    | Solana Core           | <pre>```@wormhole-foundation/sdk-solana-core```</pre>          |\n    | Solana WTT            | <pre>```@wormhole-foundation/sdk-solana-tokenbridge```</pre>   |\n    | Solana CCTP           | <pre>```@wormhole-foundation/sdk-solana-cctp```</pre>          |\n    | Solana TBTC           | <pre>```@wormhole-foundation/sdk-solana-tbtc```</pre>          |\n    | Algorand Core         | <pre>```@wormhole-foundation/sdk-algorand-core```</pre>        |\n    | Algorand WTT          | <pre>```@wormhole-foundation/sdk-algorand-tokenbridge```</pre> |\n    | Aptos Core            | <pre>```@wormhole-foundation/sdk-aptos-core```</pre>           |\n    | Aptos WTT             | <pre>```@wormhole-foundation/sdk-aptos-tokenbridge```</pre>    |\n    | Aptos CCTP            | <pre>```@wormhole-foundation/sdk-aptos-cctp```</pre>           |\n    | Cosmos Core           | <pre>```@wormhole-foundation/sdk-cosmwasm-core```</pre>        |\n    | Cosmos WTT            | <pre>```@wormhole-foundation/sdk-cosmwasm-tokenbridge```</pre> |\n    | Sui Core              | <pre>```@wormhole-foundation/sdk-sui-core```</pre>             |\n    | Sui WTT               | <pre>```@wormhole-foundation/sdk-sui-tokenbridge```</pre>      |\n    | Sui CCTP              | <pre>```@wormhole-foundation/sdk-sui-cctp```</pre>             |\n\n#### Wormhole Core\n\nThe 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.\n\nExample workflow on Solana Testnet:\n\n1. Initialize a Wormhole instance for Solana.\n2. Obtain a signer and its address.\n3. Access the core messaging bridge for cross-chain messaging.\n4. Prepare a message with:\n\n    - Sender's address\n    - Encoded payload (e.g., \"lol\")\n    - Nonce (e.g., 0)\n    - Consistency level (e.g., 0)\n\n5. Generate, sign, and send the transaction to publish the message.\n6. Extract the Wormhole message ID from transaction logs for tracking.\n7. Wait (up to 60s) to receive the [Verified Action Approval (VAA)](/docs/protocol/infrastructure/vaas/){target=\\_blank} (in `Uint8Array` format) from the Wormhole network.\n8. Prepare and send a verification transaction on the receiving chain using the sender's address and the VAA.\n\n???+ example \"Example workflow\"\n    ```ts\n    import { encoding, signSendWait, wormhole } from '@wormhole-foundation/sdk';\n    import { getSigner } from './helpers/index.js';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import evm from '@wormhole-foundation/sdk/evm';\n\n    (async function () {\n      const wh = await wormhole('Testnet', [solana, evm]);\n\n      const chain = wh.getChain('Avalanche');\n      const { signer, address } = await getSigner(chain);\n\n      // Get a reference to the core messaging bridge\n      const coreBridge = await chain.getWormholeCore();\n\n      // Generate transactions, sign and send them\n      const publishTxs = coreBridge.publishMessage(\n        // Address of sender (emitter in VAA)\n        address.address,\n        // Message to send (payload in VAA)\n        encoding.bytes.encode('lol'),\n        // Nonce (user defined, no requirement for a specific value, useful to provide a unique identifier for the message)\n        0,\n        // ConsistencyLevel (ie finality of the message, see wormhole docs for more)\n        0\n      );\n      // Send the transaction(s) to publish the message\n      const txids = await signSendWait(chain, publishTxs, signer);\n\n      // Take the last txid in case multiple were sent\n      // The last one should be the one containing the relevant\n      // event or log info\n      const txid = txids[txids.length - 1];\n\n      // Grab the wormhole message id from the transaction logs or storage\n      const [whm] = await chain.parseTransaction(txid!.txid);\n\n      // Wait for the vaa to be signed and available with a timeout\n      const vaa = await wh.getVaa(whm!, 'Uint8Array', 60_000);\n      console.log(vaa);\n\n      // Note: calling verifyMessage manually is typically not a useful thing to do\n      // As the VAA is typically submitted to the counterpart contract for\n      // A given protocol and the counterpart contract will verify the VAA\n      // This is simply for demo purposes\n      const verifyTxs = coreBridge.verifyMessage(address.address, vaa!);\n      console.log(await signSendWait(chain, verifyTxs, signer));\n    })();\n    ```\n\nThe payload contains the information necessary to perform whatever action is required based on the protocol that uses it.\n\n#### Wrapped Token Transfers (WTT)\n\nThe most familiar protocol built on Wormhole is WTT. 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.\n\n!!! note \"Terminology\" \n    The SDK and smart contracts use the name Token Bridge. In documentation, this product is referred to as Wrapped Token Transfers (WTT). Both terms describe the same protocol.\n\n```ts\nimport { signSendWait } from '@wormhole-foundation/sdk';\n\nconst tb = await srcChain.getTokenBridge(); \n\nconst token = '0xdeadbeef...';\nconst txGenerator = tb.createAttestation(token); \nconst txids = await signSendWait(srcChain, txGenerator, src.signer);\n```"}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 7, "depth": 2, "title": "Transfers", "anchor": "transfers", "start_char": 14616, "end_char": 14936, "estimated_token_count": 63, "token_estimator": "heuristic-v1", "text": "## Transfers\n\nWhile using the [`ChainContext`](#chain-context) and [`Protocol`](#protocols) clients directly is possible, the SDK provides some helpful abstractions for transferring tokens.\n\nThe `WormholeTransfer` interface provides a convenient abstraction to encapsulate the steps involved in a cross-chain transfer."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 8, "depth": 3, "title": "Token Transfers", "anchor": "token-transfers", "start_char": 14936, "end_char": 23539, "estimated_token_count": 1754, "token_estimator": "heuristic-v1", "text": "### Token Transfers\n\nToken transfers between chains are straightforward using Wormhole. Create a `Wormhole` instance and use it to initialize a `TokenTransfer` or `CircleTransfer` object.\n\nThe 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:\n\n1. Initiating the transfer on the source chain.\n2. Waiting for attestation (if required).\n3. Completing the transfer on the destination chain.\n\nFor automatic transfers, the process ends after initiation. Manual transfers require attestation before completion.\n\n```ts\n  // Create a TokenTransfer object to track the state of the transfer over time\n  const xfer = await wh.tokenTransfer(\n    route.token,\n    route.amount,\n    route.source.address,\n    route.destination.address,\n    route.delivery?.automatic ?? false,\n    route.payload,\n    route.delivery?.nativeGas\n  );\n\n  const quote = await TokenTransfer.quoteTransfer(\n    wh,\n    route.source.chain,\n    route.destination.chain,\n    xfer.transfer\n  );\n  console.log(quote);\n\n  if (xfer.transfer.automatic && quote.destinationToken.amount < 0)\n    throw 'The amount requested is too low to cover the fee and any native gas requested.';\n\n  // 1) Submit the transactions to the source chain, passing a signer to sign any txns\n  console.log('Starting transfer');\n  const srcTxids = await xfer.initiateTransfer(route.source.signer);\n  console.log(`Started transfer: `, srcTxids);\n\n  // If automatic, we're done\n  if (route.delivery?.automatic) return xfer;\n\n  // 2) Wait for the VAA to be signed and ready (not required for auto transfer)\n  console.log('Getting Attestation');\n  const attestIds = await xfer.fetchAttestation(60_000);\n  console.log(`Got Attestation: `, attestIds);\n\n  // 3) Redeem the VAA on the dest chain\n  console.log('Completing Transfer');\n  const destTxids = await xfer.completeTransfer(route.destination.signer);\n  console.log(`Completed Transfer: `, destTxids);\n```\n\n??? code \"View the complete script\"\n    ```ts hl_lines=\"122\"\n    import {\n      Chain,\n      Network,\n      TokenId,\n      TokenTransfer,\n      Wormhole,\n      amount,\n      isTokenId,\n      wormhole,\n    } from '@wormhole-foundation/sdk';\n\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { SignerStuff, getSigner, waitLog } from './helpers/index.js';\n\n    (async function () {\n      // Init Wormhole object, passing config for which network\n      // to use (e.g. Mainnet/Testnet) and what Platforms to support\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Grab chain Contexts -- these hold a reference to a cached rpc client\n      const sendChain = wh.getChain('Avalanche');\n      const rcvChain = wh.getChain('Solana');\n\n      // Shortcut to allow transferring native gas token\n      const token = Wormhole.tokenId(sendChain.chain, 'native');\n\n      // A TokenId is just a `{chain, address}` pair and an alias for ChainAddress\n      // The `address` field must be a parsed address.\n      // You can get a TokenId (or ChainAddress) prepared for you\n      // by calling the static `chainAddress` method on the Wormhole class.\n      // e.g.\n      // wAvax on Solana\n      // const token = Wormhole.tokenId(\"Solana\", \"3Ftc5hTz9sG4huk79onufGiebJNDMZNL8HYgdMJ9E7JR\");\n      // wSol on Avax\n      // const token = Wormhole.tokenId(\"Avalanche\", \"0xb10563644a6AB8948ee6d7f5b0a1fb15AaEa1E03\");\n\n      // Normalized given token decimals later but can just pass bigints as base units\n      // Note: The WTT (Token Bridge) will dedust past 8 decimals\n      // This means any amount specified past that point will be returned\n      // To the caller\n      const amt = '0.05';\n\n      // With automatic set to true, perform an automatic transfer. This will invoke a relayer\n      // Contract intermediary that knows to pick up the transfers\n      // With automatic set to false, perform a manual transfer from source to destination\n      // Of the token\n      // On the destination side, a wrapped version of the token will be minted\n      // To the address specified in the transfer VAA\n      const automatic = false;\n\n      // The Wormhole relayer has the ability to deliver some native gas funds to the destination account\n      // The amount specified for native gas will be swapped for the native gas token according\n      // To the swap rate provided by the contract, denominated in native gas tokens\n      const nativeGas = automatic ? '0.01' : undefined;\n\n      // Get signer from local key but anything that implements\n      // Signer interface (e.g. wrapper around web wallet) should work\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n\n      // Used to normalize the amount to account for the tokens decimals\n      const decimals = isTokenId(token)\n        ? Number(await wh.getDecimals(token.chain, token.address))\n        : sendChain.config.nativeTokenDecimals;\n\n      // Set this to true if you want to perform a round trip transfer\n      const roundTrip: boolean = false;\n\n      // Set this to the transfer txid of the initiating transaction to recover a token transfer\n      // And attempt to fetch details about its progress.\n      let recoverTxid = undefined;\n\n      // Finally create and perform the transfer given the parameters set above\n      const xfer = !recoverTxid\n        ? // Perform the token transfer\n          await tokenTransfer(\n            wh,\n            {\n              token,\n              amount: amount.units(amount.parse(amt, decimals)),\n              source,\n              destination,\n              delivery: {\n                automatic,\n                nativeGas: nativeGas\n                  ? amount.units(amount.parse(nativeGas, decimals))\n                  : undefined,\n              },\n            },\n            roundTrip\n          )\n        : // Recover the transfer from the originating txid\n          await TokenTransfer.from(wh, {\n            chain: source.chain.chain,\n            txid: recoverTxid,\n          });\n\n      const receipt = await waitLog(wh, xfer);\n\n      // Log out the results\n      console.log(receipt);\n    })();\n\n    async function tokenTransfer<N extends Network>(\n      wh: Wormhole<N>,\n      route: {\n        token: TokenId;\n        amount: bigint;\n        source: SignerStuff<N, Chain>;\n        destination: SignerStuff<N, Chain>;\n        delivery?: {\n          automatic: boolean;\n          nativeGas?: bigint;\n        };\n        payload?: Uint8Array;\n      },\n      roundTrip?: boolean\n    ): Promise<TokenTransfer<N>> {\n      // Create a TokenTransfer object to track the state of the transfer over time\n      const xfer = await wh.tokenTransfer(\n        route.token,\n        route.amount,\n        route.source.address,\n        route.destination.address,\n        route.delivery?.automatic ?? false,\n        route.payload,\n        route.delivery?.nativeGas\n      );\n\n      const quote = await TokenTransfer.quoteTransfer(\n        wh,\n        route.source.chain,\n        route.destination.chain,\n        xfer.transfer\n      );\n      console.log(quote);\n\n      if (xfer.transfer.automatic && quote.destinationToken.amount < 0)\n        throw 'The amount requested is too low to cover the fee and any native gas requested.';\n\n      // 1) Submit the transactions to the source chain, passing a signer to sign any txns\n      console.log('Starting transfer');\n      const srcTxids = await xfer.initiateTransfer(route.source.signer);\n      console.log(`Started transfer: `, srcTxids);\n\n      // If automatic, we're done\n      if (route.delivery?.automatic) return xfer;\n\n      // 2) Wait for the VAA to be signed and ready (not required for auto transfer)\n      console.log('Getting Attestation');\n      const attestIds = await xfer.fetchAttestation(60_000);\n      console.log(`Got Attestation: `, attestIds);\n\n      // 3) Redeem the VAA on the dest chain\n      console.log('Completing Transfer');\n      const destTxids = await xfer.completeTransfer(route.destination.signer);\n      console.log(`Completed Transfer: `, destTxids);\n\n      // If no need to send back, dip\n      if (!roundTrip) return xfer;\n\n      const { destinationToken: token } = quote;\n      return await tokenTransfer(wh, {\n        ...route,\n        token: token.token,\n        amount: token.amount,\n        source: route.destination,\n        destination: route.source,\n      });\n    }\n    ```\n\nInternally, this uses the [`TokenBridge`](#wrapped-token-transfers-wtt) protocol client to transfer tokens."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 9, "depth": 3, "title": "Native USDC Transfers", "anchor": "native-usdc-transfers", "start_char": 23539, "end_char": 34888, "estimated_token_count": 2358, "token_estimator": "heuristic-v1", "text": "### Native USDC Transfers\n\nNative USDC transfers use Circle’s CCTP burn-and-mint mechanism. In the TypeScript SDK, the recommended way to execute an automatic native USDC transfer is through the routing system using the CCTP Executor route. \n\nAt a high level:\n\n- The source transaction initiates a CCTP burn and emits the messages required to complete the transfer.\n- The CCTP Executor route requests a signed execution quote and registers an execution request with a relay provider.\n- A relay provider completes the transfer by fetching the Circle attestation and submitting the destination transaction(s) required to redeem USDC.\n\nWormhole supports both CCTP v1 and [CCTP v2](https://www.circle.com/blog/cctp-v2-the-future-of-cross-chain){target=\\_blank}, and the SDK exposes a route for each version. The version to use depends on the source/destination configuration — see [CCTP-supported executors](/docs/products/reference/executor-addresses/#cctp-with-executor){target=\\_blank}.\n\n!!! note \"Required packages\"\n    Executor-based CCTP transfers require installing the SDK and the CCTP Executor route:\n\n    ```sh\n    npm install @wormhole-foundation/sdk @wormhole-labs/cctp-executor-route\n    ```\n\nThe primary difference between v1 and v2 in the SDK is the route class and the corresponding validation parameter types.\n\n=== \"CCTP v1\"\n\n    ```ts\n    import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/platforms/evm';\n    import solana from '@wormhole-foundation/sdk/platforms/solana';\n    import sui from '@wormhole-foundation/sdk/platforms/sui';\n    import '@wormhole-labs/cctp-executor-route';\n    import { cctpExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n    import type { CCTPExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV1';\n    import { getSigner } from './helper';\n    ```\n\n=== \"CCTP v2\"\n\n    ```ts\n    import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/platforms/evm';\n    import solana from '@wormhole-foundation/sdk/platforms/solana';\n    import sui from '@wormhole-foundation/sdk/platforms/sui';\n    import '@wormhole-labs/cctp-executor-route';\n    import { cctpV2StandardExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n    import type { CCTPv2ExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV2Base';\n    import { getSigner } from './helper';\n    ```\n\nThe complete examples below demonstrate how to construct a route request, validate parameters, fetch a quote, and initiate an automatic transfer.\n\n??? code \"View complete script\"\n    === \"CCTP v1\"\n\n        ```ts\n        import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/platforms/evm';\n        import solana from '@wormhole-foundation/sdk/platforms/solana';\n        import sui from '@wormhole-foundation/sdk/platforms/sui';\n        import '@wormhole-labs/cctp-executor-route';\n        import { cctpExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n        import type { CCTPExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV1';\n        import { getSigner } from './helper';\n\n        (async function () {\n          // Initialize Wormhole for the Testnet environment and add supported chains (evm, solana and sui)\n          const network = 'Testnet';\n          const wh = new Wormhole(network, [\n            evm.Platform,\n            solana.Platform,\n            sui.Platform,\n          ]);\n\n          // Grab chain contexts (cached RPC clients under the hood)\n          const src = wh.getChain('Solana');\n          const dst = wh.getChain('BaseSepolia');\n\n          // Get signers from local keys\n          const srcSigner = await getSigner(src);\n          const dstSigner = await getSigner(dst);\n\n          // Fetch the USDC contract addresses for these chains\n          const srcUsdc = circle.usdcContract.get(network, src.chain);\n          const dstUsdc = circle.usdcContract.get(network, dst.chain);\n\n          if (!srcUsdc || !dstUsdc) {\n            throw new Error(\n              'USDC is not configured on the selected source/destination'\n            );\n          }\n\n          // Build the transfer request for the CCTP v1 executor\n          const tr = await routes.RouteTransferRequest.create(wh, {\n            source: Wormhole.tokenId(src.chain, srcUsdc),\n            destination: Wormhole.tokenId(dst.chain, dstUsdc),\n            sourceDecimals: 6,\n            destinationDecimals: 6,\n            sender: srcSigner.address,\n            recipient: dstSigner.address,\n          });\n\n          // Configure the executor route (referrer fee off)\n          const ExecutorRoute = cctpExecutorRoute({ referrerFeeDbps: 0n });\n          const route = new ExecutorRoute(wh);\n\n          // Define the amount of USDC to transfer (in the smallest unit, so 1.000001 USDC = 1,000,001 units assuming 6 decimals)\n          const transferAmount = '1.000001';\n\n          // Set the native gas drop-off (0 <= nativeGas <= 1)\n          const nativeGasPercent = 0.1;\n\n          const validated = await route.validate(tr, {\n            amount: transferAmount,\n            options: { nativeGas: nativeGasPercent },\n          });\n\n          // Validate inputs and exit early on failure\n          if (!validated.valid) {\n            const { error } = validated as Extract<typeof validated, { valid: false }>;\n            throw new Error(`Validation failed: ${error.message}`);\n          }\n\n          // Quote expects the normalized params produced by validate(); cast to that shape\n          const validatedParams = validated.params as CCTPExecutorRoute.ValidatedParams;\n          const quote = await route.quote(tr, validatedParams);\n          if (!quote.success) {\n            const { error } = quote as Extract<typeof quote, { success: false }>;\n            throw new Error(`Quote failed: ${error.message}`);\n          }\n\n          // Start the transfer on the source chain via the executor\n          const receipt = await route.initiate(\n            tr,\n            srcSigner.signer,\n            quote,\n            dstSigner.address\n          );\n          if ('originTxs' in receipt && Array.isArray(receipt.originTxs)) {\n            console.log('Source transactions:', receipt.originTxs);\n\n            const lastTx = receipt.originTxs[receipt.originTxs.length - 1];\n            if (lastTx) {\n              const txid =\n                typeof lastTx === 'string' ? lastTx : lastTx.txid ?? String(lastTx);\n              const wormholeScanUrl = `https://wormholescan.io/#/tx/${txid}?network=${network}`;\n              console.log('WormholeScan URL:', wormholeScanUrl);\n            }\n          } else {\n            console.log('Receipt returned without origin transactions:', receipt);\n          }\n        })();\n        ```\n\n    === \"CCTP v2\"\n\n        ```ts\n        import { Wormhole, circle, routes } from '@wormhole-foundation/sdk';\n        import evm from '@wormhole-foundation/sdk/platforms/evm';\n        import solana from '@wormhole-foundation/sdk/platforms/solana';\n        import sui from '@wormhole-foundation/sdk/platforms/sui';\n        import '@wormhole-labs/cctp-executor-route';\n        import { cctpV2StandardExecutorRoute } from '@wormhole-labs/cctp-executor-route';\n        import type { CCTPv2ExecutorRoute } from '@wormhole-labs/cctp-executor-route/dist/esm/routes/cctpV2Base';\n        import { getSigner } from './helper';\n\n        (async function () {\n          // Initialize Wormhole for the Testnet environment and add supported chains (evm, solana and sui)\n          const network = 'Testnet';\n          const wh = new Wormhole(network, [\n            evm.Platform,\n            solana.Platform,\n            sui.Platform,\n          ]);\n\n          // Grab chain contexts (cached RPC clients under the hood)\n          const src = wh.getChain('Solana');\n          const dst = wh.getChain('BaseSepolia');\n\n          // Get signers from local keys\n          const srcSigner = await getSigner(src);\n          const dstSigner = await getSigner(dst);\n\n          // Fetch the USDC contract addresses for these chains\n          const srcUsdc = circle.usdcContract.get(network, src.chain);\n          const dstUsdc = circle.usdcContract.get(network, dst.chain);\n\n          if (!srcUsdc || !dstUsdc) {\n            throw new Error(\n              'USDC is not configured on the selected source/destination'\n            );\n          }\n\n          // Build the transfer request for the CCTP v2 executor\n          const tr = await routes.RouteTransferRequest.create(wh, {\n            source: Wormhole.tokenId(src.chain, srcUsdc),\n            destination: Wormhole.tokenId(dst.chain, dstUsdc),\n            sourceDecimals: 6,\n            destinationDecimals: 6,\n            sender: srcSigner.address,\n            recipient: dstSigner.address,\n          });\n\n          // Configure the executor route (referrer fee off)\n          const ExecutorRoute = cctpV2StandardExecutorRoute({ referrerFeeDbps: 0n });\n          const route = new ExecutorRoute(wh);\n\n          // Define the amount of USDC to transfer (in the smallest unit, so 1.000001 USDC = 1,000,001 units assuming 6 decimals)\n          const transferAmount = '1.000001';\n\n          // Set the native gas drop-off (0 <= nativeGas <= 1)\n          const nativeGasPercent = 0.1;\n\n          const validated = await route.validate(tr, {\n            amount: transferAmount,\n            options: { nativeGas: nativeGasPercent },\n          });\n\n          // Validate inputs and exit early on failure\n          if (!validated.valid) {\n            const { error } = validated as Extract<typeof validated, { valid: false }>;\n            throw new Error(`Validation failed: ${error.message}`);\n          }\n\n          // Quote expects the normalized params produced by validate(); cast to that shape\n          const validatedParams =\n            validated.params as CCTPv2ExecutorRoute.ValidatedParams;\n          const quote = await route.quote(tr, validatedParams);\n          if (!quote.success) {\n            const { error } = quote as Extract<typeof quote, { success: false }>;\n            throw new Error(`Quote failed: ${error.message}`);\n          }\n\n          // Start the transfer on the source chain via the executor\n          const receipt = await route.initiate(\n            tr,\n            srcSigner.signer,\n            quote,\n            dstSigner.address\n          );\n          if ('originTxs' in receipt && Array.isArray(receipt.originTxs)) {\n            console.log('Source transactions:', receipt.originTxs);\n\n            const lastTx = receipt.originTxs[receipt.originTxs.length - 1];\n            if (lastTx) {\n              const txid =\n                typeof lastTx === 'string' ? lastTx : lastTx.txid ?? String(lastTx);\n              const wormholeScanUrl = `https://wormholescan.io/#/tx/${txid}?network=${network}`;\n              console.log('WormholeScan URL:', wormholeScanUrl);\n            }\n          } else {\n            console.log('Receipt returned without origin transactions:', receipt);\n          }\n        })();\n        ```\n\nThe initiation and quoting flow is the same for both versions; the only difference is which CCTP Executor route class is selected based on the source/destination configuration."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 10, "depth": 3, "title": "Recovering Transfers", "anchor": "recovering-transfers", "start_char": 34888, "end_char": 40052, "estimated_token_count": 1095, "token_estimator": "heuristic-v1", "text": "### Recovering Transfers\n\nIt 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.\n\n```ts\n  const xfer = await CircleTransfer.from(wh, txid);\n\n  const attestIds = await xfer.fetchAttestation(60 * 60 * 1000);\n  console.log('Got attestation: ', attestIds);\n\n  const dstTxIds = await xfer.completeTransfer(signer);\n  console.log('Completed transfer: ', dstTxIds);\n```\n\n??? code \"View the complete script\"\n    ```ts hl_lines=\"130\"\n    import {\n      Chain,\n      CircleTransfer,\n      Network,\n      Signer,\n      TransactionId,\n      TransferState,\n      Wormhole,\n      amount,\n      wormhole,\n    } from '@wormhole-foundation/sdk';\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { SignerStuff, getSigner, waitForRelay } from './helpers/index.js';\n\n    /*\n    Notes:\n    Only a subset of chains are supported by Circle for CCTP, see core/base/src/constants/circle.ts for currently supported chains\n\n    AutoRelayer takes a 0.1 USDC fee when transferring to any chain beside Goerli, which is 1 USDC\n    */\n    //\n\n    (async function () {\n      // Init the Wormhole object, passing in the config for which network\n      // to use (e.g. Mainnet/Testnet) and what Platforms to support\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Grab chain Contexts\n      const sendChain = wh.getChain('Avalanche');\n      const rcvChain = wh.getChain('Solana');\n\n      // Get signer from local key but anything that implements\n      // Signer interface (e.g. wrapper around web wallet) should work\n      const source = await getSigner(sendChain);\n      const destination = await getSigner(rcvChain);\n\n      // 6 decimals for USDC (except for BSC, so check decimals before using this)\n      const amt = amount.units(amount.parse('0.2', 6));\n\n      // Choose whether or not to have the attestation delivered for you\n      const automatic = false;\n\n      // If the transfer is requested to be automatic, you can also request that\n      // during redemption, the receiver gets some amount of native gas transferred to them\n      // so that they may pay for subsequent transactions\n      // The amount specified here is denominated in the token being transferred (USDC here)\n      const nativeGas = automatic ? amount.units(amount.parse('0.0', 6)) : 0n;\n\n      await cctpTransfer(wh, source, destination, {\n        amount: amt,\n        automatic,\n        nativeGas,\n      });\n\n    })();\n\n    async function cctpTransfer<N extends Network>(\n      wh: Wormhole<N>,\n      src: SignerStuff<N, any>,\n      dst: SignerStuff<N, any>,\n      req: {\n        amount: bigint;\n        automatic: boolean;\n        nativeGas?: bigint;\n      }\n    ) {\n\n      const xfer = await wh.circleTransfer(\n        // Amount as bigint (base units)\n        req.amount,\n        // Sender chain/address\n        src.address,\n        // Receiver chain/address\n        dst.address,\n        // Automatic delivery boolean\n        req.automatic,\n        // Payload to be sent with the transfer\n        undefined,\n        // If automatic, native gas can be requested to be sent to the receiver\n        req.nativeGas\n      );\n\n      // Note, if the transfer is requested to be Automatic, a fee for performing the relay\n      // will be present in the quote. The fee comes out of the amount requested to be sent.\n      // If the user wants to receive 1.0 on the destination, the amount to send should be 1.0 + fee.\n      // The same applies for native gas dropoff\n      const quote = await CircleTransfer.quoteTransfer(\n        src.chain,\n        dst.chain,\n        xfer.transfer\n      );\n      console.log('Quote', quote);\n\n      console.log('Starting Transfer');\n      const srcTxids = await xfer.initiateTransfer(src.signer);\n      console.log(`Started Transfer: `, srcTxids);\n\n      if (req.automatic) {\n        const relayStatus = await waitForRelay(srcTxids[srcTxids.length - 1]!);\n        console.log(`Finished relay: `, relayStatus);\n        return;\n      }\n\n      console.log('Waiting for Attestation');\n      const attestIds = await xfer.fetchAttestation(60_000);\n      console.log(`Got Attestation: `, attestIds);\n\n      console.log('Completing Transfer');\n      const dstTxids = await xfer.completeTransfer(dst.signer);\n      console.log(`Completed Transfer: `, dstTxids);\n    }\n\n    export async function completeTransfer(\n      wh: Wormhole<Network>,\n      txid: TransactionId,\n      signer: Signer\n    ): Promise<void> {\n\n      const xfer = await CircleTransfer.from(wh, txid);\n\n      const attestIds = await xfer.fetchAttestation(60 * 60 * 1000);\n      console.log('Got attestation: ', attestIds);\n\n      const dstTxIds = await xfer.completeTransfer(signer);\n      console.log('Completed transfer: ', dstTxIds);\n    }\n    ```\n\nWhen using Executor-based routes, transfers are typically completed automatically. Manual recovery is only required if execution fails or the transfer is interrupted."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 11, "depth": 2, "title": "Routes", "anchor": "routes", "start_char": 40052, "end_char": 48770, "estimated_token_count": 1830, "token_estimator": "heuristic-v1", "text": "## Routes\n\nWhile 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.\n\nTo 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.\n\nThe following section demonstrates setting up and validating a token transfer using Wormhole's routing system.\n\n```ts\n  // Create new resolver, passing the set of routes to consider\n  const resolver = wh.resolver([\n    routes.TokenBridgeRoute, // manual WTT (Token Bridge)\n    routes.AutomaticTokenBridgeRoute, // automatic WTT (Token Bridge)\n    routes.CCTPRoute, // manual CCTP\n    routes.AutomaticCCTPRoute, // automatic CCTP\n    routes.AutomaticPorticoRoute, // Native eth transfers\n  ]);\n```\n\nOnce created, the resolver can be used to provide a list of input and possible output tokens.\n\n```ts\n  // What tokens are available on the source chain?\n  const srcTokens = await resolver.supportedSourceTokens(sendChain);\n  console.log(\n    'Allowed source tokens: ',\n    srcTokens.map((t) => canonicalAddress(t))\n  );\n\n  const sendToken = Wormhole.tokenId(sendChain.chain, 'native');\n\n  // Given the send token, what can we possibly get on the destination chain?\n  const destTokens = await resolver.supportedDestinationTokens(\n    sendToken,\n    sendChain,\n    destChain\n  );\n  console.log(\n    'For the given source token and routes configured, the following tokens may be receivable: ',\n    destTokens.map((t) => canonicalAddress(t))\n  );\n  // Grab the first one for the example\n  const destinationToken = destTokens[0]!;\n```\n\nOnce 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.\n\n```ts\n  // Creating a transfer request fetches token details\n  // Since all routes will need to know about the tokens\n  const tr = await routes.RouteTransferRequest.create(wh, {\n    source: sendToken,\n    destination: destinationToken,\n  });\n\n  // Resolve the transfer request to a set of routes that can perform it\n  const foundRoutes = await resolver.findRoutes(tr);\n  console.log(\n    'For the transfer parameters, we found these routes: ',\n    foundRoutes\n  );\n```\n\nChoosing 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).\n\nOnce 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.\n\n```ts\n  console.log(\n    'This route offers the following default options',\n    bestRoute.getDefaultOptions()\n  );\n\n  // Specify the amount as a decimal string\n  const amt = '0.001';\n  // Create the transfer params for this request\n  const transferParams = { amount: amt, options: { nativeGas: 0 } };\n\n  // Validate the transfer params passed, this returns a new type of ValidatedTransferParams\n  // which (believe it or not) is a validated version of the input params\n  // This new var must be passed to the next step, quote\n  const validated = await bestRoute.validate(tr, transferParams);\n  if (!validated.valid) throw validated.error;\n  console.log('Validated parameters: ', validated.params);\n\n  // Get a quote for the transfer, this too returns a new type that must\n  // be passed to the next step, execute (if you like the quote)\n  const quote = await bestRoute.quote(tr, validated.params);\n  if (!quote.success) throw quote.error;\n  console.log('Best route quote: ', quote);\n```\n\nFinally, assuming the quote looks good, the route can initiate the request with the quote and the `signer`.\n\n```ts\n    const receipt = await bestRoute.initiate(\n      tr,\n      sender.signer,\n      quote,\n      receiver.address\n    );\n    console.log('Initiated transfer with receipt: ', receipt);\n```\n\n??? code \"View the complete script\"\n\n    ```ts\n    import {\n      Wormhole,\n      canonicalAddress,\n      routes,\n      wormhole,\n    } from '@wormhole-foundation/sdk';\n\n    import evm from '@wormhole-foundation/sdk/evm';\n    import solana from '@wormhole-foundation/sdk/solana';\n    import { getSigner } from './helpers/index.js';\n\n    (async function () {\n      // Setup\n      const wh = await wormhole('Testnet', [evm, solana]);\n\n      // Get chain contexts\n      const sendChain = wh.getChain('Avalanche');\n      const destChain = wh.getChain('Solana');\n\n      // Get signers from local config\n      const sender = await getSigner(sendChain);\n      const receiver = await getSigner(destChain);\n\n      // Create new resolver, passing the set of routes to consider\n      const resolver = wh.resolver([\n        routes.TokenBridgeRoute, // manual WTT (Token Bridge)\n        routes.AutomaticTokenBridgeRoute, // automatic WTT (Token Bridge)\n        routes.CCTPRoute, // manual CCTP\n        routes.AutomaticCCTPRoute, // automatic CCTP\n        routes.AutomaticPorticoRoute, // Native eth transfers\n      ]);\n\n      // What tokens are available on the source chain?\n      const srcTokens = await resolver.supportedSourceTokens(sendChain);\n      console.log(\n        'Allowed source tokens: ',\n        srcTokens.map((t) => canonicalAddress(t))\n      );\n\n      const sendToken = Wormhole.tokenId(sendChain.chain, 'native');\n\n      // Given the send token, what can we possibly get on the destination chain?\n      const destTokens = await resolver.supportedDestinationTokens(\n        sendToken,\n        sendChain,\n        destChain\n      );\n      console.log(\n        'For the given source token and routes configured, the following tokens may be receivable: ',\n        destTokens.map((t) => canonicalAddress(t))\n      );\n      // Grab the first one for the example\n      const destinationToken = destTokens[0]!;\n\n      // Creating a transfer request fetches token details\n      // Since all routes will need to know about the tokens\n      const tr = await routes.RouteTransferRequest.create(wh, {\n        source: sendToken,\n        destination: destinationToken,\n      });\n\n      // Resolve the transfer request to a set of routes that can perform it\n      const foundRoutes = await resolver.findRoutes(tr);\n      console.log(\n        'For the transfer parameters, we found these routes: ',\n        foundRoutes\n      );\n\n      const bestRoute = foundRoutes[0]!;\n      console.log('Selected: ', bestRoute);\n\n      console.log(\n        'This route offers the following default options',\n        bestRoute.getDefaultOptions()\n      );\n\n      // Specify the amount as a decimal string\n      const amt = '0.001';\n      // Create the transfer params for this request\n      const transferParams = { amount: amt, options: { nativeGas: 0 } };\n\n      // Validate the transfer params passed, this returns a new type of ValidatedTransferParams\n      // which (believe it or not) is a validated version of the input params\n      // This new var must be passed to the next step, quote\n      const validated = await bestRoute.validate(tr, transferParams);\n      if (!validated.valid) throw validated.error;\n      console.log('Validated parameters: ', validated.params);\n\n      // Get a quote for the transfer, this too returns a new type that must\n      // be passed to the next step, execute (if you like the quote)\n      const quote = await bestRoute.quote(tr, validated.params);\n      if (!quote.success) throw quote.error;\n      console.log('Best route quote: ', quote);\n\n      // If you're sure you want to do this, set this to true\n      const imSure = false;\n      if (imSure) {\n        // Now the transfer may be initiated\n        // A receipt will be returned, guess what you gotta do with that?\n        const receipt = await bestRoute.initiate(\n          tr,\n          sender.signer,\n          quote,\n          receiver.address\n        );\n        console.log('Initiated transfer with receipt: ', receipt);\n\n        // Kick off a wait log, if there is an opportunity to complete, this function will do it\n        // See the implementation for how this works\n        await routes.checkAndCompleteTransfer(bestRoute, receipt, receiver.signer);\n      } else {\n        console.log('Not initiating transfer (set `imSure` to true to do so)');\n      }\n    })();\n    ```\n\nSee 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."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 12, "depth": 3, "title": "Routes as Plugins", "anchor": "routes-as-plugins", "start_char": 48770, "end_char": 49873, "estimated_token_count": 264, "token_estimator": "heuristic-v1", "text": "### Routes as Plugins\n\nRoutes 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}.\n\n```ts\nimport { Network, routes } from '@wormhole-foundation/sdk-connect';\n\nexport class CustomRoute<N extends Network>\n  extends routes.Route<N>\n  implements routes.StaticRouteMethods<typeof CustomRoute>\n{\n  static meta = {\n    name: 'CustomRoute',\n  };\n  // implementation...\n}\n```\n\nA 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."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 13, "depth": 3, "title": "Executor Routes", "anchor": "executor-routes", "start_char": 49873, "end_char": 50091, "estimated_token_count": 41, "token_estimator": "heuristic-v1", "text": "### Executor Routes\n\nSome routes, such as the CCTP Executor routes, are provided as external plugins. These routes integrate with Wormhole’s routing system to enable automated execution via off-chain relay providers."}
{"page_id": "tools-typescript-sdk-sdk-reference", "page_title": "Wormhole TS SDK", "index": 14, "depth": 2, "title": "See Also", "anchor": "see-also", "start_char": 50091, "end_char": 50212, "estimated_token_count": 39, "token_estimator": "heuristic-v1", "text": "## See Also\n\nThe TSdoc is available [on GitHub](https://wormhole-foundation.github.io/wormhole-sdk-ts/){target=\\_blank}."}
