Notus API

Cross-Chain Swap Guide

Step-by-step guide to swapping tokens across different chains using the Notus API.

Steps

Create a directory

mkdir my-create-cross-chain-swap
cd my-create-cross-chain-swap
touch index.js

Init project

npm init -y
pnpm init -y
yarn init -y
bun init -y

Install viem

We’ll use viem, a library for blockchain interactions, to simplify our integration. Install it by running:

npm i viem
pnpm add viem
yarn add viem
bun add viem

Initialize Wallet Account

Use your private key to initialize a wallet account. This will allow you to sign messages and interact with the blockchain.

import { privateKeyToAccount } from 'viem/accounts'

const BASE_URL = "https://api.notus.team/api/v1"
const API_KEY = "<api-key>"

const USDC_POLYGON = '0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359'
const USDC_ARBITRUM = "0xaf88d065e77c8cc2239327c5edb3a432268e5831"

const privateKey = '0x<private-key>'
const account = privateKeyToAccount(privateKey)

Register a Smart Wallet Address

Before initiating a cross-chain swap, register and retrieve the smart wallet address used for Account Abstraction.

async function main() {
  const FACTORY_ADDRESS = "0x0000000000400CdFef5E2714E63d8040b700BC24"
  const externallyOwnedAccount = account.address

  let res = await fetch(`${BASE_URL}/wallets/register`, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "x-api-key": API_KEY,
    },
    body: JSON.stringify({
      externallyOwnedAccount: externallyOwnedAccount,
      factory: FACTORY_ADDRESS,
      salt: "0",
    }),
  });

  if (!res?.ok) {
    return
  }

  const response = await res.json();

  const smartWalletAddress = response.wallet.accountAbstraction
}

Note: At this stage, the smart wallet address is not yet deployed onchain. Deployment happens automatically with the user's first onchain transaction (e.g., swap or transfer) via a UserOperation.

Create a Cross-chain Swap Quote

Query a quote for cross-chain swaps (e.g., USDC on Arbitrum to USDC on Polygon).

const { data } = await fetch(`${BASE_URL}/crypto/swap`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': API_KEY,Step-by-step guide to swapping tokens across different chains using the Notus API.
  },
  body: JSON.stringify(
    {
      payGasFeeToken: USDC_ARBITRUM,
      tokenIn: USDC_ARBITRUM,
      tokenOut: USDC_POLYGON,
      amountIn: "5",
      walletAddress: smartWalletAddress,
      toAddress: smartWalletAddress,
      signerAddress: externallyOwnedAccount,
      chainIdIn: 42161,
      chainIdOut: 137,
      gasFeePaymentMethod: "DEDUCT_FROM_AMOUNT",
    }
  ),
}).then((res) => res.json())

For cross-chain swaps involving a native token, use the following address as tokenIn: 0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee. This ensures that the Notus API recognizes the asset as a native token.

Note: The payGasFeeToken field should contain the address of an ERC-20 token held in the smart wallet. This token will be used to pay both the partner’s transactionFeePercent and the gas fees for the UserOperation. In most cases, payGasFeeToken is the same as token, typically the token the user already holds in their wallet.

Route Profile (Optional)

You can optimize your cross-chain swap quotes by specifying a routeProfile parameter in your request. Route profiles define the order and which quotes are returned in the array, ordered from "best" to "worst".

const { data } = await fetch(`${BASE_URL}/crypto/swap`, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'x-api-key': API_KEY,
  },
  body: JSON.stringify({
    // ... other parameters
    routeProfile: "FASTEST_BRIDGE", // Optional parameter
  }),
}).then((res) => res.json())

Available Route Profiles:

  • QUICKEST_QUOTE (Default): Returns a quote as soon as one that works is found. This is the quickest endpoint as it returns the first that can be executed. If none can be executed, it returns all of them to show why they could not execute.

  • FASTEST_BRIDGE: Useful only for cross-chain swaps. Returns the cross-chain route that should execute on all chains at the fastest time possible. This is a slower query, so refrain from calling it too frequently.

  • BEST_OUTPUT: Aggregates multiple swap providers to find the optimal path that maximizes returns by considering the guaranteed minimum output and deducting execution fees. This is a slower query, so refrain from calling it too frequently.

For cross-chain swaps, choose FASTEST_BRIDGE when you want the quickest execution across chains, or BEST_OUTPUT when you want to maximize the output amount. Use QUICKEST_QUOTE for immediate results.

Execute Cross-chain Swap

Once you have a quote, sign and execute the cross-chain swap operation.

  const signature = await account.signMessage({
    message: {
      raw: data.quoteId,
    },
  })
  
  const { userOpHash } = await fetch(`${BASE_URL}/crypto/execute-user-op`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': API_KEY,
    },
    body: JSON.stringify({ signature, quoteId: data.quoteId }),
  }).then((res) => res.json())

  console.log(userOpHash)