Skip to content

Get Started

Settlement is Wormhole’s intent-based execution layer, enabling fast, multichain token transfers. It coordinates routing logic, relayers, and on-chain infrastructure to let users express what they want to be done, not how.

This guide walks you through performing a real token swap using the Mayan Swift route, one of the three integrated Settlement protocols, with the Wormhole TypeScript SDK.

By the end, you'll have a working script that:

  • Resolves token transfer routes using Mayan Swift
  • Quotes and validates the best route
  • Initiates a swap on a source chain and completes the transfer on a destination chain

Note

Mayan Swift currently supports mainnet only. Attempting to run this demo on a testnet will fail.

Prerequisites

Before you begin, ensure you have the following:

This example uses Ethereum as the source chain and Solana as the destination. As a result, you'll need an Ethereum wallet with ETH for gas and a Solana wallet with SOL for fees. You can adapt the example to match your preferred chains.

Set Up a Project

Start by scaffolding a basic Node.js project and installing the required SDKs.

  1. Create a new project folder:

    mkdir settlement-swap
    cd settlement-swap
    npm init -y
    
  2. Install the required dependencies:

    npm install @wormhole-foundation/sdk-connect \
        @wormhole-foundation/sdk-evm \
        @wormhole-foundation/sdk-solana \
        @mayanfinance/wormhole-sdk-route \
        dotenv
    npm install -D typescript tsx
    
  3. Create the file structure:

    mkdir src
    touch src/helpers.ts src/swap.ts .env .gitignore
    
  4. Set up secure access to your wallets. This guide assumes you are loading your MAINNET_ETH_PRIVATE_KEY and MAINNET_SOL_PRIVATE_KEY from a secure keystore of your choice, such as a secrets manager or a CLI-based tool like cast wallet.

    Warning

    If you use a .env file during development, add it to your .gitignore to exclude it from version control. Never commit private keys or mnemonics to your repository.

Perform a Token Swap

This section shows you how to perform a token swap using the Mayan Swift route. You will define a helper function to configure the source and destination chain signers.

Then, you'll create a script that initiates a transfer on Ethereum, uses the Mayan Swift resolver to find valid routes, sends the transaction, and completes the transfer on Solana.

  1. Open helper.ts and define the getSigner utility function to load private keys, instantiate signers for Ethereum and Solana, and return the signers along with the Wormhole-formatted address:

    src/helpers.ts
    import {
      Chain,
      ChainAddress,
      ChainContext,
      Network,
      Signer,
      Wormhole,
    } from '@wormhole-foundation/sdk-connect';
    import { getEvmSignerForKey } from '@wormhole-foundation/sdk-evm';
    import { getSolanaSigner } from '@wormhole-foundation/sdk-solana';
    
    /**
     * Returns a signer for the given chain using locally scoped credentials.
     * The required values (MAINNET_ETH_PRIVATE_KEY, MAINNET_SOL_PRIVATE_KEY)
     * must be loaded securely beforehand, for example via a keystore,
     * secrets manager, or environment variables (not recommended).
     */
    // Define Transfer Interface
    export interface SignerContext<N extends Network, C extends Chain> {
      signer: Signer<N, C>;
      address: ChainAddress<C>;
    }
    
    export async function getSigner<N extends Network, C extends Chain>(
      chain: ChainContext<N, C>
    ): Promise<SignerContext<N, C>> {
      let signer: Signer;
      const platform = chain.platform.utils()._platform;
      switch (platform) {
        case 'Solana':
          signer = await getSolanaSigner(
            await chain.getRpc(),
            getEnv('MAINNET_SOL_PRIVATE_KEY')
          );
          break;
        case 'Evm':
          signer = await getEvmSignerForKey(
            await chain.getRpc(),
            getEnv('MAINNET_ETH_PRIVATE_KEY')
          );
          break;
        default:
          throw new Error('Unrecognized platform: ' + platform);
      }
    
      return {
        signer: signer as Signer<N, C>,
        address: Wormhole.chainAddress(chain.chain, signer.address()),
      };
    }
    
  2. In swap.ts, add the following script, which will handle all of the logic required to perform the token swap:

    src/swap.ts
    import { Wormhole, routes } from '@wormhole-foundation/sdk-connect';
    import { EvmPlatform } from '@wormhole-foundation/sdk-evm';
    import { SolanaPlatform } from '@wormhole-foundation/sdk-solana';
    import { MayanRouteSWIFT } from '@mayanfinance/wormhole-sdk-route';
    import { getSigner } from './helpers';
    
    (async function () {
      // Setup
      const wh = new Wormhole('Mainnet', [EvmPlatform, SolanaPlatform]);
    
      const sendChain = wh.getChain('Ethereum');
      const destChain = wh.getChain('Solana');
    
      //  To transfer native ETH on Ethereum to native SOL on Solana
      const source = Wormhole.tokenId(sendChain.chain, 'native');
      const destination = Wormhole.tokenId(destChain.chain, 'native');
    
      // Create a new Wormhole route resolver, adding the Mayan route to the default list
      // @ts-ignore: Suppressing TypeScript error because the resolver method expects a specific type,
      // but MayanRouteSWIFT is compatible and works as intended in this context.
      const resolver = wh.resolver([MayanRouteSWIFT]);
    
      // Show supported tokens
      const dstTokens = await resolver.supportedDestinationTokens(
        source,
        sendChain,
        destChain
      );
      console.log(dstTokens.slice(0, 5));
    
      // Load signers and addresses from helpers
      const sender = await getSigner(sendChain);
      const receiver = await getSigner(destChain);
    
      // Creating a transfer request fetches token details
      // since all routes will need to know about the tokens
      const tr = await routes.RouteTransferRequest.create(wh, {
        source,
        destination,
      });
    
      // Resolve the transfer request to a set of routes that can perform it
      const foundRoutes = await resolver.findRoutes(tr);
      const bestRoute = foundRoutes[0]!;
    
      // Specify the amount as a decimal string
      const transferParams = {
        amount: '0.002',
        options: bestRoute.getDefaultOptions(),
      };
    
      // Validate the queries route
      let validated = await bestRoute.validate(tr, transferParams);
      if (!validated.valid) {
        console.error(validated.error);
        return;
      }
      console.log('Validated: ', validated);
    
      const quote = await bestRoute.quote(tr, validated.params);
      if (!quote.success) {
        console.error(`Error fetching a quote: ${quote.error.message}`);
        return;
      }
      console.log('Quote: ', quote);
    
      // Initiate the transfer
      const receipt = await bestRoute.initiate(
        tr,
        sender.signer,
        quote,
        receiver.address
      );
      console.log('Initiated transfer with receipt: ', receipt);
    
      await routes.checkAndCompleteTransfer(
        bestRoute,
        receipt,
        receiver.signer,
        15 * 60 * 1000
      );
    })();
    
  3. Execute the script to initiate and complete the transfer:

    npx tsx src/swap.ts
    

    If successful, you’ll see terminal output like this:

    npx tsx src/swap.ts Validated: { valid: true, ... } Quote: { success: true, ... } Initiated transfer with receipt: ... Checking transfer state... Current Transfer State: SourceInitiated Current Transfer State: SourceInitiated Current Transfer State: SourceInitiated Current Transfer State: DestinationFinalized

Congratulations! You've just completed a cross-chain token swap from Ethereum to Solana using Settlement.

Customize the Integration

You can tailor the example to your use case by adjusting:

  • Tokens and chains: Use getSupportedTokens() to explore what's available.
  • Source and destination chains: Modify sendChain and destChain in swap.ts.
  • Transfer settings: Update the amount or route parameters.
  • Signer management: Modify src/helpers.ts to integrate with your preferred wallet setup.

Next Steps

Once you've chosen a path, follow the corresponding guide to start building: