# Overview

The cheapest, fastest, most reliable cross-chain layer, routing value for 1,000+ integrators including MetaMask, Ripple, and MiniPay.

## What is Squid?

Squid is a single integration for seamless cross-chain swaps, bridges, and contract calls across 100+ chains, including EVM, Bitcoin, Solana, Ripple, Hedera, and Cosmos.

Whether you're building a wallet, DEX, DeFi protocol, or any application that needs cross-chain functionality, Squid provides the infrastructure to connect your users across blockchains.

### Key Highlights

* **🔗 100+ Chains Supported** — EVM, Cosmos, Bitcoin, Solana, Hedera, XRPL, and more
* **⚡ Sub-5 Second Execution** — powered by Squid Intents
* **🛡️ $6B+ Volume Securely Routed** — across[ 4M+ transactions](https://axelarscan.io/interchain?contractAddress=0xce16f69375520ab01377ce7b88f5ba8c48f8d666)
* **🔌 Multiple Integration Options** — Widget, API, or SDK
* **🧩 Custom Contract Calls** — execute any on-chain action cross-chain via hooks
* ♟️ **No MEV, Zero Slippage** — trades executed exactly as intended

## Build With Squid

[**Apply for an Integrator ID**](https://squidrouter.typeform.com/integrator-id?typeform-source=app.gitbook.com) then explore how to build below:

<table data-card-size="large" data-column-title-hidden data-view="cards" data-full-width="false"><thead><tr><th align="center"></th><th data-hidden data-type="content-ref"></th><th data-hidden><select></select></th><th data-hidden></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td align="center"><strong>Explore Widgets</strong></td><td></td><td></td><td></td><td><a href="/files/nGnTbL2elBulAZuiCLYG">/files/nGnTbL2elBulAZuiCLYG</a></td><td><a href="/pages/zIsPfPrcLWhxVh714mUu">/pages/zIsPfPrcLWhxVh714mUu</a></td></tr><tr><td align="center"><strong>Explore API &#x26; SDK</strong></td><td></td><td></td><td></td><td><a href="/files/y6hmihmzRazGMwP8kBIt">/files/y6hmihmzRazGMwP8kBIt</a></td><td><a href="/pages/UH7BqQfSNr9LsvoqUIsq">/pages/UH7BqQfSNr9LsvoqUIsq</a></td></tr></tbody></table>

### Choose Your Integration

| Integration | Best For                                             | Get Started                                         |
| ----------- | ---------------------------------------------------- | --------------------------------------------------- |
| **Widget**  | Fastest to integrate — drop-in cross-chain swap UI   | [Explore Widgets](/widget-integration/add-a-widget) |
| **API**     | Full control using any language or client            | [API Docs](/api-and-sdk-integration/api)            |
| **SDK**     | JavaScript/TypeScript projects with helper utilities | [SDK Docs](/api-and-sdk-integration/sdk)            |

## Squid's Integrators Include

See us in [Metamask](https://metamask.io/), [MiniPay (Opera)](https://minipay.to/), [Brave Browser](https://brave.com/wallet/), [Keplr](https://www.keplr.app/), [Valora](https://valora.xyz/), and [many others](https://www.squidrouter.com/ecosystem)!

Try a [cross-chain swap](https://app.squidrouter.com/) and see the speed for yourself!


# Integrator Quickstart

Create your first Squid cross-chain route request

### Step 1: Get Your Integrator ID

1. Apply for an[ integrator ID](https://squidrouter.typeform.com/integrator-id?typeform-source=app.gitbook.com).
2. Check your email for the integrator ID.

Step 2: Make Your First Route Request

Replace `YOUR_INTEGRATOR_ID` in the following curl command with your actual integrator ID and replace `ADD_ADDRESS` with an address, then paste it into your terminal and hit enter:

```xml
curl -X POST 'https://v2.api.squidrouter.com/v2/route' \
-H 'x-integrator-id: YOUR_INTEGRATOR_ID' \
-H 'Content-Type: application/json' \
-d '{
  "fromAddress": "ADD_ADDRESS",
  "fromChain": "56",
  "fromToken": "0x55d398326f99059fF775485246999027B3197955",
  "fromAmount": "1000000000000000",
  "toChain": "42161",
  "toToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
  "toAddress": "ADD_ADDRESS"
}'
```

**Congrats, you've submitted your first route request!**

#### Parameter Explanation:

* `fromAddress`: The address initiating the swap (replace with your address)
* `fromChain`: The source chain ID (56 is BNB Chain)
* `fromToken`: The token address to swap from (USDT on BNB Chain in this example)
* `fromAmount`: The amount to swap (in the smallest unit of the token)
* `toChain`: The destination chain ID (42161 is Arbitrum)
* `toToken`: The token address to swap to (USDC on Arbitrum in this example)
* `toAddress`: The address receiving the swapped tokens

### Step 3: Interpret the Response

If successful, you'll receive a JSON response with the optimal route details. Key fields include:

* `route.estimate.toAmount`: Estimated amount you'll receive
* `route.estimate.feeCosts`: Breakdown of fees
* `route.transactionRequest`: Data needed to execute the swap

### Build With Squid

Now that you've created a route request. Choose how you want to build with Squid.

<div><figure><img src="/files/EuvMbG6RhyPSGjiqJEH5" alt=""><figcaption></figcaption></figure> <figure><img src="/files/y6hmihmzRazGMwP8kBIt" alt=""><figcaption></figcaption></figure></div>

## **Squid’s Integrators Include**


# Add A Widget

Squid's widgets are the easiest way to integrate Squid functionality into the frontend of your app. They are extremely customizable from a theming and functionality point of view.

Currently Squid supports a cross-chain swap widget that can be integrated into your application via iFrame, React, NextJS or Vite.

<figure><picture><source srcset="/files/Qf1331BubT2delstqwlI" media="(prefers-color-scheme: dark)"><img src="/files/nGnTbL2elBulAZuiCLYG" alt=""></picture><figcaption></figcaption></figure>

Our new [Widget Studio](https://studio.squidrouter.com/) allows you to customize the widget to your branding specifications.


# Swap widget

### Introduction

Squid has a widget for cross-chain swaps which can be customized and installed by partners with ease.

The widget is a UI component that leverages Squid’s API and SDK, making it easy to implement cross-chain functionality into any front end with minimal dev effort. It’s perfect for projects who are looking to go cross-chain and want to expand to new users across different crypto ecosystems.

### Widget features

* Set default chains and tokens to onboard liquidity
* 100+ Supported Chains and thousands of supported tokens
* Widget Studio to Customize the theme for any brand
* Speed and security powered by Axelar
* Custom slippage parameters and Degen Mode
* Transaction history to view recent sessions

{% hint style="info" %}
💡 Check out Squid's [Widget Studio ](https://studio.squidrouter.com/)to customize and use the widget, live on mainnet.
{% endhint %}

<figure><img src="/files/OUCra4qM3RVXXA3kM2ax" alt=""><figcaption></figcaption></figure>


# Getting Started

Supported environments, chains, tokens and wallets

### Environments

The widget itself is made with [React](https://reactjs.org/). Which means you can import it as a component on [NextJS](https://nextjs.org/) and other classic react apps (for example create-react-apps).

We will roll out support to other frameworks in the future based on their demand.

You can also use it as an Iframe. Check out \[[Iframe Installation](/old-v2-documentation-deprecated/add-a-widget/widget/iframe-installation) ]\(../../../old-v2-documentation-deprecated/add-a-widget/widget/iframe-installation.md)for more information.

**Currently supported environments:**

* React
* Next.js
* Vite

The widget currently uses the following dependencies wagmi and ethers dependencies.

```
yarn add wagmi@^2.12.8 ethers@^6
```

### Examples

Example repos for all our supported integrations can be found on [GitHub](https://github.com/0xsquid/widget-integrations).

### Supported chains and tokens

For all supported chains and tokens, check out [Broken mention](broken://pages/28KiTP7gRUG2YwHycgQG)

### Supported wallets

**EVM:** Metamask, Trust Wallet, XDEFI Wallet, Rabbi, Zerion, Coinbase Wallet, WalletConnect, Rainbow, Blockchain.com, Cosmostation, BitGet Wallet, OKX Wallet, Coin98, Defi Connect, Exodus

**Cosmos:** Keplr, XDEFI Wallet, Leap, Cosmostation, Cosmos Extension


# Installing the Widget

Preparing to integrate the widget into your app

## Installing the Squid Widget

### Prerequisites

Before installing the Squid Widget, ensure you have:

1. Registered for an Integrator ID with the Squid Team.
2. Node.js and npm (or yarn) installed on your system.

### Getting an Integrator ID

To use the Squid Widget, you need to register for an Integrator ID:

1. Complete the [Integrator ID request form](https://squidrouter.typeform.com/integrator-id?typeform-source=docs.squidrouter.com).
2. You will receive your Integrator ID via email.

### Installation

#### Step 1: Install the package

Install the Squid Widget npm package using one of the following commands:

Using npm:

```bash
npm install @0xsquid/widget
```

Using yarn:

```bash
yarn add @0xsquid/widget
```

#### Step 2: Update dependencies (if necessary)

Squid v2.0 uses Wagmi v2 and ethers v6. If you have these packages in your project, update them:

```bash
yarn add wagmi@^2.12.8 ethers@^6
```

For more information on upgrading Wagmi, refer to the [official Wagmi upgrade guide](https://wagmi.sh/react/migration-guide).

### Next Steps

After installation, you'll need to integrate the widget into your project. We provide specific guides for different frameworks:

* [React Integration Guide](/widget-integration/add-a-widget/widget/react-installation)
* [NextJS Integration Guide](/widget-integration/add-a-widget/widget/nextjs-installation)
* [Vite Integration Guide](/widget-integration/add-a-widget/widget/vite-installation)
* [iFrame Integration Guide](/widget-integration/add-a-widget/widget/iframe-installation)

Choose the guide that matches your project's setup.

### Support

If you have any questions or need assistance, please join our [Discord server](https://discord.gg/squidrouter) and post in the **#⛛│developers** channel.

### Breaking Changes

Be aware that Squid v2.0 introduces several breaking changes, including:

* Updated API URL(v2.api)
* Renamed and removed properties
* New theming system

Refer to our [Migration Guide](broken://pages/IMLtI2E2mq7J8LHdcFx4) for detailed information on these changes and how to adapt your integration.


# React Installation

Installing the React component

## React Installation Guide for Squid Widget

This guide will help you integrate the Squid Widget into your React application. For a complete working example, check out our full React example.

### Prerequisites

Ensure you have completed the steps in the Installing the Widget guide before proceeding.

### Basic Integration

After installing the npm package, follow these steps to add the widget to your React app:

1. Import the SquidWidget component:

```jsx
import { SquidWidget } from "@0xsquid/widget";
```

2. Add the widget to your component:

```jsx
function App() {
  return (
    <div className="App">
      <SquidWidget
        config={{
          integratorId: "<your-integrator-id>",
          apiUrl: "https://v2.api.squidrouter.com",
          defaultTokensPerChain: [
            {
              address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
              chainId: "1",
            },
          ],
          initialAssets: {
            from: {
              address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
              chainId: "1",
            },
            to: {
              address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
              chainId: "42161",
            },
          },
        }}
      />
    </div>
  );
}
```

Make sure to replace `<your-integrator-id>` with the Integrator ID you received from Squid.

### Customization

To customize the widget's appearance and behavior:

1. Use the Squid Widget Studio to generate a custom configuration.
2. Copy the generated config and paste it into your `config` prop.

For example:

```jsx
<SquidWidget
  config={{
    integratorId: "<your-integrator-id>",
    apiUrl: "https://v2.api.squidrouter.com",
    theme: {
      // Your custom theme options here
    },
    themeType: "dark", // or "light"
    // Other configuration options
  }}
/>
```

### Advanced Configuration

For more detailed configuration options, explore the [Widget Studio](https://studio.squidrouter.com/).

### Troubleshooting

If you encounter any issues:

1. Ensure you're using the latest version of the widget (^3.0.10).
2. Check that you've updated to Wagmi v2 and ethers v6 if your project uses these dependencies.
3. Review the Migration Guide if you're upgrading from an earlier version.


# NextJS Installation

Integrating the widget into a NextJS app

This guide will help you integrate the Squid Widget into your NextJS application. For a complete working example, check out our[ **full NextJS example**](https://github.com/0xsquid/widget-integrations/tree/main/packages/squid-v2/nextjs/next-13).

We have also built a [**NextJS 14 example**](https://github.com/0xsquid/widget-integrations/tree/main/packages/squid-v2/nextjs/next-14#client-components)**.**

### Prerequisites

Ensure you have completed the steps in the[ Installing the Widget guide ](/widget-integration/add-a-widget/widget/installing-the-widget)before proceeding.

### Installation Steps

#### Step 1: Install Dependencies

Install the Squid Widget and necessary dependencies:

```bash
yarn add @0xsquid/widget@^3.0.10
```

#### Step 2: Configure NextJS

The configuration differs based on your NextJS version:

**For NextJS 13.1 and newer**

Add the following to your `next.config.js`:

```javascript
const nextConfig = {
  transpilePackages: ["@0xsquid/widget", "@0xsquid/react-hooks"]
}

module.exports = nextConfig
```

**For NextJS versions older than 13.1**

1. Install the `next-transpile-modules` package:

```bash
yarn add next-transpile-modules
```

2. Update your `next.config.js`:

```javascript
const withTM = require("next-transpile-modules")(["@0xsquid/widget", "@0xsquid/react-hooks"]);

const nextConfig = {
  // Your NextJS config
};

module.exports = withTM(nextConfig);
```

#### Step 3: Integrate the Widget

Add the Squid Widget to your desired page. For example, in `src/pages/index.tsx`:

```jsx
import { SquidWidget } from "@0xsquid/widget";

export default function Home() {
  return (
    <div>
      <SquidWidget
        config={{
          integratorId: "<your-integrator-id>",
          apiUrl: "https://v2.api.squidrouter.com",
          // Add other configuration options here
        }}
      />
    </div>
  );
}
```

Replace `<your-integrator-id>` with the Integrator ID you received from Squid.

### Customization

To customize the widget's appearance and behavior:

1. Use the[ **Squid Widget Studio**](https://studio.squidrouter.com/) to generate a custom configuration.
2. Copy the generated config and paste it into your `config` prop.

### Running Your NextJS App

After setting up the widget, you can start your NextJS development server:

```bash
yarn dev
```

### Troubleshooting

If you encounter any issues:

1. Ensure you're using the latest version of the widget (^3.0.10).
2. Check that you've correctly configured the `next.config.js` file.
3. Verify that you've added the correct `integratorId` and `apiUrl` in the widget config.
4. Review the Migration Guide if you're upgrading from an earlier version.


# Vite Installation

## Vite Installation Guide for Squid Widget

This guide will help you integrate the Squid Widget into your Vite + TypeScript project.

For a complete working example, check out our [**full Vite example**](https://github.com/0xsquid/widget-integrations/tree/main/packages/squid-v2/vite/vite-5.5-typescript).

### Prerequisites

Ensure you have the following installed:

* Node.js
* Yarn or npm
* Git (for cloning the example repository)

### Installation Steps

#### Step 1: Install Dependencies

First, install the Squid Widget and necessary dependencies:

```bash
yarn add @0xsquid/widget@^3.0.10
```

#### Step 2: Add Polyfills

Squid requires some polyfills for browser compatibility. Follow these steps to add them:

1. Install the `vite-plugin-node-polyfills` plugin:

```bash
yarn add vite-plugin-node-polyfills -D
```

2. Update your `vite.config.ts` file:

```typescript
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { nodePolyfills } from "vite-plugin-node-polyfills"

export default defineConfig({
  plugins: [
    react(),
    nodePolyfills()
  ]
})
```

#### Step 3: Integrate the Widget

Add the Squid Widget to your desired component. For example, in `src/App.tsx`:

```tsx
import { SquidWidget } from "@0xsquid/widget";

function App() {
  return (
    <div>
      <SquidWidget
        config={{
          integratorId: "<your-integrator-id>",
          apiUrl: "https://v2.api.squidrouter.com",
          // Add other configuration options here
        }}
      />
    </div>
  );
}

export default App;
```

Replace `<your-integrator-id>` with the Integrator ID you received from Squid.

### Running Your Vite App

After setting up the widget, you can start your Vite development server:

```bash
yarn dev
```

### Example Project

For a full working example, you can clone our example repository:

```bash
# Clone the repo
git clone https://github.com/0xsquid/widget-integrations.git

# Move to the Vite example folder
cd packages/squid-v2/vite/vite-5.5-typescript

# Install dependencies
yarn install

# Start the development server
yarn dev
```

### Customization

To customize the widget's appearance and behavior:

1. Use the [**Squid Widget Studio** ](https://studio.squidrouter.com/)to generate a custom configuration.
2. Copy the generated config and paste it into your `config` prop in the `SquidWidget` component.

### Troubleshooting

If you encounter any issues:

1. Ensure you're using the latest version of the widget (^3.0.10).
2. Verify that you've correctly configured the `vite.config.ts` file with the polyfills.
3. Check that you've added the correct `integratorId` and `apiUrl` in the widget config.
4. Make sure all dependencies are properly installed.


# Iframe Installation

Integrating the widget as an Iframe

## Squid Widget iFrame Integration Guide

While the Squid Widget is primarily designed as a React component, you can integrate it into other frontend frameworks (such as Vue, Angular, etc.) using an iframe. This guide will walk you through the process of setting up and customizing the Squid Widget iframe.

### Why Use the iFrame?

* **Framework Compatibility**: If you're not using React, NextJS, or Vite the iframe method allows you to integrate the Squid Widget into any web application.
* **Simplicity**: Embedding an iframe is straightforward and doesn't require additional dependencies.
* **Isolation**: The widget runs in its own context, minimizing potential conflicts with your existing code.

### iFrame Source URL

The base URL for the Squid Widget iframe is:

```
https://studio.squidrouter.com/iframe?config=...
```

The `config` parameter at the end of the URL will contain your custom configuration settings.

### Customization

To customize your widget:

1. Visit the [Squid Widget Studio](https://www.squidstudio.app).
2. Adjust the widget settings to your preferences.
3. Click the "Get iframe" button when you're satisfied with the customization.
4. You'll be redirected to a standalone widget page with a URL that includes your custom configuration.

### Embedding the Widget

Once you have your customized iframe URL, you can embed it in your HTML like this:

```html
<iframe
  title="squid_widget"
  width="430"
  height="684"
  src="https://studio.squidrouter.com/iframe?config=....."
></iframe>
```

Important notes:

* Adjust the `width` and `height` attributes as needed to fit your layout.
* Replace the `src` URL with your customized URL from the [**Squid Widget Studio**](https://studio.squidrouter.com/) which you can find when you click the export button.


# Customization Guide

## Squid Widget Customization Guide

The Squid Widget offers extensive customization options to tailor its appearance and behavior to your needs. This guide covers how to configure the widget using both the[ **Squid Widget Studio** ](https://studio.squidrouter.com/)and manual configuration.

### Using the Squid Widget Studio

For interactive customization:

1. Visit the [Squid Widget Studio](https://studio.squidrouter.com/).
2. Adjust settings to your preferences.
3. Click the "Copy Config" button to get the configuration code.
4. Paste the copied configuration into your React component.

<figure><img src="/files/OUCra4qM3RVXXA3kM2ax" alt=""><figcaption></figcaption></figure>

### Configuration Options

The widget can be configured in several areas:

1. **General Settings**: Set the widget name and API URL.
2. **User Defaults**: Configure default settings like slippage.
3. **Visual Theme**: Customize the widget's appearance.
4. **Content**: Modify titles and animations.
5. **Token Selection**: Set default and initial tokens and chains.

### Basic Configuration Example

For a basic setup with default values:

```jsx
import { SquidWidget } from '@0xsquid/widget';

function App() {
  return <SquidWidget />;
}
```

### Full Configuration Example

For a comprehensive setup with custom options:

```jsx
import { SquidWidget } from "@0xsquid/widget"

function App() {
  return (
    <SquidWidget
      config={{
        integratorId: "<your-integrator-id>",
        theme: {
          borderRadius: {
            "button-lg-primary": "3.75rem",
            container: "1.875rem",
            input: "9999px"
            // ... other border radius settings
          },
          fontSize: {
            caption: "0.875rem",
            "body-medium": "1.40625rem"
            // ... other font size settings
          },
          fontWeight: {
            "body-medium": "400",
            "heading-large": "400"
            // ... other font weight settings
          },
          fontFamily: {
            "squid-main": "Geist, sans-serif"
          },
          boxShadow: {
            container:
              "0px 2px 4px 0px rgba(0, 0, 0, 0.20), 0px 5px 50px -1px rgba(0, 0, 0, 0.33)"
          },
          color: {
            "grey-100": "#FBFBFD",
            "royal-500": "#9E79D2",
            "status-positive": "#7AE870"
            // ... other color settings
          }
        },
        themeType: "dark",
        apiUrl: "https://v2.api.squidrouter.com",
        priceImpactWarnings: {
          warning: 3,
          critical: 5
        },
        initialAssets: {
          from: {
            address: "0xd4d42f0b6def4ce0383636770ef773390d85c61a", // SUSHI
            chainId: "42161" // Arbitrum
          },
          to: {
            address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // GLMR
            chainId: "1284" // Moonbeam
          }
        }
        // ... other configuration options
      }}
    />
  )
}
```

### Additional Configuration Options

* `disabledChains`: Disable specific chains.
* `slippage`: Set the default slippage tolerance.
* `hideAnimations`: Toggle widget animations.
* `mainLogoUrl`: Set a custom logo URL.
* `priceImpactWarnings`: Customize price impact limits.

###


# Default User Settings

### **Default slippage:** *slippage*

The default slippage must be selected from the slippage options, which can be a number between 0 and 1. Setting `slippage` to `undefined` will make Squid to define the best slippage for each route:

```jsx
slippage: 1 // number between 0-1, or undefined for "Auto" mode
```

### **Disable chains settings:** *disabledChains*

You can disable chains for a specific direction by specifying them in the `disabledChains` setting.

Disabled chains will not be displayed in the chains list on the widget:

```jsx
disabledChains: {
  source: [
    "1", // Ethereum
    "137" // Polygon
  ],
  destination: [
    "osmosis-1" // Osmosis
  ];
};
```

### **Price impact warning trigger points:** *priceImpactWarnings*

The user will receive a warning in the UI if the price impact percentage is over the `warning` value, and will be unable to swap if the price impact is over the `critical` value.

We recommend keeping these as default.

```jsx
priceImpactWarnings: {
  warning: 3,
  critical: 5,
}
```


# Theme Customization

The `style` attribute enables customisation of the widget theme's colors, opacity and the inclusion of a divider between the "from" and "to" sections.

### Full theme customization example

```jsx
<SquidWidget config={
  {
    style: {
      neutralContent: "#9DA7B1",
      baseContent: "#FFFDFD",
      base100: "#434565",
      base200: "#202230",
      base300: "#161522",
      error: "#ED6A5E",
      warning: "#FFB155",
      success: "#62C555",
      primary: "#AB67CB",
      secondary: "#37394C",
      secondaryContent: "#B2BCD3",
      neutral: "#383A4C",
      roundedBtn: "24px",
      roundedBox: "20px",
      roundedDropDown: "0px",
      displayDivider: false,
      advanced: {
        transparentWidget: false,
        },
      }
    }
  } />
```

### Styling via CSS

To style each component of the Widget via CSS, you can use the following IDs selectors:

* Widget container: `squid-widget`
* Widget header: `squid-widget-header`
* Widget header logo: `squid-header-logo`
* Widget header title: `squid-header-title`
* Swap direction text ("from" or "to"): `squid-swap-direction-txt`
* Primary Hover button: `squid-primary-hover-button`
* Secondary hover button: `squid-secondary-hover-button`
* Dropdown button: `squid-dropdown-btn`
* Dropdown icon: `squid-dropdown-icon`
* Dropdown label: `squid-dropdown-label`
* Icon button: `squid-icon-button`
* Submit swap button: `squid-submit-swap-btn`
* Swap source container: `squid-swap-source`
* Swap destination container: `squid-swap-destination`

Then, in your CSS, add your custom styles:

```css
#squid-swap-source {
  background-color: #091428;
  color: #fff;
}

#squid-swap-destination {
  background-color: #000309;
  color: #fff;
}
```

### Display divider

If you would like to include a divider between the "From" and "To" sections, set this to true. When set to true, both "From" and "To" sections are set to `base200`, and the divider color is set to `base300`.

```jsx
displayDivider: true
```

### Transparent widget

If you would like the widget to be slightly transparent, there is an advanced attribute for this:

```jsx
advanced:{
      transparentWidget: true,
 }
```

### Theme configuration visual guide

<figure><img src="/files/KY1GDeys9rsXvvsvOU3g" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/U6DH2KVjH9SLxl1jy85w" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/zeEHJl3LbSJTnWcpqbBk" alt=""><figcaption></figcaption></figure>


# Configuring Content

## Squid Widget: Configuring Content Guide

This guide explains how to customize various content elements of the Squid Widget, including the logo, title headings, and animations.

### Changing the Logo

You can set a custom logo for your widget using the `mainLogoUrl` property:

```jsx
<SquidWidget
  config={{
    mainLogoUrl: "https://your-domain.com/path-to-your-logo.png"
  }}
/>
```

**Notes:**

* Recommended logo dimensions are 36px x 36px.
* If this field is empty (`""`), the logo in the top left corner of the widget will be invisible.
* Ensure the image URL is accessible and loads quickly for the best user experience.

### Customizing Title Headings

You can customize the text for various sections of the widget using the `titles` property:

```jsx
<SquidWidget
  config={{
    titles: {
      swap: "Convert",
      settings: "Settings",
      wallets: "Wallets",
      tokens: "Tokens",
      chains: "Networks",
      history: "Transaction History",
      transaction: "Transaction Details",
      destination: "Destination Address",
    }
  }}
/>
```

**Available title customizations:**

* `swap`: Main action button (default: "Swap")
* `settings`: Settings page title
* `wallets`: Wallets selection page title
* `tokens`: Token selection page title
* `chains`: Chain (network) selection page title
* `history`: Transaction history page title
* `transaction`: Transaction details page title
* `destination`: Label for destination address input

**Note:** If you set any of these strings to an empty value (`""`), the corresponding title will be invisible.

### Managing Animations

The Squid Widget includes custom Lottie animations by default. You can choose to hide these animations:

```jsx
<SquidWidget
  config={{
    hideAnimations: true
  }}
/>
```

* Set `hideAnimations` to `true` to disable all custom animations.
* Set `hideAnimations` to `false` (default) to keep the animations enabled.

### Best Practices

1. **Consistency:** Ensure that your custom content aligns with your brand and the overall user experience of your application.
2. **Localization:** Consider providing localized versions of titles if your application supports multiple languages.
3. **Performance:** If using a custom logo, optimize the image for web to ensure fast loading times.
4. **Accessibility:** When customizing text, maintain clear and descriptive labels to support all users, including those using screen readers.

### Full Example

Here's an example that combines all of these content configurations:

```jsx
import { SquidWidget } from '@0xsquid/widget';

function App() {
  return (
    <SquidWidget
      config={{
        mainLogoUrl: "https://your-domain.com/your-logo.png",
        titles: {
          swap: "Transfer",
          settings: "Preferences",
          wallets: "Connect Wallet",
          tokens: "Select Token",
          chains: "Choose Network",
          history: "Past Transfers",
          transaction: "Transfer Details",
          destination: "Recipient Address",
        },
        hideAnimations: false,
        // ... other configuration options
      }}
    />
  );
}

export default App;
```


# Default Chains and Tokens

## Squid Widget v2.0: Default Chains and Tokens Configuration Guide

This guide explains how to configure default chains and tokens for the Squid Widget v2.0. Note that there have been significant changes from previous versions.

### Finding Chain IDs and Token Addresses

Before configuring, you'll need to know the correct chain IDs and token addresses:

* **Chain IDs**:
  * Use Squid's [API playground](https://api.squidrouter.com/docs)
  * Or access the [chains endpoint](https://api.squidrouter.com/v1/chains) directly
* **Token Addresses**:
  * Use the [tokens endpoint](https://api.squidrouter.com/v1/tokens)
  * Or filter by chain in the [API playground](https://api.squidrouter.com/docs#/tokens/get_v1_tokens) (input the chain ID in the `/tokens` reference)

### Configuring Initial Assets (Chains and Tokens)

In Squid v2.0, `initialFromChainId` and `initialToChainId` have been replaced by the `initialAssets` object:

```jsx
<SquidWidget
  config={{
    initialAssets: {
      from: {
        address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // Token address
        chainId: "1", // Ethereum
      },
      to: {
        address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // Token address
        chainId: "42161", // Arbitrum
      },
    },
    // ... other configuration options
  }}
/>
```

### Configuring Default Tokens Per Chain

The `defaultTokens` property has been renamed to `defaultTokensPerChain`:

```jsx
<SquidWidget
  config={{
    defaultTokensPerChain: [
      {
        address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH on Ethereum
        chainId: "1",
      },
      {
        address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", // ETH on Arbitrum
        chainId: "42161",
      },
    ],
    // ... other configuration options
  }}
/>
```

### Visible Tokens And Chains

Limit the tokens and chains visible on your widget by applying `availableChains` and `availableTokens` on the `source` or `destination`.

```jsx
<SquidWidget
  config={{
    "availableChains": {
      "destination": [
        "56",
        "8453",
        "42161"
      ]
    },
    "availableTokens": {
      "destination": {
        "56": [
          "0xf3527ef8de265eaa3716fb312c12847bfba66cef",
          "0x7788a3538c5fc7f9c7c8a74eac4c898fc8d87d92"
        ],
        "8453": [
          "0xf3527ef8de265eaa3716fb312c12847bfba66cef",
          "0x7788a3538c5fc7f9c7c8a74eac4c898fc8d87d92"
        ],
        "42161": [
          "0xf3527ef8de265eaa3716fb312c12847bfba66cef",
          "0x7788a3538c5fc7f9c7c8a74eac4c898fc8d87d92"
        ]
      }
    }
   // ... other configuration options
}}
/>
```

### Removed Features

Please note that the following features have been removed in Squid v2.0:

* `favTokens`: Favorite tokens are no longer supported.
* Several other properties including `companyName`, `titles`, `enableExpress`, `mainLogoUrl`, and others. Refer to the migration guide for a full list.

### Full Example

Here's a complete example combining these configurations:

```jsx
import { SquidWidget } from '@0xsquid/widget';

function App() {
  return (
    <SquidWidget
      config={{
        integratorId: "<your-integrator-id>",
        apiUrl: "https://v2.api.squidrouter.com",
        initialAssets: {
          from: {
            address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
            chainId: "1",
          },
          to: {
            address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
            chainId: "42161",
          },
        },
        defaultTokensPerChain: [
          {
            address: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
            chainId: "1",
          },
          {
            address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
            chainId: "42161",
          },
        ],
        // ... other configuration options
      }}
    />
  );
}

export default App;
```


# Configuration Types

This document outlines the configuration types available for the Squid Widget v2.0. For an implementation example, refer to the Full Configuration Example.

### Core Configuration Types

```typescript
export interface SquidConfig {
  integratorId: string;
  apiUrl?: string;
  theme?: Theme;
  themeType?: 'dark' | 'light';
  initialAssets?: {
    from: TokenData;
    to: TokenData;
  };
  defaultTokensPerChain?: TokenData[];
  priceImpactWarnings?: {
    warning: number;
    critical: number;
  };
  availableChains?: {
    source?: ChainId[];
    destination?: ChainId[];
  };
  loadPreviousStateFromLocalStorage?: boolean;
  slippage?: SlippageOption;
  hideAnimations?: boolean;
  preferDex?: DexName[] | string[];
  collectFees?: {
    integratorAddress: string;
    fee: number; // Basis points (e.g., 50 = 0.05%)
  };
  degenMode?: boolean;
}

export type ChainId = number | string;

export type SlippageOption = 0.5 | 1 | 1.5 | 3;

export type TokenData = {
  address: string;
  chainId: ChainId;
};

export type DexName = string; // Specific DEX names to be listed here
```

### Theme Configuration

```typescript
export interface Theme {
  borderRadius?: {
    "button-lg-primary"?: string;
    "button-lg-secondary"?: string;
    "button-lg-tertiary"?: string;
    "button-md-primary"?: string;
    "button-md-secondary"?: string;
    "button-md-tertiary"?: string;
    "container"?: string;
    "input"?: string;
    "menu-sm"?: string;
    "menu-lg"?: string;
    "modal"?: string;
  };
  fontSize?: {
    "caption"?: string;
    "body-small"?: string;
    "body-medium"?: string;
    "body-large"?: string;
    "heading-small"?: string;
    "heading-medium"?: string;
    "heading-large"?: string;
  };
  fontWeight?: {
    "caption"?: string;
    "body-small"?: string;
    "body-medium"?: string;
    "body-large"?: string;
    "heading-small"?: string;
    "heading-medium"?: string;
    "heading-large"?: string;
  };
  fontFamily?: {
    "squid-main"?: string;
  };
  boxShadow?: {
    "container"?: string;
  };
  color?: {
    "grey-100"?: ColorType;
    "grey-200"?: ColorType;
    "grey-300"?: ColorType;
    "grey-400"?: ColorType;
    "grey-500"?: ColorType;
    "grey-600"?: ColorType;
    "grey-700"?: ColorType;
    "grey-800"?: ColorType;
    "grey-900"?: ColorType;
    "royal-300"?: ColorType;
    "royal-400"?: ColorType;
    "royal-500"?: ColorType;
    "royal-700"?: ColorType;
    "status-positive"?: ColorType;
    "status-negative"?: ColorType;
    "status-partial"?: ColorType;
    "highlight-700"?: ColorType;
    "animation-bg"?: ColorType;
    "animation-text"?: ColorType;
    "button-lg-primary-bg"?: ColorType;
    "button-lg-primary-text"?: ColorType;
    "button-lg-secondary-bg"?: ColorType;
    "button-lg-secondary-text"?: ColorType;
    "button-lg-tertiary-bg"?: ColorType;
    "button-lg-tertiary-text"?: ColorType;
    "button-md-primary-bg"?: ColorType;
    "button-md-primary-text"?: ColorType;
    "button-md-secondary-bg"?: ColorType;
    "button-md-secondary-text"?: ColorType;
    "button-md-tertiary-bg"?: ColorType;
    "button-md-tertiary-text"?: ColorType;
    "input-bg"?: ColorType;
    "input-placeholder"?: ColorType;
    "input-text"?: ColorType;
    "input-selection"?: ColorType;
    "menu-bg"?: ColorType;
    "menu-text"?: ColorType;
    "menu-backdrop"?: ColorType;
    "modal-backdrop"?: ColorType;
  };
}

export type ColorType = string; // The color format must be of type #FFFFFF
```

### Important Notes

1. The `apiUrl` is now [`https://v2.api.squidrouter.com`](https://v2.api.squidrouter.com) by default.
2. `initialFromChainId` and `initialToChainId` have been replaced by `initialAssets`.
3. `defaultTokens` has been renamed to `defaultTokensPerChain`.
4. `favTokens` has been removed and is no longer supported.
5. Several properties have been removed in v2.0, including `companyName`, `titles`, `enableExpress`, `mainLogoUrl`, and others. Refer to the migration guide for a full list of removed properties.
6. A new `degenMode` property has been added.

### Deprecated or Removed Types

The following types and properties are no longer used in Squid Widget v2.0:

* `ConfigTheme` (replaced by `Theme`)
* `enableExpress`
* `enableGetGasOnDestination`
* `mainLogoUrl`
* `titles`
* `internalSameChainSwapAllowed`
* `advanced.shareOnTwitter`
* `advanced.disableTradeLimit`
* `favTokens`
* `comingSoonChainIds`


# Collect Fees

### Integrator Fee Structure

Squid v2 allows integrators to implement their own fee structure on top of Squid's platform fees. This document details the structure of Integrator fees implemented on through Squid.

<mark style="color:yellow;">**To implement fees please contact the Squid team.**</mark>\
Note, Squid splits all fees collected by integrators 50/50. Please see the Platform Fee Structure section for more detail.

#### Integrator Fee Configuration

As an integrator, you can implement the following fee structures:

1. Flat fee: A fixed amount per transaction
2. Percentage fee: A percentage of the transaction amount
3. Secondary address fees (optional): Fees sent to a second address
4. Option to waive platform fee (if allowed by Squid)

#### Implementing Integrator Fees

In order to prevent abuse an abuse of the fee collection system, we implement the `collectFees` parameter on the backend for integrators.

#### Fee Precision

You can set fees with precision up to thousandths of a percent (0.001% - 100% or 0.00001 - 1 in decimal form).

#### Fee Display

Within the returned route request, all fees (including your integrator fees and Squid's platform fees) are aggregated into a single "Service fee" in the route response. This appears in the `feeCosts` array and `route.actions`:

```json
{
  "feeCosts": [
    {
      "amount": "31178739678247",
      "amountUsd": "0.12",
      "description": "Service fee",
      "name": "Service fee",
      "token": {
        "type": "evm",
        "chainId": "42161",
        "address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
        "name": "Ethereum",
        "symbol": "ETH",
        "decimals": 18,
        "logoURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/tokens/eth.svg",
        "coingeckoId": "ethereum",
        "usdPrice": 3798.076408348585
      }
    }
  ],
  "actions": [
    {
      // ... other action properties
      "provider": "Service fee",
      "description": "Service fee",
      "priceImpact": 0,
      "exchangeRate": "0.99"
    }
  ]
}
```

### Platform Fee Structure

<mark style="color:yellow;">Squid splits all fees collected by integrators 50/50.</mark>

In the future, Squid may charge additional platform fees on top of integrator fees. These may include:

* Platform Base Fee
* Chain-specific Fees
* Token-specific Fees
* Volatility Tier Fees

The total fee for a transaction is calculated as:

```
Total Fee = Platform Fees + Integrator Fees
```

Note: In some cases, Squid may allow integrators to waive certain platform fees. Please contact us for more information on fee customization options.


# Information for Integrators

Here you will find a brief onboarding guide to ensure the integration is as smooth as possible for your team and users

We're thrilled that you have chosen to integrate our widget and appreciate your trust in Squid 🦑

If you have any questions or concerns during the integration process, please don't hesitate to reach out to us on [Discord](https://discord.gg/squidrouter).

### Staying updated

If you have integrated the widget, please let us know so we can share the news with our community! To stay updated with any changes or new features, please follow us on [Twitter](https://twitter.com/squidrouter) or join our [Discord](https://discord.gg/squidrouter).

### User support

{% hint style="info" %}
A full user guide can be found [here](https://docs.widget.squidrouter.com/) which contains a step-by-step guide on how to do a swap and how to troubleshoot any errors or issues.
{% endhint %}

Once you have integrated the widget, we recommend you create a support channel in your own community for users to troubleshoot issues that users may encounter while using the widget.

If you our your users discover any persistent issues or errors while using the widget, please contact us on [Discord](https://discord.gg/squidrouter).

Should you need to provide guidance on how to use the widget or troubleshoot technical issues, here are the most common user issues and how to resolve them:

<details>

<summary>The user is unable to initiate a swap</summary>

The most likely reason for is is that their balance is insufficient to complete the trade and cover any bridge or swap fees. The user should try a lower swap amount, or top up their account with more of the native gas token.

</details>

<details>

<summary>The swap is marked as complete, but the user does not see their tokens</summary>

If this happens, it's likely that the user has received axlUSDC on the destination chain unexpectedly. This can happen as a result of price volatility and low slippage, which causes the transaction to revert.

The user can complete their swap by swapping from axlUSDC to their desired token. Squid will support swaps on the same chain soon, but until then they can use a DEX on their destination chain to finish the transaction.

</details>

<details>

<summary>Transaction failed or could not initiate</summary>

If the initial swap on the source chain swap did not initiate, the user's tokens will still be in their wallet on the source chain, aside from a small amount that may have been spent on gas. They should return to the swap page and try again.

</details>

<details>

<summary>Transaction is paused</summary>

If gas prices rise and the transaction pauses as a result, the user can manually add gas to re-start the transaction by visiting the transaction's page in Axelarscan's UI.

</details>

### Safety and security

The safety and security of users and their assets is of the utmost importance to us.

If a chain or token has downtime or is compromised, Squid will remove it from the chain and token lists as soon as we are notified, and the widget will update automatically to reflect this change.

**If you ever encounter a security incident relating to the widget or one of Squid's supported chains, tokens or routes, please inform Squid immediately on** [**Discord**](https://discord.gg/squidrouter) **or** [**Twitter**](https://twitter.com/squidrouter)**.**

### Fees

#### DEX fees

Squid does not charge any DEX fees, but swaps are routed through other DEXs, such as Uniswap, Curve and Osmosis, who do charge fees. These fees are included in the total amount out provided by the widget's quote.

Squid currently earns no revenue from swaps, but has fee contracts audited, and will introduce a small fee in the future.


# Set default chains and tokens via URL

{% hint style="info" %}
Squid website only! This is possible for widget integrators by setting [default chains and tokens](/old-v2-documentation-deprecated/add-a-widget/widget/customization-guide/default-chains-and-tokens) via iframe URL or widget config
{% endhint %}

You can customize the chains and tokens that are selected by default when visiting [https://app.squidrouter.com](https://app.squidrouter.com/) via the `chains` and `tokens` query parameters.

The first value (`x`) represents the source, and separated by a comma, the second one (`y`) represents the destination:

```
chains=x,y // chain id
tokens=x,y // token address
```

For example, the following URL will open the Squid app using Arbitrum and MAGIC for source and Ethereum and DAI for destination:

```
https://v2.api.squidrouter.com/?
chains=42161,1
&tokens=0x539bde0d7dbd336b79148aa742883198bbf60342,
0x6b175474e89094c44da98b954eedeac495271d0f
```


# Errors

Here is a list of errors that some users were facing that have a known fix

### Wagmi Import error

```bash
SyntaxError: The requested module '@wagmi/core' does not provide an export named 'getClient'
    at ModuleJob._instantiate (node:internal/modules/esm/module_job:124:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:190:5) {
  digest: undefined
  
```

This error can be fixed by installing explicitly the @wagmi/connectors package


# Stake widget

Squid provides a react component or iframe widget for quickly building a "Stake or deposit from any chain" flow.

This uses Squid's [Broken mention](broken://pages/19kRhbLXejm0jXx6sIDa) feature, where the Squid contract can make arbitrary calls to any contract after a bridge or swap has completed.

* Configure the destination token needed to swap/deposit or stake.
* Configure the contract calls (hooks) to be made on the destination token. (stake, lend, deposit etc)

Installation is easy, and should take 30min-3 hours depending on the complexity of your staking or deposit function calls.


# Installing the Widget

Preparing to integrate the widget into your app

If you have any questions along the way, please contact us on our [Discord](https://discord.com/invite/squidrouter) in the ***⛓│developers*****&#x20;channel**.

### Installation

{% hint style="info" %}
To install the widget you need to register a partner ID with the Squid Team, please [complete this form](https://form.typeform.com/to/cqFtqSvX?) to acquire one.
{% endhint %}

```tsx
<
SquidStakingWidget
 config={{
  integratorId: "<partner-id>",
  // ... Other config options, such as theme, titles, etc.
}} />
```

`integratorId` for squid to keep track of partners, complete the [form](https://l19g3aali76.typeform.com/integrator-id) to acquire it.

Install the Squid Widget npm package:

```
npm i @0xsquid/staking-widget
```

or

```
yarn add @0xsquid/staking-widget
```


# Configuration

Staking widget configuration

The configuration of this widget is almost the same as the Swap widget. Take a look at these docs:

* [Customization Guide](/old-v2-documentation-deprecated/add-a-widget/widget/customization-guide)
* [Theme Customization](/old-v2-documentation-deprecated/add-a-widget/widget/customization-guide/theme-customization)

In addtion to the standard widget config, the staking widget requires a `stakeConfig`.

### Working example

{% @github-files/github-code-block url="<https://github.com/0xsquid/widget-integrations/blob/main/packages/next-app/pages/staking.tsx>" %}

### Adding the Staking transactions

Basically the stakeConfig is here to tell the widget what happens after the cross chain swap.

*Here's an example flow:*

* User wants to stake USDC on Moonbeam from BNB on Binance
* Normal cross chain swap happens with Squid (swap to axlUSDC, bridge, swap to destination token, configured by the developer)
* Now it's time to execute customContractCalls:
  * Give approval to SquidMultiCall to send dest token (let's say GLMR received earlier)
  * Effectively stake this amount on Moonbeam
  * Send staked token to user

The main attribute to update is `customContractCalls`.

You can read more about the configuration of customContractCalls here: [Broken mention](broken://pages/19kRhbLXejm0jXx6sIDa)

### stakeConfig structure

```typescript
export interface StakeConfig {
  // TokenData will have all informations about the stakedToken,
  // such as symbol, image, name, chainId, etc)
  stakedToken: TokenData;
  
  // This method will be used to compute the exchange rate between the staked token and the token to stake
  // Basically a multiplier from 0 to x
  // Then if the amount that the route gets is 100, and the exchange rate is 0.5, we'll show 50 as the amount to be received for stakedToken
  // If nothing is specified, the exchange rate will be 1
  stakedTokenExchangeRateGetter?: () => Promise<number>;


  // At the moment we cannot unstake directly through the widget, 
  // If you want to tell the user that he can unstake, we'll display a link for this
  unstakeLink?: string;
  
  // Intro page is optional, it will display a page before proposing to swap,
  // This can be useful for the user to understand what will be possible
  introPage?: {
    title: string;
    logoUrl: string;
    stakingContract?: {
      address: string;
      explorerLink?: string;
    };
  };
  
  // This is mandatory, and different from stakedToken
  // This token won't be displayed but will be used to stake
  // Route will be like this: 
  // -  User selects BNB on Binance
  // -  We swap this to axlUSDC using Axelar
  // -  axlUSDC is bridged to the chainId of token below
  // -  axlUSDC is swapped to token below
  tokenToStake: {
    chainId: number | string;
    address: string;
  };
  
  // After swap/bridge is done, custom contract call can be executed
  // For example staking the "tokenToStake" into "stakedToken"
  customContractCalls: (Omit<ContractCall, "callData"> & {
    callData?: (routeVariables: CallDataGetter) => string;
  })[];
}
```


# Importing The widget

Install dependencies:

```bash
npm i @0xsquid/staking-widget @0xsquid/sdk ethers
```

And import the widget in your app:

```typescript
import { SquidStakingWidget } from "@0xsquid/staking-widget";
import { SquidCallType } from "@0xsquid/sdk";
import { ethers } from "ethers";

import erc20Abi from "./abi/erc20Abi";
import pinjamStakingPoolAbi from "./abi/pinjamStakingPoolAbi";

const pinjamStakingPoolInterface = new ethers.Interface(
  pinjamStakingPoolAbi
);

const kavaId = 2222;
const pinjamAxlUsdcPoolAddress = "0x11c3d91259b1c2bd804344355c6a255001f7ba1e";
const axlUsdcKavaAddress = "0xeb466342c4d449bc9f53a865d5cb90586f405215";
const pAxlUsdcAddress = "0x5c91f5d2b7046a138c7d1775bffea68d5e95d68d";
const erc20Interface = new ethers.Interface(erc20Abi);

export default function App() {
  const stakeConfig = {
    tokensConfig: [
      {
        stakedTokenExchangeRateGetter: async () => {
          return 1;
        },
        unstakeLink: "https://app.pinjamlabs.com/staking",
        customContractCalls: [
          {
            callType: SquidCallType.FULL_TOKEN_BALANCE,
            target: axlUsdcKavaAddress,
            value: "0",
            callData: () => {
              return erc20Interface.encodeFunctionData("approve", [
                pinjamAxlUsdcPoolAddress,
                "0",
              ]);
            },
            payload: {
              tokenAddress: axlUsdcKavaAddress,
              inputPos: 1,
            },
            estimatedGas: "50000",
          },
          {
            callType: SquidCallType.FULL_TOKEN_BALANCE,
            target: pinjamAxlUsdcPoolAddress,
            value: "0",
            callData: (route: any) => {
              if (route.destinationAddress) {
                return pinjamStakingPoolInterface.encodeFunctionData(
                  "deposit",
                  [axlUsdcKavaAddress, "0", route.destinationAddress, true]
                );
              }
              return "0x0000000000000000000000000000000000000000";
            },
            payload: {
              tokenAddress: axlUsdcKavaAddress,
              inputPos: 1,
            },
            estimatedGas: "250000",
          },
        ],

        stakedToken: {
          chainId: kavaId,
          address: pAxlUsdcAddress,
          name: "paxlUSDC",
          symbol: "paxlUSDC",
          decimals: 6,
          logoURI:
            "https://assets.coingecko.com/coins/images/6319/thumb/USD_Coin_icon.png?1547042389",
          coingeckoId: "usd-coin",
        },
        tokenToStake: {
          chainId: kavaId,
          address: axlUsdcKavaAddress,
        },
        stakingContract: {
          address: "0xe5274e38e91b615d8822e8512a29a16ff1b9c4af",
          explorerLink: "https://kava.mintscan.io/account/",
        },
        logoUrl: "https://app.pinjamlabs.com/icons/pinkav.svg",
      },
    ],

    introPage: {
      title: "Stake paxlUSDC on Kava",
      description: "Stake paxlUSDC on Kava to earn rewards",
    },
  };

  return (
    <SquidStakingWidget
      config={{
        apiUrl: "https://v2.api.squidrouter.com",
        integratorId: "<your integrator id>",
        stakeConfig,
      }}
    />
  );
}
```


# API

## Overview

Squid API is for devs using a client other than javascript. The API offers nearly the full functionality of the SDK, and is only missing some helper functions for front end work.

Below is the most basic example of building with Squid, a cross-chain swap. In this example, we will cover the key concepts involved in the swap.

To find all examples, please visit our [examples repo](https://github.com/0xsquid/examples).

## Getting Started: Cross-chain Swaps

This example walks through the index.js code included in the [**EVMtoEVM API swap example**](https://github.com/0xsquid/examples/tree/main/V2/api/evmToEVMSwap)**.**

Once you download the example folder [**evmToEVMSwap**](https://github.com/0xsquid/examples/tree/main/V2/api/evmToEVMSwap) **u**se the `yarn install` to install the necessary packages and create a .env file modeled based off the `.env.example` folder.

**The following actions take place in the index.js:**

* Loading necessary packages and environmental variables
* Defining route parameters, RPC provider, and wallet signer
* Creating the route request and the transaction status functions
* Defining the route parameters and requesting the route
* Executing the route transactions
* Checking the status of the transactions

```typescript

import { ethers } from "ethers";
import axios from "axios";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables from .env file
const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;
const FROM_CHAIN_RPC: string = process.env.FROM_CHAIN_RPC_ENDPOINT!;

// Define chain and token addresses
const fromChainId = "56"; // BNB
const toChainId = "42161"; // Arbitrum
const fromToken = "0x55d398326f99059fF775485246999027B3197955"; // USDT
const toToken = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; // USDC

// Define the amount to be sent
const amount = "1000000000000000";

// Set up JSON RPC provider and signer 
const provider = new ethers.providers.JsonRpcProvider(FROM_CHAIN_RPC);
const signer = new ethers.Wallet(privateKey, provider);

// Function to get the optimal route for the swap using Squid API
const getRoute = async (params: any) => {
  try {
    const result = await axios.post(
      "https://v2.api.squidrouter.com/v2/route",

      params,
      {
        headers: {
          "x-integrator-id": integratorId,
          "Content-Type": "application/json",
        },
      }
    );
    const requestId = result.headers["x-request-id"]; // Retrieve request ID from response headers
    return { data: result.data, requestId: requestId };
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to get the status of the transaction using Squid API
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
        quoteId: params.quoteId, // Required for Coral V2 transactions
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to periodically check the transaction status until it completes
const updateTransactionStatus = async (txHash: string, requestId: string, quoteId: string) => {
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId, // Required for Coral V2 transactions
  };

  let status;
  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found"];
  const maxRetries = 10; // Maximum number of retries for status check
  let retryCount = 0;

  do {
    try {
      status = await getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error) {
      if (error.response && error.response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before retrying
        continue;
      } else {
        throw error; // Rethrow other errors
      }
    }

    if (!completedStatuses.includes(status.squidTransactionStatus)) {
      await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before checking the status again
    }
  } while (!completedStatuses.includes(status.squidTransactionStatus));
};

// Set up parameters for swapping tokens
(async () => {
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
    slippage: 1,
    slippageConfig: {
      autoMode: 1,
    },
  };

  console.log("Parameters:", params);

  // Get the swap route using Squid API
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;
  const quoteId = route.quoteId; // Save quoteId — required for Coral V2 status tracking
  console.log("Calculated route:", route);
  console.log("requestId:", requestId);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest;

  // Execute the swap transaction
  const tx = await signer.sendTransaction({
    to: transactionRequest.target,
    data: transactionRequest.data,
    value: transactionRequest.value,
    gasPrice: await provider.getGasPrice(),
    gasLimit: transactionRequest.gasLimit,
  });
  console.log("Transaction Hash:", tx.hash);
  const txReceipt = await tx.wait();

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink = "https://axelarscan.io/gmp/" + txReceipt.transactionHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Update transaction status until it completes
  await updateTransactionStatus(txReceipt.transactionHash, requestId, quoteId);
})();

```


# Swap & Bridge Example

The swap and bridge example leverages the same index.js code included in the [API Overview section](/old-v2-documentation-deprecated/api).

**The following actions take place in the index.js:**

* Loading necessary packages and environmental variables
* Defining route parameters, RPC provider, and wallet signer
* Creating the route request and the transaction status functions
* Defining the route parameters and requesting the route
* Approve the Squid Contract to spend the tokens
* Executing the route transactions
* Checking the status of the transactions

```typescript

import { ethers } from "ethers";
import axios from "axios";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables from .env file
const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;
const FROM_CHAIN_RPC: string = process.env.FROM_CHAIN_RPC_ENDPOINT!;

// Define chain and token addresses
const fromChainId = "56"; // BNB
const toChainId = "42161"; // Arbitrum
const fromToken = "0x55d398326f99059fF775485246999027B3197955"; // USDT
const toToken = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; // USDC

// Define the amount to be sent
const amount = "1000000000000000";

// Set up JSON RPC provider and signer 
const provider = new ethers.providers.JsonRpcProvider(FROM_CHAIN_RPC);
const signer = new ethers.Wallet(privateKey, provider);

// Function to get the optimal route for the swap using Squid API
const getRoute = async (params: any) => {
  try {
    const result = await axios.post(
      "https://v2.api.squidrouter.com/v2/route",
      params,
      {
        headers: {
          "x-integrator-id": integratorId,
          "Content-Type": "application/json",
        },
      }
    );
    const requestId = result.headers["x-request-id"]; // Retrieve request ID from response headers
    return { data: result.data, requestId: requestId };
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to get the status of the transaction using Squid API
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
        quoteId: params.quoteId, // Required for Coral V2 transactions
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to periodically check the transaction status until it completes
const updateTransactionStatus = async (txHash: string, requestId: string, quoteId: string) => {
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId, // Required for Coral V2 transactions
  };

  let status;
  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found"];
  const maxRetries = 10; // Maximum number of retries for status check
  let retryCount = 0;

  do {
    try {
      status = await getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error) {
      if (error.response && error.response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before retrying
        continue;
      } else {
        throw error; // Rethrow other errors
      }
    }

    if (!completedStatuses.includes(status.squidTransactionStatus)) {
      await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before checking the status again
    }
  } while (!completedStatuses.includes(status.squidTransactionStatus));
};

// Function to approve the transactionRequest.target to spend fromAmount of fromToken
const approveSpending = async (transactionRequestTarget: string, fromToken: string, fromAmount: string) => {
  const erc20Abi = [
    "function approve(address spender, uint256 amount) public returns (bool)"
  ];
  const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
  try {
    const tx = await tokenContract.approve(transactionRequestTarget, fromAmount);
    await tx.wait();
    console.log(`Approved ${fromAmount} tokens for ${transactionRequestTarget}`);
  } catch (error) {
    console.error('Approval failed:', error);
    throw error;
  }
};

// Set up parameters for swapping tokens
(async () => {
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
  };

  console.log("Parameters:", params);

  // Get the swap route using Squid API
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;
  const quoteId = route.quoteId; // Save quoteId — required for Coral V2 status tracking
  console.log("Calculated route:", route);
  console.log("requestId:", requestId);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest;

  // Approve the transactionRequest.target to spend fromAmount of fromToken
  await approveSpending(transactionRequest.target, fromToken, amount);

  // Execute the swap transaction
  const tx = await signer.sendTransaction({
    to: transactionRequest.target,
    data: transactionRequest.data,
    value: transactionRequest.value,
    gasPrice: await provider.getGasPrice(),
    gasLimit: transactionRequest.gasLimit,
  });
  console.log("Transaction Hash:", tx.hash);
  const txReceipt = await tx.wait();

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink = "https://axelarscan.io/gmp/" + txReceipt.transactionHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Update transaction status until it completes
  await updateTransactionStatus(txReceipt.transactionHash, requestId, quoteId);
})();


```


# Staking Example

In this example, we utilize a [post-hook](/old-v2-documentation-deprecated/key-concepts/hooks/build-a-posthook) to swap from Binance to Arbitrum and lend on Arbitrum.

This example can also be found in the [examples repo](https://github.com/0xsquid/examples/tree/main/V2/api/swapEVMToEVMAndLendPosthook).

```typescript
// Import necessary libraries
import { ethers } from "ethers";
import axios from "axios";

// Load environment variables from .env file
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables from .env file
const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;
const FROM_CHAIN_RPC: string = process.env.RPC_ENDPOINT!;
const aaveArbitrumPoolAddress: string = "0x794a61358D6845594F94dc1DB02A252b5b4814aD"; // Aave v3 pool on Arbitrum
const usdcArbitrumAddress: string = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; // USDC on Arbitrum

// Define chain and token addresses
const fromChainId = "56"; // Binance
const toChainId = "42161"; // Arbitrum
const fromToken = "0x55d398326f99059fF775485246999027B3197955"; // Define departing token

// Define amount to be swapped and deposited
const amount = "1000000000000000000";

// Import erc20 contract ABI
import erc20Abi from "../abi/erc20Abi";

// Define Aave pool ABI
const aavePoolAbi = [
  "function withdraw(address asset, uint256 amount, address to) external returns (uint256)",
  "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external"
];

// Set up JSON RPC provider and signer 
const provider = new ethers.providers.JsonRpcProvider(FROM_CHAIN_RPC);
const signer = new ethers.Wallet(privateKey, provider);

// Creating Contract interfaces
const aaveArbitrumPoolContract = new ethers.Contract(aaveArbitrumPoolAddress, aavePoolAbi, signer);
const toTokenContract = new ethers.Contract(usdcArbitrumAddress, erc20Abi, signer);

// Approve the Aave pool contract to spend the USDC
const erc20Interface = new ethers.utils.Interface(erc20Abi);
const approvalData = erc20Interface.encodeFunctionData("approve", [
  aaveArbitrumPoolAddress,
  ethers.constants.MaxUint256,
]);

// Create contract interface and encode supply function for Aave lending pool
const aavePoolInterface = new ethers.utils.Interface(aavePoolAbi);
const supplyData = aavePoolInterface.encodeFunctionData("supply", [
  usdcArbitrumAddress,
  "0", // Amount will be replaced with the full token balance
  signer.address,
  0 // referralCode
]);

// Function to get the optimal route for the swap using Squid API
const getRoute = async (params: any) => {
  try {
    const result = await axios.post(
      "https://v2.api.squidrouter.com/v2/route",
      params,
      {
        headers: {
          "x-integrator-id": integratorId,
          "Content-Type": "application/json",
        },
      }
    );
    const requestId = result.headers["x-request-id"]; // Retrieve request ID from response headers
    return { data: result.data, requestId: requestId };
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to get the status of the transaction using Squid API
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Function to periodically check the transaction status until it completes
const updateTransactionStatus = async (txHash: string, requestId: string) => {
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
  };

  let status;
  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found"];
  const maxRetries = 20; // Increased maximum number of retries for status check
  let retryCount = 0;
  let consecutiveFailures = 0;

  console.log(`Starting status monitoring for transaction: ${txHash}`);
  console.log(`Request ID: ${requestId}`);

  do {
    try {
      console.log(`Checking status... (attempt ${retryCount + 1}/${maxRetries})`);
      status = await getStatus(getStatusParams);
      
      console.log(`✅ Status check successful: ${status.squidTransactionStatus}`);
      consecutiveFailures = 0; // Reset failure counter on success
      
      // If not completed, wait before next check
      if (!completedStatuses.includes(status.squidTransactionStatus)) {
        console.log("Transaction still processing. Waiting 5 seconds before next check...");
        await new Promise((resolve) => setTimeout(resolve, 5000));
      }
      
    } catch (error: any) {
      if (error.response && error.response.status === 404) {
        retryCount++;
        consecutiveFailures++;
        
        console.log(`❌ Transaction not found in indexer (404 error)`);
        console.log(`   Retry attempt: ${retryCount}/${maxRetries}`);
        console.log(`   Consecutive failures: ${consecutiveFailures}`);
        
        if (error.response.data && error.response.data.message) {
          console.log(`   API message: ${error.response.data.message}`);
        }
        
        if (retryCount >= maxRetries) {
          console.error("❌ Max retries reached. Transaction may still be processing.");
          console.error("💡 This doesn't mean the transaction failed - it may just take longer to index.");
          console.error(`🔗 Check manually: https://axelarscan.io/gmp/${txHash}`);
          break;
        }
        
        // Implement exponential backoff for 404 errors
        let waitTime;
        if (consecutiveFailures <= 3) {
          waitTime = 10000; // 10 seconds for first few failures
        } else if (consecutiveFailures <= 6) {
          waitTime = 20000; // 20 seconds for subsequent failures
        } else {
          waitTime = 30000; // 30 seconds for persistent failures
        }
        
        console.log(`⏳ Waiting ${waitTime/1000} seconds before retry...`);
        await new Promise((resolve) => setTimeout(resolve, waitTime));
        continue;
        
      } else {
        // Handle non-404 errors
        console.error("❌ Unexpected error checking status:", error.message);
        
        if (error.response) {
          console.error(`   HTTP Status: ${error.response.status}`);
          console.error(`   Status Text: ${error.response.statusText}`);
          if (error.response.data) {
            console.error(`   Response:`, error.response.data);
          }
        }
        
        retryCount++;
        consecutiveFailures++;
        
        if (retryCount >= maxRetries) {
          console.error("❌ Max retries reached due to persistent errors.");
          throw error;
        }
        
        console.log(`⏳ Waiting 15 seconds before retry due to error...`);
        await new Promise((resolve) => setTimeout(resolve, 15000));
        continue;
      }
    }
    
  } while (status && !completedStatuses.includes(status.squidTransactionStatus));

  if (status && completedStatuses.includes(status.squidTransactionStatus)) {
    console.log(`🎉 Transaction completed with status: ${status.squidTransactionStatus}`);
    
    // Provide additional context based on final status
    switch (status.squidTransactionStatus) {
      case "success":
        console.log("✅ Transaction completed successfully!");
        break;
      case "partial_success":
        console.log("⚠️  Transaction partially completed. Some operations may have failed.");
        break;
      case "needs_gas":
        console.log("⛽ Transaction needs additional gas to complete.");
        break;
      case "not_found":
        console.log("❓ Transaction not found in final check.");
        break;
    }
  } else {
    console.log("⏹️  Status monitoring ended without completion confirmation.");
    console.log(`🔗 Monitor progress: https://axelarscan.io/gmp/${txHash}`);
  }
};

// Function to approve the transactionRequest.target to spend fromAmount of fromToken
const approveSpending = async (transactionRequestTarget: string, fromToken: string, fromAmount: string) => {
  const erc20Abi = [
    "function approve(address spender, uint256 amount) public returns (bool)"
  ];
  const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
  try {
    const tx = await tokenContract.approve(transactionRequestTarget, fromAmount);
    await tx.wait();
    console.log(`Approved ${fromAmount} tokens for ${transactionRequestTarget}`);
  } catch (error) {
    console.error('Approval failed:', error);
    throw error;
  }
};

// Set up parameters for swapping tokens
(async () => {
  // Set up parameters for swapping tokens and depositing into Aave lending pool
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: usdcArbitrumAddress,
    toAddress: signer.address,
    slippage: 1, //optional, Squid will dynamically calculate if removed
    postHook: {
      chainType: "evm",
      calls: [
        {
          callType: 1,
          target: usdcArbitrumAddress,
          value: "0",
          callData: approvalData,
          payload: {
            tokenAddress: usdcArbitrumAddress,
            inputPos: "1",
          },
          estimatedGas: "50000",
          chainType: "evm",
        },
        {
          callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
          target: aaveArbitrumPoolAddress,
          value: "0",
          callData: supplyData,
          payload: {
            tokenAddress: usdcArbitrumAddress,
            inputPos: "1",
          },
          estimatedGas: "200000",
          chainType: "evm",
        },
      ],
      provider: "Aave",
      description: "Deposit to Aave on Arbitrum",
      logoURI: "https://app.aave.com/favicon.ico",
    },
  };

  console.log("Parameters:", params);

  // Get the swap route using Squid API
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;
  console.log("Calculated route:", route);
  console.log("requestId:", requestId);

  const transactionRequest = route.transactionRequest;

  // Approve the transactionRequest.target to spend fromAmount of fromToken
  await approveSpending(transactionRequest.target, fromToken, amount);

  // Execute the swap transaction
  const tx = await signer.sendTransaction({
    to: transactionRequest.target,
    data: transactionRequest.data,
    value: transactionRequest.value,
    gasLimit: (BigInt(transactionRequest.gasLimit) * BigInt(2)).toString(),
  });

  const txReceipt = await tx.wait();
  console.log("Transaction Hash: ", txReceipt.transactionHash);

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink = "https://axelarscan.io/gmp/" + txReceipt.transactionHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Update transaction status until it completes
  await updateTransactionStatus(txReceipt.transactionHash, requestId);
})();

```


# Cross-chain NFT Purchase Example

Robust documentation for a cross-chain NFT Purchase coming soon.

Please refer to this example of purchasing an [NFT on Polygon from any chain](https://github.com/0xsquid/examples/blob/main/V2/api/oldExamples/mintPolygonNftFromAnyChain/src/index.ts) from our [example repo.](https://github.com/0xsquid/examples/tree/main)

```typescript
// Import necessary libraries
import { ethers } from "ethers";
import axios from "axios";

// Load environment variables from the .env file
import * as dotenv from "dotenv";
dotenv.config();

const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!; // get one at https://form.typeform.com/to/cqFtqSvX
const rpcEndpoint: string = process.env.RPC_ENDPOINT!;
const nftContractAddress: string = process.env.NFT_CONTRACT_ADDRESS!;

// Define chain and token addresses
const fromChainId = "1"; // Define departing chain, set to Ethereum by default
const polygonId = "137"; // Polygon
const nativeToken = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"; // Define departing token

// Define amount to be sent
const amount = "10000000000000000";

// Import necessary ABI's
import nftContractAbi from "../abi/squidEasterEggNftAbi";
import erc20Abi from "../abi/erc20Abi";

// Set up JSON RPC provider and signer for source chain (Ethereum)
const provider = new ethers.providers.JsonRpcProvider(rpcEndpoint);
const signer = new ethers.Wallet(privateKey, provider);

const getRoute = async (params: any) => {
  try {
    const result = await axios.post(
      "https://v2.api.squidrouter.com/v2/route",
      params,
      {
        headers: {
          "x-integrator-id": integratorId,
          "Content-Type": "application/json",
        },
      }
    );
    const requestId = result.headers["x-request-id"];
    return { data: result.data, requestId: requestId };
  } catch (error) {
    // Log the error response if it's available.
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Create contract interfaces and encode calldata
const nftContractInterface = new ethers.utils.Interface(nftContractAbi);
const mintEncodedData = nftContractInterface.encodeFunctionData("mint", [
  signer.address,
]);

const erc20ContractInterface = new ethers.utils.Interface(erc20Abi);
const transferRemainingBalanceEncodeData =
  erc20ContractInterface.encodeFunctionData("transfer", [signer.address, "0"]);

(async () => {
  // Set up parameters for swapping tokens and minting NFT on Polygon
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: nativeToken,
    fromAmount: amount,
    toChain: polygonId,
    toToken: nativeToken,
    toAddress: signer.address,
    slippage: 1,   //optional, Squid will dynamically calculate if removed
    quoteOnly: false,
    // Customize contract call for minting NFT on Polygon
    postHooks: [
      {
        callType: 0, // SquidCallType.DEFAULT
        target: nftContractAddress,
        value: "0",
        callData: mintEncodedData,
        payload: {
          tokenAddress: nativeToken,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
      {
        callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
        target: nativeToken,
        value: "0",
        callData: transferRemainingBalanceEncodeData,
        payload: {
          tokenAddress: nativeToken,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
    ],
  };

  console.log("Parameters:", params);

  // Get the swap route using Squid API
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;
  console.log("Calculated route:", route);
  console.log("requestId:", requestId);

  const transactionRequest = route.transactionRequest;

  // Execute the swap and minting transaction
  const contract = new ethers.Contract(
    transactionRequest.targetAddress,
    nftContractAbi,
    signer
  );
  const tx = await contract.send(transactionRequest.data, {
    value: transactionRequest.value,
    gasPrice: await provider.getGasPrice(),
    gasLimit: transactionRequest.gasLimit,
  });
  const txReceipt = await tx.wait();

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink =
    "https://axelarscan.io/gmp/" + txReceipt.transactionHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Wait a few seconds before checking the status
  await new Promise((resolve) => setTimeout(resolve, 5000));

  // Retrieve the transaction's route status
  const getStatusParams = {
    transactionId: txReceipt.transactionHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: polygonId,
  };
  const status = await getStatus(getStatusParams);

  // Display the route status
  console.log(`Route status: ${status.squidTransactionStatus}`);
})();
```


# Get Route Status

### API Endpoint

```
GET https://v2.api.squidrouter.com/v2/status
```

### Code Example

```javascript
// Function to get the status of the transaction using Squid API
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
        quoteId: params.quoteId, // Required for Coral V2 transactions
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};
```

### Request Parameters

| Parameter       | Type   | Required                    | Description                                                                                                                                   |
| --------------- | ------ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `transactionId` | string | Yes                         | Transaction hash from the transaction submitted to the source chain                                                                           |
| `fromChainId`   | string | Yes                         | The source chain ID                                                                                                                           |
| `toChainId`     | string | Yes                         | The destination chain ID                                                                                                                      |
| `requestId`     | string | No                          | The request ID (legacy parameter)                                                                                                             |
| `quoteId`       | string | Yes (required for Coral V2) | The quote ID from the route response. Required for Coral V2 status tracking. Also enables volume and token activity sharing with integrators. |

#### Getting Quote ID from Route Response

The `quoteId` can be found at the top level of the route response:

```json
{
    "route": {
        "quoteId": "6f388be5205ee044cd7fd5047a4ce72e"
    }
}
```

### Request Headers

| Header            | Description                                                                                                                 |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `x-integrator-id` | Integrator ID for Squid to keep track of partners, complete the [form](https://form.typeform.com/to/cqFtqSvX) to acquire it |

### Response Parameters

| Parameter                   | Type    | Description                                                                                |
| --------------------------- | ------- | ------------------------------------------------------------------------------------------ |
| `id`                        | string  | Transaction hash                                                                           |
| `status`                    | string  | Transaction status from Axelarscan (see status values below)                               |
| `gasStatus`                 | string  | Transaction gas status returned from Axelarscan (see gas status values below)              |
| `isGMPTransaction`          | boolean | Returns `true` if the transaction is a GMP transaction, `false` if it is a bridge transfer |
| `squidTransactionStatus`    | string  | Simplified status for transaction (see squid transaction status values below)              |
| `axelarTransactionUrl`      | string  | URL to view the transaction on Axelarscan                                                  |
| `fromChain.transactionId`   | string  | Transaction hash on the source chain                                                       |
| `fromChain.blockNumber`     | number  | Transaction block number on source chain                                                   |
| `fromChain.callEventStatus` | string  | SquidMulticall contract event status relating to `transactionId` on source chain           |
| `fromChain.callEventLog`    | array   | SquidMulticall event logs for `transactionId` on source chain                              |
| `fromChain.chainData`       | object  | Complete chain configuration and contract addresses for source chain                       |
| `fromChain.transactionUrl`  | string  | Block explorer URL for the source chain transaction                                        |
| `toChain.transactionId`     | string  | Transaction hash on destination chain                                                      |
| `toChain.blockNumber`       | number  | Transaction block number on destination chain                                              |
| `toChain.callEventStatus`   | string  | Latest SquidMulticall event status on destination chain                                    |
| `toChain.callEventLog`      | array   | SquidMulticall event logs on destination chain                                             |
| `toChain.chainData`         | object  | Complete chain configuration and contract addresses for destination chain                  |
| `toChain.transactionUrl`    | string  | Block explorer URL for the destination chain transaction                                   |
| `timeSpent`                 | object  | Timing breakdown showing time spent in different phases of the transaction                 |
| `error`                     | object  | Error returned from Axelarscan GMP API                                                     |
| `requestId`                 | string  | The request ID associated with the transaction                                             |
| `integratorId`              | string  | The integrator ID associated with the transaction                                          |

#### Squid Transaction Status Values

Simplified status for transaction. There are 6 possible states:

```typescript
{
  SUCCESS = "success",
  NEEDS_GAS = "needs_gas", 
  ONGOING = "ongoing",
  PARTIAL_SUCCESS = "partial_success",
  NOT_FOUND = "not_found",
  REFUND_STATUS = "refund"
}
```

**SUCCESS**

This indicates the transaction has completed on all chains. Whether a single chain, 2 chain or 3 chain call, the swap, stake, NFT purchase, bridge etc. has completed without any reversions and the user has received the intended funds.

**NEEDS\_GAS**

This state is specific for Axelar transactions. If the gas price has spiked on the destination chain and execution cannot complete, Squid will return this status. The best user flow in this case is to send the user to Axelarscan to view the paused transaction.

**ONGOING**

There is nothing wrong, nothing to do, just relax and wait. The transaction should have an `estimatedRouteDuration` in seconds that you can read from the `/route` response. We generally recommend contacting support after either 15 minutes has passed, or double the `estimatedRouteDuration`, whichever is larger.

**PARTIAL\_SUCCESS**

This status indicates that the transaction has completed some of its steps. Currently, there is only one case that could cause this state. In the future there will be many, but we will provide more metadata around the `PARTIAL_SUCCESS`. For now, this is what has happened:

* The source chain transaction successfully executed, along with any swaps or contract calls.
* The destination chain transaction has executed, but reverted during execution. This is usually due to slippage on volatile assets, but if you are trying to buy an NFT or do some cross-chain staking, then it could indicate that the custom hook had a failure.

If there is a partial success, the user will have received the bridged token in their wallet on the destination chain. In most cases this is axlUSDC.

**NOT\_FOUND**

The Squid API cannot find an on-chain record of the transaction. This is usually due to our various services or service providers not having indexed the completed transaction. This state is often returned for 5-10 seconds after the transaction was executed, while chain indexing occurs.

This should not persist after maximum a few minutes (some chains such as Filecoin take a very long time to index, and for block inclusion). If it does, then get in touch with us on Discord.

**REFUND\_STATUS**

This status is specific to failed Coral routes. When a Coral transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Coral routes when passing the user's address as the `fromAddress`.

**How Coral refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Coral, or a smart contract like Multicall)
* When refunded, funds are sent to the `order.fromAddress` which is encoded to the user, not the caller
* The `fromAddress` from the route request is used as the `order.fromAddress` for refunds
* This ensures that even if the transaction was initiated through a smart contract, the refund goes to the actual user

### Example Response

```json
{
    "id": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
    "status": "success",
    "gasStatus": "",
    "isGMPTransaction": false,
    "axelarTransactionUrl": "",
    "fromChain": {
        "transactionId": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
        "blockNumber": "339763809",
        "callEventStatus": "",
        "callEventLog": [],
        "chainData": {
            "id": "42161",
            "chainId": "42161",
            "networkIdentifier": "arbitrum",
            "chainName": "Chain 42161",
            "axelarChainName": "Arbitrum",
            "type": "evm",
            "networkName": "Arbitrum",
            "nativeCurrency": {
                "name": "Arbitrum",
                "symbol": "ETH",
                "decimals": 18,
                "icon": "https://raw.githubusercontent.com/axelarnetwork/axelar-docs/main/public/images/chains/arbitrum.svg"
            },
            "chainIconURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/arbitrum.webp",
            "blockExplorerUrls": [
                "https://arbiscan.io/"
            ],
            "swapAmountForGas": "2000000",
            "sameChainSwapsSupported": true,
            "compliance": {
                "trmIdentifier": "arbitrum"
            },
            "boostSupported": true,
            "enableBoostByDefault": true,
            "rpcList": [
                "https://arb1.arbitrum.io/rpc"
            ],
            "visible": true,
            "chainNativeContracts": {
                "wrappedNativeToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
                "ensRegistry": "",
                "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
                "usdcToken": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8"
            },
            "feeCurrencies": [],
            "currencies": [],
            "features": []
        },
        "transactionUrl": "https://arbiscan.io/tx/0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d"
    },
    "toChain": {
        "transactionId": "0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186",
        "blockNumber": "30616439",
        "callEventStatus": "",
        "callEventLog": [],
        "chainData": {
            "id": "8453",
            "chainId": "8453",
            "networkIdentifier": "base",
            "chainName": "Chain 8453",
            "axelarChainName": "base",
            "type": "evm",
            "networkName": "Base",
            "nativeCurrency": {
                "name": "Base",
                "symbol": "ETH",
                "decimals": 18,
                "icon": "https://raw.githubusercontent.com/axelarnetwork/axelar-docs/main/public/images/chains/base.svg"
            },
            "chainIconURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/chains/base.svg",
            "blockExplorerUrls": [
                "https://basescan.org/"
            ],
            "swapAmountForGas": "2000000",
            "sameChainSwapsSupported": true,
            "boostSupported": true,
            "enableBoostByDefault": true,
            "rpcList": [
                "https://developer-access-mainnet.base.org"
            ],
            "visible": true,
            "chainNativeContracts": {
                "wrappedNativeToken": "0x4200000000000000000000000000000000000006",
                "ensRegistry": "",
                "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
                "usdcToken": "0x66627F389ae46D881773B7131139b2411980E09E"
            },
            "feeCurrencies": [],
            "currencies": [],
            "features": [],
            "axelarFeeMultiplier": 150
        },
        "transactionUrl": "https://basescan.org/tx/0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186"
    },
    "timeSpent": {
        "total": 2
    },
    "routeStatus": [
        {
            "chainId": "42161",
            "txHash": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
            "status": "success",
            "action": "send"
        },
        {
            "chainId": "8453",
            "txHash": "0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186",
            "status": "success",
            "action": "call"
        }
    ],
    "squidTransactionStatus": "success"
}
```


# SDK

## Overview

The SDK is ideal for integrating cross-chain swaps, bridges, and deposits into applications that utilize JavaScript or Typescript, while the API can be used for similar purposes in a more language-agnostic manner.

## Types

We recommend using the types from our npm package. If you are using our API without our SDK, you can find the types inside `node_modules/@0xsquid/sdk/dist/types/index.d.ts` after [Broken mention](broken://pages/pQzBnlnLhbC4MQnwWa7c)

```typescript
import { Token, ChainData } from '@0xsquid/sdk/dist/types'
```

## **Installing the SDK**

### From the terminal, install [our SDK](https://www.npmjs.com/package/@0xsquid/sdk)

```bash
npm install --save @0xsquid/sdk@2.12.0 # or higher
```

### Now in your typescript file

```typescript
import { Squid } from "@0xsquid/sdk"; // Import Squid SDK

// Initialize the Squid client with the base URL and integrator ID
const getSDK = (): Squid => {
  const squid = new Squid({
    baseUrl: "https://v2.api.squidrouter.com",
    integratorId: integratorId,
  });
  return squid;
};

```

Next, explore the first [**Swap & Bridging with the Squid SDK** ](/old-v2-documentation-deprecated/api/swap-and-bridge-example)to understand the fundamentals.


# Cross-chain Swap Example

Here is an example of a cross-chain swap that you can run out of the box. Head to our [examples repo](https://github.com/0xsquid/examples/tree/main/V2/sdk/evmToEVMSwap), download the folder and run:

```
yarn install
```

Create a .env file and replace the values shared in the .env.example file. Then run

```
yarn start
```

This will run the index.ts below

```typescript

import { Squid } from "@0xsquid/sdk"; // Import Squid SDK
import { ethers } from "ethers"; // Import ethers v6
import * as dotenv from "dotenv"; // Import dotenv for environment variables
dotenv.config(); // Load environment variables from .env file

// Retrieve environment variables
const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;
const FROM_CHAIN_RPC: string = process.env.FROM_CHAIN_RPC_ENDPOINT!;

if (!privateKey || !integratorId || !FROM_CHAIN_RPC) {
  console.error("Missing environment variables. Ensure PRIVATE_KEY, INTEGRATOR_ID, and FROM_CHAIN_RPC_ENDPOINT are set.");
  process.exit(1);
}

// Define chain and token addresses
const fromChainId = "56"; // BNB chain ID
const toChainId = "42161"; // Arbitrum chain ID
const fromToken = "0x55d398326f99059fF775485246999027B3197955"; // USDT token address on BNB
const toToken = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"; // USDC token address on Arbitrum

// Define the amount to be sent (in smallest unit, e.g., wei for Ethereum)
const amount = "1000000000000000"; 

// Set up JSON RPC provider and signer using the private key and RPC URL
// Create provider with the full URL
const provider = new ethers.JsonRpcProvider(FROM_CHAIN_RPC);
// Create wallet with the private key
const signer = new ethers.Wallet(privateKey, provider);

// Initialize the Squid client with the base URL and integrator ID
const getSDK = (): Squid => {
  const squid = new Squid({
    baseUrl: "https://v2.api.squidrouter.com",
    integratorId: integratorId,
  });
  return squid;
};

// Function to approve the transactionRequest.target to spend fromAmount of fromToken
const approveSpending = async (transactionRequestTarget: string, fromToken: string, fromAmount: string) => {
  const erc20Abi = [
    "function approve(address spender, uint256 amount) public returns (bool)"
  ];
  const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
  try {
    const tx = await tokenContract.approve(transactionRequestTarget, fromAmount);
    await tx.wait();
    console.log(`Approved ${fromAmount} tokens for ${transactionRequestTarget}`);
  } catch (error) {
    console.error('Approval failed:', error);
    throw error;
  }
};

// Main function
(async () => {
  // Initialize Squid SDK
  const squid = getSDK();
  await squid.init();
  console.log("Initialized Squid SDK");

  // Set up parameters for swapping tokens
  const params = {
    fromAddress: await signer.getAddress(),
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: await signer.getAddress()
  };

  console.log("Parameters:", params); // Printing the parameters for QA

  // Get the swap route using Squid SDK
  const { route, requestId } = await squid.getRoute(params);
  const quoteId = route.quoteId; // Save quoteId — required for Coral V2 status tracking
  console.log("Calculated route:", route.estimate.toAmount);
  console.log("quoteId:", quoteId);

  // Get the transaction request from route
  if (!route.transactionRequest) {
    console.error("No transaction request in route");
    process.exit(1);
  }

  // For SquidData objects, we need to check what type it is and extract the target
  let target: string;
  if ('target' in route.transactionRequest) {
    target = route.transactionRequest.target;
  } else {
    console.error("Cannot determine target address from transaction request");
    console.log("Transaction request:", route.transactionRequest);
    process.exit(1);
  }

  // Approve the target to spend fromAmount of fromToken
  await approveSpending(target, fromToken, amount);

  // Execute the swap transaction
  const txResponse = await squid.executeRoute({
    signer: signer as any, // Cast to any to bypass type checking issues
    route,
  });

  // Handle the transaction response - could be an ethers v6 TransactionResponse or something else
  let txHash: string = 'unknown';
  
  if (txResponse && typeof txResponse === 'object') {
    if ('hash' in txResponse) {
      // This is an ethers TransactionResponse
      txHash = txResponse.hash as string;
      await (txResponse as any).wait?.(); // Wait for the transaction to be mined if possible
    } else if ('transactionHash' in txResponse) {
      // This might be a v5 style response or custom Squid format
      txHash = (txResponse as any).transactionHash as string;
    } else {
      // Fallback - try to find a hash property
      txHash = (txResponse as any).hash as string || 'unknown';
    }
  }

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink = "https://axelarscan.io/gmp/" + txHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Wait a few seconds before checking the status
  await new Promise((resolve) => setTimeout(resolve, 5000));

  // Parameters for checking the status of the transaction
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    integratorId: integratorId,
    quoteId: quoteId, // Required for Coral V2 transactions
  };

  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found"];
  const maxRetries = 10; // Maximum number of retries for status check
  let retryCount = 0;
  
  // Get the initial status
  let status = await squid.getStatus(getStatusParams);
  console.log(`Initial route status: ${status.squidTransactionStatus}`);

  // Loop to check the transaction status until it is completed or max retries are reached
  do {
    try {
      // Wait a few seconds before checking the status
      await new Promise((resolve) => setTimeout(resolve, 5000));

      // Retrieve the transaction's route status
      status = await squid.getStatus(getStatusParams);

      // Display the route status
      console.log(`Route status: ${status.squidTransactionStatus}`);

    } catch (error: unknown) {
      // Handle error if the transaction status is not found
      if (error instanceof Error && (error as any).response && (error as any).response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        continue;
      } else {
        throw error;
      }
    }

  } while (status && !completedStatuses.includes(status.squidTransactionStatus));

  // Wait for the transaction to be executed
  console.log("Swap transaction executed:", txHash);
})();
```


# Staking Example

This example walks you through how to implement the SDK to allow a wallet to swap from Binance to Arbitrum and lend on Radiant.

Download the full example [**here**](https://github.com/0xsquid/examples/tree/main/V2/sdk/swapEVMtoEVMAndLendPosthook)**.**

```typescript
// Import necessary libraries
import { ethers } from "ethers";
import { Squid } from "@0xsquid/sdk";
import { ChainType, EvmContractCall } from "@0xsquid/squid-types"; 

// Load environment variables from the .env file
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables from .env file
const privateKey: string = process.env.PRIVATE_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;
const FROM_CHAIN_RPC: string = process.env.RPC_ENDPOINT!;
const aaveArbitrumPoolAddress: string = "0x794a61358D6845594F94dc1DB02A252b5b4814aD"; // Aave v3 pool on Arbitrum
const usdcArbitrumAddress: string = "0xaf88d065e77c8cC2239327C5EDb3A432268e5831";

// Define chain and token addresses
const fromChainId = "56"; // Binance
const toChainId = "42161"; // Arbitrum
const fromToken = "0x55d398326f99059fF775485246999027B3197955"; // Define departing token

// Define amount to be sent
const amount = "100000000000000000";

// Set up JSON RPC provider and signer using the private key and RPC URL
const provider = new ethers.JsonRpcProvider(FROM_CHAIN_RPC);
const signer = new ethers.Wallet(privateKey, provider);

// Import erc20 contract ABI
import erc20Abi from "../abi/erc20Abi";

// Define Aave pool ABI (simplified for this example)
const aavePoolAbi = [
  "function supply(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external"
];

// Function to get Squid SDK instance
const getSDK = (): Squid => {
  const squid = new Squid({
    baseUrl: "https://v2.api.squidrouter.com",
    integratorId: integratorId,
  });
  return squid;
};

// Function to approve the transactionRequest.target to spend fromAmount of fromToken
const approveSpending = async (transactionRequestTarget: string, fromToken: string, fromAmount: string) => {
  const erc20Abi = [
    "function approve(address spender, uint256 amount) public returns (bool)"
  ];
  const tokenContract = new ethers.Contract(fromToken, erc20Abi, signer);
  try {
    const tx = await tokenContract.approve(transactionRequestTarget, fromAmount);
    await tx.wait();
    console.log(`Approved ${fromAmount} tokens for ${transactionRequestTarget}`);
  } catch (error) {
    console.error('Approval failed:', error);
    throw error;
  }
};


// Main function
(async () => {
  // Initialize Squid SDK
  const squid = getSDK();
  await squid.init();
  console.log("Initialized Squid SDK");

  // Creating Contract interfaces
  // Approve the Aave pool contract to spend the USDC
  const erc20Interface = new ethers.Interface(erc20Abi);
  const approvalData = erc20Interface.encodeFunctionData("approve", [
    aaveArbitrumPoolAddress,
    ethers.MaxUint256, // ethers v6 uses MaxUint256 directly on ethers
  ]);

  // Create contract interface and encode supply function for Aave lending pool
  const aavePoolInterface = new ethers.Interface(aavePoolAbi);
  
  const userAddress = await signer.getAddress();
  
  const supplyData = aavePoolInterface.encodeFunctionData(
    "supply",
    [
      usdcArbitrumAddress,
      "0", // Amount will be replaced with the full token balance
      userAddress,
      0, // referralCode
    ]
  );

  
  
  // Set up parameters for swapping tokens and depositing into Aave lending pool
  const params = {
    fromAddress: userAddress,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: usdcArbitrumAddress,
    toAddress: userAddress,
    quoteOnly: false,
    postHook: {
      chainType: ChainType.EVM,
      calls: [
        {
          chainType: ChainType.EVM, 
          callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
          target: usdcArbitrumAddress,
          value: "0", // this will be replaced by the full native balance of the multicall after the swap
          callData: approvalData,
          payload: {
            tokenAddress: usdcArbitrumAddress,
            inputPos: 1,
          },
          estimatedGas: "50000",
        } as EvmContractCall,
        {
          chainType: ChainType.EVM,
          callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
          target: aaveArbitrumPoolAddress,
          value: "0",
          callData: supplyData,
          payload: {
            tokenAddress: usdcArbitrumAddress,
            inputPos: 1,
          },
          estimatedGas: "200000",
        } as EvmContractCall,
      ],
      provider: "Aave",
      description: "Deposit to Aave on Arbitrum",
      logoURI: "https://app.aave.com/favicon.ico",
    },
  };
  

  console.log("Parameters:", params); // Printing the parameters for QA

  // Get the swap route using Squid SDK
  const { route, requestId } = await squid.getRoute(params);
  const quoteId = route.quoteId; // Save quoteId — required for Coral V2 status tracking
  console.log("Calculated route:", route.estimate.toAmount);
  console.log("quoteId:", quoteId);

  // Get the transaction request from route
  if (!route.transactionRequest) {
    console.error("No transaction request in route");
    process.exit(1);
  }

  // For SquidData objects, we need to check what type it is and extract the target
  let target: string;
  if ('target' in route.transactionRequest) {
    target = route.transactionRequest.target;
  } else {
    console.error("Cannot determine target address from transaction request");
    console.log("Transaction request:", route.transactionRequest);
    process.exit(1);
  }

  // Approve the target to spend fromAmount of fromToken
  await approveSpending(target, fromToken, amount);

  // Execute the swap transaction
  const txResponse = await squid.executeRoute({
    signer: signer as any, // Cast to any to bypass type checking issues
    route,
  });

  // Handle the transaction response - could be an ethers v6 TransactionResponse or something else
  let txHash: string = 'unknown';
  
  if (txResponse && typeof txResponse === 'object') {
    if ('hash' in txResponse) {
      // This is an ethers TransactionResponse
      txHash = txResponse.hash as string;
      await (txResponse as any).wait?.(); // Wait for the transaction to be mined if possible
    } else if ('transactionHash' in txResponse) {
      // This might be a v5 style response or custom Squid format
      txHash = (txResponse as any).transactionHash as string;
    } else {
      // Fallback - try to find a hash property
      txHash = (txResponse as any).hash as string || 'unknown';
    }
  }

  // Show the transaction receipt with Axelarscan link
  const axelarScanLink = "https://axelarscan.io/gmp/" + txHash;
  console.log(`Finished! Check Axelarscan for details: ${axelarScanLink}`);

  // Wait a few seconds before checking the status
  await new Promise((resolve) => setTimeout(resolve, 5000));

  // Parameters for checking the status of the transaction
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    integratorId: integratorId,
    quoteId: quoteId, // Required for Coral V2 transactions
  };

  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found"];
  const maxRetries = 10; // Maximum number of retries for status check
  let retryCount = 0;
  
  // Get the initial status
  let status = await squid.getStatus(getStatusParams);
  console.log(`Initial route status: ${status.squidTransactionStatus}`);

  // Loop to check the transaction status until it is completed or max retries are reached
  do {
    try {
      // Wait a few seconds before checking the status
      await new Promise((resolve) => setTimeout(resolve, 5000));

      // Retrieve the transaction's route status
      status = await squid.getStatus(getStatusParams);

      // Display the route status
      console.log(`Route status: ${status.squidTransactionStatus}`);

    } catch (error: unknown) {
      // Handle error if the transaction status is not found
      if (error instanceof Error && (error as any).response && (error as any).response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        continue;
      } else {
        throw error;
      }
    }

  } while (status && !completedStatuses.includes(status.squidTransactionStatus));

  // Wait for the transaction to be executed
  console.log("Swap transaction executed:", txHash);
})();

```


# Cross-chain NFT Purchase Example

This example walks you through how to implement the SDK to purchase an NFT on any chain.

Download the full example [**here**](https://github.com/0xsquid/examples/blob/main/V2/sdk/oldExamples/buyNftFromAnyChain/src/index.ts)**.**

```typescript
import { Squid } from "@0xsquid/sdk";
import { ethers } from "ethers";

// Environment
// add to a file named ".env" to prevent them being uploaded to github
import * as dotenv from "dotenv";
dotenv.config();
const avaxRpcEndpoint = process.env.AVAX_RPC_ENDPOINT;
const privateKey = process.env.PRIVATE_KEY;

// ABIs
import erc1155Abi from "../abi/erc1155Abi";
import erc20Abi from "../abi/erc20Abi";
import treasureMarketplaceAbi from "../abi/treasureMarketplaceAbi";

// Squid call types for multicall
const SquidCallType = {
  DEFAULT: 0,
  FULL_TOKEN_BALANCE: 1,
  FULL_NATIVE_BALANCE: 2,
  COLLECT_TOKEN_BALANCE: 3,
};

// addresses and IDs
const avalancheId = 43114;
const arbitrumId = 42161;
const nativeToken = "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE";
const squidMulticall = "0x4fd39C9E151e50580779bd04B1f7eCc310079fd3";
const magicToken = "0x539bdE0d7Dbd336b79148AA742883198BBF60342";
const treasureAddress = "0x09986b4e255b3c548041a30a2ee312fe176731c2"; // treasure contract
const moonrockNftAddress = "0xc5295c6a183f29b7c962df076819d44e0076860e";
const moonrockOwner = "0xa5c53eb116EC0CE355D8be38b0EB424ce520A4db";

// amount of AVAX to send (currently 0.05 AVAX)
const amount = "30000000000000000";

const getSDK = () => {
  const squid = new Squid({
    baseUrl: "https://v2.api.squidrouter.com",
    integratorId: process.env.INTEGRATOR_ID,
  });
  return squid;
};

(async () => {
  // set up your RPC provider and signer
  const provider = new ethers.JsonRpcProvider(avaxRpcEndpoint);
  const signer = new ethers.Wallet(privateKey, provider);
  console.log("Signer address: ", signer.address);

  // instantiate the SDK
  const squid = getSDK();
  // init the SDK
  await squid.init();
  console.log("Squid inited");

  // Generate the encoded data to approve the Treasure contract to spend Magic
  const erc20ContractInterface = new ethers.Interface(erc20Abi);
  const approveEncodeData = erc20ContractInterface.encodeFunctionData(
    "approve",
    [treasureAddress, "0"]
  );

  // Generate the encoded data to buy the NFT on Treasure
  // This example buys a MoonRock NFT on Treasure on mainnet
  // https://trove.treasure.lol/collection/smol-treasures/1
  const treasureMarketplaceInterface = new ethers.Interface(
    treasureMarketplaceAbi
  );
  const _buyItemParams = {
    nftAddress: moonrockNftAddress,
    tokenId: 1,
    owner: moonrockOwner,
    quantity: 1,
    maxPricePerItem: "990000000000000000",
    paymentToken: magicToken,
    usinEth: false,
  };
  const buyMoonRockNftEncodeData =
    treasureMarketplaceInterface.encodeFunctionData("buyItems", [
      [_buyItemParams],
    ]);

  // Generate the encoded data to transfer the NFT to signer's address
  const erc1155Interface = new ethers.Interface(erc1155Abi);
  const transferNftEncodeData = erc1155Interface.encodeFunctionData(
    "safeTransferFrom",
    [squidMulticall, signer.address, 1, 1, 0x00]
  );

  // Generate the encoded data to send any remaining Magic back to signer's address
  const transferMagicEncodeData = erc20ContractInterface.encodeFunctionData(
    "transfer",
    [signer.address, "0"]
  );

  const { route, requestId } = await squid.getRoute({
    toAddress: signer.address,
    fromChain: avalancheId,
    fromToken: nativeToken,
    fromAmount: amount,
    toChain: arbitrumId,
    toToken: magicToken,
    slippage: 1,   //optional, Squid will dynamically calculate if removed
    // enableExpress: false, // default is true on all chains except Ethereum
    postHook: [
      description: "Buy Milady 2039 on Ethereum"
      {
        callType: SquidCallType.FULL_TOKEN_BALANCE,
        target: magicToken,
        value: "0",
        callData: approveEncodeData,
        payload: {
          tokenAddress: magicToken,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
      {
        callType: SquidCallType.DEFAULT,
        target: treasureAddress,
        value: "0",
        callData: buyMoonRockNftEncodeData,
        payload: {
          tokenAddress: "1",
          inputPos: 1,
        },
        estimatedGas: "80000",
      },
      {
        callType: SquidCallType.DEFAULT,
        target: moonrockNftAddress,
        value: "0",
        callData: transferNftEncodeData,
        payload: {
          tokenAddress: "0x",
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
      {
        callType: SquidCallType.FULL_TOKEN_BALANCE, // transfer any remaining MAGIC to the user's account
        target: magicToken,
        value: "0",
        callData: transferMagicEncodeData,
        payload: {
          tokenAddress: magicToken,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
    ],
  });
  const quoteId = route.quoteId; // Save quoteId — required for Coral V2 status tracking
  console.log("quoteId:", quoteId);

  const tx = (await squid.executeRoute({
    signer,
    route,
  })) as unknown as ethers.TransactionResponse;
  const txReceipt = await tx.wait();

  const axelarScanLink = "https://axelarscan.io/gmp/" + txReceipt.hash;
  console.log(
    "Finished! Please check Axelarscan for more details: ",
    axelarScanLink,
    "\n"
  );

  console.log(
    "Track status via API call to: https://api.squidrouter.com/v1/status?transactionId=" +
      txReceipt.hash,
    "\n"
  );

  // It's best to wait a few seconds before checking the status
  await new Promise((resolve) => setTimeout(resolve, 5000));

  const status = await squid.getStatus({
    transactionId: txReceipt.hash,
    requestId: requestId,
    integratorId: process.env.INTEGRATOR_ID,
    quoteId: quoteId, // Required for Coral V2 transactions
  });

  console.log("Status: ", status);
})();
```


# Get Route Status

This method aims to provide the status of the transaction

## Get Route Status

Squid provides a status of cross-chain transactions. You can access this status using the `getStatus` method on our SDK.

You can also check completion of most cross chain transactions on Squid by copying the transaction hash into [SquidScan](https://scan.squidrouter.com/). Note, for some Cosmos transactions and others in the future this will not work.

### Usage

```typescript
const status = await squid.getStatus({
    transactionId,
    requestId,       // optional
    integratorId,    // optional
    quoteId,         // Required for Coral V2 transactions
    bridgeType,      // optional
})
```

### Request Parameters

| Parameter       | Type   | Required | Description                                                                                                                                   |
| --------------- | ------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `transactionId` | string | Yes      | The transaction hash                                                                                                                          |
| `quoteId`       | string | Yes      | The quote ID from the route response. Required for Coral V2 status tracking. Also enables volume and token activity sharing with integrators. |
| `requestId`     | string | No       | The request ID (legacy parameter)                                                                                                             |
| `integratorId`  | string | No       | Your integrator ID                                                                                                                            |
| `bridgeType`    | string | No       | The bridge type (e.g., `chainflip`, `chainflipmultihop` for BTC/SOL transactions)                                                             |

#### Getting Quote ID from Route Response

The `quoteId` can be found at the top level of the route response. Including this parameter in status requests will enable volume and specific token activity sharing with integrators in the near future:

```json
{
    "route": {
        "quoteId": "6f388be5205ee044cd7fd5047a4ce72e"
    }
}
```

### Understanding squidTransactionStatus

The most important response param is `squidTransactionStatus`. This param will tell you what to show the user. There are 6 possible states:

```typescript
{
  SUCCESS = "success",
  NEEDS_GAS = "needs_gas",
  ONGOING = "ongoing",
  PARTIAL_SUCCESS = "partial_success",
  NOT_FOUND = "not_found",
  REFUND = "refund"
}
```

#### SUCCESS

This indicates the transaction has completed on all chains. Whether a single chain, 2 chain or 3 chain call, the swap, stake, NFT purchase, bridge etc. has completed without any reversions and the user has received the intended funds.

#### NEEDS\_GAS

This state is specific for Axelar transactions. If the gas price has spiked on the destination chain and execution cannot complete, Squid will return this status. The best user flow in this case is to send the user to Axelarscan to view the paused transaction.

#### ONGOING

There is nothing wrong, nothing to do, just relax and wait. The transaction should have an `estimatedRouteDuration` in seconds that you can read from the `/route` response. We generally recommend contacting support after either 15 minutes has passed, or double the `estimatedRouteDuration`, whichever is larger.

#### PARTIAL\_SUCCESS

This status indicates that the transaction has completed some of its steps. Currently, there is only one case that could cause this state. In the future there will be many, but we will provide more metadata around the `PARTIAL_SUCCESS`. For now, this is what has happened:

* The source chain transaction successfully executed, along with any swaps or contract calls.
* The destination chain transaction has executed, but reverted during execution. This is usually due to slippage on volatile assets, but if you are trying to buy an NFT or do some cross-chain staking, then it could indicate that the custom hook had a failure.

If there is a partial success, the user will have received the bridged token in their wallet on the destination chain. In most cases this is axlUSDC.

#### NOT\_FOUND

The Squid API cannot find an on-chain record of the transaction. This is usually due to our various services or service providers not having indexed the completed transaction. This state is often returned for 5-10 seconds after the transaction was executed, while chain indexing occurs.

This should not persist after maximum a few minutes (some chains such as Filecoin take a very long time to index, and for block inclusion). If it does, then get in touch with us on Discord.

#### REFUND

This status is specific to failed Coral routes. When a Coral transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Coral routes when passing the user's address as the `fromAddress`.

**How Coral refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Coral, or a smart contract like Multicall)
* When refunded, funds are sent to the `order.fromAddress` which is encoded to the user, not the caller
* The `fromAddress` from the route request is used as the `order.fromAddress` for refunds
* This ensures that even if the transaction was initiated through a smart contract, the refund goes to the actual user

### How to Share Block Explorer Links

Generally, the best thing to do is to share `https://axelarscan.io/gmp/<txHash>` with a user.

With the caveat that if you are doing a transaction between two Cosmos chains, this link may not be correct. For now we simply recommend you always using this approach, we are upgrading our status capability and the status endpoint will always return the correct block explorer link to share.

### Response Parameters

The response includes detailed information about both source and destination chains, transaction URLs, timing data, and the current status.

#### Example Response

```json
{
    "id": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
    "status": "success",
    "gasStatus": "",
    "isGMPTransaction": false,
    "axelarTransactionUrl": "",
    "fromChain": {
        "transactionId": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
        "blockNumber": "339763809",
        "callEventStatus": "",
        "callEventLog": [],
        "chainData": {
            "id": "42161",
            "chainId": "42161",
            "networkIdentifier": "arbitrum",
            "chainName": "Chain 42161",
            "axelarChainName": "Arbitrum",
            "type": "evm",
            "networkName": "Arbitrum",
            "nativeCurrency": {
                "name": "Arbitrum",
                "symbol": "ETH",
                "decimals": 18,
                "icon": "https://raw.githubusercontent.com/axelarnetwork/axelar-docs/main/public/images/chains/arbitrum.svg"
            },
            "chainIconURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/webp128/chains/arbitrum.webp",
            "blockExplorerUrls": [
                "https://arbiscan.io/"
            ],
            "swapAmountForGas": "2000000",
            "sameChainSwapsSupported": true,
            "compliance": {
                "trmIdentifier": "arbitrum"
            },
            "boostSupported": true,
            "enableBoostByDefault": true,
            "rpcList": [
                "https://arb1.arbitrum.io/rpc"
            ],
            "visible": true,
            "chainNativeContracts": {
                "wrappedNativeToken": "0x82af49447d8a07e3bd95bd0d56f35241523fbab1",
                "ensRegistry": "",
                "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
                "usdcToken": "0xff970a61a04b1ca14834a43f5de4533ebddb5cc8"
            },
            "feeCurrencies": [],
            "currencies": [],
            "features": []
        },
        "transactionUrl": "https://arbiscan.io/tx/0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d"
    },
    "toChain": {
        "transactionId": "0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186",
        "blockNumber": "30616439",
        "callEventStatus": "",
        "callEventLog": [],
        "chainData": {
            "id": "8453",
            "chainId": "8453",
            "networkIdentifier": "base",
            "chainName": "Chain 8453",
            "axelarChainName": "base",
            "type": "evm",
            "networkName": "Base",
            "nativeCurrency": {
                "name": "Base",
                "symbol": "ETH",
                "decimals": 18,
                "icon": "https://raw.githubusercontent.com/axelarnetwork/axelar-docs/main/public/images/chains/base.svg"
            },
            "chainIconURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/chains/base.svg",
            "blockExplorerUrls": [
                "https://basescan.org/"
            ],
            "swapAmountForGas": "2000000",
            "sameChainSwapsSupported": true,
            "boostSupported": true,
            "enableBoostByDefault": true,
            "rpcList": [
                "https://developer-access-mainnet.base.org"
            ],
            "visible": true,
            "chainNativeContracts": {
                "wrappedNativeToken": "0x4200000000000000000000000000000000000006",
                "ensRegistry": "",
                "multicall": "0xcA11bde05977b3631167028862bE2a173976CA11",
                "usdcToken": "0x66627F389ae46D881773B7131139b2411980E09E"
            },
            "feeCurrencies": [],
            "currencies": [],
            "features": [],
            "axelarFeeMultiplier": 150
        },
        "transactionUrl": "https://basescan.org/tx/0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186"
    },
    "timeSpent": {
        "total": 2
    },
    "routeStatus": [
        {
            "chainId": "42161",
            "txHash": "0x7591aa38d646ac26b57f7235836cb7e7b63a32534bdd2e5dcecf06136744a94d",
            "status": "success",
            "action": "send"
        },
        {
            "chainId": "8453",
            "txHash": "0x4579e4df67994f4b1790d51c1586cbe79048dafd9c69467de1ecc887b4a25186",
            "status": "success",
            "action": "call"
        }
    ],
    "squidTransactionStatus": "success"
}
```


# Key Concepts

## Overview

These concepts are functionalities that persist throughout Squid's Widget, API, and SDK that enable a seamless cross-chain experience for both users and developer. Please read through each feature to understand how they are implemented across Squid

## Squid Functionality

The functionality of the Squid boils down to **3 main functionalities**:

1. [**Route Requests**](/old-v2-documentation-deprecated/key-concepts/get-a-route)**(Fetching a Route):** Calculating the most optimized path from one asset to another.
2. [**Route Execution**](/old-v2-documentation-deprecated/key-concepts/execute-the-route)**:** The submission and execution of that path on chain.
3. [**Transaction Status**](/old-v2-documentation-deprecated/key-concepts/track-status)**:** The validation that the transaction has been completed.

There are **3 advanced functionalities** enhance Squid's API capabilities:

1. [**Transaction Hooks**](https://docs.squidrouter.com/) **(Pre/Post):** Allow transactions to be prepended(prehook) or appended(posthook) to asset transfers for a user. Think unstaking then transferring an asset or transfering an asset across chain then staking.
2. [**Boost:** ](/old-v2-documentation-deprecated/key-concepts/boost)Squids novel boost functionality allows cross-chain transactions to be settled in less than 20seconds by using an intent-model, a smart contract overlay which allows a provider to optimistically fulfill a transaction.
3. [**Collecting Fees**](/old-v2-documentation-deprecated/key-concepts/collect-fees-1)**:** Always integrators to collect fees associated with transactions. Note, this function is currently not available for v2 yet.

#### **A Note On Up-Time**

Squid aims for 100% up-time with multiple guardrails in place to prevent unintended downtime. If you believe Squid may be experiencing downtime you can check our [status page ](https://status.v2.api.squidrouter.com)to see if there are any outages.


# Squid Aggregator

The Squid Aggregator is the routing layer that connects users to the best cross-chain execution paths across the entire crypto ecosystem.

Instead of relying on a single bridge or liquidity source, Squid indexes multiple interoperability protocols, liquidity networks, and settlement systems. When a user submits an action, Squid determines the best route across these services to execute it quickly, securely, and efficiently.

Think of it as the connectivity layer of crypto.

Just like internet routers decide how packets move across networks, the Squid Aggregator decides how value moves across chains.

This architecture allows Squid to support swaps, contract calls, and complex cross-chain actions while abstracting away the complexity of fragmented infrastructure.

## Widget


# Squid Intents

Squid’s intent-based execution protocol designed for fast, solver-driven cross-chain settlement.

**What it enables**

* Intent-based swaps
* Solver auctions for optimal execution
* TEE-verified settlement
* Support for EVM and non-EVM chains


# Cosmos

Access liquidity and assets across the Cosmos ecosystem through IBC-connected chains.

**What it enables**

* Native Cosmos asset transfers
* IBC interoperability
* Access to Cosmos ecosystem liquidity


# CCTP

Circle’s **Cross-Chain Transfer Protocol** for native USDC transfers across supported chains.

**What it enables**

* Native USDC bridging
* Burn-and-mint settlement
* Reduced bridge risk


# Chainflip

A decentralized cross-chain liquidity protocol designed for native asset swaps.

**What it enables**

* Native asset swaps across chains
* BTC, ETH, and other non-EVM assets
* Decentralized liquidity routing


# Axelar

A decentralized interoperability network providing cross-chain messaging and execution.

**What it enables**

* General Message Passing (GMP)
* Cross-chain contract execution
* Access to all Axelar-connected ecosystems


# Layer Zero

A cross-chain messaging protocol designed to enable applications to communicate across multiple blockchains.

**What it enables**

* Cross-chain messaging between applications
* Omnichain application development
* Secure communication between supported chains


# Route Request Parameters

Building with Squid, fundamentally starts with requesting a route.

The `getRoute` type is used to define the parameters required for bridging assets between different blockchain networks.

```typescript


const params = {
  fromChain: number | string; //the chainID assets are being bridged FROM
  toChain: number | string; //the chainID assets are being bridged TO
  fromToken: string;  //the asset address being swapped FROM, "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" for native assets
  toToken: string;  // The asset address being swapped TO, "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE" for native assets
  fromAmount: string; // The unadjusted decimal amount of assets to send. Mutually exclusive with toAmount.
  toAmount: string; // The unadjusted decimal amount of assets to receive (exact output). Mutually exclusive with fromAmount. Requires ExactOutputRouting feature flag.
  fromAddress: string; // The address FROM which assets are being sent to be bridged
  toAddress: string; // The address TO which bridged assets will be sent to
  slippage: number; //OPTIONAL, If set it determines the max slippage across the route (0.01-99.99) 1 = 1% slippage.
  quoteOnly: boolean; //OPTIONAL, If true, returns only a quote for the route. Omits transaction data needed for execution. Defaults to false
  fallbackAddresses?:{ 
    //For Cosmos routes where either the source or destination chains are not of coinType 118, the SDK necessitates an additional argument. 
    ///This argument is fallbackAddresses, which is an array of objects containing an address and its associated coin type.
    //See more here
    coinType: number;
    address: string;
  };
};

```

## Parameter Summaries

| Parameter             | Type                      | Required                         | Description                                                                                                                                                                                                                             |
| --------------------- | ------------------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fromChain`           | `number \| string`        | Yes                              | The chain ID of the network from which assets are being bridged.                                                                                                                                                                        |
| `toChain`             | `number \| string`        | Yes                              | The chain ID of the network to which assets are being bridged.                                                                                                                                                                          |
| `fromToken`           | `string`                  | Yes                              | The address of the asset being swapped from. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for native assets.                                                                                                                        |
| `toToken`             | `string`                  | Yes                              | The address of the asset being swapped to. Use `0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE` for native assets.                                                                                                                          |
| `fromAmount`          | `string`                  | One of `fromAmount` / `toAmount` | The unadjusted decimal amount of assets to send. Mutually exclusive with `toAmount`.                                                                                                                                                    |
| `toAmount`            | `string`                  | One of `fromAmount` / `toAmount` | The unadjusted decimal amount of assets to receive (exact output). The system calculates the required `fromAmount`. Requires `ExactOutputRouting` feature flag. See [Exact Output](/api-and-sdk-integration/key-concepts/exact-output). |
| `fromAddress`         | `string`                  | Yes                              | The address from which assets are being sent for bridging.                                                                                                                                                                              |
| `toAddress`           | `string`                  | Yes                              | The address to which bridged assets will be sent.                                                                                                                                                                                       |
| `slippage`            | `number`                  | No                               | Maximum allowable slippage across the route (0.01–99.99). A value of 1 = 1% slippage.                                                                                                                                                   |
| `quoteOnly`           | `boolean`                 | No                               | If true, returns only a quote without transaction data. Defaults to false.                                                                                                                                                              |
| `customContractCalls` | `ContractCall[]`          | No                               | Custom contract calls to be included in the route.                                                                                                                                                                                      |
| `fallbackAddresses`   | `{ coinType, address }[]` | No                               | For Cosmos routes where source or destination chains are not coinType 118.                                                                                                                                                              |
| `bypassGuardrails`    | `boolean`                 | No                               | Waives Squid's slippage guardrails. **If set to true, the integrator is liable for any loss of funds during the route.**                                                                                                                |


# Exact Output (toAmount)

## Overview

By default, Squid routes use **exact input** — you specify how much to send (`fromAmount`) and receive the best available output. With **exact output**, you specify how much you want to receive (`toAmount`) and the system calculates the required input amount.

This lets users say "I want to receive exactly X tokens" instead of "I want to send exactly X tokens."

{% hint style="info" %}
Exact output requires the `ExactOutputRouting` feature flag. Contact the Squid team to enable it for your integrator ID.
{% endhint %}

***

## Usage

Specify `toAmount` instead of `fromAmount` in your route request. Exactly one must be provided.

```json
// Forward (existing) — specify how much to send
{
  "fromAmount": "1000000000000000000",
  "fromToken": "...",
  "toToken": "..."
}

// Exact output — specify how much to receive
{
  "toAmount": "1000000",
  "fromToken": "...",
  "toToken": "..."
}
```

The response will include a calculated `fromAmount` representing how much input is needed to receive exactly `toAmount`. The `toAmountMin` will equal the `toAmount` — the output is guaranteed.

***

## Slippage

Slippage works in reverse compared to forward mode:

|            | Forward (fromAmount)         | Exact Output (toAmount)                   |
| ---------- | ---------------------------- | ----------------------------------------- |
| **Output** | May receive less than quoted | **Guaranteed** — `toAmountMin = toAmount` |
| **Input**  | Fixed at `fromAmount`        | May need to send slightly more            |

In exact output mode, slippage is applied to the **input** side. You may need to provide up to `fromAmount × (1 + slippage)` as input. Any unused input tokens are automatically returned to your address.

***

## Supported Route Types

| Route Type                                                  | Supported |
| ----------------------------------------------------------- | --------- |
| EVM single-chain swaps                                      | ✅         |
| EVM-to-EVM cross-chain (Coral V2)                           | ✅         |
| All chains accessible via Coral V2                          | ✅         |
| Routes with post-hooks                                      | ✅         |
| Routes with pre-hooks                                       | ❌         |
| Traditional bridge (Axelar GMP, Chainflip, ITS, Noble CCTP) | ❌         |
| Cosmos routes (Osmosis, Astroport)                          | ❌         |
| Solana single-chain (Jupiter)                               | ❌         |

***

## Limitations

* **Feature flag required** — `ExactOutputRouting` must be enabled for your integrator ID.
* **No pre-hooks** — Pre-hooks are not supported because the input amount is unknown at pre-hook execution time. Post-hooks work normally.
* **Coral V2 only for cross-chain** — Traditional bridge protocols are not supported for cross-chain exact output routes.
* **Some DEXes unsupported** — Paths through Curve, KyberSwap Elastic, Osmosis, Astroport, Printr, or Saddle will fail in exact output mode.


# Get a route

{% hint style="info" %}
We recommend getting a new route or quote every 20 seconds to refresh prices.
{% endhint %}

{% tabs %}
{% tab title="SDK" %}

```typescript
// Set up parameters for swapping tokens and depositing into Radiant lending pool
const params = {
  fromAddress: signer.address,
  fromChain: arbitrumId,
  fromToken: usdcArbitrumAddress,
  fromAmount: amount,
  toChain: polygonId,
  toToken: nativeToken,
  toAddress: signer.address,
  slippage: 1,
  quoteOnly: false,
};

// Get the swap route using Squid SDK
const { route, requestId } = await squid!.getRoute(params);

```

You can then explore the route response. This includes all the information on your quote `route.estimate` and all the data needed to generate a transaction `route.transactionRequest`.
{% endtab %}

{% tab title="API" %}

```typescript
// Function to get the optimal route for the swap using Squid API
const getRoute = async (params: any) => {
  try {
    const result = await axios.post(
      "https://v2.api.squidrouter.com/v2/route",
      params,
      {
        headers: {
          "x-integrator-id": integratorId,
          "Content-Type": "application/json",
        },
      }
    );
    const requestId = result.headers["x-request-id"]; // Retrieve request ID from response headers
    return { data: result.data, requestId: requestId };
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};

// Get the swap route using Squid API
const routeResult = await getRoute(params);
const route = routeResult.data.route;
const requestId = routeResult.requestId;
console.log("Calculated route:", route);
console.log("requestId:", requestId);
```

{% endtab %}

{% tab title="Widgets" %}
All Squid widgets will get a route when the user can entered all the necessary parameters.

Widgets refresh quotes every 20 seconds.
{% endtab %}
{% endtabs %}


# Execute the route

{% tabs %}
{% tab title="SDK" %}

```typescript
//   Execute the swap and deposit transaction
  const tx = (await squid.executeRoute({
    signer,
    route,
  })) as unknown as ethers.providers.TransactionResponse;
  const txReceipt = await tx.wait();
```

If you want to execute yourself, manually. You can get all the data needed for execution from `route.transactionRequest` . Including calldata, target address, value to send and gas recommendations.
{% endtab %}

{% tab title="API" %}

```typescript
const transactionRequest = route.transactionRequest;

  // Execute the swap transaction
  const contract = new ethers.Contract(
    transactionRequest.targetAddress,
    [],
    signer
  );

  const tx = await contract.send(transactionRequest.data, {
    value: transactionRequest.value,
    gasPrice: await provider.getGasPrice(),
    gasLimit: transactionRequest.gasLimit,
  });
  const txReceipt = await tx.wait();
```

{% endtab %}
{% endtabs %}


# Transaction Types

When requesting a route, the API returns a `transactionType` field that determines how the transaction should be constructed and submitted on-chain. The type depends on the source chain and whether the route involves DEX swaps.

***

## `DEPOSIT_ADDRESS_CALLDATA`

* **Source chains:** All EVMs (except Hedera), XRPL, Solana
* **Conditions:** Direct route (no DEX swaps)
* **Example routes:** Ethereum:USDC → Base:ETH, Solana:SOL → Arbitrum:USDC, XRPL:RLUSD → XRPL:XRP

**Code examples:**

| Route         | API                                                                                           | SDK                                                                                           |
| ------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| EVM → EVM     | [evmToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/api/evmToEVMSwap)             | [evmToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/evmToEVMSwap)             |
| Solana → EVM  | [solanaToEVM\_Swap](https://github.com/0xsquid/examples/tree/main/V2/api/solanaToEVM_Swap)    | —                                                                                             |
| XRPL → EVM    | [xrplToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/api/xrplToArbitrumSwap) | [xrplToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/xrplToArbitrumSwap) |
| EVM → XRPL    | [baseToXrplSwap](https://github.com/0xsquid/examples/tree/main/V2/api/baseToXrplSwap)         | [baseToXrplSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/baseToXrplSwap)         |
| Stellar → EVM | [stellarToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/api/stellarToEVMSwap)     | [stellarToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/stellarToEVMSwap)     |

***

## `DEPOSIT_ADDRESS_WITH_SIGNATURE`

* **Source chains:** Hedera
* **Conditions:** Direct route (no DEX swaps)
* **Example routes:** Hedera:HBAR → Arbitrum:USDC, Hedera:USDC → Arbitrum:USDC

**Code examples:**

| Route        | API                                                                                               | SDK                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Hedera → EVM | [hederaToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/api/hederaToArbitrumSwap) | [hederaToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/hederaToArbitrumSwap) |

***

## `ON_CHAIN_EXECUTION_WITH_SIGNATURE`

* **Source chains:** Hedera
* **Conditions:** Pre-hook (DEX swap) + Coral step
* **Example route:** Hedera:SAUCE → Arbitrum:USDC

**Code examples:**

| Route        | API                                                                                               | SDK                                                                                               |
| ------------ | ------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| Hedera → EVM | [hederaToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/api/hederaToArbitrumSwap) | [hederaToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/hederaToArbitrumSwap) |

***

## `ON_CHAIN_EXECUTION`

* **Source chains:** All EVMs (except Hedera), Cosmos
* **Conditions:** DEX swap as first action (Single-chain DEX swap, Pre-hook (DEX swap) + Coral step, DEX swap + Axelar bridge step)
* **Example routes:** Arbitrum:USDC → Arbitrum:ETH, Arbitrum:USDT → Base:ETH, Osmosis:USDC → Base:USDC

**Code examples:**

| Route                    | API                                                                                             | SDK                                                                                     |
| ------------------------ | ----------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| EVM pre-hook → EVM       | [evmPrehooktoEVM](https://github.com/0xsquid/examples/tree/main/V2/api/evmPrehooktoEVM)         | [evmPrehooktoEVM](https://github.com/0xsquid/examples/tree/main/V2/sdk/evmPrehooktoEVM) |
| Cosmos → EVM             | [cosmostoEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/api/cosmostoEVMSwap)         | —                                                                                       |
| Cosmos → EVM (post-hook) | [CosmostoEVMPostHook](https://github.com/0xsquid/examples/tree/main/V2/api/CosmostoEVMPostHook) | —                                                                                       |

***

## `CHAINFLIP_DEPOSIT_ADDRESS`

* **Source chains:** Solana, Bitcoin
* **Conditions:** Chainflip as first step
* **Example routes:** Bitcoin:BTC → Arbitrum:ETH, Solana:SOL → Arbitrum:ETH

**Code examples:**

| Route         | API                                                                                          | SDK |
| ------------- | -------------------------------------------------------------------------------------------- | --- |
| Bitcoin → EVM | [bitcoinToEVM\_Swap](https://github.com/0xsquid/examples/tree/main/V2/api/bitcoinToEVM_Swap) | —   |


# Hooks

Squid is a transaction bundler at heart. Squid's hooks enable users to sign one transaction and that transaction handles a series of contract interactions like staking, minting, or withdrawing and on either the source chain(the are executing the transaction from) or the destination chain(the chain that they are receiving bridged assets on).

<figure><img src="/files/1bJeAzJcnCu3E2flrCC3" alt=""><figcaption></figcaption></figure>

### **Key Benefits**

* **Automation:** Both preHooks and postHooks automate repetitive and necessary tasks, reducing manual intervention and the potential for errors.
* **Efficiency:** By handling preparatory and follow-up actions automatically, preHooks and postHooks streamline the transaction process, improving efficiency and user satisfaction.
* **Flexibility:** Developers can customize workflows to meet specific needs, such as integrating additional checks, swaps, or minting processes tailored to their applications.

### **Examples**

Squid's hooks are what makes it possible to do *anything* across chain.

* Buy or mint an NFT after a bridging assets
* Cross-chain swap then stake the assets
* Unstake assets then perform a cross-chain swap
* Performa cross-chain swap and then deposit into an exchange


# How do hooks work

Squid's hooks are powered by the [Squid Multicall contract.](https://docs.squidrouter.com/additional-resources/contracts) An arbitrary number of calls can be executed before or after a swap or bridge.

<figure><img src="/files/LFTvoiWAOQENEXv3c1uE" alt=""><figcaption></figcaption></figure>

Note that hooks can be executed before or after a single chain swap too.

<figure><img src="/files/62UQXrWcVcuT8YJBCfCu" alt=""><figcaption></figcaption></figure>


# Build a preHook

`preHooks` are executed on the Squid Multicall contract on the `fromChain` before any swaps or bridging has occurred.

After `preHooks`, the full balance on the Multicall will be swapped or bridged across chains.

The `fromToken` and `fromAmount` in your route request should be the amount of tokens you expect to on the Multicall after the `preHooks` are executed.

The snippet example below illustrates wrapping ETH on Arbitrum then bridging to Binance Smart Chain using both our API and SDK.

{% tabs %}
{% tab title="SDK" %}
To try the full working SDK preHook example, visit our [SDK Examples Repository](https://github.com/0xsquid/examples/tree/main/V2/sdk).

<pre class="language-typescript"><code class="lang-typescript">
//import Squid SDK and types
import { Squid } from "@0xsquid/sdk";
import { ChainType, EvmContractCall } from "@0xsquid/squid-types";

<strong>// Import WETH ABI
</strong>import wethAbi from "../abi/wethAbi"; // Adjust the path if necessary

// Function to get Squid SDK instance
const getSDK = (): Squid => {
  const squid = new Squid({
    baseUrl: "https://v2.api.squidrouter.com",
    integratorId: integratorId,
  });
  return squid;
};

// Main function
(async () => {
  // Initialize Squid SDK
  const squid = getSDK();
  await squid.init();
  console.log("Initialized Squid SDK");

  // Creating Contract interfaces
  const wethInterface = new ethers.utils.Interface(wethAbi);
  const wrapEncodedData = wethInterface.encodeFunctionData("deposit");

  // Set up parameters for wrapping ETH to wETH and bridging to BUSD on Binance Smart Chain
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: WETH_ADDRESS, // WETH on Arbitrum
    fromAmount: amount.toString(),
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
    slippageConfig: {
      autoMode: 1,
    },
    slippage: 1,
    preHook: {
      chainType: ChainType.EVM,
      fundAmount: amount.toString(),
      fundToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // Native ETH
<strong>       calls: [
</strong>        {
          chainType: ChainType.EVM,
          callType: 2, // 2 corresponds to CALL_DATA
          target: WETH_ADDRESS,
          value: amount.toString(), // Amount of ETH to wrap
          callData: wrapEncodedData,
          payload: {
            tokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // Native ETH
            inputPos: 0,
          },
          estimatedGas: "500000",
        } as EvmContractCall,
      ],
      provider: "Integration Test", //This should be the name of your product or application that is triggering the hook
      description: "Wrap native ETH",
      logoURI: "https://pbs.twimg.com/profile_images/1548647667135291394/W2WOtKUq_400x400.jpg", //Add your logo here
    },
  };

  console.log("Parameters:", params);

  // Get the swap route using Squid SDK
  const { route, requestId } = await squid.getRoute(params);
  console.log("Calculated route:", route.estimate.toAmount);


</code></pre>

{% endtab %}

{% tab title="API" %}
To try the full working API preHook example, visit our [API Examples Repository](https://github.com/0xsquid/examples/tree/main/V2/api).

```typescript

// Import WETH ABI
import wethAbi from "../abi/wethAbi"; // Adjust the path if necessary

// Creating Contract interfaces
const wethContract = new ethers.Contract(WETH_ADDRESS, wethAbi, signer);

// Set up parameters for wrapping ETH to wETH and bridging to BUSD on Binance Smart Chain
(async () => {
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: WETH_ADDRESS, // WETH on Arbitrum
    fromAmount: amount.toString(),
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
    slippageConfig: {
      autoMode: 1,
    },
    preHook: {
      chainType: "evm",
      fundAmount: amount.toString(),
      fundToken: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // Native ETH
      provider: "Integration Test",
      description: "Wrap native ETH",
      logoURI: "http://",
      calls: [
        {
          chainType: "evm",
          callType: 2,
          target: WETH_ADDRESS,
          value: "0",
          callData: wethContract.interface.encodeFunctionData("deposit"), // Function signature for deposit() in WETH contract
          payload: {
            tokenAddress: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE", // Native ETH
            inputPos: 0,
          },
          estimatedGas: "500000",
        },
      ],
    },
  };

  console.log("Parameters:", params);
  
```

{% endtab %}
{% endtabs %}


# Build a postHook

After the swap or bridge is executed, the resulting tokens will be left on the Squid Multicall contract. From there the `postHooks` calls will be executed.

{% tabs %}
{% tab title="SDK" %}
Create contract interfaces for the posthook

```typescript
// Creating Contract interfaces
// Approve the lending contract to spend the erc20
const erc20Interface = new ethers.utils.Interface(erc20Abi);
const approvalerc20 = erc20Interface.encodeFunctionData("approve", [
  radiantLendingPoolAddress,
  ethers.constants.MaxUint256,
]);

// Create contract interface and encode deposit function for Radiant lending pool
const radiantLendingPoolInterface = new ethers.utils.Interface(
  radiantLendingPoolAbi
);
const depositEncodedData = radiantLendingPoolInterface.encodeFunctionData(
  "deposit",
  [
    usdcArbitrumAddress,
    "0", // Placeholder for dynamic balance
    signer.address,
    0,
  ]
);
```

Create postHook

```typescript

// Set up parameters for swapping tokens and depositing into Radiant lending pool
const params = {
  fromAddress: signer.address,
  fromChain: fromChainId,
  fromToken: fromToken,
  fromAmount: amount,
  toChain: toChainId,
  toToken: usdcArbitrumAddress,
  toAddress: signer.address,
  slippage: 1,
  quoteOnly: false,
  enableBoost: true,
  slippage: 1, //OPTIONAL to set slippage, it will be set dynamically if not included
  postHook: {
    chainType: ChainType.EVM,
    calls: [
      {
        chainType: ChainType.EVM, 
        callType: 1,// SquidCallType.FULL_TOKEN_BALANCE
        target: usdcArbitrumAddress,
        value: "0", // this will be replaced by the full native balance of the multicall after the swap
        callData: approvalerc20,
        payload: {
          tokenAddress: usdcArbitrumAddress,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
      {
        chainType: ChainType.EVM,
        callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
        target: radiantLendingPoolAddress,
        value: "0",
        callData: depositEncodedData,
        payload: {
          tokenAddress: usdcArbitrumAddress,
          inputPos: 1,
        },
        estimatedGas: "50000",
      },
    ],
    provider: "Integration Test", //This should be the name of your product or application that is triggering the hook
    description: "Wrap native ETH",
    logoURI: "https://pbs.twimg.com/profile_images/1548647667135291394/W2WOtKUq_400x400.jpg", //Add your logo here
  },
};

```

{% endtab %}

{% tab title="API" %}
Import the ABIs and create the contract interface

```typescript
// Import Radiant lending pool ABI
import radiantLendingPoolAbi from "../abi/radiantLendingPoolAbi";

// Import erc20 contract ABI
import erc20Abi from "../abi/erc20Abi";

// Set up JSON RPC provider and signer 
const provider = new ethers.providers.JsonRpcProvider(FROM_CHAIN_RPC);
const signer = new ethers.Wallet(privateKey, provider);



// Creating Contract interfaces

// Approve the lending contract to spend the erc20
const erc20Interface = new ethers.utils.Interface(erc20Abi);
const approvalerc20 = erc20Interface.encodeFunctionData("approve", [
  radiantLendingPoolAddress,
  ethers.constants.MaxUint256,
]);

// Create contract interface and encode deposit function for Radiant lending pool
const radiantLendingPoolInterface = new ethers.utils.Interface(
  radiantLendingPoolAbi
);
const depositEncodedData = radiantLendingPoolInterface.encodeFunctionData(
  "deposit",
  [
    usdcArbitrumAddress,
    "0", // Placeholder for dynamic balance
    signer.address,
    0,
  ]
);
```

Build the parameters to including the postHook

<pre class="language-typescript"><code class="lang-typescript">
<strong>params = {
</strong>    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: amount,
    toChain: toChainId,
    toToken: usdcArbitrumAddress,
    toAddress: signer.address,
    slippage: 1,
    slippageConfig: {
      autoMode: 1,
    },
    postHook: {
      chainType: "evm",
      //fundAmount: amount,  //only required for prehooks
      //fundToken: usdcArbitrumAddress, //only required for prehooks
      calls: [
        {
          callType: 1,
          target: usdcArbitrumAddress,
          value: "0", // this will be replaced by the full native balance of the multicall after the swap
          callData: approvalerc20,
          payload: {
            tokenAddress: usdcArbitrumAddress, // unused in callType 2, dummy value
            inputPos: "1", // unused
          },
          estimatedGas: "50000",
          chainType: "evm",
        },
        {
          callType: 1, // SquidCallType.FULL_TOKEN_BALANCE
          target: radiantLendingPoolAddress,
          value: "0",
          callData: depositEncodedData,
          payload: {
            tokenAddress: usdcArbitrumAddress,
            inputPos: "1",
          },
          estimatedGas: "50000",
          chainType: "evm",
        },
      ],
      description: "",
      
    },
  };

</code></pre>

{% endtab %}
{% endtabs %}


# Using the full ERC20 or Native balance in a call

The Squid Multicall can update the value of a param on-chain before or after the Swap or bridge has occurred. This lets you do the following:

* Send the remainder of tokens to the user's address, after minting or buying something at a fixed price
* Stake the full amount received from a swap
* Unstake, then swap the full amount across chains

This is designated by using `callType`

```typescript
export enum SquidCallType {
  DEFAULT = 0,
  FULL_TOKEN_BALANCE = 1,
  FULL_NATIVE_BALANCE = 2,
  COLLECT_TOKEN_BALANCE = 3, // unused in hooks
}
```

{% tabs %}
{% tab title="FULL\_ERC20\_BALANCE" %}

```typescript
const sendRemainderToUserCall = {
        callType: SquidCallType.FULL_TOKEN_BALANCE, // transfer any remaining MAGIC to the user's account
        target: magicToken,
        value: "0",
        callData: transferMagicEncodeData,
        payload: {
          tokenAddress: magicToken,
          inputPos: 1,
        },
        estimatedGas: "50000",
},
```

{% endtab %}

{% tab title="FULL\_NATIVE\_BALANCE" %}

```typescript
const mintLoanWithFullNativeBalanceCall = {
        callType: SquidCallType.FULL_NATIVE_BALANCE,
        target: moonwellGlmrAddress,
        value: "0", // this will be replaced by the full native balance of the multicall after the swap
        callData: mintEncodeData,
        payload: {
          tokenAddress: "0x", // unused in callType 2, dummy value
          inputPos: 1, // unused
        },
        estimatedGas: "250000",
},
```

{% endtab %}

{% tab title="DEFAULT" %}

```typescript
const repayLoanCall = {		
	callType: SquidCallType.DEFAULT, 0
	target: aavePoolAddress,
	value: '0',
	callData: repayEncodedData,
	estimatedGas: '50000',
	payload: {
		tokenAddress: "", // unused in callType 0, dummy value
		inputPos: 0, // unused in callType 0, dummy value
}
```

{% endtab %}
{% endtabs %}


# Transfer the remainder to the user

Always remember to transfer all tokens left over from the swap or from your calls to the user's address, or your own contract address, at the end of the postHooks.

If you don't do this, there will likely be some funds left on the Squid Multicall Contract after your transaction has completed.

The best way to do this is to add a call sending the full ERC20 or NATIVE balance of the multicall to the address desired. [Using the full ERC20 or Native balance in a call](/old-v2-documentation-deprecated/key-concepts/hooks/using-the-full-erc20-or-native-balance-in-a-call)


# Get a route and execute as normal

From here on, there is no change needed in your flow ✅

Continue: [Execute the route](/old-v2-documentation-deprecated/key-concepts/execute-the-route)


# Track status

Our status API returns the status of a cross chain transaction. The response param `status.squidTransactionStatus` tells the user what they need to do next.

{% hint style="danger" %}
**Coral V2 Transactions**: Status polling is **required** for Coral V2. After executing a Coral V2 transaction, you **must** call the status API with the `quoteId` parameter. A Coral V2 transaction will fail unless status is called with `quoteId`. See [Integrating Coral V2](broken://pages/AEwKOP0YWxgPtJw2kFko) for details.
{% endhint %}

### API Endpoint

```
GET https://v2.api.squidrouter.com/v2/status
```

#### Parameters

| Parameter       | Type   | Required                    | Description                                                                                                                                   |
| --------------- | ------ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `transactionId` | string | Yes                         | The transaction hash                                                                                                                          |
| `quoteId`       | string | Yes (required for Coral V2) | The quote ID from the route response. Required for Coral V2 status tracking. Also enables volume and token activity sharing with integrators. |
| `fromChainId`   | string | Yes                         | The source chain ID                                                                                                                           |
| `toChainId`     | string | Yes                         | The destination chain ID                                                                                                                      |
| `requestId`     | string | No                          | The request ID (legacy parameter)                                                                                                             |

#### Example Request

```
/v2/status?transactionId=40E494A80393963DBC2D493E3EB6E39B7C48810CD345BF0FA8E48683B9841C43&fromChainId=cosmoshub-4&toChainId=osmosis-1&quoteId=27232c0b82fa6661b2799894bd0da80c
```

### Code Examples

#### Getting Quote ID from Route Response

The `quoteId` can be found at the top level of the route response. Including this parameter in status requests will enable volume and specific token activity sharing with integrators in the near future:

```json
{
    "route": {
        "quoteId": "6f388be5205ee044cd7fd5047a4ce72e"
    }
}
```

#### Updated SDK Interface

```typescript
interface StatusParams {
  transactionId: string;
  requestId?: string;
  integratorId?: string;
  quoteId?: string;
}
```

#### Function to Get Transaction Status

```javascript
// Function to get the status of the transaction using Squid API
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
        quoteId: params.quoteId, // Required for Coral V2 transactions
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    console.error("Error with parameters:", params);
    throw error;
  }
};
```

#### Polling for Transaction Status

```javascript
// Function to periodically check the transaction status until it completes
const updateTransactionStatus = async (txHash: string, requestId?: string, quoteId?: string) => {
  const getStatusParams = {
    transactionId: txHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId, // Required for Coral V2 transactions
  };

  let status;
  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found", "refund_status"];
  const maxRetries = 10; // Maximum number of retries for status check
  let retryCount = 0;

  do {
    try {
      status = await getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error) {
      if (error.response && error.response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before retrying
        continue;
      } else {
        throw error; // Rethrow other errors
      }
    }

    if (!completedStatuses.includes(status.squidTransactionStatus)) {
      await new Promise((resolve) => setTimeout(resolve, 5000)); // Wait for 5 seconds before checking the status again
    }
  } while (!completedStatuses.includes(status.squidTransactionStatus));
};
```

### Understanding squidTransactionStatus

This param will tell you what to show the user. There are 6 possible states:

```typescript
{
  SUCCESS = "success",
  NEEDS_GAS = "needs_gas",
  ONGOING = "ongoing",
  PARTIAL_SUCCESS = "partial_success",
  NOT_FOUND = "not_found",
  REFUND_STATUS = "refund"
}
```

#### SUCCESS

This indicates the transaction has completed on all chains. Whether a single chain, 2 chain or 3 chain call, the swap, stake, NFT purchase, bridge etc. has completed without any reversions and the user has received the intended funds.

#### NEEDS\_GAS

This state is specific for Axelar transactions. If the gas price has spiked on the destination chain and execution cannot complete, Squid will return this status. The best user flow in this case is to send the user to Axelarscan to view the paused transaction.

#### ONGOING

There is nothing wrong, nothing to do, just relax and wait. The transaction should have an `estimatedRouteDuration` in seconds that you can read from the `/route` response. We generally recommend contacting support after either 15 minutes has passed, or double the `estimatedRouteDuration`, whichever is larger.

#### PARTIAL\_SUCCESS

This status indicates that the transaction has completed some of its steps. Currently, there is only one case that could cause this state. In the future there will be many, but we will provide more metadata around the `PARTIAL_SUCCESS`. For now, this is what has happened:

* The source chain transaction successfully executed, along with any swaps or contract calls.
* The destination chain transaction has executed, but reverted during execution. This is usually due to slippage on volatile assets, but if you are trying to buy an NFT or do some cross-chain staking, then it could indicate that the custom hook had a failure.

If there is a partial success, the user will have received the bridged token in their wallet on the destination chain. In most cases this is axlUSDC.

#### NOT\_FOUND

The Squid API cannot find an on-chain record of the transaction. This is usually due to our various services or service providers not having indexed the completed transaction. This state is often returned for 5-10 seconds after the transaction was executed, while chain indexing occurs.

This should not persist after maximum a few minutes (some chains such as Filecoin take a very long time to index, and for block inclusion). If it does, then get in touch with us on Discord.

#### REFUND

This status is specific to failed Coral routes. When a Coral transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Coral routes when passing the user's address as the `fromAddress`. Refunds typically take \~10 minutes

**How Coral refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Coral, or a smart contract like Multicall)
* When refunded, funds are sent to the `order.fromAddress` which is encoded to the user, not the caller
* The `fromAddress` from the route request is used as the `order.fromAddress` for refunds
* This ensures that even if the transaction was initiated through a smart contract, the refund goes to the actual user


# Types

We recommend using the types from our npm package. If you are using our API without our SDK, you can find the types inside `node_modules/@0xsquid/sdk/dist/types/index.d.ts` after [Broken mention](broken://pages/pQzBnlnLhbC4MQnwWa7c)

```typescript
import { Token, ChainData } from '@0xsquid/sdk/dist/types'
```


# Collect Fees

### Integrator Fee Structure

Squid allows integrators to implement their own fee structure on top of Squid's platform fees. This document details the structure of Integrator fees implemented on through Squid.

<mark style="color:yellow;">**To implement fees please contact the Squid team.**</mark>\
Note, Squid splits all fees collected by integrators 50/50. Please see the Platform Fee Structure section for more detail.

#### Integrator Fee Configuration

As an integrator, you can implement the following fee structures:

1. Flat fee: A fixed amount per transaction
2. Percentage fee: A percentage of the transaction amount
3. Secondary address fees (optional): Fees sent to a second address
4. Option to waive platform fee (if allowed by Squid)

#### Fee Display

Within the returned route request, all fees (including your integrator fees and Squid's platform fees) are aggregated into a single "Service fee" in the route response. This appears in the `feeCosts` array and `route.actions`:

```json
{
  "feeCosts": [
    {
      "amount": "31178739678247",
      "amountUsd": "0.12",
      "description": "Service fee",
      "name": "Service fee",
      "token": {
        "type": "evm",
        "chainId": "42161",
        "address": "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
        "name": "Ethereum",
        "symbol": "ETH",
        "decimals": 18,
        "logoURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/tokens/eth.svg",
        "coingeckoId": "ethereum",
        "usdPrice": 3798.076408348585
      }
    }
  ],
  "actions": [
    {
      // ... other action properties
      "provider": "Service fee",
      "description": "Service fee",
      "priceImpact": 0,
      "exchangeRate": "0.99"
    }
  ]
}
```

### Platform Fee Structure

<mark style="color:yellow;">Squid splits all fees collected by integrators 50/50.</mark>

In the future, Squid may charge additional platform fees on top of integrator fees.

The total fee for a transaction is calculated as:

```
Total Fee = Platform Fees + Integrator Fees
```

Note: In some cases, Squid may allow integrators to waive certain platform fees. Please contact us for more information on fee customization options.


# Collect Fees

Integrators can reach out to Squid to implement fee capture on their cross-chain swaps.

Squid takes 50% of any fees collected by an integratorAddress.

Example route request with \`collectFees\`

```typescript

const params = {
    fromChain: 5, // Goerli testnet
    fromToken: "0xB4FBF271143F4FBf7B91A5ded31805e42b2208d6", // WETH on Goerli
    fromAmount: "50000000000000000", // 0.05 WETH
    toChain: 43113, // Avalanche Fuji Testnet
    toToken: "0x57f1c63497aee0be305b8852b354cec793da43bb", // aUSDC on Avalanche Fuji Testnet
    fromAddress: "0xAD3A87a43489C44f0a8A33113B2745338ae71A9D", // ethers.signer.address; transaction sender address
    toAddress: "0xAD3A87a43489C44f0a8A33113B2745338ae71A9D", // the recipient of the trade
    slippage: 1.00, // 1.00 = 1% max slippage across the entire route
    enableForecall: true, // instant execution service, defaults to true
    quoteOnly: false // optional, defaults to false, 
    collectFees: { 
        integratorAddress: "0x", 
        fee: 50
    }
};
```

| Property          | Description                                                                                                        |
| ----------------- | ------------------------------------------------------------------------------------------------------------------ |
| integratorAddress | The EVM address of the integrator that will receive the fee                                                        |
| fee               | The amount in "basis points" for the fee. 50 = 0.50%. there is currently soft limit of 1% fee allowed for each tx. |

**New objects in route response**

```json
feeCosts": [
    {
        "name": "Integrator Fee",
        "description": "Integrator Fee",
        "percentage": "0.9%",
        "token": {
            "chainId": 43113,
            "address": "0x57f1c63497aee0be305b8852b354cec793da43bb",
            "name": "Axelar USDC",
            "symbol": "aUSDC",
            "decimals": 6,
            "logoURI": "https://raw.githubusercontent.com/axelarnetwork/axelar-docs/main/public/images/assets/usdc.svg",
            "coingeckoId": "axlusdc",
            "commonKey": "uausdc"
        },
        "amount": "14190",
        "amountUSD": "0.0142"
    },
]
```

**Fee collection token**\
Fees are collected in the bridge token, most of the time this will be [axlUSDC](https://docs.axelar.dev/learn/axlusdc) as this is the primary bridging token, if the source or destination token is an [Axelar wrapped](https://docs.axelar.dev/resources/mainnet#assets) token the fee could be taken in that token, to unwrap Axelar token see [here](https://docs.axelar.dev/resources/wrapped-tokens)

The API route response will tell whether it is the source or destination chain that has the fee taken

\
You can see the "collectFees" object returned by the api in the "params" section of the response. This specific route will take fees on destination.

```json

"params": {
    "collectFees": {
        "integratorAddress": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
        "fee": 90,
        "feeLocation": "DESTINATION"
    },
    ....
}

```

**Fee logic**

Fees are are currently only supported on EVM chains, although fees will eventually be supported on Cosmos chains. The fee is generally taken on the chain where swaps happen. The following table outlines where the fee is taken based on the route.

swaps = some swap to or from a token to the bridge token (eg axlUSDC)

send only = no swaps

Cosmos = not supported

<table><thead><tr><th>Source</th><th>Destination</th><th>Fee taken</th><th data-hidden></th></tr></thead><tbody><tr><td>EVM (with swaps)</td><td>EVM (with swaps)</td><td>Source</td><td></td></tr><tr><td>EVM (no swaps)</td><td>EVM (with swaps)</td><td>Destination</td><td></td></tr><tr><td>EVM (no swaps)</td><td>EVM (no swaps)</td><td>Destination</td><td></td></tr><tr><td>EVM (with swaps)</td><td>EVM (no swaps)</td><td>Source</td><td></td></tr><tr><td>EVM (with swaps)</td><td>Cosmos</td><td>Source</td><td></td></tr><tr><td>EVM (no swaps)</td><td>Cosmos</td><td>None</td><td></td></tr></tbody></table>

**How to check fee balances**

You can check the Squid fee collector smart contracts for the balance of each token for the integrator address.\
The feeCollector contract addresses are documented in the next section.\
\
You can read balances by putting in the "token address" and "integratorAddress" into the getBalance function\
<https://testnet.snowtrace.io/address/0xf80De6D6CF6846Ae7c3243F4b6486EF662C59d29#readProxyContract>

**Fee Collector contract address**

| Network | Address                                    |
| ------- | ------------------------------------------ |
| Testnet | 0xf80De6D6CF6846Ae7c3243F4b6486EF662C59d29 |
| Mainnet | 0x19cd4F3820E7BBed45762a30BFA37dFC6c9C145b |
|         |                                            |


# Fee collector contract addresses

Testnet: `0xf80De6D6CF6846Ae7c3243F4b6486EF662C59d29`

Mainnet: `0x19cd4F3820E7BBed45762a30BFA37dFC6c9C145b`


# Get supported tokens and chains

{% hint style="info" %}
See all our supported chains and tokens at [https://app.squidrouter.com](https://v2.app.squidrouter.com)
{% endhint %}

{% tabs %}
{% tab title="SDK" %}

```typescript
// access using squid.tokens
const fromToken = squid.tokens.find(
  (t) =>
    t.symbol.toLocaleLowerCase() === "USDC" && t.chainId === "1"
);

// access using squid.chains
const fromChain = squid.chains.find(
  (c) =>
    c.chainId === "1"
);

```

{% endtab %}

{% tab title="API" %}

```typescript
const getChains = async () => {
	const result = await axios.get('https://v2.api.squidrouter.com/v2/chains', {
		headers: {
			'x-integrator-id': integratorId,
		},
	});
	return result.data;
};

const getTokens = async () => {
	const result = await axios.get('https://v2.api.squidrouter.com/v2/tokens', {
		headers: {
			'x-integrator-id': integratorId,
		},
	});
	return result.data;
};
```

{% endtab %}

{% tab title="Widgets" %}
Every widget will automatically pull down all Squid's supported tokens and chains.

You can limit the available tokens and chains using this guide:[Default Chains and Tokens](/old-v2-documentation-deprecated/add-a-widget/widget/customization-guide/default-chains-and-tokens)
{% endtab %}
{% endtabs %}

***

## POST Endpoints: Dynamic Field Selection

The API also exposes POST versions of `/v2/tokens`, `/v2/chains`, and `/v2/sdk-info` that let you request only the fields you need, reducing payload size and improving bandwidth efficiency. The existing GET endpoints remain unchanged.

{% hint style="info" %}
**PR**: [#1876 - Update sdk-info, tokens, and chains controllers](https://github.com/0xsquid/squid-api/pull/1876)
{% endhint %}

### How It Works

* Send a `fields` array in the POST body to specify which fields to return.
* Fields containing dots (e.g. `chain.internalRpc`) are **rejected** with a `400` error to prevent nested property access.
* If the requested fields don't exist on an object, the empty object is excluded from the response.

### POST `/v2/tokens`

```json
// Request
{ "fields": ["symbol", "address", "chainId", "decimals", "usdPrice"] }

// Response
{
  "tokens": [
    { "symbol": "ETH", "address": "0xeee...eee", "chainId": "1", "decimals": 18, "usdPrice": 3200.50 }
  ]
}
```

Optional query parameters (e.g. `?chainId=1`) work the same as the GET endpoint.

### POST `/v2/chains`

```json
// Request
{ "fields": ["chainId", "chainName", "networkName", "chainIconURI"] }

// Response (single chain via ?chainId=1)
{
  "chain": { "chainId": "1", "chainName": "Ethereum", "networkName": "ethereum", "chainIconURI": "https://..." }
}

// Response (all chains)
{
  "chains": [
    { "chainId": "1", "chainName": "Ethereum", "networkName": "ethereum" }
  ]
}
```

### POST `/v2/sdk-info`

Requires **both** `tokenFields` and `chainFields`:

```json
// Request
{
  "tokenFields": ["symbol", "address", "chainId", "decimals"],
  "chainFields": ["chainId", "chainName", "chainIconURI"]
}

// Response
{
  "chains": [{ "chainId": "1", "chainName": "Ethereum", "chainIconURI": "https://..." }],
  "tokens": [{ "symbol": "ETH", "address": "0xeee...", "chainId": "1", "decimals": 18 }],
  "axelarscanURL": "https://axelarscan.io/",
  "isInMaintenanceMode": false
}
```

### Error Responses

All POST endpoints return `400 BAD_REQUEST` for validation failures:

| Scenario                                        | Error Message                                                                  |
| ----------------------------------------------- | ------------------------------------------------------------------------------ |
| Missing or empty `fields` array                 | Fields array is required and must contain at least one field                   |
| All fields are blocked                          | All requested fields are blocked. Please provide at least one valid field.     |
| Nested field paths (dots)                       | Nested field paths are not allowed. Please provide only top-level field names. |
| sdk-info missing `tokenFields` or `chainFields` | Both tokenFields and chainFields must be provided with at least one field each |

### Behavior Notes

* **Sorting preserved** — field filtering applies after sorting, so ordering is correct regardless of selected fields.
* **Feature flags enforced** — chain/token access restrictions are applied before field filtering.
* **Future-proof** — new fields on data models are automatically available via POST (unless blocked).

***

### Supported Chains

| networkIdentifier | chainId             | type    |
| ----------------- | ------------------- | ------- |
| ethereum          | 1                   | evm     |
| arbitrum          | 42161               | evm     |
| avalanche         | 43114               | evm     |
| optimism          | 10                  | evm     |
| polygon           | 137                 | evm     |
| base              | 8453                | evm     |
| linea             | 59144               | evm     |
| binance           | 56                  | evm     |
| mantle            | 5000                | evm     |
| fantom            | 250                 | evm     |
| moonbeam          | 1284                | evm     |
| celo              | 42220               | evm     |
| scroll            | 534352              | evm     |
| kava              | 2222                | evm     |
| filecoin          | 314                 | evm     |
| blast             | 81457               | evm     |
| fraxtal           | 252                 | evm     |
| immutable         | 13371               | evm     |
| osmosis           | osmosis-1           | cosmos  |
| crescent          | crescent-1          | cosmos  |
| kujira            | kaiyo-1             | cosmos  |
| terra-2           | phoenix-1           | cosmos  |
| juno              | juno-1              | cosmos  |
| umee              | umee-1              | cosmos  |
| comdex            | comdex-1            | cosmos  |
| evmos             | evmos\_9001-2       | cosmos  |
| regen             | regen-1             | cosmos  |
| stargaze          | stargaze-1          | cosmos  |
| assetmantle       | mantle-1            | cosmos  |
| axelarnet         | axelar-dojo-1       | cosmos  |
| cosmoshub         | cosmoshub-4         | cosmos  |
| injective         | injective-1         | cosmos  |
| agoric            | agoric-3            | cosmos  |
| fetch             | fetchhub-4          | cosmos  |
| ki                | kichain-2           | cosmos  |
| noble             | noble-1             | cosmos  |
| dydx              | dydx-mainnet-1      | cosmos  |
| neutron           | neutron-1           | cosmos  |
| carbon            | carbon-1            | cosmos  |
| sei               | pacific-1           | cosmos  |
| secret-snip       | secret-4            | cosmos  |
| stride            | stride-1            | cosmos  |
| acre              | acre\_9052-1        | cosmos  |
| archway           | archway-1           | cosmos  |
| bitcanna          | bitcanna-1          | cosmos  |
| bitsong           | bitsong-2b          | cosmos  |
| cheqd             | cheqd-mainnet-1     | cosmos  |
| celestia          | celestia            | cosmos  |
| coreum            | coreum-mainnet-1    | cosmos  |
| decentr           | mainnet-3           | cosmos  |
| desmos            | desmos-mainnet      | cosmos  |
| dymension         | dymension\_1100-1   | cosmos  |
| irisnet           | irishub-1           | cosmos  |
| impacthub         | ixo-5               | cosmos  |
| jackal            | jackal-1            | cosmos  |
| lumnetwork        | lum-network-1       | cosmos  |
| likecoin          | likecoin-mainnet-2  | cosmos  |
| kava-ibc          | kava\_2222-10       | cosmos  |
| nolus             | pirin-1             | cosmos  |
| akash             | akashnet-2          | cosmos  |
| chihuahua         | chihuahua-1         | cosmos  |
| cronos            | cronosmainnet\_25-1 | cosmos  |
| gravitybridge     | gravity-bridge-3    | cosmos  |
| mars              | mars-1              | cosmos  |
| migaloo           | migaloo-1           | cosmos  |
| persistence       | core-1              | cosmos  |
| omniflixhub       | omniflixhub-1       | cosmos  |
| quicksilver       | quicksilver-2       | cosmos  |
| sommelier         | sommelier-3         | cosmos  |
| terra             | columbus-5          | cosmos  |
| teritori          | teritori-1          | cosmos  |
| sentinel          | sentinelhub-2       | cosmos  |
| humans            | humans\_1089-1      | cosmos  |
| c4e               | perun-1             | cosmos  |
| saga              | ssc-1               | cosmos  |
| nibiru            | cataclysm-1         | cosmos  |
| bitcoin           | bitcoin             | bitcoin |
| lava              | lava-mainnet-1      | cosmos  |
| kyve              | kyve-1              | cosmos  |
| solana            | solana-mainnet-beta | solana  |
| xion              | xion-mainnet-1      | cosmos  |
| berachain         | 80094               | evm     |
| saga\_evm         | 5464                | cosmos  |
| elys              | elys-1              | cosmos  |
| allora            | allora-mainnet-1    | cosmos  |
| flippandomainnet  | 2.73727E+15         | cosmos  |
| soundmoney        | 2.73593E+15         | cosmos  |
| ngmi              | 2.71277E+15         | cosmos  |
| babylon           | bbn-1               | cosmos  |
| sui               | sui-mainnet         | sui     |
| gnosis            | 100                 | evm     |
| sonic             | 146                 | evm     |
| soneium           | 1868                | evm     |
| peaq              | 3338                | evm     |
| hyper-evm         | 999                 | evm     |
| xrpl-evm          | 1440000             | evm     |
| xrpl              | xrpl-mainnet        | xrpl    |
| stellar           | stellar-mainnet     | stellar |


# Wallet History

The Wallet History API allows you to retrieve all cross-chain transaction records associated with a specific wallet address. This provides a comprehensive view of a user's historical interactions with

#### API Endpoint

<table data-header-hidden><thead><tr><th width="111.24609375"></th><th></th></tr></thead><tbody><tr><td><strong>Method</strong></td><td><strong>Endpoint</strong></td></tr><tr><td><code>GET</code></td><td><code>https://v2.api.squidrouter.com/v2/history/wallet</code></td></tr></tbody></table>

#### Parameters

| **Parameter**     | **Type** | **Required** | **Description**                                                         |
| ----------------- | -------- | ------------ | ----------------------------------------------------------------------- |
| `address`         | `string` | Yes          | The EVM or Cosmos wallet address to query.                              |
| `x-integrator-id` | `header` | Yes          | Your unique integrator ID. Requests count toward your Rate Limit (RPS). |

#### Key Features

* Global History: Returns all transactions associated with the wallet across all integrators.
* Time Range: Returns history for the last 3 months.
* No Pagination: This endpoint returns the full result set in a single response.

#### Example Request

```
curl --location 'https://v2.api.squidrouter.com/v2/history/wallet?address=ADD_ADDRESS_HERE' \
--header 'x-integrator-id: your-integrator-id'
```

```
const getWalletHistory = async (address, integratorId) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/history/wallet", {
      params: { address },
      headers: { "x-integrator-id": integratorId },
    });
    return result.data;
  } catch (error) {
    console.error("Error fetching history:", error.response?.data || error.message);
    throw error;
  }
};
```

#### Example Response

```
[
    {
        "transactionId": "0x081e2b20246ce3a6798e617b12e9bbe45d4487441cfab6273422dbd69f56c501",
        "bridgeType": "rfq",
        "createdAt": "2026-01-13T22:41:03.988Z",
        "fromChainId": "999",
        "quote": {
            "route": {
                "estimate": {
                    "fromAmount": "3916444925567914",
                    "toAmount": "90851975792151072",
                    "fromAmountUSD": "0.09",
                    "toAmountUSD": "0.09",
                    "fromToken": {
                        "address": "0x5555555555555555555555555555555555555555",
                        "chainId": "999",
                        "decimals": 18,
                        "logoURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/tokens/whype.svg",
                        "name": "Wrapped HYPE",
                        "symbol": "WHYPE",
                        "coingeckoId": "wrapped-hype",
                        "usdPrice": 25.169077678,
                        "type": "evm"
                    },
                    "toToken": {
                        "address": "0x55d398326f99059ff775485246999027b3197955",
                        "chainId": "56",
                        "decimals": 18,
                        "logoURI": "https://raw.githubusercontent.com/0xsquid/assets/main/images/tokens/usdt.svg",
                        "name": "USDT",
                        "symbol": "USDT",
                        "coingeckoId": "tether",
                        "usdPrice": 0.9998056774098082,
                        "type": "evm"
                    },
                    "estimatedRouteDuration": 10
                }
            }
        },
        "quoteId": "bb398cb754d3015474ad673658845af1",
        "statusResponse": {
            "id": "0x081e2b20246ce3a6798e617b12e9bbe45d4487441cfab6273422dbd69f56c501",
            "status": "success",
            "squidTransactionStatus": "success",
            "transactionUrl": "https://hyperevmscan.io/tx/0x081e2b20246ce3a6798e617b12e9bbe45d4487441cfab6273422dbd69f56c501"
        },
        "toChainId": "56",
        "updatedAt": "2026-01-13T22:41:03.988Z",
        "totalFeesUSD": 0.008399678805983213
    }
]
```


# Supported Chains by Bridge Type

### Supported Chains by Bridge Type

{% hint style="info" %}
This table shows which chains are currently supported by each bridge type. Reach out to the Squid team for the latest availability.
{% endhint %}

| Arbitrum                      | ✅  | ✅ | ✅ |
| ----------------------------- | -- | - | - |
| Avalanche                     | ✅  | ✅ | ✅ |
| Base                          | ✅  | ✅ | ✅ |
| Berachain                     | ✅  | ✅ | ✅ |
| Binance                       | ✅  | ✅ | ✅ |
| Bitcoin                       | ☑️ | ❌ | ❌ |
| Blast                         | ✅  | ✅ | ✅ |
| Celo                          | ✅  | ✅ | ✅ |
| Citrea                        | ✅  | ❌ | ✅ |
| Cosmos                        | ☑️ | ❌ | ✅ |
| Cosmos - other chains         | ☑️ | ❌ | ✅ |
| Ethereum                      | ✅  | ✅ | ✅ |
| Fantom (deprecated for Sonic) | ☑️ | ❌ | ✅ |
| Filecoin                      | ☑️ | ❌ | ✅ |
| Fraxtal                       | ☑️ | ❌ | ✅ |
| Gnosis                        | ✅  | ✅ | ✅ |
| Hedera                        | ✅  | ❌ | ✅ |
| HyperEVM                      | ✅  | ✅ | ✅ |
| Immutable zkEVM               | ☑️ | ❌ | ✅ |
| Kava                          | ☑️ | ❌ | ✅ |
| Linea                         | ✅  | ✅ | ✅ |
| Mantle                        | ☑️ | ❌ | ✅ |
| Mantra                        | ✅  | ❌ | ✅ |
| Monad                         | ☑️ | ❌ | ✅ |
| Moonbeam                      | ☑️ | ❌ | ✅ |
| Noble                         | ☑️ | ❌ | ❌ |
| Optimism                      | ✅  | ✅ | ✅ |
| Peaq                          | ✅  | ✅ | ✅ |
| Polygon                       | ✅  | ✅ | ✅ |
| Saga EVM                      | ✅  | ❌ | ✅ |
| Scroll                        | ☑️ | ❌ | ✅ |
| Soneium                       | ✅  | ✅ | ✅ |
| Solana                        | ☑️ | ❌ | ❌ |
| Sonic                         | ☑️ | ✅ | ✅ |
| Stellar                       | ☑️ | ❌ | ✅ |
| Sui                           | ❌  | ❌ | ✅ |
| XRPL                          | ☑️ | ❌ | ✅ |
| XRPL EVM                      | ✅  | ✅ | ✅ |

{% hint style="warning" %}
Please contact the Squid team to confirm current availability and to enable Coral on your integrator ID.
{% endhint %}


# Squid Intents

<figure><img src="/files/6Yq5uWM3ojyRDzKWVRaK" alt=""><figcaption></figcaption></figure>

## Squid's Intent Swaps Protocol

Squid Intents is Squid's intent-based settlement protocol transforming how regular crosschain swaps are executed. It turns user intent into simple onchain transfers and handling complex execution offchain using Trusted Execution Environment (TEE)-verified settlement. Squid Intents offers unparalleled reliability, better pricing, and a smoother user experience across EVM and non-EVM chains alike.

As crosschain logic is handled by TEEs, it delivers efficiency while maintaining the decentralized and non-custodial nature of the protocol while ensuring that Squid can expand to any chain and any token, including chains that don’t have smart contracts.

Squid’s TEEs are powered by [Cubist](https://cubist.dev/blog/squid-launches-sub-second-cross-chain-swaps-enabled-by-cubists-new-private-smart-contract-tech), who we chose for their formidable security background, having secured over $10B USD already, and their commitment to crypto's original values: decentralization and privacy. Their approach ensures high availability, censorship resistance, and decentralized upgrade and deployment pathways for protocols developing on their platform.

### Why Squid Intents?

* Sub-5 second execution for most transactions
* Zero slippage guaranteed through direct market maker integration
* 90% reduction in gas costs compared to traditional AMM-based routing
* MEV protection built into the protocol architecture
* No route expiry: routes don't expire, submit your transaction at any time after receiving a quote
* 15-minute refunds: if a transaction fails, funds are automatically returned on the source chain
* Integrator fee support built in

<figure><img src="/files/8til9V2WD9A1NJpCOA7b" alt=""><figcaption></figcaption></figure>

### Squid Intents Competitive landscape

<table data-header-hidden><thead><tr><th width="134.73046875">Feature</th><th>Squid Intents</th><th>Across Protocol</th><th>deBridge (DLN)</th><th>UniswapX</th><th>NEAR Confidential</th><th>Circle CCTP</th></tr></thead><tbody><tr><td><strong>TEE-Verified Settlement</strong></td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>✅</td><td>❌</td></tr><tr><td><strong>Post-Deposit RFQ Auctions</strong></td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td><strong>Native Bitcoin Support</strong></td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td><strong>Native Solana Support</strong></td><td>✅</td><td>✅</td><td>✅</td><td>❌</td><td>❌</td><td>✅</td></tr><tr><td><strong>Native XRPL Support</strong></td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td><strong>Guaranteed 15-Min Refunds</strong></td><td>✅</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td><strong>No Route Expiry</strong></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td><strong>Multisig Compatibility</strong></td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td><td>✅</td></tr><tr><td><strong>Zero-TVL Architecture</strong></td><td>❌</td><td>❌</td><td>✅</td><td>❌</td><td>❌</td><td>❌</td></tr><tr><td><strong>MEV-Resistant Privacy</strong></td><td>❌</td><td>❌</td><td>❌</td><td>❌</td><td>✅</td><td>❌</td></tr></tbody></table>

### How It Works

Squid Intents uses the `/v2/route` endpoint as all Squid transactions. For **EVM-to-EVM** swaps, the flow is identical to a standard Squid integration — request a route, execute it, and poll for status.

The route response's `transactionRequest` object will include a `transaction_request_type` field that indicates how to execute:

* `"ON_CHAIN_EXECUTION"` — standard on-chain transaction (EVM)
* `"DEPOSIT_ADDRESS_CALLDATA"` — submit a deposit to the provided address with the specified calldata (non-EVM)
* `"DEPOSIT_ADDRESS_WITH_SIGNATURE"` — submit a signed deposit to the provided address (non-EVM)

### Getting Squid Intents Enabled

Squid Intents is not enabled by default. To get started:

1. If you don't already have a Squid integration, [apply for an integrator ID](https://squidrouter.typeform.com/integrator-id)
2. Contact the Squid team to enable Squid Intents on your integrator ID
3. Follow the [Integrating Squid Intents](/api-and-sdk-integration/coral-intent-swaps/integrating-squid-intents) guide

{% hint style="warning" %}
**Widget Users**: Coral V2 requires `@0xsquid/widget` version **6.5.0 or newer**. Please ensure your widget is updated before enabling Coral V2.
{% endhint %}

### Supported Chains

Squid Intents currently supports the following chains:

**EVM Chains**: Celo, BNB Chain, Citrea, Peaq, HyperEVM, Avalanche, Optimism, Arbitrum, Linea, Berachain, Polygon, Gnosis, Base, Sonic, Hedera, XRPL EVM, Soneium, Blast

**Coming Soon**: Bitcoin, Solana


# Integrating Squid Intents

Integrating Squid Intents follows the same flow as a standard Squid integration. If you already have Squid integrated, the only steps are to have Squid Intents enabled on your integrator ID, poll for status with a `quoteId`, and handle the transaction request type.

Squid Intents must be enabled on your integrator ID. Reach out to the Squid team to get started.

### Route Request <a href="#route-request" id="route-request"></a>

Squid Intents uses the `/v2/route` endpoint. When Squid Intents is enabled and a route is available, it will be automatically selected.

**There are no expiry constraints** — You do not need to submit the transaction within a time window.

#### EVM Route Request Example <a href="#evm-route-request-example" id="evm-route-request-example"></a>

<a class="button secondary">Copy</a>

```
const params = {
  fromAddress: signer.address,
  fromChain: "42161",          // Arbitrum
  fromToken: usdcAddress,
  fromAmount: amount,
  toChain: "1",                // Ethereum
  toToken: nativeToken,
  toAddress: signer.address,
  quoteOnly: false,
};

// Get the route
const routeResult = await axios.post(
  "https://v2.api.squidrouter.com/v2/route",
  params,
  {
    headers: {
      "x-integrator-id": integratorId,
      "Content-Type": "application/json",
    },
  }
);

const route = routeResult.data.route;
const quoteId = route.quoteId; // Save this — required for status tracking
console.log("Quote ID:", quoteId);
```

### Transaction Request Types <a href="#transaction-request-types" id="transaction-request-types"></a>

The route response's `transactionRequest` object will include a `transaction_request_type` field that determines how to execute the transaction. There are three types:

TypeDescription

`ON_CHAIN_EXECUTION`

Standard on-chain transaction (EVM). Execute like any Squid transaction.

`DEPOSIT_ADDRESS_CALLDATA`

Deposit to the provided address with the specified calldata. Used for certain non-EVM chains.

`DEPOSIT_ADDRESS_WITH_SIGNATURE`

Submit a signed deposit to the provided address. Used for certain non-EVM chains.

### Executing the Route <a href="#executing-the-route" id="executing-the-route"></a>

#### `ON_CHAIN_EXECUTION` (EVM Transactions) <a href="#on_chain_execution-evm-transactions" id="on_chain_execution-evm-transactions"></a>

For EVM-to-EVM Squid Intents routes where `transaction_request_type` is `ON_CHAIN_EXECUTION`, execution is the same as any Squid transaction:

<a class="button secondary">Copy</a>

```
const tx = await signer.sendTransaction({
  to: route.transactionRequest.target,
  data: route.transactionRequest.data,
  value: route.transactionRequest.value,
  gasLimit: route.transactionRequest.gasLimit,
  gasPrice: route.transactionRequest.gasPrice,
});

const receipt = await tx.wait();
console.log("Transaction hash:", receipt.transactionHash);
```

#### `DEPOSIT_ADDRESS_CALLDATA` & `DEPOSIT_ADDRESS_WITH_SIGNATURE` <a href="#deposit_address_calldata-and-deposit_address_with_signature" id="deposit_address_calldata-and-deposit_address_with_signature"></a>

For certain chains, Squid Intents uses a **deposit address flow** instead of standard on-chain execution. The `transaction_request_type` field will be one of:

* `"DEPOSIT_ADDRESS_CALLDATA"` — submit a deposit to the provided address with the specified calldata
* `"DEPOSIT_ADDRESS_WITH_SIGNATURE"` — submit a signed deposit to the provided address

<a class="button secondary">Copy</a>

```
const route = routeResult.data.route;
const transactionRequest = route.transactionRequest;

// Check the type to determine the execution flow
console.log("Transaction type:", transactionRequest.transaction_request_type);
// "ON_CHAIN_EXECUTION", "DEPOSIT_ADDRESS_CALLDATA", or "DEPOSIT_ADDRESS_WITH_SIGNATURE"

// Follow the deposit instructions in the transactionRequest
// The specific fields will vary by chain and type
```

### Status Tracking <a href="#status-tracking" id="status-tracking"></a>

**Status polling is required for Squid Intents.** After executing a Squid Intent transaction, you **must** call the status API with the `quoteId` parameter. A Squid Intent transaction will fail unless status is called with `quoteId`.

#### Getting the Quote ID <a href="#getting-the-quote-id" id="getting-the-quote-id"></a>

The `quoteId` is returned at the top level of the route response:

<a class="button secondary">Copy</a>

```
{
    "route": {
        "quoteId": "6f388be5205ee044cd7fd5047a4ce72e"
    }
}
```

#### Polling for Status <a href="#polling-for-status" id="polling-for-status"></a>

<a class="button secondary">Copy</a>

```
// Function to get the status of a Coral V2 transaction
const getStatus = async (params) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params: {
        transactionId: params.transactionId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
        quoteId: params.quoteId, // Required for Coral V2
      },
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    throw error;
  }
};

// Poll for transaction completion
const updateTransactionStatus = async (txHash, quoteId) => {
  const getStatusParams = {
    transactionId: txHash,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId, // Required for Coral V2
  };

  let status;
  const completedStatuses = ["success", "partial_success", "needs_gas", "not_found", "refund"];
  const maxRetries = 10;
  let retryCount = 0;

  do {
    try {
      status = await getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error) {
      if (error.response && error.response.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached. Transaction not found.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        await new Promise((resolve) => setTimeout(resolve, 5000));
        continue;
      } else {
        throw error;
      }
    }

    if (!completedStatuses.includes(status.squidTransactionStatus)) {
      await new Promise((resolve) => setTimeout(resolve, 5000));
    }
  } while (!completedStatuses.includes(status.squidTransactionStatus));
};
```

### Refund Behavior <a href="#refund-behavior" id="refund-behavior"></a>

When a Squid Intent transaction fails, funds are automatically refunded on the source chain. Refunds typically complete within **\~15 minutes**.

* Funds are transferred from the `msg.sender` on the source chain
* Refunds are sent to the `order.fromAddress`, which corresponds to the `fromAddress` in the route request
* This ensures refunds go to the actual user even if the transaction was initiated through a smart contract

### Squid Intents Limitations <a href="#coral-v2-limitations" id="coral-v2-limitations"></a>

* Bitcoin and Solana support is coming soon


# Become A Solver

Whitelabeling Squid Intents

### Overview

<mark style="color:yellow;">**With Squid intents whitelabeling, integrators can deploy their own solver network and multi-chain liquidity within Squid’s cross-chain routing infrastructure.**</mark> This enables a seamless, branded trading experience while leveraging Coral’s intent-based order system.

### Why Whitelabel Squid Intents?

* **Brand & Liquidity Control**: Enable your users to swap seamlessly between ecosystems under your brand, managing liquidity and user experience end-to-end.
* **Revenue Opportunities**: Capture spread, fees, and revenue from every order routed through your network.
* **Scalability**: Leverage Squid’s vetted cross-chain connectivity without reimplementing complex bridging and messaging logic.

### Prerequisites

* **On-Chain Liquidity**: Provision assets across one or more EVM-compatible chains.
* **Solver Infrastructure**: Host an orderbook and execution engine capable of generating quotes in Coral’s RFQ format.
* **Technical Alignment**: Support REST or WebSocket endpoints and adhere to Coral’s order lifecycle conventions (RFQ, fill, settlement).

### Business Case

Whitelabeling Coral allows you to:

* Integrate seamlessly into existing trading terminals or DeFi frontends.
* Extend your market-making services to permissionless cross-chain order filling
* Differentiate with proprietary pricing algorithms and liquidity incentives.

### Getting Started

1. **Discuss Partnership**: Reach out to Squid to align on requirements and liquidity commitments.
2. **Production Launch**: Go live under your own brand, supported by Coral’s monitoring and support.

### Contact

For more information or to express interest, contact: <nick@squidrouter.com> Telegram: @nickpayiatis


# Chain Integration Guides

This section provides detailed integration guides for specific chains supported by Squid. Each guide walks through the available integration methods — Widget, API, and SDK — along with chain-specific parameters, supported tokens, and working code examples.

* [Bitcoin and Solana](/api-and-sdk-integration/chain-integration-guides/bitcoin-and-solana)
* [XRPL Integration](/api-and-sdk-integration/chain-integration-guides/xrpl-integration)


# Bitcoin and Solana

Bitcoin and Solana cross-chain swaps are now on Squid!

The cross-chain swap mechanism is powered by [Chainflip](https://chainflip.io/).

Currently, Bitcoin and Solana integrations are in a closed beta. Please reach out if you would like to have the functionality enabled for your integrator ID.

This brief outlines what you need to know in order to enable swaps to and from Bitcoin and Solana. You can also explore the detailed[ **ready-to-run examples in our Github repo**](https://github.com/0xsquid/examples/tree/main/V2/api).

### Creating a Route

Currently swaps are only supported to EVM chains. You can swap from EVM chains to Solana and BTC just as you would in a typical cross-chain swap.

When swapping **from** Solana or BTC, the `/v2/route` endpoint will return one of two transaction types depending on the token pair. You should check the `transactionRequest.type` field in the response to determine which flow to follow.

#### Transaction Type: `ON_CHAIN_EXECUTION` (Direct Swaps)

For certain token pairs, Chainflip provides direct swap access. In this case, the route response returns a `transactionRequest` with `type: "ON_CHAIN_EXECUTION"` containing raw transaction data that can be signed and submitted directly on-chain — similar to a standard EVM swap.

**Direct Swap Pairs (Solana)**

| From Token | To Token | To Chain         |
| ---------- | -------- | ---------------- |
| SOL        | ETH      | Ethereum (1)     |
| SOL        | USDC     | Arbitrum (42161) |
| SOL        | ETH      | Arbitrum (42161) |
| USDC       | ETH      | Ethereum (1)     |
| USDC       | USDC     | Arbitrum (42161) |
| USDC       | ETH      | Arbitrum (42161) |

**Example Request (SOL → ETH on Ethereum)**

```json
{
    "fromAddress": "35tWpkpFr7UawcpuXm6ir1nN1v5tfoJgKj84xv1YukZn",
    "fromAmount": "100000000",
    "fromChain": "solana-mainnet-beta",
    "fromToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
    "toAddress": "0x2d0178a76632443B0A64EFEEBc42AE25E8c4B949",
    "toChain": "1",
    "toToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
    "slippage": 1
}
```

**Example Response**

```json
{
    "transactionRequest": {
        "type": "ON_CHAIN_EXECUTION",
        "target": "",
        "data": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAQADBx738cKik3CAiHapY2..."
    }
}
```

For direct swaps, status checking follows the standard pattern using the on-chain transaction hash — no special `bridgeType` parameter is needed.

#### Transaction Type: `CHAINFLIP_DEPOSIT_ADDRESS` (Deposit Address Flow)

All other Solana and BTC routes (i.e., any pair **not** listed in the direct swap pairs table above) will return a `transactionRequest` with `type: "CHAINFLIP_DEPOSIT_ADDRESS"`. This requires an additional step: you must pass the `transactionRequest` body to the deposit address endpoint to get a deposit address, then transfer the assets to that address.

**Example Request (SOL → USDC on Base)**

```json
{
    "fromAddress": "35tWpkpFr7UawcpuXm6ir1nN1v5tfoJgKj84xv1YukZn",
    "fromAmount": "100000000",
    "fromChain": "solana-mainnet-beta",
    "fromToken": "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
    "toAddress": "0x2d0178a76632443B0A64EFEEBc42AE25E8c4B949",
    "toChain": "8453",
    "toToken": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
    "slippage": 1
}
```

**Example Response**

```json
{
    "transactionRequest": {
        "type": "CHAINFLIP_DEPOSIT_ADDRESS",
        "request": {
            "quote": {
                "intermediateAmount": "17908621",
                "egressAmount": "4083107065211964"
            }
        }
    }
}
```

**Step 2: Get the Deposit Address**

Take the `transactionRequest` body from the route response and submit it to the deposit address endpoint ([https://v2.api.squidrouter.com/v2/deposit-address](https://v2.api.squidrouter.com/v2/)) using the same headers as the route request endpoint.

**Deposit-address Endpoint Body Example**

```json
{
    "type": "CHAINFLIP_DEPOSIT_ADDRESS",
    "request": {
        "amount": "70000",
        "fromChain": "bitcoin",
        "fromAsset": "BTC",
        "toChain": "42161",
        "toAsset": "USDC",
        "fromAddress": "bc1qzea6nfdfmztwjcn8htqn4tk9j3v2uawf4rck0g",
        "toAddress": "0xC601C9100f8420417A94F6D63e5712C21029525e",
        "maxBoostFeeBps": 5,
        "fillOrKillParams": {
            "minPrice": "95922.744760479036194738",
            "refundAddress": "bc1qzea6nfdfmztwjcn8htqn4tk9j3v2uawf4rck0g",
            "retryDurationBlocks": 150
        }
    }
}
```

The deposit address endpoint ([https://v2.api.squidrouter.com/v2/deposit-address](https://v2.api.squidrouter.com/v2/)) will return the deposit address(**`depositAddress`**) which is where the asset should be transferred, the amount(**`amount`**), which is the amount that should be transferred, and the **`chainflipStatusTrackingId`**, which will be used for the status tracking.

```json
{
    "depositAddress": "bc1pdlqe7rw4ep6w6d6q7j3vu300l577wqdn7sw6q3ya3lvlssv5wahq77765y",
    "amount": "70000",
    "chainflipStatusTrackingId": "5994435-Bitcoin-26351"
}
```

#### Bitcoin Parameters

* ChainID: `bitcoin`
* Native Token: `satoshi`
* Minimum Swap Amount: `.0007 BTC`
* The Bitcoin wallet address should be a Native SegWit (Bech32) address

#### Solana Parameters

* ChainID: `solana-mainnet-beta`
* Native Token: `0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee`
* Supported Tokens: SOL, USDC(`EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`)
* Minimum Swap Amount: `$20 USD`

### Key Implementation Differences

#### Status Checking

Status checking depends on the transaction type returned by the route endpoint:

**For Direct Swaps (`ON_CHAIN_EXECUTION`):**

Use the standard status checking flow with the on-chain transaction hash — the same as any EVM-to-EVM swap. No special `bridgeType` parameter is needed.

**For Deposit Address Swaps (`CHAINFLIP_DEPOSIT_ADDRESS`):**

Unlike EVM-to-EVM or EVM-to-Cosmos swaps, deposit address swaps from Bitcoin and Solana require setting a **`bridgeType`** parameter and setting the **`transactionId`** parameter as the `chainflipStatusTrackingId` returned from the deposit-address endpoint.

When calling the status API([https://v2.api.squidrouter.com/v2/status](https://v2.api.squidrouter.com/v2/)), the bridgeType should be set as **`chainflip`** if the bridge destination is Arbitrum(42161) or **`chainflipmultihop`** if the bridge destination is another EVM chain that is not Arbitrum

```typescript
// Status checking params for deposit address swaps:
{
  transactionId: chainflipStatusTrackingId, // Use chainflipStatusTrackingId from the deposit-address endpoint
  fromChainId: fromChainId,
  toChainId: toChainId,
  bridgeType: "chainflip" // Required for SOL or BTC to Arbitrum and chainflipmultihop to any other EVM,
}
```

This chainflipID can be found in the returned object from the [https://v2.api.squidrouter.com/v2/deposit-address](https://v2.api.squidrouter.com/v2/) endpoint.

```json
{
    "depositAddress": "bc1pdlqe7rw4ep6w6d6q7j3vu300l577wqdn7sw6q3ya3lvlssv5wahq77765y",
    "amount": "70000",
    "chainflipStatusTrackingId": "5994435-Bitcoin-26351"
}

```

### Route Parameters Examples

**Bitcoin Example**

```typescript
const params = {
  fromAddress: sourceAddress,
  fromChain: "bitcoin",
  fromToken: "satoshi",
  fromAmount: "70000", // Amount in satoshis
  toChain: "42161",
  toToken: toToken,
  toAddress: destinationAddress,
  quoteOnly: false
};
```

**Solana Example**

```typescript
const params = {
  fromAddress: wallet.publicKey.toString(),
  fromChain: "solana-mainnet-beta",
  fromToken: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
  fromAmount: "100000000", // Amount in lamports
  toChain: "42161",
  toToken: toToken,
  toAddress: destinationAddress,
  quoteOnly: false
};
```

#### Important Notes

1. Check the `transactionRequest.type` field in the route response to determine which flow to use
2. For direct swap pairs (`ON_CHAIN_EXECUTION`), sign and submit the transaction data directly on-chain
3. For all other pairs (`CHAINFLIP_DEPOSIT_ADDRESS`), retrieve the deposit address from the `/deposit-address` endpoint and transfer assets there
4. Deposit address swaps require the `bridgeType` parameter for status checks; direct swaps use the standard transaction hash
5. Status monitoring for deposit address swaps should use the `chainflipStatusTrackingId` from the deposit-address response
6. Transaction confirmation times vary significantly between chains


# XRPL Integration

Integrate cross-chain swaps to, from, and within the XRP Ledger using Squid. XRPL support is powered by [**Squid Intents**](/api-and-sdk-integration/coral-intent-swaps) — Squid's intent-based execution protocol for fast, solver-driven cross-chain settlement.

> **Squid Intents must be enabled on your integrator ID.** Reach out to the Squid team to request Squid Intents access before integrating with XRPL.

***

## XRPL Parameters

| Parameter    | Value          |
| ------------ | -------------- |
| **Chain ID** | `xrpl-mainnet` |

### Supported Destination Tokens

The following tokens are currently supported as destination tokens on XRPL via Squid Intents:

| Token     | Address                                                                       |
| --------- | ----------------------------------------------------------------------------- |
| **XRP**   | `xrp`                                                                         |
| **RLUSD** | `524c555344000000000000000000000000000000.rmxckbedwqr76quhesumdegf4b9xj8m5de` |
| **SOIL**  | `534F494C00000000000000000000000000000000.rfmS3zqrQrka8wVyhXifEeyTwe8AMz2Yhw` |

***

## Widget Integration

The fastest way to add XRPL swaps to your application is through the Squid Widget. You can prototype your widget configuration interactively using [**Widget Studio**](https://studio.squidrouter.com/).

### Locking Destination to XRPL

To configure the widget so the destination is always XRPL, use the `initialAssets`, `availableChains`, and `availableTokens` configuration options:

```jsx
<SquidWidget
  config={{
    integratorId: "<your-integrator-id>",
    apiUrl: "https://v2.api.squidrouter.com",
    initialAssets: {
      to: {
        address: "xrp",
        chainId: "xrpl-mainnet",
      },
    },
    availableChains: {
      destination: ["xrpl-mainnet"],
    },
    availableTokens: {
      destination: {
        "xrpl-mainnet": [
          "xrp",
          "524c555344000000000000000000000000000000.rmxckbedwqr76quhesumdegf4b9xj8m5de",
          "534F494C00000000000000000000000000000000.rfmS3zqrQrka8wVyhXifEeyTwe8AMz2Yhw",
        ],
      },
    },
    // ... other configuration options
  }}
/>
```

This configuration:

* Sets the default destination token to XRP on XRPL
* Restricts the destination chain selector to XRPL only
* Limits destination token choices to XRP, RLUSD, and SOIL
* Leaves the source chain and token open for the user to select

For more widget customization options, see the [Widget Customization Guide](/widget-integration/add-a-widget/widget/customization-guide).

***

## API Integration

### Route to XRPL (EVM → XRPL)

To route from an EVM chain to XRPL, set `toChain` to `xrpl-mainnet` and `toToken` to one of the supported XRPL token addresses.

```typescript
const params = {
  fromAddress: "0xYourEVMAddress",
  fromChain: "8453",                  // Base
  fromToken: "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",  // ETH
  fromAmount: "1000000000000000",      // Amount in wei
  toChain: "xrpl-mainnet",
  toToken: "xrp",
  toAddress: "rYourXRPLAddress",
  quoteOnly: false,
};

const routeResult = await axios.post(
  "https://v2.api.squidrouter.com/v2/route",
  params,
  {
    headers: {
      "x-integrator-id": "<your-integrator-id>",
      "Content-Type": "application/json",
    },
  }
);

const route = routeResult.data.route;
const quoteId = route.quoteId;  // Required for status tracking
```

**Transaction type:** `DEPOSIT_ADDRESS_CALLDATA` — The route response will include a deposit address and calldata. Transfer the specified amount to the deposit address to initiate the swap.

### Same-Chain Swap on XRPL (XRPL → XRPL)

You can also perform same-chain swaps between XRPL tokens.

```typescript
const params = {
  fromAddress: "rYourXRPLAddress",
  fromChain: "xrpl-mainnet",
  fromToken: "xrp",
  fromAmount: "10000000",             // Amount in drops (10 XRP)
  toChain: "xrpl-mainnet",
  toToken: "524c555344000000000000000000000000000000.rmxckbedwqr76quhesumdegf4b9xj8m5de", // RLUSD
  toAddress: "rYourXRPLAddress",
  quoteOnly: false,
};
```

**Transaction type:** `DEPOSIT_ADDRESS_CALLDATA`

### Route from XRPL (XRPL → EVM)

To route from XRPL to an EVM chain, set `fromChain` to `xrpl-mainnet`.

```typescript
const params = {
  fromAddress: "rYourXRPLAddress",
  fromChain: "xrpl-mainnet",
  fromToken: "xrp",
  fromAmount: "10000000",             // Amount in drops (10 XRP)
  toChain: "42161",                   // Arbitrum
  toToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",  // USDC
  toAddress: "0xYourEVMAddress",
  quoteOnly: false,
};
```

**Transaction type:** `DEPOSIT_ADDRESS_CALLDATA`

### Status Tracking

XRPL routes are powered by Squid Intents, which **requires** the `quoteId` for status polling. The `quoteId` is returned in the route response.

```typescript
const getStatus = async (params) => {
  const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
    params: {
      transactionId: params.transactionId,
      fromChainId: params.fromChainId,
      toChainId: params.toChainId,
      quoteId: params.quoteId,  // Required for Squid Intents
    },
    headers: {
      "x-integrator-id": "<your-integrator-id>",
    },
  });
  return result.data;
};
```

> **Important:** A Squid Intent transaction will fail unless status is polled with the `quoteId`. See the [Integrating Squid Intents](/api-and-sdk-integration/coral-intent-swaps/integrating-squid-intents) guide for full status polling details.

### API Code Examples

| Route       | Example                                                                                       |
| ----------- | --------------------------------------------------------------------------------------------- |
| EVM → XRPL  | [baseToXrplSwap](https://github.com/0xsquid/examples/tree/main/V2/api/baseToXrplSwap)         |
| XRPL → XRPL | [xrplSameChainSwap](https://github.com/0xsquid/examples/tree/main/V2/api/xrplSameChainSwap)   |
| XRPL → EVM  | [xrplToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/api/xrplToArbitrumSwap) |

***

## SDK Integration

The Squid SDK provides the same XRPL routing capabilities. After initializing the SDK with your integrator ID, use `squid.route()` with the same parameters as the API examples above, then execute using the returned transaction request.

For full SDK setup and execution details, see the [SDK documentation](/api-and-sdk-integration/sdk).

### SDK Code Examples

| Route       | Example                                                                                       |
| ----------- | --------------------------------------------------------------------------------------------- |
| EVM → XRPL  | [baseToXrplSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/baseToXrplSwap)         |
| XRPL → XRPL | [xrplSameChainSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/xrplSameChainSwap)   |
| XRPL → EVM  | [xrplToArbitrumSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/xrplToArbitrumSwap) |

***

## Transaction Types

All XRPL routes use the `DEPOSIT_ADDRESS_CALLDATA` transaction type. This applies to:

* **EVM → XRPL** — Direct route, no DEX swap on source
* **XRPL → EVM** — Direct route from XRPL to any EVM chain
* **XRPL → XRPL** — Same-chain swaps between XRPL tokens

The route response will return a `transactionRequest` containing the deposit address and calldata. Transfer the specified amount to the deposit address to initiate the swap.

For a full reference of all transaction types across all chains, see the [Transaction Types](/api-and-sdk-integration/key-concepts/transaction-types) page.


# MCP: AI Agent Integration

AI agents can now perform cross-chain token swaps through natural language using the **Squid MCP** — a [Model Context Protocol](https://modelcontextprotocol.io) server that connects AI assistants like Claude to [Squid Router](https://squidrouter.com).

Instead of writing code to interact with swap APIs, developers can give an AI assistant access to Squid's cross-chain infrastructure and let users swap tokens by simply describing what they want. The MCP handles wallet management, route quoting, swap execution, and status tracking — all through conversation.

{% hint style="warning" %}
The MCP-managed wallet stores a private key in the OS keychain. This wallet is intended for development, testing, and small-amount transactions. Do not store significant funds in the agent wallet.
{% endhint %}

## Features

* **Wallet management** — generate and store a private key in the OS keychain; retrieve the agent wallet address
* **Token & chain discovery** — list all EVM chains and tokens supported by Squid Router
* **Balance checking** — query native and ERC-20 balances across all EVM chains
* **Cross-chain swaps** — get a route quote, review it, then execute with background monitoring
* **Swap status** — poll the status of any in-flight swap by transaction hash

{% hint style="info" %}
The Squid MCP currently supports **EVM chains only**.
{% endhint %}

***

## Getting Started

### Requirements

* [**Node.js** ≥ 22](https://nodejs.org/en/download)
* **yarn** — `npm install -g yarn`
* A [**Squid Integrator ID**](https://squidrouter.typeform.com/integrator-id)

### 1. Clone the repo and build

```bash
# Download the repository
git clone https://github.com/0xsquid/squid-mcp.git
cd squid-mcp

# Install dependencies
yarn install

# Compile the source
yarn build
```

### 2. Connect to your MCP client

Add the MCP server to your AI client of choice.

#### Claude Desktop

1. Open the Claude Desktop settings

![macOS menu bar with the Claude app menu open, showing Settings... highlighted](/files/enQRROYU33bHY2yKibo7)<br>

2. Go to **Settings > Desktop app > Developer** and click **"Edit Config"**

![Claude Desktop Settings page with the Developer section selected, showing an Edit Config button](/files/0ec5vZ2pvRpkfkoJ27HR)<br>

3. This will open `claude_desktop_config.json` in your file explorer

![macOS Finder window showing the Claude config directory with claude\_desktop\_config.json highlighted](/files/BN1WwmVYDm1n78nvysJU)<br>

4. Open the file with a text editor and add `squid-mcp` under `mcpServers`:

```json
{
  "mcpServers": {
    "squid-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/squid-mcp/dist/index.js"]
    }
  }
}
```

<br>

5. Restart Claude Desktop — you should now see the Squid MCP available and running

![Claude Desktop Developer page showing squid-mcp listed with status running](/files/UsnhN8HxyitdQj3MOdu3)

<details>

<summary>Using fnm or nvm?</summary>

Claude Desktop does not inherit your shell environment, so the `node` shim on your `PATH` may not resolve correctly. Use the absolute path to the node binary instead:

```json
{
  "mcpServers": {
    "squid-mcp": {
      "command": "/Users/your-user/.local/share/fnm/node-versions/v22.0.0/installation/bin/node",
      "args": ["/absolute/path/to/squid-mcp/dist/index.js"]
    }
  }
}
```

To find the path for your active version:

```bash
ls ~/.local/share/fnm/node-versions/
```

</details>

#### Claude Code (CLI)

```bash
claude mcp add squid-mcp node /absolute/path/to/squid-mcp/dist/index.js
```

If successful, you should see:

```
Added stdio MCP server squid-mcp with command: node /Users/your-user/squid-mcp/dist/index.js to local config
File modified: /Users/your-user/.claude.json
```

To verify it was added successfully, run `/mcp` in Claude Code.

![Claude Code CLI showing squid-mcp listed under Local MCPs with a green checkmark](/files/V0qlDT3bPfg9wT0phJWO)

***

## Available Tools

| Tool                | Description                                                  |
| ------------------- | ------------------------------------------------------------ |
| `setup_wallet`      | Generate a new wallet and store it in the OS keychain        |
| `get_agent_address` | Return the agent wallet address                              |
| `get_chains`        | List all EVM chains supported by Squid Router                |
| `get_tokens`        | List tokens on a given chain (filterable by symbol/name)     |
| `get_balances`      | Show non-zero balances across all chains (or a specific one) |
| `get_route`         | Get a swap route quote (stores it as a pending route)        |
| `execute_swap`      | Execute the pending route; monitors completion in background |
| `get_status`        | Poll the status of a swap by transaction hash                |

***

## Typical Swap Workflow

```
1. setup_wallet        → create the agent wallet (first time only)
2. get_agent_address   → confirm the wallet address and fund it
3. get_balances        → check available funds
4. get_tokens          → look up token addresses if needed
5. get_route           → review quote (amounts, fees, slippage, ETA)
6. execute_swap        → submit (only after you approve the route)
7. get_status          → poll until "success" or "error"
```

Once the wallet is set up and funded, you can simply tell the AI assistant what you want to do in natural language — for example:

> *"Swap 1 USDC on Ethereum to ETH on Base"*

The assistant will use the tools above to get a quote, present it for your approval, and execute the swap.

***

## Export Your Private Key

To back up or import the agent wallet key into another wallet:

```bash
yarn build && yarn export-key
```

The key is printed only to your local terminal — it is never sent to the AI assistant or any MCP context.


# Squid MPP Adapter

AI agents and backend services can now accept and make payments across any EVM chain using the **Squid MPP adapter** — a [Machine Payments Protocol (MPP)](https://tempo.xyz) adapter powered by Squid to abstract away the complexity of cross-chain bridging.

Instead of managing bridges or writing complex multi-chain payment logic, developers can integrate the Squid MPP adapter to automatically handle bridging and paying for 402 resources in a single, seamless integration. Clients settle automatically by scanning their available balances across all Squid-supported EVM chains and routing through the Squid API to [Tempo mainnet](https://tempo.xyz).

***

### Features

* **Auto chain selection** — scans all Squid-supported EVM chains for available balances and picks the best source token automatically
* **Cross-chain bridging** — routes tokens from any supported chain to Tempo mainnet via Squid Router
* **HTTP 402 payment flow** — standard MPP challenge/credential cycle: server issues a challenge, client pays and retries with a credential

> **Info** The Squid MPP adapter currently supports **EVM chains only**.

***

### Getting Started

#### Requirements

* [**Node.js** ≥ 18](https://nodejs.org/en/download)
* A [**Squid Integrator ID**](https://squidrouter.typeform.com/integrator-id)

#### Server integration

Protect any HTTP endpoint so that only clients who have paid can access it. Install the [`mppx`](https://mpp.dev/sdk/typescript) library:

```bash
npm install mppx
```

Generate a secret key for credential signing:

```bash
openssl rand -hex 32
```

Add the output to your environment variables:

```env
MPP_SECRET_KEY=<output from above>
```

Add `mppx.charge()` as middleware on any route you want to gate. The `tempo()` method configures the settlement token and recipient on Tempo mainnet:

```ts
import { Mppx, tempo } from "mppx"

const mppx = Mppx.create({
  secretKey: process.env.MPP_SECRET_KEY!,
  methods: [
    tempo({
      currency: "0x20c0000000000000000000000000000000000000", // PathUSD on Tempo
      recipient: process.env.RECIPIENT_ADDRESS!
    })
  ]
})

// Protect any route — amount is in PathUSD units
app.get("/resource", mppx.charge({ amount: "0.01" }), c => {
  return c.json({ data: "secret content" })
})
```

Unauthenticated requests receive an HTTP 402 with the charge parameters. Requests that include a valid credential pass through to the handler.

Learn more about protecting endpoints with MPP at the official [MPP docs](https://mpp.dev/quickstart/server).

#### Client integration

Access any MPP-protected endpoint and pay from any supported EVM chain — no manual bridging required. Install `@0xsquid/mpp` alongside `mppx` and `viem`:

```bash
npm install @0xsquid/mpp mppx viem
```

You will need a funded agent wallet (USDC or any Squid-supported token on any supported chain) and your Squid Integrator ID.

```env
# Private key of the agent wallet
PRIVATE_KEY=0x...
```

Wrap your fetch calls with `Mppx.create()` using `squid()` as the payment method. When a 402 is received, the library handles the entire bridge flow:

```ts
import { privateKeyToAccount } from "viem/accounts"
import { Mppx } from "mppx"
import { squid } from "@0xsquid/mpp"

const account = privateKeyToAccount(process.env.PRIVATE_KEY! as `0x${string}`)

const { fetch: mppxFetch } = Mppx.create({
  polyfill: false,
  methods: [
    squid({
      account,
      integratorId: "your-integrator-id"
    })
  ]
})

const response = await mppxFetch("https://mpp-server.com/resource")
console.log(await response.json())
```

**`squid(config)` options**

| Option         | Type                                | Required | Description                                                                             |
| -------------- | ----------------------------------- | -------- | --------------------------------------------------------------------------------------- |
| `account`      | `Account`                           | Yes      | A [viem Account](https://viem.sh/docs/accounts/local) (e.g. from `privateKeyToAccount`) |
| `integratorId` | `string`                            | Yes      | Your Squid integrator ID                                                                |
| `onPayment`    | `(summary: PaymentSummary) => void` | No       | Callback fired after a successful payment with amount, token, and source chain info     |

Learn more about MPP clients at the official [MPP docs](https://mpp.dev/quickstart/client).

***

### Payment Flow

```
Client                Server              Squid API             Tempo Chain
  |                     |                     |                      |
  |-- GET /resource --> |                     |                      |
  |<- HTTP 402 -------- |                     |                      |
  |   { amount,         |                     |                      |
  |     currency,       |                     |                      |
  |     recipient }     |                     |                      |
  |                     |                     |                      |
  | [find optimal source token]               |                      |
  |                     |                     |                      |
  |-- get route quote ----------------------> |                      |
  |<- bridge route -------------------------- |                      |
  |                     |                     |                      |
  |-- submit bridge tx ---------------------> |                      |
  |-- poll bridge status -------------------> |                      |
  |                     |                     |-- pay on Tempo ----> |
  |                     |                     |<- payment tx hash -- |
  |<- payment tx hash ----------------------- |                      |
  |                     |                     |                      |
  |-- GET /resource --> |                     |                      |
  |   + credential      |-- verify tx -----------------------------> |
  |                     |<- payment confirmed ---------------------- |
  |<- 200 OK ---------- |                     |                      |
```


# Circle's EURC Integration Guide

This guide will help you integrate EURC cross-chain transfers into your application using Squid's widget, API, or SDK in as little as 20 minutes. You'll learn how to enable seamless cross-chain transfers to EURC on Base, Ethereum, and Avalanche. While this guide focuses on EURC, it extends to all tokens listed on Squid.

### Supported EURC Contract Addresses

Base: `0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42`

Ethereum: `0x1abaea1f7c830bd89acc67ec4af516284b1bc33c`

Avalanche: `0xc891eb4cbdeff6e073e859e987815ed1505c2acd`

### Integration Options

Squid makes it easy to integrate EURC into your app using the Squid widget. Out of the box, you can allow users to bridge any asset from over 80+ supported chains into EURC on the chain of your choice. There are three ways you can integrate Squid:

1. Widget
   1. This is as simple as an iframe or your can natively integrate it into your app using React, NextJS or Vite.
2. API (language-agnostic)
   1. RESTful endpoints for any programming language
   2. Supporting cross-chain swaps into custom application flows.
3. SDK (for JavaScript/TypeScript applications)
   1. Supporting cross-chain swaps into custom application flows.
   2. Full programmatic control for custom integration

### Helpful Resources

Here is a short list of resources that will help you on your journey to integrate EURC into your application with Squid.

* In order to utilize Squid, you must first request an [integrator ID](https://squidrouter.typeform.com/integrator-id?typeform-source=circle)(API Key) which will be sent to your email.
* Squids full documentation is at <https://docs.squidrouter.com/>
* Squid also has convenient ready-to-run API and SDK [Github repository](https://github.com/0xsquid/examples).
* Explore Squid’s Widget Studio to customize it to your application’s style: <https://studio.squidrouter.com/>

### Widget Installation Options

#### 1. iFrame Integration (Universal Method)

The simplest way to integrate EURC acquisition into any application is using Squid's iFrame implementation. This method works with any framework or platform and requires minimal setup.

```html
<iframe
  title="squid_widget"
  width="430"
  height="684"
  src="<https://studio.squidrouter.com/iframe?config=>{
    'integratorId': '<your-integrator-id>',
    'defaultTokensPerChain': [
      {
        'address': '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
        'chainId': '8453'
      }
      // Add other EURC tokens as needed
    ]
  }"
></iframe>

```

To customize the iFrame implementation:

1. Visit the [Squid Widget Studio](https://studio.squidrouter.com/)
2. Configure your preferences
3. Click "Get iFrame" to receive your custom configuration
4. Copy the generated iFrame code into your application

*You can find the full iframe documentation* [*here*](https://docs.squidrouter.com/widget-integration/add-a-widget/widget/iframe-installation)*.*

#### 2. React Integration

For React applications, import and implement the Squid Widget:

```tsx
import { SquidWidget } from "@0xsquid/widget";

function App() {
  return (
    <div className="App">
      <SquidWidget
        config={{
          integratorId: "<your-integrator-id>",
          apiUrl: "<https://v2.api.squidrouter.com>",
          // Configure EURC as default token for supported chains
          defaultTokensPerChain: [
            {
              address: "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42",
              chainId: "8453", // Base
            },
            {
              address: "0x1abaea1f7c830bd89acc67ec4af516284b1bc33c",
              chainId: "1", // Ethereum
            },
            {
              address: "0xc891eb4cbdeff6e073e859e987815ed1505c2acd",
              chainId: "43114", // Avalanche
            }
          ],
          // Set initial assets
          initialAssets: {
            from: {
              address: "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42",
              chainId: "8453", // Base
            },
            to: {
              address: "0x1abaea1f7c830bd89acc67ec4af516284b1bc33c",
              chainId: "1", // Ethereum
            }
          }
        }}
      />
    </div>
  );
}

```

*You can find the full React documentation* [here](https://docs.squidrouter.com/widget-integration/add-a-widget/widget/react-installation)*.*

#### 3. NextJS Integration

Add the following to your `next.config.js`:

```jsx
const nextConfig = {
  transpilePackages: ["@0xsquid/widget", "@0xsquid/react-hooks"]
}

module.exports = nextConfig

```

Then implement the widget similar to the React example above.

*You can find the full NextJS documentation* [here](https://docs.squidrouter.com/widget-integration/add-a-widget/widget/nextjs-installation)*.*

#### 4. Vite Integration

Update your `vite.config.ts` to include:

```tsx
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { nodePolyfills } from "vite-plugin-node-polyfills"

export default defineConfig({
  plugins: [
    react(),
    nodePolyfills()
  ]
})

```

*You can find the full Vite documentation* [here](https://docs.squidrouter.com/widget-integration/add-a-widget/widget/vite-installation)*.*

### Customization

#### Theme Customization

Use the Squid Widget Studio to customize the appearance:

```tsx
config={{
  theme: {
    borderRadius: {
      "button-lg-primary": "3.75rem",
      container: "1.875rem",
      input: "9999px"
    },
    color: {
      "primary-500": "#YOUR_BRAND_COLOR",
      "secondary-500": "#YOUR_SECONDARY_COLOR"
    }
  },
  themeType: "dark" // or "light"
}}

```

*You can find the full customization documentation* [here](https://docs.squidrouter.com/widget-integration/add-a-widget/widget/customization-guide)*.*

### API Integration

This documentation details how to request a route, execute a transaction, and check the status of the transaction. You can find the full API integration documentation [here](https://docs.squidrouter.com/api-and-sdk-integration/api).

#### Route Generation

```tsx
const getRoute = async (params) => {
  const response = await axios.post(
    "<https://v2.api.squidrouter.com/v2/route>",
    {
      fromAddress: "0x...", // Your wallet address
      fromChain: "8453", // Base
      fromToken: "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", // EURC on Base
      fromAmount: "1000000000000000000", // Amount in wei
      toChain: "1", // Ethereum
      toToken: "0x1abaea1f7c830bd89acc67ec4af516284b1bc33c", // EURC on Ethereum
      toAddress: "0x...", // Recipient address
      slippage: 1,
    },
    {
      headers: {
        "x-integrator-id": "<your-integrator-id>",
        "Content-Type": "application/json",
      },
    }
  );
  return { data: response.data, requestId: response.headers["x-request-id"] };
};

```

#### Transaction Execution

```tsx
const executeCrossChainTransfer = async (route) => {
  const tx = await signer.sendTransaction({
    to: route.transactionRequest.target,
    data: route.transactionRequest.data,
    value: route.transactionRequest.value,
    gasPrice: await provider.getGasPrice(),
    gasLimit: route.transactionRequest.gasLimit,
  });
  return await tx.wait();
};

```

#### Transaction Status Check

```tsx
const getStatus = async (params) => {
  const response = await axios.get(
    "<https://v2.api.squidrouter.com/v2/status>",
    {
      params: {
        transactionId: params.transactionId,
        requestId: params.requestId,
        fromChainId: params.fromChainId,
        toChainId: params.toChainId,
      },
      headers: {
        "x-integrator-id": "<your-integrator-id>",
      },
    }
  );
  return response.data;
};

```

### SDK Integration

This documentation details how to request a route, execute a transaction, and check the status of the transaction. You can find the full SDK integration documentation [here](https://docs.squidrouter.com/api-and-sdk-integration/sdk).

#### Installing the SDK

```bash
npm install --save @0xsquid/sdk@2.8.27 # or higher
```

#### Basic EURC Integration Example

```tsx
import { Squid } from "@0xsquid/sdk";
import { ethers } from "ethers";

// Initialize Squid SDK
const squid = new Squid({
  baseUrl: "<https://v2.api.squidrouter.com>",
  integratorId: "<your-integrator-id>",
});
await squid.init();

// EURC cross-chain transfer parameters
const params = {
  fromAddress: signer.address,
  fromChain: "8453", // Base
  fromToken: "0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42", // EURC on Base
  fromAmount: ethers.utils.parseUnits("10", 18).toString(),
  toChain: "1", // Ethereum
  toToken: "0x1abaea1f7c830bd89acc67ec4af516284b1bc33c", // EURC on Ethereum
  toAddress: signer.address,
  enableBoost: true,
};

// Get route and execute transfer
const { route, requestId } = await squid.getRoute(params);
await approveSpending(route.transactionRequest.target, params.fromToken, params.fromAmount);
const tx = await squid.executeRoute({ signer, route });

```

#### Monitoring Transaction Status

```tsx
const getStatusParams = {
  transactionId: tx.hash,
  requestId: requestId,
  integratorId: "<your-integrator-id>",
  fromChainId: "8453",
  toChainId: "1",
};

let status = await squid.getStatus(getStatusParams);
console.log(`Route status: ${status.squidTransactionStatus}`);
```


# Integrate Your Chain

## Adding a New Chain to Squid

To onboard a new chain to Squid, the integration is executed through **Squid Intents**, our intent-based cross-chain routing protocol. Squid Intents enables seamless, efficient, and secure swaps across a wide network of supported blockchains by connecting users directly with market makers.

### What We Need From You

To support your chain within Squid, we require:

* **A market maker loan** to enable Squid Intents to execute swaps on your chain with deep liquidity and guaranteed execution quality.

This loan ensures that Squid intents market makers can fulfill intents rapidly, securely, and with zero slippage for users transacting with your chain.

### Why Integrate with Squid?

Squid is designed for scalable, low-latency cross-chain interactions. By integrating with Squid, your chain gains:

* **Access to 100+ Chains** already supported by Squid, including Solana, BTC, and major EVMs
* **Execution in Under 5 Seconds** for most swaps
* **Zero Slippage**, with direct market maker fulfillment
* **Up to 90% Gas Cost Reduction** compared to traditional AMM-based routing
* **MEV Protection** and **Enterprise-grade Security**

### Technical Requirements

* Squid Intents uses a **RFQ intent-based protocol design** and **TEE-verified batched settlement**.
* Smart contracts are **audited**, **non-upgradeable**, and **ownerless**, ensuring security and neutrality.

### Next Steps

If you're interested in adding your chain to Squid via Coral, please reach out to the Squid Integration team at <nick@squidrouter.com> or on [Telegram](https://t.me/nickpayiatis) to begin integration discussions and initiate the market maker loan.


# Contracts

Squid's contract addresses are the same on every EVM chain.

## **Mainnet**

### **SquidRouter**

| Chain   | address                                                                                                                   |
| ------- | ------------------------------------------------------------------------------------------------------------------------- |
| All     | 0xce16F69375520ab01377ce7B88f5BA8C48F8D666                                                                                |
| Blast   | [0x492751eC3c57141deb205eC2da8bFcb410738630](https://blastexplorer.io/address/0xDC3D8e1Abe590BCa428a8a2FC4CfDbD1AcF57Bd9) |
| Fraxtal | [0xDC3D8e1Abe590BCa428a8a2FC4CfDbD1AcF57Bd9](https://fraxscan.com/address/0xdc3d8e1abe590bca428a8a2fc4cfdbd1acf57bd9)     |

### **SquidMulticall**

0xaD6Cea45f98444a922a2b4fE96b8C90F0862D2F4


# Additional Dev Resources

Additional Dev Resources is a repository of topics and information that can help developers and builders who are looking to utilize Squid's widgets, API, or SDK.

**To quickly navigate the topics use the Ask feature, in the top right, which will help you navigate to documentation related to your question.**


# Choose How To Integrate Squid

{% tabs %}
{% tab title="Widgets" %}
Customisable React or iframe widgets built for specific user flows. Recommended in most cases.

* Fastest to implement
* Customisable themes
* Customisable supported tokens, hooks etc
* Multi-chain wallet management
* Handle all edge cases regarding cross-chain UX.
* Different widgets for Swap & Bridge, Staking, Checkout

<figure><img src="/files/HZcg1n7O5I0ww9LpTyUN" alt=""><figcaption></figcaption></figure>
{% endtab %}

{% tab title="SDK" %}
All the main Squid functions, and some more helpers, in typescript, at your fingertips. Get full control of your UI.

```typescript
const route = await squid.getRoute(params)

const fromToken = squid.tokens.find(
  (t) =>
    t.symbol.toLocaleLowerCase() === "USDC" && t.chainId === "1"
);
```

{% endtab %}

{% tab title="API" %}
Write your own client code for Squid.

Best for traders, wallets, mobile apps, or anyone who prefers not to use Javascript and ethers/wagmi etc.

```typescript
const getRoute = async (params: any) => {
	const result = await axios.get('https://api.squidrouter.com/v1/route', {
		params: params,
		headers: {
			'x-integrator-id': integratorId,
		},
	});
	return result.data;
};
```

{% endtab %}
{% endtabs %}

<figure><img src="/files/stCbQ86vln4Mn39a0I2C" alt=""><figcaption></figcaption></figure>


# Squid x Tenderly

Mainnet fork dev environment

Squid has worked with [Tenderly](https://tenderly.co/) to build a powerful cross-chain development environment. This environment is a replicated Mainnet fork of most Squid-supported EVM chains. This lets users and developers test using mainnet liquidity, and is our recommended development environment.

You can spend funds from your account in this environment without spending them on mainnet.

Mainnet fork environment base URL <https://axelar-relayer.testsquidrouter.com/api>

Polygon mainnet fork RPC <https://rpc.tenderly.co/fork/94010ea6-20cb-4a3a-b8b6-c7cb5e4574e8>

Arbitrum mainnet fork RPC <https://rpc.tenderly.co/fork/ba53ac43-0a0f-4f0a-9735-5b5de80c028f>

You can get other RPCs from this front end <https://squid-widget-git-main-v2-0xsquid.vercel.app/?apiUrl=https://axelar-relayer.testsquidrouter.com/api>

* Try connecting your wallet and clicking “switch network” on the source wallet. Metamask should pop up with the new chain config (MAKE SURE YOU DON'T SUBMIT TO REAL MAINNET)

{% tabs %}
{% tab title="Users" %}
Users can test swapping in our dev environment

{% embed url="<https://squid-widget-git-main-v2-0xsquid.vercel.app/?apiUrl=https://axelar-relayer.testsquidrouter.com/api>" fullWidth="true" %}
{% endtab %}

{% tab title="Widget" %}
Set your base URL to <https://axelar-relayer.testsquidrouter.com/api>
{% endtab %}

{% tab title="SDK" %}
Set your base URL to <https://axelar-relayer.testsquidrouter.com/api>

<pre class="language-typescript"><code class="lang-typescript">import { Squid } from "@0xsquid/sdk";

<strong>(async () => {
</strong>  // instantiate the SDK
  const squid = new Squid();

  squid.setConfig({
    baseUrl: "https://axelar-relayer.testsquidrouter.com/api", // for testnet use "https://testnet.v2.api.squidrouter.com"
    integratorId: "your-integrator-id"
  });

  // init the SDK
  await squid.init();
  console.log("Squid inited");
})();
</code></pre>

{% endtab %}

{% tab title="API" %}
Set your base URL to <https://axelar-relayer.testsquidrouter.com/api>

```typescript
const baseUrl = "https://v2.api.squidrouter.com/v2"
```

{% endtab %}

{% tab title="Debug" %}
You can use Tenderly's block explorer and debugger on any transaction submitted to these RPCs.

{% embed url="<https://dashboard.tenderly.co/explorer>" %}
{% endtab %}
{% endtabs %}

###


# Testnet or Mainnet?

### Mainnet

Currently Squid only supports mainnet since maintaining liquidity across testnets is not feasible.


# Understanding Gas Payments

Cross-chain transactions are all about gas.

The lack of atomicity, as well as varying prices of gas on different chains makes reliable execution very difficult to obtain. It's something we pride ourselves on, as for over a year we've been working closely with Axelar's relay team to hone gas payments to get reliable and cheap execution for our users.

Here are the basics:

Squid separates gas fee payments into source chain and cross-chain gas fees.

### Source chain gas fees

Source chain gas fees are paid by the user as normal for any crypto transaction.

1. The Squid API/SDK/Widget recommends the `gasLimit` for the transaction.
   * i.e. the maximum amount of gas that the source transaction will consume.
2. The user's wallet recommends a good price per unit of `gas` that will get the transaction executed on chain.
   * This amount is variable and so the exact cost of the source chain transaction is unknown until the user completes the tx.

### Cross-chain gas fees

Squid bundles all cross-chain gas fees into a single payment, whether the transaction includes multiple hops or just one hop. The complexity is abstracted away from any developer using the Squid API/SDK/Widget.

From EVM

* For transactions from EVM chains, Axelar takes a gas payment using `value` in native tokens on the source chain. If we are sending USDC from Arbitrum, we pay native ETH to the Axelar gas service contract as part of source chain transaction. Hence, the user needs enough native gas on the source chain to pay for the entire transaction, and this is independent from the amount the user is swapping/bridging.
* You can find the `value` amount to be paid in the API or SDK route response at `route.estimate.transactionRequest.value`
* Axelar's model for cross-chain gas fee payment is currently a pay for what you use model. The user over pays on the source chain, then gets refunded the value that isn't used during the transaction.

From Cosmos via Axelar

* Gas fees are paid as part of the token to be bridged. For example if swapping from ATOM to ETH, Squid will swap first to axlUSDC, bridge to Ethereum, then swap for ETH. The bridged token is axlUSDC, so the cross-chain gas payment to Axelar will be paid in axlUSDC.

From Cosmos via IBC

* IBC currently is subsidised by relayers and has no implemented fee model, so cross-chain gas payments are free. This will change in the future and Squid's API/SDK will adapt to the new models.


# SDK easter eggs


# Setting toAmount

If you want to buy something worth a certain amount, the best method is to overestimate by more than the expected slippage. We have a method on the SDK to estimate the required `fromAmount` you need to get a `toAmount` on the destination chain. It uses coingecko prices to approximate a number.

Get a `fromAmount` based on `fromToken`, `toToken` and `toAmount`.

Example usage:

```typescript
const ETH = squid.getTokenData(
  "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
  "1"
);

const USDC = squid.getTokenData(
  "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "1"
);

const usdcToEth = await squid.getFromAmount({
  fromToken: USDC,
  toAmount: "1",
  toToken: ETH
}); // expected: ~1600

const ethToUsdc = await squid.getFromAmount({
  fromToken: ETH,
  toAmount: "200",
  toToken: USDC
}); // expected: ~0.12...

// you can also specify slippage percentage (default is 1.5%)
const usdcToEth3 = await squid.getFromAmount({
  fromToken: USDC,
  toAmount: "1",
  toToken: ETH,
  slippagePercentage: 3
}); // expected: ~1648
```


# getAllBalances

Squid's SDK provides a function to get the balance of every token we support by providing an address for each environment.

```typescript
const squid = new Squid({
  baseUrl: "https://v2.api.squidrouter.com",
  integratorId: "squid-test"
});

await squid.init();

const allBalances = await squid.getAllBalances({
  chainIds: ["osmosis-1", 43114, 8453],
  evmAddress: "0x344b63c2BcB4B61765083735e8F49Bb203415a33",
  cosmosAddresses: [
    {
        address: "cosmos1awrua7e2kj69d7vn5qt5tccrhavmj9xajl58pw",
        chainId: "cosmoshub-4",
        coinType: 118
     }
  ]
})
// result:
// {
//   cosmos: [
//     {
//       balance: "676727870",
//       denom:
//         "ibc/E6931F78057F7CC5DA0FD6CEF82FF39373A6E0452BF1FD76910B93292CF356C1",
//       chainId: "osmosis-1",
//       decimals: 6
//     },
//     {
//       balance: "5987424",
//       denom: "uosmo",
//       chainId: "osmosis-1",
//       decimals: 6
//     }
//   ],
//   evm: [
//     {
//       balance: "2981435909446986",
//       symbol: "ETH",
//       address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
//       decimals: 18,
//       chainId: "8453"
//     },
//     {
//       balance: "788395441854562446",
//       symbol: "AVAX",
//       address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
//       decimals: 18,
//       chainId: "43114"
//     }
//   ]
// }

const evmBalances = await squid.getEvmBalances({
  userAddress: "0x344b63c2BcB4B61765083735e8F49Bb203415a33",
  chains: [1, 43114, 8453]
})

// result:
// [
//     {
//       balance: "41345097216001030",
//       symbol: "ETH",
//       address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
//       decimals: 18,
//       chainId: "1"
//     }, {
//       balance: "9424225",
//       symbol: "USDC",
//       address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
//       decimals: 6,
//       chainId: "1"
//     }, {
//       balance: "81435909446986",
//       symbol: "ETH",
//       address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
//       decimals: 18,
//       chainId: "8453"
//     }, {
//       balance: "788395441854562446",
//       symbol: "AVAX",
//       address: "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",
//       decimals: 18,
//       chainId: "43114"
//     }
//   ]

const cosmos = await squid.getCosmosBalances({
  addresses: [
    {
      chainId: "cosmoshub",
      address: "cosmos1awrua7e2kj69d7vn5qt5tccrhavmj9xajl58pw",
      coinType: 118
    }
  ]
})
// result:
//  [
//    {
//       balance: "1804685",
//       denom: "uatom",
//       chainId: "cosmoshub-4",
//       decimals: 6
//     }
//   ]

```


# Advanced set up

To get started you will need to instantiate and configure the Squid SDK:

```typescript
const Squid = new Squid(config)
```

The optional `config` parameter can be used to pass custom configuration to the SDK:

```typescript
type Config = {
  apiKey?: string
  baseUrl?: string
  executionSettings?: {
    infiniteApproval?: boolean
  }
}
```

| Property                           | Description                                                                                                                                       |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| apiKey                             | *API KEY* to have access to *Squid API* (not implemented yet)                                                                                     |
| baseUrl                            | Set the *Squid API URL*, this should be used to set the *environment*                                                                             |
| executionSettings                  | Customize *executeRoute* method behavior                                                                                                          |
| executionSettings.infiniteApproval | Set to *false* if you only want to approve the specific amount of tokens to be send in the *executedRoute* method. (infinite approval as default) |


# Manually approve a route

Usually, the squid sdk will handle approvals, but if you want to manually approve the Squid smart contracts to use tokens for a route, you can use the below command that execute the `approveRoute` method with `ApproveRoute` object as argument and return a `boolean`.

Type: [Types](/old-v2-documentation-deprecated/key-concepts/types#approveroute)

```javascript
const isApproved = await squid.approveRoute({ signer, route })
```

This will approve `amount` or `infiniteAmount` of `fromToken` required to do the transfer. Once the tokens are approved, you can execute the route.

### Checking route approval

You can also check if the route has been approved using the following method that retrieves an object with `isApproved` and `message` properties

```typescript
const { isApproved, message } = await squid.isRouteApproved({ sender, route })
```


# Manually approve an ERC20

You can also manually approve the Squid smart contract to use ERC20 tokens using `squid.approve` [Types](/old-v2-documentation-deprecated/key-concepts/types#approve)

<pre class="language-typescript"><code class="lang-typescript">await squid.approve({
<strong>  signer,
</strong>  spender: "0x6972A415e0572bd2E5E3c7DF307d0AFe32D30955",
  tokenAddress: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
  amount: "100000000000000000000" // if not passed, inifite approval take place
})
</code></pre>


# Architecture

Squid is built around one principle: blockchains are settlement layers, not execution layers. Everything that can be handled offchain, is. Squid Intents is the intent-based settlement protocol at the core of this architecture. It takes what you want to do and handles all the coordination, routing, and verification offchain, so the chain only ever sees what must be true in any trade: a token transfer.

Because execution logic lives offchain rather than in smart contracts deployed on individual chains, Squid is not constrained by which chains support smart contracts. This is what gives Squid access to any chain and any token, including Bitcoin, Solana, XRPL, and beyond.

### The Execution Engine

Squid Intents uses TEE-verified settlement. A TEE is a sealed environment inside a processor where code runs in hardware-enforced isolation, producing a cryptographic proof that execution was correct. Squid's TEEs are powered by Cubist, who have secured over $10B and maintain decentralized upgrade and deployment pathways.

<figure><img src="/files/aVMysY4W7Ve0lqlUWcTq" alt=""><figcaption></figcaption></figure>

### How a Transaction Gets Routed

1. **You submit your intent via the Squid API, SDK, or widget.** You receive the best quote, sign, and deposit on the source chain.
2. **The Squid API opens an offchain RFQ auction. Market makers compete in real time to fill your order.** The winning market maker fills the order on the destination chain and submits proof to the TEE.
3. **The TEE verifies the fill and signs the release. Funds are released to the market maker on the source chain.**
4. **You receive your tokens on the destination chain once settled. Only a token transfer ever touched the chain.** If anything fails, you are automatically refunded on the source chain within 15 minutes.

<figure><img src="/files/fmpS0Jf0cboLBjyHqdtF" alt=""><figcaption></figcaption></figure>


# FAQ

## What is Squid?

Squid is a single integration for seamless cross-chain swaps, bridges, and contract calls across 100+ chains, including EVM, Bitcoin, Solana, Ripple, Hedera, and Cosmos.

## What is Squid Intents?

Squid Intents is Squid's intent-based settlement protocol. You tell Squid what you want, and it handles the execution. No expiry windows, no slippage, no failed transactions you have to chase down.

## Is Coral still live?

Coral was Squid's original execution engine, built on Axelar and Layer Zero's General Message Passing protocol. It handled cross-chain execution and settlement across EVM chains and safely moved billions. Squid Intents is what we built on top of it once we knew what scale beyond EVM required.

## Is Squid a bridge?

Not exactly. Squid uses multiple protocols including Axelar and Layer Zero to route and settle cross-chain transactions. The experience is closer to a swap than a bridge, without the wrapped tokens, the waiting, or the risk.

## What are the fees?

Squid charges no protocol fees. Users pay gas on the source chain only. With Squid Intents, gas costs are reduced by up to 90% compared to traditional AMM-based routing.

## What is an RFQ auction?

RFQ stands for Request for Quote. Instead of routing through automated liquidity pools, Squid Intents runs an auction where market makers compete to fill your order. The winner gets the trade, you get the best available price at execution time with zero slippage.

## What happens if my transaction fails?

Your funds are automatically refunded on the source chain within approximately 15 minutes. No manual intervention needed.

## Do routes expire?

No. Unlike older bridging solutions, Squid Intents routes do not expire. You can submit your transaction at any time after receiving a quote.

## Which chains does Squid support?

Squid supports 100+ chains including Ethereum, Arbitrum, Base, Hedera, Citrea, XRPL EVM, and more. Bitcoin and Solana support is coming soon.

## What tokens can I swap?

Any token on any supported chain. Squid is not limited to chains with smart contracts.

## Has the protocol been audited?

Yes. Squid has completed 9 audits and has never suffered a security breach or hack.

## How do I integrate Squid?

Through the Squid API, SDK, or widget. All Squid Intents transactions use the /v2/route endpoint. See the integration docs for details.

## What is a TEE?

A Trusted Execution Environment is a sealed area inside a processor where code runs in complete isolation, enforced by hardware rather than network consensus. It produces cryptographic proof that the code ran correctly. Squid's TEEs are powered by Cubist.

## Is Squid built on Axelar?

Squid integrates with Axelar but is not exclusively built on Axelar. While squids early days used much of Axelar's GMP technology, Squid Intents and many of Squids other products do not utilize GMP anymore.


# Liquidity model

With the introduction of Squid Intents, Squids liquidity model has evolved to provide superior pricing and efficiency. By leveraging post-deposit RFQ auctions and TEE-verified batched settlement, Squid Intents minimizes onchain logic and maximizes execution quality. Squid Intents sources liquidity differently from traditional AMM-based bridges. Instead of routing through fixed liquidity pools, Squid Intents runs post-deposit RFQ auctions where market makers compete to fill your order at the best available price.

<figure><img src="/files/LxrVat1Rh8mfxDQPMOx6" alt=""><figcaption></figcaption></figure>

This approach allows for tighter pricing, reduced slippage, and a more robust liquidity provision across diverse chains. The system now supports a wider range of market makers and ensures that users consistently receive the best available market price at execution time. Squid supports swapping any to any token across all the chains it supports, utilising existing liquidity.

### Here is how it works:

RFQ Auctions When you submit a swap, Squid Intents opens an auction on the source chain after your deposit lands. Market makers bid to fulfill the order on the destination chain. The winning solver settles your tokens directly, hedging their position milliseconds after winning. You get the best market price at execution time, not a pre-quoted estimate padded for volatility.

### Offchain Coordination, Onchain Settlement

All execution logic runs offchain inside Squid's TEE-verified infrastructure. The only thing that touches the chain is what must be true in any trade: a token transfer. This keeps gas costs near zero and eliminates the slippage risk that comes with routing through AMM pools.

### Any Token, Any Chain

Squid Intents is not dependent on wrapped or synthetic assets to route liquidity. Market makers supply liquidity natively across chains, which means Squid can support any token on any chain, including chains without smart contracts like Bitcoin, Solana, and XRPL.<br>


# Transaction times and fees

## Fees

Squid currently charges no fees. The user will only pay gas fees on source and destination chains.

It is possible for our partners to charge fees via our SDK or API. Partners can elect a % fee they would like to charge, and Squid will receive a portion of this fee.

### Source Chain transactions

#### EVM

Fees are comprised of the following and are paid in Native Gas

* Gas amount needed for any swaps, approvals and transfers
* If the "from token" is the Native gas token, this amount is also added to the gas payment
* The execution fees for the destination chain

#### Cosmos

Cosmos transactions are different to EVM transaction as the destination chain gas fees are taken out of the bridge token. e.g for a route that is Osmo:Osmosis > ETH:Ethereum, usually the bridge token will be axlUSDC, and this is where the GMP (bridge) fee will be taken from. If the route is axlWETH > WETH the fee will be taken in WETH.\
Gas payment for source chain will be only the amount needed for the execution on the Cosmos chain, all IBC relaying comes at 0 cost.

### General message passing fees (swap on destination chain)

Just like the source chain transactions, the amount gas charged is calculated base off how many swaps, transfers and approvals there are.

For transactions where there is a swap on the destination chain, fees are paid using the Native token on the source chain. This fee is paid to Axelar's relayers, who trustlessly pass messages and proofs across chains.

Axelar's relayers hold gas on every chain and provide a pricing API which Squid calls to get the expected gas price for a trade. For example if the destination trade will probably cost 50 cents of AVAX in gas, then Squid will instruct the user to pay Axelar's gas service 50 cents worth of Moonbeam, as per the pricing which Axelar gives our backend.

### CCTP Noble Fees

CCTP bridge is not considered a transfer and there is no fee for this.


# Brand Assets

This repository contains Squid's official brand assets.

## Squid Text Logo

### Text Logo - Black

{% file src="/files/ajPiPF2zNrqGmWfMuyrz" %}

{% file src="/files/qit8ahGbGizp17mOgZSr" %}

### Text Logo - White

{% file src="/files/estFZ2QGfI3fh7HVRazI" %}

{% file src="/files/9jPDIBlVAlrvqe0adefO" %}

## Squid Icon Logo

### Icon Logo - Yellow

{% file src="/files/bt2Yp3i4FTc1rVhiY3sO" %}

{% file src="/files/hMDzrgQs6cqv3f5ai5ta" %}

### Icon Logo - Purple

{% file src="/files/NAMZj6VdjqiUDLpuPCtY" %}

{% file src="/files/w9GEC3UCP2335CoIQ9F5" %}

### Icon Logo - Black

{% file src="/files/s1CfDjmPuRusDdi6aVgE" %}

{% file src="/files/AwzS2hAqHBZxgEGxSost" %}

### Icon Logo - White

{% file src="/files/hYzKGFfuVMoTMLka1Nix" %}

{% file src="/files/1Ex493cGd68B7DRblfOO" %}


# "Powered by Squid" Policy

## Policy

Squid requires any app integrating the Squid SDK or API to display a "Powered by Squid" logo.

### "Powered by" Wordmark - Black

{% file src="/files/BI6TLaZXbdAaex9MXW9U" %}

{% file src="/files/KlKmKv3hVobCfpGFZvqN" %}

### "Powered by" Wordmark - White

{% file src="/files/5fNMfk2HuAvl1wSZAEch" %}

{% file src="/files/TbVCFQIMgPV9HpEPKq2d" %}


# Audits & Security

## **Security**

Squid's smart contracts are designed to never hold liquidity, they only orchestrate calls to DEXs, and any other involved contracts. They do this, and deal with edge cases around cross-chain mechanics. This avoids security risks usually associated with token bridges.

Squid's TEEs are also undergoing constant monitoring.

## Audits

**To date, Squid has undergone 9 audits.** Squid emphasizes the security of its platform and the safety of users' assets. Regular audits are conducted to ensure the integrity and security of Squid’s smart contracts and protocols.

* 6 audits by [Ackee Blockchain](https://ackee.xyz/)
* 1 by [Consensys Diligence](https://consensys.io/diligence/)
* 1 Audit by [0xKaden](https://twitter.com/0xkaden?lang=en)
* 1 Audit by [n-Var](https://github.com/0xsquid/audits/blob/main/audits/2024-09%20n-var.pdf)

We conduct ongoing audits that review all changes to the code to ensure a high degree of security.

## Audit Records

<table><thead><tr><th width="144" align="center">Date</th><th>Auditor</th><th>Scope</th></tr></thead><tbody><tr><td align="center">2024-04</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2024-04%20Kaden.pdf">Kaden</a></td><td><code>SquidRouter.sol</code>, <code>SquidMulticall.sol</code></td></tr><tr><td align="center">2024-01</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2024-01%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>DepositReceiver.sol</code>, <code>ReceiverImplementation.sol</code>, <code>SquidDepositService.sol</code>, <code>SquidRouter.sol</code>, <code>SquidMulticall.sol</code></td></tr><tr><td align="center">2023-06</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2023-06%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>DepositReceiver.sol</code>, <code>ReceiverImplementation.sol</code>, <code>SquidDepositService.sol</code>, <code>SquidRouter.sol</code>, <code>SquidMulticall.sol</code></td></tr><tr><td align="center">2023-02</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2023-02%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>SquidRouter.sol</code></td></tr><tr><td align="center">2022-11</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2022-11%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>SquidFeeCollector.sol</code>,<code>SquidFeeCollectorProxy.sol</code></td></tr><tr><td align="center">2022-10</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2022-10%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>RoledPausable.sol</code>,<code>SquidMulticall.sol</code>,<code>SquidRouter.sol</code>,<code>SquidRouterProxy.sol</code>,<code>/interfaces/*</code></td></tr><tr><td align="center">2022-09</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2022-09%20Consensys%20Diligence.pdf">Consensys Diligence</a></td><td><code>SquidRouter.sol</code>,<code>SquidMulticall.sol</code>, <code>SquidProxy.sol</code></td></tr><tr><td align="center">2022-06</td><td><a href="https://github.com/0xsquid/audits/blob/main/audits/2022-06%20Ackee%20Blockchain.pdf">Ackee Blockchain</a></td><td><code>SquidSwapExecutable.sol</code>,<code>DistributionENSExecutable.sol</code>,<code>SquidToken.sol</code></td></tr></tbody></table>


# Contact

🫂 Come find us on Discord or Twitter :)

* Discord: <https://discord.gg/squidrouter>
* Twitter: [@squidrouter](https://twitter.com/squidrouter)
* Website: [https://squidrouter.com](https://squidrouter.com/)


# SDK

All notable changes to the SDK NPM package will be documented in this page.


# v1.3

#### 1.3.9 (2023-02-01)

#### Bug Fixes

* Fix issue where gas underestimation issue on source and destination chain

#### 1.3.7 (2023-01-30)

#### Features

* Add support for receiving gas on destination chain
* Add option to ignore gas price in executeRoute

#### 1.3.5 (2023-01-12)

#### Features

* Add new parameter to override approval action
* Add an option to set prefer dex in getRoute method
* Support for EIP1559 type transactions

#### Bug Fixes

* Handle infinite approval setting in executeRoute method parameter instead of global config

#### 1.3.1 (2022-12-13)

#### Features

* Return time spent related parameter in transaction status response
* Add new supported chains

#### 1.3.0 (2022-12-08)

#### Features

* Add new parameter to return USD value in getRoute endpoint response


# v1.2

v1.2 Release Notes

### 1.2.0 (2022-11-21)

#### Features

* Add support for custom contract calls type


# API

All notable changes to the REST API will be documented in this page.


# v1.9

API v1.9 Release Notes

#### 1.9.1 (2023-02-12)

#### Features

* Update axelarjs-sdk to v0.12.4 (Improved gas price estimations)

#### 1.9.0 (2023-02-09)

#### Features

* add Platypus dex support
* add Wombat dex support
* add Sushiswap router
* Increased number of supported tokens on all chains

#### Bug Fixes

* improved gas calculation logic
* slightly increased slippage for stable swaps


# v1.8

API v1.8 Release Notes

#### 1.8.7 (2023-02-07)

#### Features

* Increase cache timeout for `/token-price` API endpoint to 180 seconds

#### Bug Fixes

* Reduce response time for `/route` API endpoint by up to 60%

#### 1.8.6 (2023-02-04)

#### Bug Fixes

* Add support for Curve registry and Ellipsis dex

#### 1.8.4 (2023-02-01)

#### Features

* Enable cache-control on some of endpoints to improve response time

#### 1.8.3 (2023-01-30)

#### Features

* Refactor error messages to make them more human readable

#### Bug Fixes

* Fix for some scenarios where gas limit calculation is underestimated on source and destination chain

#### 1.8.2 (2023-01-28)

#### Bug Fixes

* Refactor status endpoint to support new Axelarscan API endpoint

#### 1.8.1 (2023-01-28)

#### Bug Fixes

* Add more buffer to gas amount when Polygon is set as destination chain


# v1.7

API v1.7 Release Notes

#### 1.7.0 (2023-01-27)

#### Features

* Add support for TraderJoe on Avalanche chain
* Support new option to receive gas on destination chain

#### Bug Fixes

* Fix a bug when sending axlUSDC on cosmos from any EVM chain


# v1.6

API v1.6 Release Notes

Features

* Add new *timeSpent* param to status API response
* Support for Binance and Arbitrum Chain support

Improvements

* update Moonbeam RPC server to improve performance

Bug Fixes

* corrected token config issues with missing URL
* fixed issue with custom contract calls for single call use case




---

[Next Page](/llms-full.txt/1)

