Anxious to get started? See a live example of this code in our example app.

1

Install Library

Install the library using npm or yarn:

If you’re using yarn (or another package manager that doesn’t install peer dependencies by default) you may need to install these peer dependencies as well:

  yarn add viem @solana/web3.js
2

Initialize Client

To start integrating with the Skip Go API, initialize a SkipClient instance. This skipClient provides helper methods for common actions such as querying assets and chains, constructing routes, and executing transactions.

import { SkipClient } from "@skip-go/client";

const skipClient = new SkipClient({
  // Signers will be set up in the following section
});

The SkipClient constructor accepts an optional configuration object of type SkipClientOptions. Here’s a brief overview:

  • apiURL?: string: Override the default API URL
  • endpointOptions?: EndpointOptions: Provide RPC and REST endpoints for specific chains
  • aminoTypes?: AminoConverters: Additional amino types to be for message encoding
  • registryTypes?: Iterable<[string, GeneratedType]>: Additional registry types
3

Setup Signers

To execute transactions, you need to set up signers for the ecosystems you plan to interact with. Below are examples for Cosmos SDK, EVM, and Solana (SVM). Note that for EVM and SVM, you’ll need to install additional libraries.

Signer Setup

Finalizing the Client Initialization

Now, pass the signers and your optional configuration options into your SkipClient instance:

const skipClient = new SkipClient({
  getCosmosSigner,
  getEVMSigner,
  getSVMSigner,
  // ...configOptions,
});
4

Query Basic Info

With your client initialized, you can query balances, supported chains and assets.

5

Get a Route

Once you’ve selected your source and destination chains and tokens, you can generate a route and get a quote. See it in context here.

Read more about affiliate fees, Smart Relay and EVM Swaps.

6

Get Required Addresses

After generating a route, you need to provide user addresses for the required chains. The route.requiredChainAddresses array lists the chain IDs for which addresses are needed.

Only use addresses your user can sign for. Funds could get stuck in any address you provide, including intermediate chains in certain failure conditions. Ensure your user can sign for each address you provide. See Cross-chain Failure Cases for more details.

We recommend storing the user’s addresses and creating a function like getAddress that retrieves the address based on the chain ID.

// get user addresses for each requiredChainAddress to execute the route
  const userAddresses = await Promise.all(
  route.requiredChainAddresses.map(async (chainID) => ({
    chainID,
    address: await getAddress(chainID),
  }))
);
7

Execute the Route

Once you have a route, you can execute it in a single function call by passing in the route, the user addresses for at least the chains the route includes, and optional callback functions. This also registers the transaction for tracking.

await skipClient.executeRoute({
  route,
  userAddresses,
  // Executes after all of the operations triggered by a user's signature complete.
  // For multi-tx routes that require multiple user signatures, this will be called once for each tx in sequence
  onTransactionCompleted: async (chainID, txHash, status) => {
    console.log(
      `Route completed with tx hash: ${txHash} & status: ${status.state}`
    );
  },
  // called after the transaction that the user signs gets broadcast on chain
  onTransactionBroadcast: async ({ txHash, chainID }) => {
    console.log(`Transaction broadcasted with tx hash: ${txHash}`);
  },
  // called after the transaction that the user signs is successfully registered for tracking
  onTransactionTracked: async ({ txHash, chainID }) => {
    console.log(`Transaction tracked with tx hash: ${txHash}`);
  },
  // called after the user signs a transaction
  onTransactionSigned: async ({ txHash, chainID }) => {
    console.log(`Transaction signed with tx hash: ${txHash}`);
  },
  // validate gas balance on each chain
  onValidateGasBalance: async ({ chainID, txIndex, status }) => {
    console.log(`Validating gas balance for chain ${chainID}...`);
  },
});

For routes that consist of multiple transactions, this will monitor each transaction until it completes, then generate the transaction for the next step and prompt the user to sign it.

Alternatively, the route object allows you to generate, sign, and submit messages individually. You can also implement your own solutions for any or all of these steps. For more details on these lower-level functions, refer to skipClient.messages, skipClient.signMultiChainMessageDirect, and skipClient.submitTransaction.

8

Transaction Tracking

Once the user has signed a transaction to execute a cross-chain action, you can track it with:

  • skipClient.trackTransaction: Requests tracking for a transaction that’s already been submitted to the network through an RPC, using the transaction hash
  • skipClient.submitTransaction: Publishes the signed transaction to the network & begins tracking the cross-chain actions this transaction produces

After you’ve used one of these two functions to kick-off realtime tracking for a cross-chain action, you can request the current status of the transaction using skipClient.transactionStatus.

We also provide a waitForTransaction helper function that hangs until the entire cross-chain action flow has completed, which you can use instead of configuring your own polling via transactionStatus.

Have questions or feedback? Help us get better!

Join our Discord and select the “Skip Go Developer” role to share your questions and feedback.