# $QUID Token

$QUID is the native token of Squid. Learn about $QUID utility and tokenomics, including total supply, allocation, vesting, and the ecosystem functions $QUID is designed to support.

For an introduction to $QUID, see: [What is $QUID? Everything you need to know about the native token of Squid](https://www.squidrouter.com/squid-school/what-is-quid-token).

| Action                                       | Chain | Address                                                                                                                 |
| -------------------------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------- |
| [Buy $QUID](http://app.squidrouter.com/quid) | Base  | [`0x1a44233FAe8D50F1AeB3a5d58dd426ff4814Cb53`](https://basescan.org/token/0x1a44233FAe8D50F1AeB3a5d58dd426ff4814Cb53)   |
| [Stake $QUID](http://stake.squidrouter.com/) | Base  | [`0x13af2Db622d167745518aBfD59a8C4FFEe54937a`](https://basescan.org/address/0x13af2Db622d167745518aBfD59a8C4FFEe54937a) |

**Token Icons:** [Download $QUID token icons](https://docs.squidrouter.com/additional-resources/brand-assets#token-icon-circular)

## $QUID at a Glance

<figure><img src="/files/Qucix0tS8KFACeYwdhlq" alt="$QUID at a glance — key token details"><figcaption><p>$QUID at a glance</p></figcaption></figure>

| Detail                | Value              |
| --------------------- | ------------------ |
| **Token Name**        | Squid              |
| **Token Symbol**      | QUID               |
| **Token Chain**       | Base               |
| **Total Supply**      | 1,000,000,000      |
| **Public Sale Price** | $0.045 Per Token   |
| **Sale Allocation**   | 50M (5% Of Supply) |
| **Public Sale FDV**   | $45,000,000        |
| **TGE**               | Q3 2026            |


# $QUID Tokenomics

Full breakdown of $QUID tokenomics including fixed supply, allocation percentages, vesting schedules, and the token emission timeline.

## Token Supply

$QUID has a fixed total supply of **1,000,000,000 tokens**. Genesis supply equals maximum supply: there is no further minting, and no validator or emission rewards are allocated. Allocations are fixed at TGE and sum to 100% of total supply.

## Token Allocation

| Category            | Allocation | Tokens            | TGE Unlock | Cliff |
| ------------------- | ---------- | ----------------- | ---------- | ----- |
| Investors           | 30.39%     | 303,946,126       | 0%         | 12 mo |
| Team & Advisors     | 23.95%     | 239,481,903       | 0%         | 12 mo |
| Strategic Partners  | 10.00%     | 100,000,000       | 0%         | 12 mo |
| Public Sale         | 5.00%      | 50,000,000        | 100%       | —     |
| Ecosystem Growth    | 7.50%      | 75,000,000        | \~93%      | —     |
| Foundation Treasury | 23.16%     | 231,571,971       | 10%        | —     |
| **TOTAL**           |            | **1,000,000,000** |            |       |

<figure><img src="/files/K0M7ITTB5YYFMrVgmkUl" alt="$QUID Token Allocation breakdown"><figcaption><p>$QUID Token Allocation</p></figcaption></figure>

## Vesting Schedule

All insider tokens (Investors, Team, Strategic Partners) are subject to a **12-month cliff** with no TGE unlock, followed by linear vesting enforced by smart contracts.

| Category            | TGE Unlock | Cliff | Cliff Unlock | Linear Vesting                                |
| ------------------- | ---------- | ----- | ------------ | --------------------------------------------- |
| Investors           | 0%         | 12 mo | 25%          | Linear to Month 24                            |
| Team & Advisors     | 0%         | 12 mo | 25%          | Linear to Month 36                            |
| Strategic Partners  | 0%         | 12 mo | 25%          | Linear to Month 36                            |
| Public Sale         | 100%       | —     | —            | —                                             |
| Ecosystem Growth    | \~93%      | —     | —            | 70M at TGE; 5M linear M1–M12 (Year-1 staking) |
| Foundation Treasury | 10%        | —     | —            | 90% linear over 36 months                     |

Public Sale tokens are **100% unlocked at TGE** with no vesting or lock-up. All insider tokens (Investors, Team, Strategic Partners) are locked for 12 months following TGE.

<figure><img src="/files/NNilQlJamZH4X2WJFLG9" alt="$QUID Allocation, Unlock &#x26; Vesting"><figcaption><p>$QUID Allocation, Unlock &#x26; Vesting</p></figcaption></figure>

## Token Emission Schedule

Below is the token emission schedule for $QUID, which demonstrates the rate and timeline at which $QUID tokens will be released into the circulating supply.

<figure><img src="/files/K4wfMMGyAvof0LM3jZ0W" alt="$QUID Token Emission Schedule"><figcaption><p>$QUID Token Emission Schedule</p></figcaption></figure>


# $QUID Utility

$QUID utility within the Squid ecosystem including staking, governance, buyback mechanisms, and broader ecosystem functionality.

## $QUID Utility

$QUID is designed to support ecosystem functions including staking, governance, token-related mechanisms, and broader ecosystem utility. These features may be introduced, modified, or expanded over time, subject to governance, product development, and applicable constraints.

<figure><img src="/files/o80g5LyJzuVTVCpbfRyr" alt="$QUID Token Utility — Governance, Staking, Buybacks, In-App Utility"><figcaption><p>$QUID Token Utility</p></figcaption></figure>

## Staking

$QUID holders may choose to stake their tokens to participate in ecosystem activities, including governance. Staking rewards are distributed from a dedicated, pre-allocated portion of the fixed total supply and do not require the creation of new tokens beyond the fixed supply.

**Year 1.** The Year 1 staking allocation is **5,000,000 $QUID (0.5% of total supply)**, distributed to eligible participants from a dedicated allocation. Distribution amounts are determined according to staking participation and program parameters.

**Year 2 and beyond.** Future staking allocations and program parameters may be modified through governance as the ecosystem evolves.

### Illustrative Year 1 Reward Examples

The examples below are illustrative only and are based on a fixed reward allocation. Actual participation levels and outcomes may vary. Illustrative rates are not guaranteed and are subject to change. These examples assume the fixed Year 1 staking allocation is distributed over a 12-month period and are calculated against the illustrative token-staked amounts shown below.

| Staking Participation     | Tokens Staked | Illustrative APY\* |
| ------------------------- | ------------- | ------------------ |
| 10% of circulating supply | \~22.4M       | \~22.3%            |
| 25% of circulating supply | \~55.9M       | \~8.9%             |
| 50% of circulating supply | \~111.9M      | \~4.5%             |

*\*Illustrative estimates only. Actual results are not guaranteed and may vary based on participation levels and other factors. Rates are subject to change.*

## Governance

$QUID governance is designed to evolve over time. During the early stages of ecosystem development, governance may focus on a limited set of protocol and ecosystem decisions while the platform continues to mature.

As the ecosystem develops, governance scope may expand to include additional areas such as protocol parameters, treasury-related decisions, staking program parameters, and other ecosystem initiatives. The timing and scope of any expansion will depend on ecosystem needs and governance processes.

Governance participation is determined by governance rules in effect at the time. Subject to those rules, governance weight may be associated with staked $QUID.

## Buyback Mechanisms

Following TGE, governance may determine whether a portion of treasury resources is allocated to token-related mechanisms, including the potential purchase of $QUID on the open market. Buybacks are not active at launch. The timing, scope, implementation, activation, and parameters of any such mechanisms will be determined through governance and remain subject to protocol priorities, legal and regulatory considerations, and applicable constraints.

Any tokens acquired through these mechanisms may be managed in accordance with governance-approved policies.

## Ecosystem Utility

$QUID is intended to play a role within the Squid ecosystem. Planned functionality may evolve over time and is subject to product development, governance decisions, and applicable constraints. Specific features, requirements, and eligibility criteria may change.


# Full Token and Sale Disclosures

Full $QUID token and sale disclosures including legal notices, regulatory information, and links to the complete tokenomics framework.

For the complete tokenomics framework, including additional detail on allocation methodology and program parameters, please review the $QUID Token Disclosures document: <https://squidrouter.com/squid-token-sale-disclosures.pdf>

{% hint style="warning" %}
This crypto-asset marketing communication has not been reviewed or approved by any competent authority in any Member State of the European Union. The offeror of the crypto-asset is solely responsible for the content of this crypto-asset marketing communication.
{% endhint %}

A crypto-asset whitepaper for $QUID has been published. The offeror and person seeking admission to trading is Squid (BVI) Ltd. For more information, visit: <https://www.squidrouter.com/>. Tel: +44 7347334617. Email: <token@squid.foundation>.

{% hint style="info" %}
Geographic restrictions vary by sale platform. Please confirm your eligibility on the platform you intend to use before applying.
{% endhint %}

*This article is provided for educational and informational purposes only. This is not investment advice or a recommendation or solicitation for on-chain participation in any mentioned chains, tokens, or assets. Please do your own research before swapping any on-chain assets.*


# 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/EG6DMOA76fuzqDb61OKf">/pages/EG6DMOA76fuzqDb61OKf</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.

Squid currently supports:

* A cross-chain [**Swap Widget**](/widget-integration/add-a-widget/widget) that can be integrated via iFrame, React, Next.js or Vite.
* A cross-chain [**Deposit Widget**](/widget-integration/add-a-widget/deposit-widget) for accepting deposits and one-shot payments into a fixed destination address and token.

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

<figure><img src="/files/kqAngJoEOX9isAUuTfDO" alt=""><figcaption><p>Deposit Widget</p></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 [Supported Chains and Tokens](/chains-and-tokens/get-supported-tokens-and-chains)

### 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

For details on breaking changes, see the [API Changelog](/changelog/api) and [SDK Changelog](/changelog/sdk).


# 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


# Deposit widget

### Introduction

Squid's Deposit Widget is a drop-in React component that lets your users deposit any token, from any supported chain, into a destination address you control — receiving the exact token you specify on the destination chain.

The widget wraps Squid's cross-chain routing API and SDK, so integrators get a fully-featured deposit / payment flow (route quoting, wallet connection, transaction execution and progress tracking) with minimal dev effort. It's the fastest way to accept cross-chain deposits or one-shot payments into your app.

### Widget features

* Two modes: `deposit` (user-entered amount) and `payment` (fixed amount, ideal for checkouts)
* Cross-chain routing across all chains supported by Squid (EVM, Cosmos, XRPL, and more)
* Fully themeable via the shared Squid theming system (light / dark + custom palette overrides)
* Integrator branding (name + logo) rendered inside the widget
* Built-in route preview, progress and success / error screens
* Transaction history view, scoped to your destination address

{% hint style="info" %}
💡 Need a cross-chain swap UI instead of a deposit / payment flow? Check out the [Swap Widget](/widget-integration/add-a-widget/widget).
{% endhint %}


# Getting Started

Supported environments, chains, tokens and wallets

### Environments

The Deposit Widget is a [React](https://reactjs.org/) component, so it works in any React-based app — [Next.js](https://nextjs.org/), Vite, Create React App, and similar.

**Currently supported environments:**

* React (18 or 19)
* Next.js
* Vite

### Supported chains and tokens

The Deposit Widget supports every chain and token available on Squid's routing API, including EVM chains, Cosmos chains, XRPL, Bitcoin and Solana. The destination chain and token are fixed by you (the integrator) via configuration; users pick any supported source chain and token from inside the widget.

### Supported wallets

The widget reuses Squid's wallet stack, so it supports the same wallets as the Swap Widget:

**EVM:** MetaMask, Trust Wallet, Rabby, Zerion, Coinbase Wallet, WalletConnect, Rainbow, BitGet Wallet, OKX Wallet, and more.

**Cosmos:** Keplr, Leap, Cosmostation.

**Other:** Wallets for any non-EVM chain Squid supports on the source side (e.g. XRPL, Solana, Bitcoin) are surfaced when those chains are selected.


# Installing the Widget

Preparing to integrate the Deposit Widget into your app

## Installing the Squid Deposit Widget

### Prerequisites

Before installing the Deposit Widget, ensure you have:

1. Registered for an Integrator ID with the Squid Team.
2. Node.js and a package manager (npm, yarn or pnpm) installed.
3. A React 18 or React 19 app to host the widget.

### Getting an Integrator ID

To use the Deposit 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

Using npm:

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

Using yarn:

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

#### Step 2: Provide React 18+ in your app

The widget declares `react` and `react-dom` (`^18 || ^19`) as peer dependencies — make sure your app satisfies one of these versions.

### Next Steps

After installation, follow the framework-specific guide:

* [React Integration Guide](/widget-integration/add-a-widget/deposit-widget/react-installation)
* [Next.js Integration Guide](/widget-integration/add-a-widget/deposit-widget/nextjs-installation)
* [Vite Integration Guide](/widget-integration/add-a-widget/deposit-widget/vite-installation)

Once the widget is rendered, head to [Configuration](/widget-integration/add-a-widget/deposit-widget/configuration) to customize destination, branding and theme.

### Support

When you receive your Integrator ID, we'll follow up by email to set up a dedicated Telegram group with your team. That group is your direct line to the Squid team for any questions or assistance during integration.


# React Installation

Installing the React component

## React Installation Guide for the Deposit Widget

This guide will help you integrate the Squid Deposit Widget into your React application.

### Prerequisites

Ensure you have completed the steps in the [Installing the Widget](/widget-integration/add-a-widget/deposit-widget/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 `DepositWidget` component and the `DepositConfig` type:

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";
```

2. Define a config and render the widget:

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "0xYourReceivingAddress",
  destinationToken: {
    address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
    chainId: "42161",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};

function App() {
  return (
    <div className="App">
      <DepositWidget config={config} />
    </div>
  );
}
```

Replace `<your-integrator-id>` with the Integrator ID you received from Squid, and `destinationAddress` / `destinationToken` with the address and token you want to receive.

### Customization

Pass `theme` and `themeType` to the config to brand the widget:

```tsx
<DepositWidget
  config={{
    ...config,
    themeType: "dark", // or "light"
    theme: {
      // your theme overrides — see Configuration page
    },
  }}
/>
```

See the [Configuration](/widget-integration/add-a-widget/deposit-widget/configuration) page for the full list of options.


# Next.js Installation

Integrating the Deposit Widget into a Next.js app

This guide will help you integrate the Squid Deposit Widget into your Next.js application.

### Prerequisites

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

### Installation Steps

#### Step 1: Install the package

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

#### Step 2: Render the widget

The widget uses browser-only APIs (wallets, `window`), so it must render on the client. The simplest way is to mark the page or component as a Client Component:

```tsx
"use client";

import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "0xYourReceivingAddress",
  destinationToken: {
    address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
    chainId: "42161",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};

export default function Page() {
  return <DepositWidget config={config} />;
}
```

If you need to keep the parent as a Server Component, wrap the widget in a client-only child or load it dynamically with `next/dynamic` and `ssr: false`.

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

### Customization

Pass `theme` and `themeType` to brand the widget — see the [Configuration](/widget-integration/add-a-widget/deposit-widget/configuration) page for all available options.

### Running Your Next.js App

```bash
yarn dev
```


# Vite Installation

Integrating the Deposit Widget into a Vite app

## Vite Installation Guide for the Deposit Widget

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

### Prerequisites

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

### Installation Steps

#### Step 1: Install the package

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

#### Step 2: Add Polyfills

The widget's underlying wallet stack relies on some Node built-ins, so Vite needs browser polyfills:

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: Render the widget

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

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "0xYourReceivingAddress",
  destinationToken: {
    address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
    chainId: "42161",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};

function App() {
  return <DepositWidget config={config} />;
}

export default App;
```

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

### Customization

Pass `theme` and `themeType` to brand the widget — see the [Configuration](/widget-integration/add-a-widget/deposit-widget/configuration) page for all available options.

### Running Your Vite App

```bash
yarn dev
```


# Configuration

Full reference for the Deposit Widget's config prop

The Deposit Widget takes a single `config` prop, typed as `DepositConfig`. Like the Swap Widget, it accepts your **Integrator ID** and a **theme** for customization. On top of that, it adds the settings specific to deposits and payments: the destination address and token, and the `mode`.

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

<DepositWidget config={config} />;
```

### Modes

`DepositConfig` is a discriminated union over `mode`:

* **`"deposit"`** — the user enters the amount to send. Use this for top-ups, account funding, and any flow where the amount is open-ended.
* **`"payment"`** — the integrator fixes the amount via an extra `amount: string` field. Use this for checkout / pay-this-invoice flows.

### Config fields

| Field                      | Type                     | Required              | Description                                                                                            |
| -------------------------- | ------------------------ | --------------------- | ------------------------------------------------------------------------------------------------------ |
| `mode`                     | `"deposit" \| "payment"` | ✅                     | Selects the widget flow. In `"payment"` mode, `amount` is required.                                    |
| `amount`                   | `string`                 | ✅ (payment mode only) | Fixed amount the user will pay, in destination-token units (human-readable string, e.g. `"25.5"`).     |
| `destinationAddress`       | `string`                 | ✅                     | Address that receives the deposit on the destination chain.                                            |
| `destinationToken.address` | `string`                 | ✅                     | Token contract address on the destination chain.                                                       |
| `destinationToken.chainId` | `string`                 | ✅                     | Squid chain ID of the destination chain (e.g. `"42161"` for Arbitrum, `"xrpl-mainnet"` for XRPL).      |
| `integrator.id`            | `string`                 | ✅                     | Your Integrator ID. Required for Squid to route and account for your traffic.                          |
| `integrator.name`          | `string`                 | ✅                     | Displayed in the widget header so users know which app they're paying / depositing to.                 |
| `integrator.logoUrl`       | `string`                 | ✅                     | URL of your logo, displayed alongside the name.                                                        |
| `apiUrl`                   | `string`                 | ❌                     | Override the Squid API endpoint. Defaults to Squid's production API.                                   |
| `theme`                    | `Theme`                  | ❌                     | Theme object (colors, border radii, shadows, font sizes / weights). See **Theme customization** below. |
| `themeType`                | `"light" \| "dark"`      | ❌                     | Selects the base palette before `theme` overrides apply. Defaults to `"light"`.                        |

### Deposit-mode example

```tsx
const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "0xYourReceivingAddress",
  destinationToken: {
    address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
    chainId: "42161",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};
```

### Payment-mode example

```tsx
const config: DepositConfig = {
  mode: "payment",
  amount: "25.00",
  destinationAddress: "0xYourReceivingAddress",
  destinationToken: {
    address: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC on Arbitrum
    chainId: "42161",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};
```

### Theme customization

To customize the widget's appearance:

1. Use the [Widget Studio](https://studio.squidrouter.com/) to generate a custom theme.
2. Copy the generated `theme` (and `themeType`) and paste them into your `config`.


# 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 [Hooks](https://github.com/0xsquid/squid-documentation/tree/main/widget-integration/api-and-sdk-integration/key-concepts/hooks/README.md) 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: [Hooks](/api-and-sdk-integration/key-concepts/hooks)

### 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.

### Base URL

All API endpoints use the following base URL:

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

### Squid Intents (Enabled by Default)

Squid Intents is **enabled by default** on all integrations. When a Squid Intents route is used, you **must** pass the `quoteId` in the status call for the transaction to be executed successfully. Failing to poll status with the `quoteId` will cause the transaction to fail.

{% hint style="danger" %}
After executing a Squid Intents transaction, you **must** call the status API with the `quoteId` parameter. See [Track Status](/api-and-sdk-integration/key-concepts/track-status) for details.
{% endhint %}

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 Squid Intents 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 Squid Intents 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,
  };

  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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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      | The quote ID from the route response.                               |

#### 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 Squid Intents routes. When a Squid Intents transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Squid Intents routes when passing the user's address as the `fromAddress`.

**How Squid Intents refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Squid Intents, 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"
            },
            "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,
            "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"
}
```


# Authentication

All Squid API requests require authentication via an **integrator ID**. This page covers how to obtain credentials, use them correctly, and follow security best practices.

***

## Get Your Integrator ID

1. **Apply** via the [Integrator ID request form](https://squidrouter.typeform.com/integrator-id).
2. **Check your email** — you will receive your integrator ID shortly after applying.

{% hint style="info" %}
The integrator ID is required for all API, SDK, and widget integrations. The Squid API will reject any request without a valid integrator ID.
{% endhint %}

***

## Using Your Integrator ID

### API Requests

Include your integrator ID in the `x-integrator-id` HTTP header on every request:

```bash
curl -X POST 'https://v2.api.squidrouter.com/v2/route' \
  -H 'x-integrator-id: YOUR_INTEGRATOR_ID' \
  -H 'Content-Type: application/json' \
  -d '{ ... }'
```

### SDK Initialization

Pass your integrator ID when creating the Squid SDK instance:

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

const squid = new Squid({
  baseUrl: "https://v2.api.squidrouter.com",
  integratorId: "YOUR_INTEGRATOR_ID",
});

await squid.init();
```

### Widget Configuration

Include your integrator ID in the widget configuration:

```typescript
<SquidWidget
  config={{
    integratorId: "YOUR_INTEGRATOR_ID",
    // ... other config options
  }}
/>
```

***

## Error Response

If the integrator ID is missing or invalid, the API returns:

```json
{
  "message": "x-integrator-id header is missing",
  "type": "UNAUTHORIZED"
}
```

***

## Security Best Practices

{% hint style="warning" %}
**Never expose your integrator ID in client-side code** if your ID has elevated privileges or custom rate limits. For public-facing widget integrations, the standard integrator ID is safe to include in frontend code.
{% endhint %}

* **Server-side usage**: For API integrations, make Squid API calls from your backend server, never directly from browser JavaScript.
* **Environment variables**: Store your integrator ID in environment variables (`.env`), not in source code.


# Rate Limiting

The Squid API enforces rate limits to ensure fair usage and protect infrastructure. This page documents the rate limiting behavior you may encounter when integrating.

***

## Authentication Required

All API requests must include a valid `x-integrator-id` header. Requests without this header will receive:

```json
{
  "message": "x-integrator-id header is missing",
  "type": "UNAUTHORIZED"
}
```

***

## Request Rate (RPS)

Every integrator ID is issued with a **requests-per-second (RPS)** limit that controls how many API calls you can make per second across all endpoints.

| Stage                     | Default RPS | Notes                                                        |
| ------------------------- | ----------- | ------------------------------------------------------------ |
| **Testing / Development** | 1 RPS       | Issued with every new integrator ID                          |
| **Production**            | 10 RPS      | Request an upgrade from the Squid team when ready to go live |
| **High Volume**           | Custom      | Contact the team for higher limits based on your usage needs |

### How to request an RPS increase

1. Ensure your integration is tested and production-ready.
2. Contact the Squid team via [Discord](https://discord.gg/squidrouter) or <support@squidrouter.com>.
3. Specify your expected traffic volume and use case.

{% hint style="warning" %}
If you exceed your RPS limit, requests will be throttled. Make sure to request an upgrade **before** launching to production to avoid interruptions for your users.
{% endhint %}

***

## Wallet-Based Quote Rate Limit

When requesting routes with `quoteOnly: false` (the default), the API enforces a per-wallet rate limit to prevent duplicate transaction data from being generated.

### Why this limit exists

When `quoteOnly` is `false`, the API generates full transaction call data (including signed solver quotes for Squid Intents routes). Submitting identical requests for the same wallet in rapid succession would produce the same call data, wasting compute and potentially causing transaction conflicts.

### Error Response

If you exceed the rate limit, the API returns:

```json
{
  "error": "Too many quote requests for this address",
  "retryAfter": 1
}
```

| Field        | Type     | Description                               |
| ------------ | -------- | ----------------------------------------- |
| `error`      | `string` | Human-readable error message              |
| `retryAfter` | `number` | Number of seconds to wait before retrying |

### How to handle this

1. **Wait and retry** — respect the `retryAfter` value before sending another request for the same wallet.
2. **Use `quoteOnly: true` for price discovery** — if you only need a price estimate (e.g., for display purposes), set `quoteOnly: true` in your route request. This returns a quote without generating transaction data and is not subject to the same rate limit.
3. **Cache quotes** — if your UI needs to refresh prices, cache the previous quote and only request a new one after a reasonable interval.

### Example: Using quoteOnly for price display

```typescript
// For UI price display — not rate limited
const quoteParams = {
  fromAddress: userAddress,
  fromChain: "56",
  fromToken: "0x55d398326f99059fF775485246999027B3197955",
  fromAmount: "1000000000000000",
  toChain: "42161",
  toToken: "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
  toAddress: userAddress,
  quoteOnly: true,  // Only returns pricing, no tx data
};

// When user clicks "Swap" — request full route with tx data
const execParams = {
  ...quoteParams,
  quoteOnly: false,  // Generates transaction data (rate limited per wallet)
};
```

{% hint style="info" %}
The rate limit applies **per wallet address**. Different wallet addresses can request routes concurrently without triggering the limit.
{% endhint %}

***

## General Best Practices

* **Separate quote from execution** — use `quoteOnly: true` for displaying prices and only request full transaction data when the user initiates a swap.


# Error Codes

This page documents the error responses you may encounter when using the Squid API. Understanding these errors will help you build robust error handling into your integration.

***

## HTTP Error Responses

| HTTP Status | Type             | Description                                                                         |
| ----------- | ---------------- | ----------------------------------------------------------------------------------- |
| `400`       | `BAD_REQUEST`    | Invalid or missing request parameters                                               |
| `401`       | `UNAUTHORIZED`   | Missing or invalid `x-integrator-id` header                                         |
| `404`       | `NOT_FOUND`      | Resource not found (e.g., unknown transaction ID)                                   |
| `429`       | `RATE_LIMITED`   | Too many requests — see [Rate Limiting](/api-and-sdk-integration/api/rate-limiting) |
| `500`       | `INTERNAL_ERROR` | Server-side error — retry with backoff                                              |

***

## Route Request Errors

These errors are returned by the `POST /v2/route` endpoint:

| Error Message                              | Cause                                                    | Resolution                                                                                                        |
| ------------------------------------------ | -------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `x-integrator-id header is missing`        | Request missing the required auth header                 | Add the `x-integrator-id` header to every request                                                                 |
| `Too many quote requests for this address` | Duplicate `quoteOnly: false` request for the same wallet | Wait `retryAfter` seconds, or use `quoteOnly: true` for price display                                             |
| `No route found`                           | No valid route exists for the given parameters           | Check that source/destination chains and tokens are supported. Verify sufficient liquidity exists.                |
| `Amount too low`                           | The `fromAmount` is below the minimum for the route      | Increase the swap amount                                                                                          |
| `Amount too high`                          | The `fromAmount` exceeds the maximum for the route       | Decrease the swap amount                                                                                          |
| `Unsupported chain`                        | The specified chain ID is not supported                  | Check the [supported chains list](/chains-and-tokens/get-supported-tokens-and-chains)                             |
| `Unsupported token`                        | The specified token address is not whitelisted           | Verify the token address. Only [whitelisted tokens](/additional-resources/compliance-and-security) are supported. |

#### Example: Unsupported Token

```json
{
    "message": "Token is not supported for toChain: 8453 toToken: 0xeeeeeeseeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee.",
    "statusCode": 400,
    "type": "BAD_REQUEST"
}
```

#### Example: Unsupported Chain

```json
{
    "message": "toChain: 84353 unsupported chain id",
    "statusCode": 400,
    "type": "SCHEMA_VALIDATION_ERROR"
}
```

***

## Status API Errors

These errors are returned by the `GET /v2/status` endpoint:

| HTTP Status | Scenario                    | Resolution                                                                                                              |
| ----------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `404`       | Transaction not yet indexed | Retry after 5 seconds. Indexing typically takes 5–10 seconds after execution. Some chains (e.g., Filecoin) take longer. |
| `400`       | Missing required parameters | Ensure `transactionId`, `fromChainId`, `toChainId`, and `quoteId` are provided.                                         |

***

## Transaction Status Values

After a transaction is submitted, the status API returns a `squidTransactionStatus` field. See [Track Status](/api-and-sdk-integration/key-concepts/track-status) for details on each status:

| Status            | Description                                                            |
| ----------------- | ---------------------------------------------------------------------- |
| `success`         | Transaction completed on all chains                                    |
| `ongoing`         | Transaction in progress — no action needed                             |
| `needs_gas`       | Gas price spike on destination chain (Axelar routes only)              |
| `partial_success` | Source chain executed but destination reverted                         |
| `not_found`       | Transaction not yet indexed — retry shortly                            |
| `refund`          | Squid Intents route failed — funds refunded on source chain (\~10 min) |

***

## Best Practices

1. **Always check the HTTP status code** before parsing the response body.
2. **Log the full error response** — Squid error payloads include descriptive messages.
3. **Use `quoteOnly: true`** for price discovery to avoid rate limit errors.


# 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 installing the SDK (`npm install @0xsquid/sdk`).

```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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents 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 Squid Intents routes. When a Squid Intents transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Squid Intents routes when passing the user's address as the `fromAddress`.

**How Squid Intents refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Squid Intents, 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"
            },
            "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,
            "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"
}
```


# Chains, Tokens & Prices

The Squid SDK provides utility methods for querying chain configurations, token data, and prices. These methods are available after calling `squid.init()`.

## Setup

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

const squid = new Squid({
  baseUrl: "https://v2.api.squidrouter.com",
  integratorId: "your-integrator-id",
});

await squid.init();

// After init(), these properties are populated:
console.log(squid.chains.length);  // e.g. 92 supported chains
console.log(squid.tokens.length);  // e.g. 9689 supported tokens
```

***

## Chain Data

### `squid.chains`

After `init()`, the `chains` property contains an array of all supported chains.

### `squid.getChainData(chainId)`

Look up a specific chain by its chain ID.

```typescript
const chain = squid.getChainData("42161");
```

**Returns:**

```json
{
  "chainId": "42161",
  "chainName": "Chain 42161",
  "networkName": "Arbitrum",
  "chainType": "evm",
  "nativeCurrency": {
    "name": "Arbitrum",
    "symbol": "ETH",
    "decimals": 18,
    "icon": "https://..."
  },
  "squidContracts": {
    "squidRouter": "0xce16F69375520ab01377ce7B88f5BA8C48F8D666"
  }
}
```

| Field            | Type     | Description                                                                          |
| ---------------- | -------- | ------------------------------------------------------------------------------------ |
| `chainId`        | `string` | Chain identifier                                                                     |
| `chainName`      | `string` | Internal chain name                                                                  |
| `networkName`    | `string` | Human-readable network name (e.g. `"Arbitrum"`, `"Ethereum"`)                        |
| `chainType`      | `string` | Chain ecosystem: `"evm"`, `"cosmos"`, `"solana"`, `"bitcoin"`, `"xrpl"`, `"stellar"` |
| `nativeCurrency` | `object` | Native token details (name, symbol, decimals, icon)                                  |
| `squidContracts` | `object` | Squid contract addresses on this chain (e.g. `squidRouter`)                          |

***

## Token Data

### `squid.tokens`

After `init()`, the `tokens` property contains an array of all supported tokens across all chains.

### `squid.getTokenData(address, chainId)`

Look up a specific token by its address and chain ID.

```typescript
const token = squid.getTokenData("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "1");
```

**Returns:**

```json
{
  "symbol": "USDC",
  "address": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  "chainId": "1",
  "name": "USDC",
  "decimals": 6,
  "coingeckoId": "usd-coin",
  "type": "evm",
  "logoURI": "https://...",
  "usdPrice": 0.9996
}
```

| Field         | Type     | Description                            |
| ------------- | -------- | -------------------------------------- |
| `symbol`      | `string` | Token symbol                           |
| `address`     | `string` | Token contract address                 |
| `chainId`     | `string` | Chain ID                               |
| `name`        | `string` | Full token name                        |
| `decimals`    | `number` | Token decimal places                   |
| `coingeckoId` | `string` | CoinGecko identifier for price lookups |
| `type`        | `string` | Chain type (e.g. `"evm"`)              |
| `logoURI`     | `string` | Token logo URL                         |
| `usdPrice`    | `number` | Current USD price                      |

***

## Token Prices

### `squid.getTokenPrice({ tokenAddress, chainId })`

Get the current USD price for a single token.

```typescript
const price = await squid.getTokenPrice({
  tokenAddress: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
  chainId: "1",
});
// Returns: 0.9996203987960182 (number)
```

**Returns:** `number` — The current USD price of the token.

### `squid.getMultipleTokensPrice({ chainId? })`

Get all tokens with their current USD prices, optionally filtered by chain ID.

```typescript
// Get prices for all tokens on Arbitrum
const tokens = await squid.getMultipleTokensPrice({ chainId: "42161" });

tokens.forEach(token => {
  console.log(`${token.symbol}: $${token.usdPrice}`);
});
```

**Returns:** `Token[]` — An array of token objects, each including a `usdPrice` field.

### `squid.getFromAmount({ fromToken, toToken, toAmount })`

Estimate how much of a source token is needed to receive a specific amount of a destination token. Useful for "exact output" UIs.

```typescript
const fromAmount = await squid.getFromAmount({
  fromToken: squid.getTokenData("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", "1"),
  toToken: squid.getTokenData("0xaf88d065e77c8cc2239327c5edb3a432268e5831", "42161"),
  toAmount: "1000000", // 1 USDC (6 decimals)
});
// Returns: "1015000" (string — ~1.015 USDC needed, accounting for fees)
```

**Returns:** `string` — The estimated source amount in the token's smallest unit.

***

## Token Approval

### `squid.isRouteApproved({ route, sender })`

Check if the sender has approved the Squid router to spend the required source token amount.

```typescript
const { isApproved, message } = await squid.isRouteApproved({
  route: routeResponse.route,
  sender: "0x...",
});

if (!isApproved) {
  console.log(message); // Describes what approval is needed
}
```

### `squid.approveRoute({ signer, route })`

Approve the Squid router to spend the source token. Required before executing ERC-20 swaps.

```typescript
const tx = await squid.approveRoute({
  signer, // ethers.js Signer
  route: routeResponse.route,
});

if (tx) {
  await tx.wait(); // Wait for approval to be mined
}
```


# 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 **2 advanced functionalities** that 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. [**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.

## Transaction Types

When requesting a route, the API returns a `transactionType` field that determines how the transaction should be constructed and submitted on-chain. Different source chains use different transaction types. See [**Transaction Types**](/api-and-sdk-integration/key-concepts/transaction-types) for the full reference.

#### **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
  overrideGasRefundAddress: string; //OPTIONAL, For Axelar transactions, refund gas to a gas sponsor address on source chain
  preHook: Hook; //OPTIONAL, Contract calls to execute on the source chain before bridging
  postHook: Hook; //OPTIONAL, Contract calls to execute on the destination chain after bridging
};

```

## 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 price quote and estimated output without generating transaction call data. Useful for displaying estimated amounts to users before they commit. Defaults to `false`. **Note:** Submitting duplicate requests with the same wallet and `quoteOnly: false` is rate-limited. |
| `overrideGasRefundAddress` | `string`           | No                               | For Axelar transactions, allows gas refunds to be sent to a gas sponsor address on the source chain instead of the sender.                                                                                                                                                                          |
| `preHook`                  | `Hook`             | No                               | Contract calls to execute on the source chain **before** bridging. See [Build a preHook](/api-and-sdk-integration/key-concepts/hooks/build-a-prehook).                                                                                                                                              |
| `postHook`                 | `Hook`             | No                               | Contract calls to execute on the destination chain **after** bridging. See [Build a postHook](/api-and-sdk-integration/key-concepts/hooks/build-a-posthook).                                                                                                                                        |
| `bypassGuardrails`         | `boolean`          | No                               | Ignores slippage warnings on the returned route response. **If set to true, the integrator is liable for any loss of funds during the route.**                                                                                                                                                      |


# Route Response Schema

When you call `POST https://v2.api.squidrouter.com/v2/route`, the API returns a route response containing the optimal path, estimated output, and (if `quoteOnly` is `false`) the transaction data needed for execution.

## Top-Level Structure

```json
{
  "route": {
    "estimate": { ... },           // Route pricing, actions, fees, and gas costs
    "transactionRequest": { ... }, // Transaction data for on-chain execution (empty when quoteOnly: true)
    "params": { ... },             // Echo of your original request parameters
    "quoteId": "string"            // Unique quote identifier — required for Squid Intents status tracking
  }
}
```

{% hint style="danger" %}
**Important:** The `quoteId` field is required for all Squid Intents status tracking. If `quoteId` is not included in status calls, the transaction will be **refunded** to the source chain.
{% endhint %}

***

## `route.estimate`

The estimate object contains all pricing information, the ordered list of actions, and cost breakdowns.

| Field                    | Type        | Description                                                        |
| ------------------------ | ----------- | ------------------------------------------------------------------ |
| `actions`                | `Action[]`  | Ordered array of steps the route will take (swaps, bridges, wraps) |
| `fromAmount`             | `string`    | Input amount in the token's smallest unit                          |
| `toAmount`               | `string`    | Estimated output amount in the token's smallest unit               |
| `toAmountMin`            | `string`    | Minimum output after accounting for slippage                       |
| `exchangeRate`           | `string`    | Overall exchange rate between source and destination tokens        |
| `aggregatePriceImpact`   | `string`    | Total price impact across all steps (e.g. `"0.0"`, `"-0.02"`)      |
| `fromAmountUSD`          | `string`    | USD value of the input amount                                      |
| `toAmountUSD`            | `string`    | USD value of the estimated output                                  |
| `toAmountMinUSD`         | `string`    | USD value of the minimum output                                    |
| `aggregateSlippage`      | `number`    | Total slippage percentage across the route                         |
| `fromToken`              | `Token`     | Full source token object                                           |
| `toToken`                | `Token`     | Full destination token object                                      |
| `feeCosts`               | `FeeCost[]` | Breakdown of fees (bridging fees, boost fees)                      |
| `gasCosts`               | `GasCost[]` | Breakdown of gas costs                                             |
| `estimatedRouteDuration` | `number`    | Estimated total time in seconds                                    |

***

## `Action` Object

Each action represents one step in the route. Actions are executed in order, with `stage: 0` for source chain actions and `stage: 1` for destination chain actions.

| Field               | Type     | Description                                                         |
| ------------------- | -------- | ------------------------------------------------------------------- |
| `type`              | `string` | Type of action: `"bridge"`, `"swap"`, or `"wrap"`                   |
| `chainType`         | `string` | Chain ecosystem (e.g. `"evm"`, `"cosmos"`)                          |
| `data`              | `object` | Provider-specific data (varies by action type — see below)          |
| `fromChain`         | `string` | Chain ID where this action starts                                   |
| `toChain`           | `string` | Chain ID where this action ends                                     |
| `fromToken`         | `Token`  | Input token for this step                                           |
| `toToken`           | `Token`  | Output token for this step                                          |
| `fromAmount`        | `string` | Input amount for this step                                          |
| `toAmount`          | `string` | Estimated output for this step                                      |
| `toAmountMin`       | `string` | Minimum output after slippage for this step                         |
| `exchangeRate`      | `string` | Exchange rate for this step                                         |
| `priceImpact`       | `string` | Price impact for this step                                          |
| `stage`             | `number` | `0` = source chain, `1` = destination chain                         |
| `provider`          | `string` | Provider name (e.g. `"Axelar"`, `"Uniswap V3"`, `"Pancakeswap V3"`) |
| `logoURI`           | `string` | Provider logo URL                                                   |
| `description`       | `string` | Human-readable description (e.g. `"Swap USDC to WETH"`)             |
| `estimatedDuration` | `number` | (Bridges only) Estimated duration in seconds                        |

### Action Type: `bridge`

Cross-chain bridge step. The `data` object contains:

```json
{
  "name": "Axelar",
  "provider": "Axelar",
  "type": "axelar-gmp",
  "logoURI": "https://..."
}
```

### Action Type: `swap`

DEX swap step. The `data` object contains:

```json
{
  "address": "0x...",           // Pool or pair address
  "chainId": "42161",
  "coinAddresses": ["0x...", "0x..."],
  "dex": "Uniswap V3",         // DEX name
  "path": ["0x...", "0x..."],   // Token swap path
  "slippage": 0.0105,
  "aggregateSlippage": 0.0105,
  "target": "0x..."            // Router contract address
}
```

### Action Type: `wrap`

Native token wrap or unwrap step. The `data` object contains:

```json
{
  "address": "0x...",           // Wrapped token contract
  "type": "WrappedNative",
  "path": ["0x...", "0x..."],
  "direction": "wrap",          // "wrap" or "unwrap"
  "target": "0x..."
}
```

***

## `route.transactionRequest`

When `quoteOnly: false`, this object contains the transaction data needed for on-chain execution. The structure depends on the [Transaction Type](/api-and-sdk-integration/key-concepts/transaction-types).

For EVM `ON_CHAIN_EXECUTION` transactions:

| Field                  | Type     | Description                                          |
| ---------------------- | -------- | ---------------------------------------------------- |
| `routeType`            | `string` | Route type (e.g. `"CALL_BRIDGE_CALL"`, `"EVM_ONLY"`) |
| `target`               | `string` | Contract address to call                             |
| `data`                 | `string` | Encoded calldata                                     |
| `value`                | `string` | Native token value to send (wei)                     |
| `gasLimit`             | `string` | Recommended gas limit                                |
| `gasPrice`             | `string` | Current gas price                                    |
| `maxFeePerGas`         | `string` | EIP-1559 max fee                                     |
| `maxPriorityFeePerGas` | `string` | EIP-1559 priority fee                                |

For `DEPOSIT_ADDRESS_WITH_SIGNATURE` transactions (Hedera):

| Field               | Type     | Description                              |
| ------------------- | -------- | ---------------------------------------- |
| `routeType`         | `string` | `"DEPOSIT_ADDRESS_WITH_SIGNATURE"`       |
| `depositAddress`    | `string` | Address to send funds to                 |
| `signatureRequired` | `object` | Contains `orderHash` that must be signed |

{% hint style="info" %}
When `quoteOnly: true`, `transactionRequest` is an empty object `{}`. This is useful for showing users estimated outputs before they commit to executing the swap.
{% endhint %}

***

## `route.params`

An echo of your original request parameters, returned for reference:

```json
{
  "fromChain": "1",
  "toChain": "42161",
  "fromToken": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
  "toToken": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
  "fromAmount": "1000000",
  "fromAddress": "0x...",
  "toAddress": "0x...",
  "slippage": 1,
  "quoteOnly": true
}
```

***

## `FeeCost` Object

| Field           | Type     | Description                                         |
| --------------- | -------- | --------------------------------------------------- |
| `name`          | `string` | Fee name (e.g. `"Gas receiver fee"`, `"Boost fee"`) |
| `description`   | `string` | Human-readable description                          |
| `amount`        | `string` | Fee amount in token's smallest unit                 |
| `amountUsd`     | `string` | Fee amount in USD                                   |
| `token`         | `Token`  | Token used for the fee                              |
| `gasLimit`      | `string` | Gas limit (if applicable)                           |
| `gasMultiplier` | `number` | Gas multiplier (if applicable)                      |

***

## `GasCost` Object

| Field       | Type     | Description                          |
| ----------- | -------- | ------------------------------------ |
| `type`      | `string` | Gas cost type (e.g. `"executeCall"`) |
| `token`     | `Token`  | Token used for gas                   |
| `amount`    | `string` | Gas cost in token's smallest unit    |
| `gasLimit`  | `string` | Gas limit                            |
| `amountUsd` | `string` | Gas cost in USD                      |

***

## `Token` Object

Token objects appear throughout the response (in `estimate`, `actions`, `feeCosts`, etc.):

| Field         | Type     | Description                  |
| ------------- | -------- | ---------------------------- |
| `address`     | `string` | Token contract address       |
| `chainId`     | `string` | Chain ID                     |
| `symbol`      | `string` | Token symbol (e.g. `"USDC"`) |
| `name`        | `string` | Full token name              |
| `decimals`    | `number` | Token decimal places         |
| `logoURI`     | `string` | Token logo URL               |
| `usdPrice`    | `number` | Current USD price            |
| `coingeckoId` | `string` | CoinGecko identifier         |
| `type`        | `string` | Chain type (e.g. `"evm"`)    |

***

## Example: Native Token Swap

An ETH swap from Arbitrum → Base produces a multi-step route:

1. **Wrap** (stage 0): Wrap ETH → WETH on Arbitrum
2. **Swap** (stage 0): Swap WETH → USDC via Uniswap V3
3. **Swap** (stage 0): Swap USDC → USDC.axl via Pancakeswap V3
4. **Bridge** (stage 0→1): Bridge USDC.axl via Axelar to Base
5. **Swap** (stage 1): Swap USDC.axl → USDC on Base
6. **Swap** (stage 1): Swap USDC → WETH via Uniswap V3
7. **Unwrap** (stage 1): Unwrap WETH → ETH on Base


# 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 (Squid Intents)                      | ✅         |
| All chains accessible via Squid Intents                     | ✅         |
| 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.
* **Squid Intents 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

This transaction type is unique to Hedera and requires an additional signing step. Instead of calling a contract directly, the user sends funds to a deposit address and provides a signed verification.

### How it works

1. **Request a route** — The route response includes a `transactionRequest` with a `depositAddress` and `signatureRequired.orderHash`.
2. **Sign the order hash** — Before sending funds, sign the `orderHash` using `signer.signMessage()`. This produces a `depositTxVerificationSignature` that proves the user authorized the deposit.
3. **Poll for token association (Hedera-specific)** — Before executing the transaction, poll using `estimateGas` to ensure the destination token is associated with the deposit address. Retry up to 15 times with 1-second delays.
4. **Send the transaction** — Transfer funds to the deposit address.
5. **Track status** — When polling status, include both `quoteId` **and** `depositTxVerificationSignature` as parameters.

```typescript
// Step 1: Sign the order hash
const orderHash = routeResponse.route.transactionRequest.signatureRequired.orderHash;
const depositTxVerificationSignature = await signer.signMessage(
  ethers.getBytes(orderHash)
);

// Step 2: Include signature in status calls
const status = await axios.get("https://v2.api.squidrouter.com/v2/status", {
  params: {
    transactionId,
    fromChainId,
    toChainId,
    quoteId,
    depositTxVerificationSignature, // Required for DEPOSIT_ADDRESS_WITH_SIGNATURE
  },
});
```

See the [Hedera Integration Guide](/api-and-sdk-integration/chain-integration-guides/hedera-integration) for complete working examples.

**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) + Squid Intents 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) + Squid Intents 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) | —   |

***

## `DEPOSIT_ADDRESS_DIRECT_TRANSFER`

* **Source chains:** Canton
* **Conditions:** Direct route from Canton (no on-chain DEX swap)
* **Example routes:** Canton:CC → Base:USDC, Canton:CC → Arbitrum:USDC

This transaction type is unique to Canton. Unlike EVM chains where a contract call executes the swap, Canton routes return a **deposit address** and an **order hash** that must be included as the transfer memo.

> Canton wallets use the CIP-103 protocol — a browser-based wallet discovery and signing standard. There is no exportable private key or Node.js signing SDK. The API and SDK examples handle routing and status tracking programmatically, but the deposit must be sent manually from a Canton wallet (Send, C8, or Nightly). For fully automated browser-based execution, use the Squid Widget.

### How it works

1. **Request a route** — The route response includes a `transactionRequest` with `target` (deposit address) and `data` (order hash).
2. **Send Canton Coin** — Transfer the specified amount to the `target` deposit address using your Canton wallet.
3. **Include the order hash as the memo** — The `data` field contains the order hash, which must be included as the transfer memo in the Canton wallet's reason field (`splice.lfdecentralizedtrust.org/reason`).
4. **Track status** — Poll using both `transactionId` and `quoteId`.

```typescript
// Extract deposit details from the route response
const depositAddress = transactionRequest.target;
const orderHash = transactionRequest.data; // Include as transfer memo

// Track status
const status = await axios.get("https://v2.api.squidrouter.com/v2/status", {
  params: {
    fromChainId: "canton",
    toChainId: "8453",
    transactionId: transactionId,
    quoteId: quoteId, // Required for Squid Intents
  },
});
```

See the [Canton Integration Guide](/api-and-sdk-integration/chain-integration-guides/canton-integration) for complete working examples.

**Code examples:**

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


# 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,
    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,
    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,
  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,
    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" %}
**Squid Intents Transactions**: Status polling is **required** for Squid Intents. After executing a Squid Intents transaction, you **must** call the status API with the `quoteId` parameter. If `quoteId` is not included in the status call, the Squid Intents transaction will be **refunded** to the source chain. See [Integrating Squid Intents](/api-and-sdk-integration/coral-intent-swaps/integrating-squid-intents) 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      | The quote ID from the route response. |
| `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 Squid Intents 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 Squid Intents 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.

**What token do I receive when a swap fails?**

The token you receive depends on the route type:

| Route Type        | Failure Behavior       | Token Received                                                                                     |
| ----------------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
| **Axelar**        | Destination swap fails | **axlUSDC** on the **destination chain**                                                           |
| **Squid Intents** | Swap fails             | **RFQ bridge token** (typically the chain's native asset or USDC) refunded on the **source chain** |

{% hint style="info" %}
For Axelar routes, you will receive axlUSDC in your destination wallet. For Squid Intents routes, the funds are refunded to your source address — see the REFUND status below.
{% endhint %}

#### 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 Squid Intents routes. When a Squid Intents transaction fails, the funds are automatically refunded on the source chain. This is the default behavior for Squid Intents routes when passing the user's address as the `fromAddress`. Refunds typically take \~10 minutes

**How Squid Intents refunds work:**

* Funds are always transferred from the `msg.sender` on the source chain (this could be the user for direct calls to Squid Intents, 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 installing the SDK (`npm install @0xsquid/sdk`).

```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`


# 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
    }
]
```


# 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
//     }
//   ]

```


# 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**: Squid Intents requires `@0xsquid/widget` version **6.5.0 or newer**. Please ensure your widget is updated before enabling Squid Intents.
{% 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. If `quoteId` is not included in the status call, the Squid Intents transaction will be **refunded** to the source chain.

#### 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 Squid Intents 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 Squid Intents
      },
      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 Squid Intents
  };

  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 Squid Intents' 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 Squid Intents' RFQ format.
* **Technical Alignment**: Support REST or WebSocket endpoints and adhere to Squid Intents' order lifecycle conventions (RFQ, fill, settlement).

### Business Case

Whitelabeling Squid Intents 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 Squid Intents' 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)
* [Stellar Integration](/api-and-sdk-integration/chain-integration-guides/stellar-integration)
* [Hedera Integration](/api-and-sdk-integration/chain-integration-guides/hedera-integration)
* [Canton Integration](/api-and-sdk-integration/chain-integration-guides/canton-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


# Bitcoin Intents

Squid Intents support for Bitcoin enables fast, solver-driven cross-chain swaps from Bitcoin (BTC) to any supported EVM chain.

## Settlement Times

Bitcoin settlement times vary based on the transaction amount:

| $0-1,000 | $1,000-50,000 | $50,000+ |
| -------- | ------------- | -------- |
| 1 block  | 3 blocks      | 5 blocks |

## Prerequisites

1. **Integrator ID**: Squid Intents must be enabled for your integrator ID. Contact the Squid team to get this set up.
2. **Bitcoin Wallet Address**: The source wallet must be a Native SegWit (Bech32) address (starting with `bc1q`).

***

## Step 1: Request Route

Request a route using the standard `/v2/route` endpoint (via API or SDK) with Bitcoin parameters:

* `fromChain`: `"bitcoin"`
* `fromToken`: `"satoshi"`
* `fromAddress`: Native SegWit address of the user (e.g. `bc1q...`)

```typescript
const params = {
  fromAddress: "bc1qzea6nfdfmztwjcn8htqn4tk9j3v2uawf4rck0g",
  fromChain: "bitcoin",
  fromToken: "satoshi",
  fromAmount: "70000", // Amount in satoshis
  toChain: "42161", // Arbitrum
  toToken: "0xaf88d065e77c8cc2239327c5edb3a432268e5831", // USDC
  toAddress: "0xC601C9100f8420417A94F6D63e5712C21029525e",
  quoteOnly: false
};

// API:
// const routeResult = await axios.post("https://v2.api.squidrouter.com/v2/route", params, { headers: { "x-integrator-id": integratorId } });
// const route = routeResult.data.route;
// const quoteId = route.quoteId;

// SDK:
// const { route, requestId } = await squid.getRoute(params);
// const quoteId = route.estimate.quoteId || route.quoteId;
```

> \[!IMPORTANT] Save the `quoteId` returned in the route response. It is mandatory for tracking transaction status.

## Step 2: Sign the PSBT

The `transactionRequest` object returned in the route response contains the transaction payload. Check the `transaction_request_type` (or `type`) field. For Squid Intents, this will be:

`DEPOSIT_ADDRESS_CALLDATA`

The `transactionRequest.data` field contains a hex-encoded Partially Signed Bitcoin Transaction (PSBT). You must prompt the user's wallet to sign this PSBT.

#### Browser Wallet Example (UniSat Wallet)

```typescript
const transactionRequest = route.transactionRequest;

if (transactionRequest.transaction_request_type === "DEPOSIT_ADDRESS_CALLDATA") {
  const psbtHex = transactionRequest.data;
  
  // Sign and finalize the PSBT with UniSat Wallet
  const signedPsbtHex = await window.unisat.signPsbt(psbtHex, {
    autoFinalized: true
  });
  
  // Broadcast the transaction
  const txHash = await window.unisat.pushPsbt(signedPsbtHex);
  console.log("Broadcasted Tx Hash:", txHash);
}
```

#### Node.js / Backend Example (`bitcoinjs-lib`)

```typescript
import * as bitcoin from 'bitcoinjs-lib';
import ECPairFactory from 'ecpair';
import * as ecc from 'tiny-secp256k1';

bitcoin.initEccLib(ecc);
const ECPair = ECPairFactory(ecc);
const keyPair = ECPair.fromWIF(privateKeyWIF, bitcoin.networks.bitcoin);

const psbt = bitcoin.Psbt.fromHex(transactionRequest.data, { network: bitcoin.networks.bitcoin });
psbt.signAllInputs(keyPair);
psbt.finalizeAllInputs();

const tx = psbt.extractTransaction();
const txHex = tx.toHex();
const txHash = tx.getId();
```

## Step 3: Broadcast Transaction

Submit the raw transaction hex to the Bitcoin network. If using a browser extension wallet like UniSat, this is done automatically using `pushPsbt`. For backend scripts, you can broadcast using a public block explorer API (e.g. Blockstream):

```typescript
const response = await axios.post('https://blockstream.info/api/tx', txHex);
```

## Step 4: Status Polling

You must poll the status API to confirm the completion of the swap.

> \[!WARNING] For all Squid Intent transactions, **you must include the `quoteId` in the status query parameters.** If `quoteId` is omitted, the transaction cannot be correlated with the Intent and will be automatically refunded on the Bitcoin chain after 15 minutes.

#### API Status Polling

```typescript
const getStatus = async (txHash: string, quoteId: string) => {
  const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
    params: {
      transactionId: txHash,
      fromChainId: "bitcoin",
      toChainId: "42161",
      quoteId: quoteId // Required for Squid Intents
    },
    headers: {
      "x-integrator-id": integratorId
    }
  });
  return result.data;
};
```

#### SDK Status Polling

```typescript
const status = await squid.getStatus({
  transactionId: txHash,
  requestId: requestId,
  integratorId: integratorId,
  fromChainId: "bitcoin",
  toChainId: "42161",
  quoteId: quoteId // Required for Squid Intents
});
```

***

## Complete Examples

Ready-to-run integration examples are available in our GitHub repository:

* **API Example**: [Bitcoin to EVM Intents API Sample](https://github.com/0xsquid/examples/tree/main/V2/api/bitcoinToEVM_Intents)
* **SDK Example**: [Bitcoin to EVM Intents SDK Sample](https://github.com/0xsquid/examples/tree/main/V2/sdk/bitcoinToEVM_Intents)


# 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 Tokens

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

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

***

## Integration Options

Choose the integration method that best fits your use case:

### [Swap Widget](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/swap-widget)

A full-featured, drop-in cross-chain swap UI. The Swap Widget gives users complete flexibility to select their source chain and token, then swap into any supported XRPL token.

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

**Best for:**

* dApps that want a ready-made swap interface with minimal dev effort
* Flows where the user chooses both the source and destination tokens
* Prototyping and testing XRPL swaps via [Widget Studio](https://studio.squidrouter.com/)

***

### [Payment Widget (Deposit Widget)](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/payment-widget)

A streamlined deposit and payment flow where the destination is fixed to XRPL. The Payment Widget supports two modes: **deposit** (user-entered amount) for account funding, and **payment** (fixed amount) for checkout and invoice flows.

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

**Best for:**

* Accepting cross-chain deposits into an XRPL address
* Checkout and invoice payment flows with a fixed amount (e.g., pay 50 RLUSD)
* On-ramp flows where users fund an XRPL account from any supported chain

***

### [API & SDK](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/api-and-sdk)

Direct integration with Squid's routing API and TypeScript SDK for full control over the swap lifecycle. Build custom UIs and backend flows with complete flexibility over routing, execution, and status tracking.

**Best for:**

* Custom swap interfaces and backend integrations
* Programmatic routing (e.g., bots, automated flows)
* Advanced use cases requiring hooks, exact output, or custom transaction handling

***

## Transaction Types

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.


# Swap Widget

The fastest way to add XRPL swaps to your application is through the Squid Swap Widget — a drop-in React component that provides a full cross-chain swap interface. Users can select any source chain and token and swap into XRPL tokens like XRP, RLUSD, or SOIL.

You can prototype and customize 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",
          "5553444300000000000000000000000000000000.rGm7WCVp9gb4jZHWTEtGUr4dd74z2XuWhE",
        ],
      },
    },
    // ... 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

***

## Locking Source to XRPL

To allow users to swap **from** XRPL to any destination, flip the configuration:

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

***

## Installation & Setup

For full installation instructions, framework-specific guides, and theming options, see the main Swap Widget documentation:

* [Getting Started](/widget-integration/add-a-widget/widget/getting-started)
* [Installing the Widget](/widget-integration/add-a-widget/widget/installing-the-widget)
* [Customization Guide](/widget-integration/add-a-widget/widget/customization-guide)

***

## Next Steps

* Use [Widget Studio](https://studio.squidrouter.com/) to visually configure and preview your widget
* Need a fixed-amount payment or deposit flow instead? See the [Payment Widget](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/payment-widget)
* For full programmatic control, see the [API & SDK](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/api-and-sdk) guide


# Payment Widget

The Squid Deposit Widget provides a streamlined deposit and payment flow for accepting cross-chain funds into an XRPL address. Unlike the Swap Widget, the destination is fixed by you (the integrator) — users only choose their source chain and token.

The widget supports two modes:

* **`deposit`** — The user enters the amount to send. Use this for account funding, top-ups, and any open-ended deposit flow.
* **`payment`** — You fix the amount. Use this for checkout, invoices, and pay-this-amount flows.

You can prototype and customize your widget configuration interactively using the [**Widget Studio**](https://studio.squidrouter.com/).

***

## Installation

Install the Deposit Widget package:

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

Or with yarn:

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

For framework-specific setup (React, Next.js, Vite), see the [Deposit Widget installation guides](/widget-integration/add-a-widget/deposit-widget/installing-the-widget).

***

## Configuration for XRPL

The Deposit Widget takes a single `config` prop, typed as `DepositConfig`. To target XRPL, set the `destinationToken.chainId` to `"xrpl-mainnet"` and the `destinationToken.address` to one of the supported XRPL token addresses.

### Supported XRPL Destination Tokens

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

### Config Fields

| Field                      | Type                     | Required              | Description                                                                                         |
| -------------------------- | ------------------------ | --------------------- | --------------------------------------------------------------------------------------------------- |
| `mode`                     | `"deposit" \| "payment"` | ✅                     | Selects the widget flow. In `"payment"` mode, `amount` is required.                                 |
| `amount`                   | `string`                 | ✅ (payment mode only) | Fixed amount the user will pay, in destination-token units (human-readable string, e.g. `"50.00"`). |
| `destinationAddress`       | `string`                 | ✅                     | The XRPL address that receives the deposit (e.g. `"rYourXRPLAddress"`).                             |
| `destinationToken.address` | `string`                 | ✅                     | Token address on XRPL (see table above).                                                            |
| `destinationToken.chainId` | `string`                 | ✅                     | Set to `"xrpl-mainnet"` for XRPL.                                                                   |
| `integrator.id`            | `string`                 | ✅                     | Your Integrator ID.                                                                                 |
| `integrator.name`          | `string`                 | ✅                     | Displayed in the widget header.                                                                     |
| `integrator.logoUrl`       | `string`                 | ✅                     | URL of your logo, displayed alongside the name.                                                     |
| `apiUrl`                   | `string`                 | ❌                     | Override the Squid API endpoint. Defaults to Squid's production API.                                |
| `theme`                    | `Theme`                  | ❌                     | Theme object for visual customization.                                                              |
| `themeType`                | `"light" \| "dark"`      | ❌                     | Base palette. Defaults to `"light"`.                                                                |

***

## Deposit Mode — Fund an XRPL Account

Use deposit mode when the user chooses how much to send. This is ideal for account funding, top-ups, or open-ended deposits.

### Deposit XRP

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "rYourXRPLAddress",
  destinationToken: {
    address: "xrp",
    chainId: "xrpl-mainnet",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};

function App() {
  return <DepositWidget config={config} />;
}
```

### Deposit RLUSD

```tsx
const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "rYourXRPLAddress",
  destinationToken: {
    address: "524c555344000000000000000000000000000000.rmxckbedwqr76quhesumdegf4b9xj8m5de",
    chainId: "xrpl-mainnet",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};
```

***

## Payment Mode — Fixed-Amount Payments on XRPL

Use payment mode when you set the exact amount. This is ideal for checkout flows, invoices, and pay-this-amount scenarios.

### Pay 50 RLUSD to an XRPL Address

```tsx
import { DepositWidget, type DepositConfig } from "@0xsquid/deposit-widget";

const config: DepositConfig = {
  mode: "payment",
  amount: "50.00",
  destinationAddress: "rYourXRPLAddress",
  destinationToken: {
    address: "524c555344000000000000000000000000000000.rmxckbedwqr76quhesumdegf4b9xj8m5de",
    chainId: "xrpl-mainnet",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};

function App() {
  return <DepositWidget config={config} />;
}
```

### Pay 100 XRP

```tsx
const config: DepositConfig = {
  mode: "payment",
  amount: "100",
  destinationAddress: "rYourXRPLAddress",
  destinationToken: {
    address: "xrp",
    chainId: "xrpl-mainnet",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
};
```

***

## Theme Customization

To customize the widget's appearance:

1. Use the [Widget Studio](https://studio.squidrouter.com/) to generate a custom theme.
2. Copy the generated `theme` (and `themeType`) and paste them into your `config`.

```tsx
const config: DepositConfig = {
  mode: "deposit",
  destinationAddress: "rYourXRPLAddress",
  destinationToken: {
    address: "xrp",
    chainId: "xrpl-mainnet",
  },
  integrator: {
    id: "<your-integrator-id>",
    name: "Your App",
    logoUrl: "https://your.app/logo.png",
  },
  themeType: "dark",
  theme: {
    // Your custom theme overrides
  },
};
```

***

## Next Steps

* For full Deposit Widget documentation (installation, theming, all config options), see the [Deposit Widget docs](/widget-integration/add-a-widget/deposit-widget)
* Need a full swap UI where the user picks both source and destination? See the [Swap Widget](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/swap-widget)
* For programmatic control, see the [API & SDK](/api-and-sdk-integration/chain-integration-guides/xrpl-integration/api-and-sdk) guide


# API & SDK

Integrate XRPL cross-chain swaps directly using Squid's routing API or TypeScript SDK. This gives you full control over the swap lifecycle — routing, execution, and status tracking — so you can build custom UIs or backend flows.

***

## 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: "YourXRPLAddress",
  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: "YourXRPLAddress",
  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: "YourXRPLAddress",
  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`

### 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) |

***

## 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.


# Stellar Integration

Integrate cross-chain swaps from Stellar to EVM chains using Squid. Stellar 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 Stellar.

***

## Stellar Parameters

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

### Supported Tokens

The following tokens are currently supported on Stellar via Squid Intents:

| Token    | Address                                                         |
| -------- | --------------------------------------------------------------- |
| **USDC** | `USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN` |

> Token addresses on Stellar follow the format `CODE-ISSUER` (e.g., `USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN`).

***

## Prerequisites

* **Stellar SDK** — Install `@stellar/stellar-sdk` to build and sign Stellar transactions.
* **Stellar Wallet** — A funded Stellar account with a secret key. The account must have a trustline for any non-native asset being sent (e.g., USDC).
* **Horizon Server** — The examples connect to the public Horizon API at `https://horizon.stellar.org`.
* **Integrator ID** — A valid Squid integrator ID with Squid Intents enabled.

***

## API Integration

### Stellar → EVM Swap

The following example demonstrates a full Stellar-to-EVM swap using the Squid API directly. It sends USDC on Stellar to USDC on Base.

```typescript
import * as StellarSdk from "@stellar/stellar-sdk";
import axios from "axios";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables
const stellarSecretKey: string = process.env.STELLAR_SECRET_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;

// Define swap parameters
const fromChainId = "stellar-mainnet";
const fromToken = "USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"; // USDC on Stellar
const fromAmount = "1000000"; // 0.1 USDC (7 decimals on Stellar)

const toChainId = "8453"; // Base
const toToken = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // USDC on Base

// Set up Stellar keypair and Horizon server
const keypair = StellarSdk.Keypair.fromSecret(stellarSecretKey);
const horizonServer = new StellarSdk.Horizon.Server("https://horizon.stellar.org");

// Get the optimal route for the swap
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: any) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    throw error;
  }
};

// Get the status of the transaction
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params,
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error: any) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    throw error;
  }
};

// Poll transaction status until completion
const updateTransactionStatus = async (txHash: string, requestId: string, quoteId?: string) => {
  const getStatusParams: any = {
    transactionId: txHash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId || requestId, // Required for Squid Intents transactions
  };

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

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

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

  console.log("Swap fully confirmed!");
};

// Main function
(async () => {
  const params = {
    fromAddress: keypair.publicKey(),
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: "0xYourEVMAddress", // Replace with your destination EVM wallet
    quoteOnly: false,
  };

  // Get the swap route
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;

  // Extract quoteId for Squid Intents transactions
  const quoteId = route?.estimate?.actions?.[0]?.coralV2Order?.quoteId
               || route?.estimate?.quoteId
               || route?.quoteId
               || routeResult.data?.quoteId;

  console.log("Calculated route. Target output:", route.estimate.toAmount);
  console.log("requestId:", requestId);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest;

  // Execute the swap transaction on Stellar
  let txHash: string;

  if (typeof transactionRequest.data === "string") {
    // Case 1: XDR-encoded transaction envelope
    // Deserialize, sign, and submit directly
    const transaction = StellarSdk.TransactionBuilder.fromXDR(
      transactionRequest.data,
      StellarSdk.Networks.PUBLIC
    );
    transaction.sign(keypair);

    const result = await horizonServer.submitTransaction(transaction as StellarSdk.Transaction);
    txHash = result.hash;
  } else {
    // Case 2: JSON payment object
    // Build a native Stellar payment transaction from the route details
    const sourceAccount = await horizonServer.loadAccount(keypair.publicKey());
    const txData = transactionRequest.data;

    let paymentAsset: StellarSdk.Asset;
    if (txData.asset && txData.asset.code && txData.asset.issuer) {
      paymentAsset = new StellarSdk.Asset(txData.asset.code, txData.asset.issuer);
    } else {
      paymentAsset = StellarSdk.Asset.native();
    }

    const builder = new StellarSdk.TransactionBuilder(sourceAccount, {
      fee: (await horizonServer.fetchBaseFee()).toString(),
      networkPassphrase: StellarSdk.Networks.PUBLIC,
    });

    builder.addOperation(
      StellarSdk.Operation.payment({
        destination: transactionRequest.target,
        asset: paymentAsset,
        amount: txData.amount || fromAmount,
      })
    );

    // Add memo if present (Squid may require memos for intent tracking)
    if (txData.memo) {
      if (txData.memoType === "hash" || txData.memoType === "MEMO_HASH") {
        builder.addMemo(StellarSdk.Memo.hash(txData.memo));
      } else if (txData.memoType === "id" || txData.memoType === "MEMO_ID") {
        builder.addMemo(StellarSdk.Memo.id(txData.memo));
      } else {
        builder.addMemo(StellarSdk.Memo.text(txData.memo));
      }
    }

    builder.setTimeout(180);

    const transaction = builder.build();
    transaction.sign(keypair);

    const result = await horizonServer.submitTransaction(transaction);
    txHash = result.hash;
  }

  console.log("Transaction confirmed! Hash:", txHash);

  // Track transaction status
  await updateTransactionStatus(txHash, requestId as string, quoteId);
})();
```

### API Code Examples

| Route         | Example                                                                                   |
| ------------- | ----------------------------------------------------------------------------------------- |
| Stellar → EVM | [stellarToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/api/stellarToEVMSwap) |

***

## SDK Integration

The Squid SDK provides the same Stellar routing capabilities. After initializing the SDK, use `squid.getRoute()` with the same parameters, then execute the transaction natively on the Stellar network.

> **Note:** Because `squid.executeRoute()` expects EVM-compatible signers by default, Stellar transactions must be dispatched natively using the Stellar SDK after obtaining the route.

```typescript
import { Squid } from "@0xsquid/sdk";
import * as StellarSdk from "@stellar/stellar-sdk";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables
const stellarSecretKey: string = process.env.STELLAR_SECRET_KEY!;
const integratorId: string = process.env.INTEGRATOR_ID!;

// Define swap parameters
const fromChainId = "stellar-mainnet";
const fromToken = "USDC-GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN";
const fromAmount = "1000000"; // 0.1 USDC (7 decimals)

const toChainId = "8453"; // Base
const toToken = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // USDC on Base

// Set up Stellar keypair and Horizon server
const keypair = StellarSdk.Keypair.fromSecret(stellarSecretKey);
const horizonServer = new StellarSdk.Horizon.Server("https://horizon.stellar.org");

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

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

  const params = {
    fromAddress: keypair.publicKey(),
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: "0xYourEVMAddress", // Replace with your destination EVM wallet
    quoteOnly: false,
  };

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

  // Extract quoteId for Squid Intents transactions
  const quoteId = (route as any).estimate?.actions?.[0]?.coralV2Order?.quoteId
               || (route as any).estimate?.quoteId
               || (route as any).quoteId;

  console.log("Calculated route. Target output:", route.estimate.toAmount);

  const transactionRequest = route.transactionRequest as any;

  // Execute the transaction natively on Stellar
  let txHash: string;

  if (typeof transactionRequest.data === "string") {
    // Case 1: XDR-encoded transaction envelope
    const transaction = StellarSdk.TransactionBuilder.fromXDR(
      transactionRequest.data,
      StellarSdk.Networks.PUBLIC
    );
    transaction.sign(keypair);

    const result = await horizonServer.submitTransaction(transaction as StellarSdk.Transaction);
    txHash = result.hash;
  } else {
    // Case 2: JSON payment object
    const sourceAccount = await horizonServer.loadAccount(keypair.publicKey());
    const txData = transactionRequest.data;

    let paymentAsset: StellarSdk.Asset;
    if (txData.asset && txData.asset.code && txData.asset.issuer) {
      paymentAsset = new StellarSdk.Asset(txData.asset.code, txData.asset.issuer);
    } else {
      paymentAsset = StellarSdk.Asset.native();
    }

    const builder = new StellarSdk.TransactionBuilder(sourceAccount, {
      fee: (await horizonServer.fetchBaseFee()).toString(),
      networkPassphrase: StellarSdk.Networks.PUBLIC,
    });

    builder.addOperation(
      StellarSdk.Operation.payment({
        destination: transactionRequest.target,
        asset: paymentAsset,
        amount: txData.amount || fromAmount,
      })
    );

    if (txData.memo) {
      if (txData.memoType === "hash" || txData.memoType === "MEMO_HASH") {
        builder.addMemo(StellarSdk.Memo.hash(txData.memo));
      } else if (txData.memoType === "id" || txData.memoType === "MEMO_ID") {
        builder.addMemo(StellarSdk.Memo.id(txData.memo));
      } else {
        builder.addMemo(StellarSdk.Memo.text(txData.memo));
      }
    }

    builder.setTimeout(180);

    const transaction = builder.build();
    transaction.sign(keypair);

    const result = await horizonServer.submitTransaction(transaction);
    txHash = result.hash;
  }

  console.log("Transaction confirmed! Hash:", txHash);

  // Track status using the SDK
  const getStatusParams: any = {
    transactionId: txHash,
    requestId: requestId,
    integratorId: integratorId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId || requestId, // Required for Squid Intents transactions
  };

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

  let status = await squid.getStatus(getStatusParams);
  console.log(`Initial status: ${status.squidTransactionStatus}`);

  do {
    try {
      await new Promise((resolve) => setTimeout(resolve, 5000));
      status = await squid.getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error: unknown) {
      if (error instanceof Error && (error as any).response?.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached.");
          break;
        }
        continue;
      } else {
        throw error;
      }
    }
  } while (status && !completedStatuses.includes(status.squidTransactionStatus as string));

  console.log("Swap fully confirmed!");
})();
```

### SDK Code Examples

| Route         | Example                                                                                   |
| ------------- | ----------------------------------------------------------------------------------------- |
| Stellar → EVM | [stellarToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/stellarToEVMSwap) |

***

## Transaction Handling

### XDR vs JSON Transaction Formats

The Squid route response for Stellar returns a `transactionRequest` whose `data` field can be in one of two formats. Your integration must handle both:

| Format                  | `typeof transactionRequest.data` | Description                                                                                                                                                         |
| ----------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **XDR Envelope**        | `string`                         | A pre-built, XDR-encoded Stellar transaction envelope. Deserialize it with `TransactionBuilder.fromXDR()`, sign, and submit.                                        |
| **JSON Payment Object** | `object`                         | A structured payment descriptor containing `target`, `asset`, `amount`, and optional `memo` fields. Build a Stellar payment transaction manually from these fields. |

**Detecting the format:**

```typescript
if (typeof transactionRequest.data === "string") {
  // XDR envelope — deserialize, sign, submit
} else {
  // JSON payment object — build transaction manually
}
```

### Memo Handling

When the transaction data includes a memo, you must attach it to your Stellar transaction. Squid uses memos for intent tracking. The supported memo types are:

| `memoType` value          | Stellar Memo Method          |
| ------------------------- | ---------------------------- |
| `"hash"` or `"MEMO_HASH"` | `StellarSdk.Memo.hash(memo)` |
| `"id"` or `"MEMO_ID"`     | `StellarSdk.Memo.id(memo)`   |
| *(default / text)*        | `StellarSdk.Memo.text(memo)` |

> **Important:** If the route response includes a memo, you must include it in the submitted transaction. Omitting the memo may cause the swap to fail.

***

## Status Tracking

Stellar routes are powered by Squid Intents, which **requires** the `quoteId` for status polling. The `quoteId` is returned in the route response.

```typescript
const statusParams = {
  transactionId: txHash,        // Stellar transaction hash
  fromChainId: "stellar-mainnet",
  toChainId: "8453",            // Destination chain ID
  quoteId: quoteId,             // Required for Squid Intents
};

const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
  params: statusParams,
  headers: {
    "x-integrator-id": "<your-integrator-id>",
  },
});
```

> **Important:** A Squid Intents transaction will not be tracked correctly 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.

### Extracting the quoteId

The `quoteId` may appear in several locations within the route response. Use a fallback chain to extract it reliably:

```typescript
const quoteId = route?.estimate?.actions?.[0]?.coralV2Order?.quoteId
             || route?.estimate?.quoteId
             || route?.quoteId;
```

***

## Important Notes

1. **Stellar transactions are dispatched natively** — Unlike EVM chains, you cannot use `squid.executeRoute()` with a standard signer. Build and submit the Stellar transaction using the Stellar SDK.
2. **Handle both transaction formats** — Check `typeof transactionRequest.data` to determine whether you received an XDR envelope or a JSON payment object.
3. **Include memos when provided** — Squid may include memo data for intent tracking. Always attach the memo to your Stellar transaction if one is present.
4. **quoteId is required for status polling** — Squid Intents transactions require the `quoteId` parameter when calling the `/v2/status` endpoint.
5. **No depositTxVerificationSignature needed** — Stellar native deposits do not require a deposit transaction verification signature.
6. **USDC uses 7 decimals on Stellar** — When specifying `fromAmount`, use 7-decimal precision (e.g., `1000000` = 0.1 USDC).
7. **Trustlines required** — Your Stellar account must have an active trustline for any non-native asset (e.g., USDC) before initiating a swap.


# Hedera Integration

Integrate cross-chain swaps from Hedera to EVM chains using Squid. Hedera 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 Hedera.

***

## Hedera Parameters

| Parameter    | Value |
| ------------ | ----- |
| **Chain ID** | `295` |

### Supported Tokens

| Token    | Address                                      |
| -------- | -------------------------------------------- |
| **USDC** | `0x000000000000000000000000000000000006f89a` |

***

## Key Concepts

### Transaction Type: `DEPOSIT_ADDRESS_WITH_SIGNATURE`

Hedera routes use the `DEPOSIT_ADDRESS_WITH_SIGNATURE` transaction type. Unlike standard EVM routes, this type:

* **Does not require ERC-20 approval** — skip the `approve()` call entirely
* **Requires signing an order hash** — the route response includes a `signatureRequired` field containing an order hash that must be signed by the sender's wallet
* **Returns a deposit address** — funds are sent directly to a deposit address via a standard EVM transaction

### Order Hash Signing

When the route response has `transactionRequest.type === 'DEPOSIT_ADDRESS_WITH_SIGNATURE'`, the `transactionRequest.signatureRequired` field contains the order hash. Sign this hash using `signer.signMessage()` to produce the `depositTxVerificationSignature`:

```typescript
const orderHash = transactionRequest.signatureRequired;
const depositTxVerificationSignature = await signer.signMessage(orderHash);
```

> **Important:** The Squid indexer expects the signature of the literal UTF-8 hex string, not raw bytes. Use `signMessage()` (which applies EIP-191 prefix) directly on the order hash string.

### Token Association Polling

Hedera uses the Hedera Token Service (HTS) which requires tokens to be explicitly associated with accounts before they can receive transfers. When Squid creates a deposit address for your route, it must complete a token association on the Hedera network. This process is asynchronous and takes a few seconds.

Poll `estimateGas` on the transaction before executing to confirm the token association is complete:

```typescript
for (let i = 0; i < 15; i++) {
  try {
    await provider.estimateGas({
      from: signer.address,
      to: transactionRequest.target,
      data: transactionRequest.data,
      value: transactionRequest.value,
    });
    console.log("Token association complete. Proceeding...");
    break;
  } catch (e) {
    if (i === 14) {
      console.warn("Polling timed out. Attempting execution anyway...");
    } else {
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  }
}
```

If the token has not yet been associated, `estimateGas` will throw an HTS system error (e.g., `TOKEN_NOT_ASSOCIATED_TO_ACCOUNT`). The loop retries up to 15 times with a 1-second delay (\~15 seconds total).

***

## API Integration

### Route from Hedera (Hedera → EVM)

To route from Hedera to an EVM chain, set `fromChain` to `295` and provide an EVM-compatible Hedera address.

#### Full Working Example

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

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 parameters
const fromChainId = "295"; // Hedera Mainnet
const fromToken = "0x000000000000000000000000000000000006f89a"; // USDC on Hedera
const fromAmount = "2000";

const toChainId = "8453"; // Base (or any supported EVM chain)
const toToken = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // USDC on Base

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

// Get route from Squid API
const getRoute = async (params: any) => {
  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 };
};

// Get transaction status
const getStatus = async (params: any) => {
  const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
    params,
    headers: {
      "x-integrator-id": integratorId,
    },
  });
  return result.data;
};

(async () => {
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
    quoteOnly: false,
  };

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

  // 1. Get the route
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;

  // Extract quoteId (required for Squid Intents status tracking)
  const quoteId =
    route?.estimate?.actions?.[0]?.coralV2Order?.quoteId ||
    route?.estimate?.quoteId ||
    route?.quoteId ||
    routeResult.data?.quoteId;

  console.log("Route received. Expected output:", route.estimate.toAmount);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest;
  let depositTxVerificationSignature: string | undefined;

  // 2. Handle DEPOSIT_ADDRESS_WITH_SIGNATURE route type
  if (
    transactionRequest.type === "DEPOSIT_ADDRESS_WITH_SIGNATURE" ||
    transactionRequest.routeType === "DEPOSIT_ADDRESS_WITH_SIGNATURE"
  ) {
    console.log("Route type is DEPOSIT_ADDRESS_WITH_SIGNATURE, skipping ERC-20 approval...");

    // Sign the order hash
    const orderHash = transactionRequest.signatureRequired;
    if (orderHash) {
      depositTxVerificationSignature = await signer.signMessage(orderHash);
      console.log("Generated deposit verification signature");
    }
  }

  // 3. Poll estimateGas to confirm token association
  console.log("Verifying Hedera token association on deposit address...");
  for (let i = 0; i < 15; i++) {
    try {
      await provider.estimateGas({
        from: signer.address,
        to: transactionRequest.target,
        data: transactionRequest.data,
        value: transactionRequest.value,
      });
      console.log("Token association confirmed. Proceeding with swap...");
      break;
    } catch (e) {
      if (i === 14) {
        console.warn("Token association polling timed out. Attempting execution anyway...");
      } else {
        await new Promise((resolve) => setTimeout(resolve, 1000));
      }
    }
  }

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

  // 5. Poll status until complete
  const statusParams: any = {
    transactionId: txReceipt!.hash,
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    bridgeType: "rfq",
    quoteId: quoteId,
  };

  // Attach the deposit verification signature for status tracking
  if (depositTxVerificationSignature) {
    statusParams.depositTxVerificationSignature = depositTxVerificationSignature;
  }

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

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

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

  console.log("Swap complete!");
  console.log(`Track on Squid Scanner: https://scan.squidrouter.com/tx/${txReceipt!.hash}`);
})();
```

***

## SDK Integration

The Squid SDK handles much of the Hedera-specific logic automatically. For `DEPOSIT_ADDRESS_WITH_SIGNATURE` routes, `executeRoute()` will:

* Automatically sign the order hash (`signatureRequired`)
* Execute the deposit transaction
* Return the `depositTxVerificationSignature` in the response

You are still responsible for:

* Polling `estimateGas` to wait for token association before calling `executeRoute()`
* Passing the `depositTxVerificationSignature` and `quoteId` to the status endpoint

### Full Working Example

```typescript
import { Squid } from "@0xsquid/sdk";
import { ethers } from "ethers";
import * as dotenv from "dotenv";
dotenv.config();

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 parameters
const fromChainId = "295"; // Hedera
const fromToken = "0x000000000000000000000000000000000006f89a"; // USDC on Hedera
const fromAmount = "2000";

const toChainId = "42161"; // Arbitrum
const toToken = "0xaf88d065e77c8cc2239327c5edb3a432268e5831"; // USDC on Arbitrum

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

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

(async () => {
  const squid = getSDK();
  await squid.init();
  console.log("Squid SDK initialized");

  // 1. Get the route
  const params = {
    fromAddress: signer.address,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: signer.address,
  };

  const { route, requestId } = await squid.getRoute(params);

  // Extract quoteId (required for Squid Intents status tracking)
  const quoteId =
    (route as any).estimate?.actions?.[0]?.coralV2Order?.quoteId ||
    (route as any).estimate?.quoteId ||
    (route as any).quoteId;

  console.log("Route received. Expected output:", route.estimate.toAmount);

  // 2. Poll estimateGas to confirm token association
  if (route.transactionRequest) {
    const txReq = route.transactionRequest as any;
    console.log("Verifying Hedera token association on deposit address...");
    for (let i = 0; i < 15; i++) {
      try {
        await provider.estimateGas({
          from: signer.address,
          to: txReq.target,
          data: txReq.data,
          value: txReq.value,
        });
        console.log("Token association confirmed. Proceeding...");
        break;
      } catch (e) {
        if (i === 14) {
          console.warn("Polling timed out. Executing anyway...");
        } else {
          await new Promise((resolve) => setTimeout(resolve, 1000));
        }
      }
    }
  }

  // 3. Execute the route (SDK handles orderHash signing automatically)
  const response = await squid.executeRoute({
    signer: signer as any,
    route,
  });

  // 4. Extract transaction hash and deposit verification signature
  let txHash = "unknown";
  let depositTxVerificationSignature: string | undefined;

  if (response && typeof response === "object") {
    if ("hash" in response) {
      txHash = response.hash as string;
      await (response as any).wait?.();
    } else if ("transactionHash" in response) {
      txHash = (response as any).transactionHash;
    }

    if ("depositTxVerificationSignature" in response) {
      depositTxVerificationSignature = (response as any).depositTxVerificationSignature;
    }
  }

  console.log(`Transaction confirmed: ${txHash}`);
  console.log(`Track on Squid Scanner: https://scan.squidrouter.com/tx/${txHash}`);

  // 5. Poll status until complete
  const statusParams: any = {
    transactionId: txHash,
    requestId: requestId,
    integratorId: integratorId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    bridgeType: "rfq",
    quoteId: quoteId,
  };

  if (depositTxVerificationSignature) {
    statusParams.depositTxVerificationSignature = depositTxVerificationSignature;
  }

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

  do {
    try {
      await new Promise((resolve) => setTimeout(resolve, 5000));
      status = await squid.getStatus(statusParams);
      console.log(`Status: ${status.squidTransactionStatus}`);
    } catch (error: unknown) {
      if (
        error instanceof Error &&
        (error as any).response?.status === 404
      ) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached.");
          break;
        }
        console.log("Transaction not found. Retrying...");
        continue;
      }
      throw error;
    }
  } while (
    !status ||
    !completedStatuses.includes(status.squidTransactionStatus as string)
  );

  console.log("Swap complete!");
})();
```

***

## Status Tracking

Hedera routes are powered by Squid Intents, which **requires** both `quoteId` and `depositTxVerificationSignature` for status polling.

| Parameter                        | Description                                                 |
| -------------------------------- | ----------------------------------------------------------- |
| `transactionId`                  | The deposit transaction hash                                |
| `fromChainId`                    | `295` (Hedera)                                              |
| `toChainId`                      | The destination chain ID                                    |
| `quoteId`                        | Returned in the route response — required for Squid Intents |
| `depositTxVerificationSignature` | The signed order hash — required for Hedera routes          |
| `bridgeType`                     | `rfq`                                                       |

```typescript
const statusParams = {
  transactionId: txHash,
  fromChainId: "295",
  toChainId: toChainId,
  quoteId: quoteId,
  depositTxVerificationSignature: depositTxVerificationSignature,
  bridgeType: "rfq",
};

const status = await axios.get("https://v2.api.squidrouter.com/v2/status", {
  params: statusParams,
  headers: { "x-integrator-id": "<your-integrator-id>" },
});
```

> **Important:** A Squid Intents transaction will not be trackable 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.

***

## Code Examples

### API Examples

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

### SDK Examples

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

***

## Important Notes

* **EVM-compatible wallets only** — Hedera integration uses Hedera's EVM-compatible layer. You need an Ethereum-style private key and can interact with Hedera using standard `ethers.js` tooling and a Hedera JSON-RPC endpoint.
* **No ERC-20 approval needed** — `DEPOSIT_ADDRESS_WITH_SIGNATURE` routes bypass the standard approval flow. Do not call `approve()` for these routes.
* **Token association is asynchronous** — Always poll `estimateGas` before sending the deposit transaction to ensure the deposit address has completed HTS token association. Skipping this step may result in a failed transaction.
* **Order hash signing is mandatory** — The `signatureRequired` field must be signed and the resulting `depositTxVerificationSignature` must be passed to the `/v2/status` endpoint for transaction tracking.
* **`quoteId` is required for status calls** — All Squid Intents transactions (including Hedera routes) require the `quoteId` parameter when polling the status endpoint.

For a full reference of all transaction types across all chains, see the [Transaction Types](/api-and-sdk-integration/key-concepts/transaction-types) page.


# Canton Integration

Integrate cross-chain swaps from Canton to EVM chains using Squid. Canton 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 Canton.

***

## Canton Parameters

| Parameter    | Value    |
| ------------ | -------- |
| **Chain ID** | `canton` |

### Supported Tokens

| Token                               | Address                                                                     |
| ----------------------------------- | --------------------------------------------------------------------------- |
| **Canton Coin (CC)** — native asset | `DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc` |

Canon Coin (CC) is the native asset on Canton. Additional tokens are supported — query the [Supported Tokens endpoint](/chains-and-tokens/get-supported-tokens-and-chains) with `chainId=canton` to get the full list of available tokens.

> Token addresses on Canton follow the format `admin::fingerprint` for the native Canton Coin, or `instrumentId::admin::fingerprint` for CIP-056 tokens (e.g., `USDCx::decentralized-usdc-admin::12208...`).

***

## Key Concepts

### Transaction Type: `DEPOSIT_ADDRESS_DIRECT_TRANSFER`

Canton routes use the `DEPOSIT_ADDRESS_DIRECT_TRANSFER` transaction type. Unlike standard EVM routes, this type:

* **Does not require ERC-20 approval** — Canton is not EVM-compatible
* **Returns a deposit address** — the route response includes a `target` field containing the deposit address for funds
* **Uses the order hash as a memo** — the `data` field in the transaction request contains the order hash, which must be included as a transfer memo when sending funds

Canton transactions can be executed in two ways:

1. **Connected wallet (browser)**: Using a CIP-103-compatible Canton wallet, the transfer is built using the Splice token-standard `TransferFactory` and submitted via `prepareExecuteAndWait`
2. **Deposit address**: Send funds directly to the deposit address with the order hash as a memo from any Canton wallet

> **Why can't Canton swaps be fully automated from a script?**
>
> Unlike EVM chains where a private key can be imported to sign transactions programmatically, Canton wallets use the **CIP-103 protocol** — a browser-based wallet discovery and signing standard. Wallet keys are managed entirely within browser extensions (Send, C8, Nightly) and communicate via `window.postMessage`. There is no exportable private key or Node.js-compatible signing SDK for Canton.
>
> The API and SDK examples handle everything that can be done programmatically: requesting a route, displaying deposit details, and polling transaction status. The only manual step is sending funds to the deposit address from your Canton wallet with the order hash as the memo.
>
> For fully automated execution in a browser environment, use the [Squid Widget](/widget-integration/add-a-widget/widget), which connects to Canton wallets via CIP-103.

### Canton Address Format

Canton addresses use the format `name::fingerprint`, where `name` is an identifier and `fingerprint` is a `1220`-prefixed SHA-256 hash (68 hex characters total). Example: `DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc`

### Token Pre-Approval (EVM → Canton)

Canton uses the **CIP-56 token standard**, which follows an **offer-and-acceptance model** for token transfers. Unlike EVM's push-only model (where tokens are sent directly to a recipient), Canton requires recipients to explicitly agree to receive a token before it can be credited to their wallet.

To streamline this, Canton supports **`TransferPreapproval`** — a smart contract that pre-authorizes incoming transfers for a specific token. Without a preapproval in place, incoming tokens arrive as a pending "transfer offer" that the recipient must manually accept in their wallet.

**How this affects integrations:**

* **Squid Widget**: The widget handles `TransferPreapproval` checks automatically. If a user's Canton wallet does not have a preapproval for the receiving token, the widget will prompt them to set one up before executing the swap.
* **API / SDK**: The `TransferPreapproval` is not exposed as an API endpoint. When building EVM → Canton swaps via the API or SDK, the route is a standard EVM transaction (`DEPOSIT_ADDRESS_CALLDATA`). The Canton-side token delivery is handled by Squid's backend. However, the user's Canton wallet must have a `TransferPreapproval` for the destination token, or they will need to manually accept the transfer offer in their wallet.

***

## API Integration

### Canton → EVM Swap

The following example demonstrates a full Canton-to-EVM swap using the Squid API directly. It sends Canton Coin (CC) to USDC on Base using the deposit-address pattern.

```typescript
// Canton to EVM Swap Using Squid API (Squid Intents)
import axios from "axios";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables
const cantonAddress: string = process.env.CANTON_ADDRESS!;
const integratorId: string = process.env.INTEGRATOR_ID!;

// Define swap parameters
const fromChainId = "canton";
const fromToken =
  "DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc"; // Canton Coin (CC)
const fromAmount = "10000000000"; // 1 CC (Canton Coin uses 10 decimals)

const toChainId = "8453"; // Base
const toToken = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // USDC on Base

// Get the optimal route for the swap
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: any) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    throw error;
  }
};

// Get the status of the transaction
const getStatus = async (params: any) => {
  try {
    const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
      params,
      headers: {
        "x-integrator-id": integratorId,
      },
    });
    return result.data;
  } catch (error: any) {
    if (error.response) {
      console.error("API error:", error.response.data);
    }
    throw error;
  }
};

// Poll transaction status until completion
const updateTransactionStatus = async (
  requestId: string,
  quoteId: string
) => {
  const getStatusParams: any = {
    requestId: requestId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId,
  };

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

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

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

  console.log("Swap fully confirmed!");
};

// Main function
(async () => {
  console.log(`Canton address: ${cantonAddress}`);

  const params = {
    fromAddress: cantonAddress,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: "0xYourEVMAddress", // Replace with your destination EVM wallet
    quoteOnly: false,
  };

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

  // Get the swap route
  const routeResult = await getRoute(params);
  const route = routeResult.data.route;
  const requestId = routeResult.requestId;

  // Extract quoteId for Squid Intents transactions
  const quoteId =
    route?.estimate?.actions?.[0]?.coralV2Order?.quoteId ||
    route?.estimate?.quoteId ||
    route?.quoteId ||
    routeResult.data?.quoteId;

  console.log("Calculated route. Target output:", route.estimate.toAmount);
  console.log("requestId:", requestId);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest;

  // Canton routes return a deposit address and order hash
  // The order hash is used as a transfer memo when sending funds
  const depositAddress = transactionRequest.target;
  const orderHash = transactionRequest.data;

  console.log("\n=== Canton Deposit Details ===");
  console.log(`Deposit Address: ${depositAddress}`);
  console.log(`Order Hash (Memo): ${orderHash}`);
  console.log(`Amount: ${fromAmount} (in smallest unit)`);
  console.log("\nSend the specified amount to the deposit address above");
  console.log("using your Canton wallet. Include the order hash as the");
  console.log("transfer memo (reason field).");
  console.log("==============================\n");

  // Track transaction status
  console.log("Waiting for deposit and tracking swap status...");
  await updateTransactionStatus(requestId as string, quoteId);

  console.log(`Track on Squid Scanner: https://scan.squidrouter.com`);
})();
```

### API Code Examples

| Route        | Example                                                                                 |
| ------------ | --------------------------------------------------------------------------------------- |
| Canton → EVM | [cantonToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/api/cantonToEVMSwap) |

***

## SDK Integration

The Squid SDK provides the same Canton routing capabilities. After initializing the SDK, use `squid.getRoute()` with the same parameters, then execute the transaction natively on the Canton network.

> **Note:** Because Canton is not EVM-compatible, `squid.executeRoute()` cannot be used directly. Canton transactions must be executed natively — either through a connected Canton wallet or by sending funds to the deposit address.

```typescript
// Canton to EVM Swap Using Squid SDK (Squid Intents)
import { Squid } from "@0xsquid/sdk";
import * as dotenv from "dotenv";
dotenv.config();

// Load environment variables
const cantonAddress: string = process.env.CANTON_ADDRESS!;
const integratorId: string = process.env.INTEGRATOR_ID!;

// Define swap parameters
const fromChainId = "canton";
const fromToken =
  "DSO::1220b1431ef217342db44d516bb9befde802be7d8899637d290895fa58880f19accc"; // Canton Coin (CC)
const fromAmount = "10000000000"; // 1 CC (Canton Coin uses 10 decimals)

const toChainId = "8453"; // Base
const toToken = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"; // USDC on Base

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

(async () => {
  const squid = getSDK();
  await squid.init();
  console.log("Initialized Squid SDK");
  console.log(`Canton address: ${cantonAddress}`);

  const params = {
    fromAddress: cantonAddress,
    fromChain: fromChainId,
    fromToken: fromToken,
    fromAmount: fromAmount,
    toChain: toChainId,
    toToken: toToken,
    toAddress: "0xYourEVMAddress", // Replace with your destination EVM wallet
    quoteOnly: false,
  };

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

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

  // Extract quoteId for Squid Intents transactions
  const quoteId =
    (route as any).estimate?.actions?.[0]?.coralV2Order?.quoteId ||
    (route as any).estimate?.quoteId ||
    (route as any).quoteId;

  console.log("Calculated route. Target output:", route.estimate.toAmount);
  console.log("requestId:", requestId);
  console.log("quoteId:", quoteId);

  const transactionRequest = route.transactionRequest as any;

  // Canton routes return a deposit address and order hash
  const depositAddress = transactionRequest.target;
  const orderHash = transactionRequest.data;

  console.log("\n=== Canton Deposit Details ===");
  console.log(`Deposit Address: ${depositAddress}`);
  console.log(`Order Hash (Memo): ${orderHash}`);
  console.log(`Amount: ${fromAmount} (in smallest unit)`);
  console.log("\nSend the specified amount to the deposit address above");
  console.log("using your Canton wallet. Include the order hash as the");
  console.log("transfer memo (reason field).");
  console.log("==============================\n");

  // Track status using the SDK
  const getStatusParams: any = {
    requestId: requestId,
    integratorId: integratorId,
    fromChainId: fromChainId,
    toChainId: toChainId,
    quoteId: quoteId,
  };

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

  console.log("Waiting for deposit and tracking swap status...");

  let status;
  do {
    try {
      await new Promise((resolve) => setTimeout(resolve, 5000));
      status = await squid.getStatus(getStatusParams);
      console.log(`Route status: ${status.squidTransactionStatus}`);
    } catch (error: unknown) {
      if (error instanceof Error && (error as any).response?.status === 404) {
        retryCount++;
        if (retryCount >= maxRetries) {
          console.error("Max retries reached.");
          break;
        }
        continue;
      } else {
        throw error;
      }
    }
  } while (
    status &&
    !completedStatuses.includes(status.squidTransactionStatus as string)
  );

  console.log("Swap fully confirmed!");
  console.log(`Track on Squid Scanner: https://scan.squidrouter.com`);
})();
```

### SDK Code Examples

| Route        | Example                                                                                 |
| ------------ | --------------------------------------------------------------------------------------- |
| Canton → EVM | [cantonToEVMSwap](https://github.com/0xsquid/examples/tree/main/V2/sdk/cantonToEVMSwap) |

***

## Transaction Handling

### Deposit Address Flow

The Squid route response for Canton returns a `transactionRequest` with:

| Field    | Description                                        |
| -------- | -------------------------------------------------- |
| `target` | The deposit address — send funds here              |
| `data`   | The order hash — include this as the transfer memo |
| `type`   | `DEPOSIT_ADDRESS_DIRECT_TRANSFER`                  |

```typescript
const depositAddress = transactionRequest.target;
const orderHash = transactionRequest.data; // Use as transfer memo
```

### Connected Wallet Flow (Widget)

For browser-based integrations using the Squid Widget, Canton swaps are executed through the connected Canton wallet:

1. The route's order hash is used as the transfer memo
2. A Splice token-standard transfer is built via the `TransferFactory`
3. The transfer is submitted through the wallet's `prepareExecuteAndWait` method
4. The memo field key is `splice.lfdecentralizedtrust.org/reason`

> For widget integration, Canton wallet connection and transaction execution are handled automatically. See the [Widget Integration](/widget-integration/add-a-widget/widget) guide.

***

## Status Tracking

Canton routes are powered by Squid Intents, which **requires** the `quoteId` for status polling.

```typescript
const statusParams = {
  fromChainId: "canton",
  toChainId: "8453",
  transactionId: transactionId,
  quoteId: quoteId, // Required for Squid Intents
};

const result = await axios.get("https://v2.api.squidrouter.com/v2/status", {
  params: statusParams,
  headers: {
    "x-integrator-id": "<your-integrator-id>",
  },
});
```

### Extracting the quoteId

The `quoteId` may appear in several locations within the route response. Use a fallback chain to extract it reliably:

```typescript
const quoteId = route?.estimate?.actions?.[0]?.coralV2Order?.quoteId
             || route?.estimate?.quoteId
             || route?.quoteId;
```

> **Important:** A Squid Intents transaction will not be tracked correctly 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.

***

## Important Notes

1. **Canton is not EVM-compatible** — Canton uses Daml smart contracts, not Solidity. Standard EVM tooling (`ethers.js`, MetaMask) does not work with Canton. Use a CIP-103-compatible Canton wallet for browser interactions.
2. **Deposit address with memo** — Canton routes return a deposit address and order hash. The order hash must be included as the transfer memo when sending funds. Omitting the memo will cause the swap to fail.
3. **Balances are private** — Canton balances can only be read through a connected wallet's ledger API. Address-only balance lookups are not supported.
4. **Canton wallet required** — Compatible browser wallets include Cantor8 (C8), Send Wallet, and Nightly. Wallets connect via the CIP-103 discovery protocol.
5. **`quoteId` is required for status polling** — All Squid Intents transactions require the `quoteId` parameter when calling the `/v2/status` endpoint.

For a full reference of all transaction types across all chains, see the [Transaction Types](/api-and-sdk-integration/key-concepts/transaction-types) page.


# Supported Chains and Tokens

{% 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 |
| hedera            | 295                 | evm     |
| canton            | canton              | canton  |

***

### Supported Token Types

Squid supports tokens across multiple chain ecosystems. Each token returned by the API includes a `type` field indicating its ecosystem:

| Token Type | Description                                       |
| ---------- | ------------------------------------------------- |
| `evm`      | ERC-20 and native tokens on EVM-compatible chains |
| `cosmos`   | Native and IBC tokens on Cosmos SDK chains        |
| `bitcoin`  | Native BTC                                        |
| `solana`   | SPL tokens and native SOL                         |
| `stellar`  | Stellar assets and native XLM                     |
| `sui`      | Sui native and fungible tokens                    |
| `xrpl`     | XRP Ledger native and issued tokens               |

### Native Token Address

For EVM chains, the native token (ETH, BNB, MATIC, etc.) is represented using the following standard address:

```
0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
```

Use this address as the `fromToken` or `toToken` value in route requests when swapping to or from a chain's native asset.

{% hint style="info" %}
You can retrieve the full list of supported tokens with their types using the `GET /v2/tokens` or `POST /v2/sdk-info` endpoints. Each token object includes a `type` field matching the values above.
{% endhint %}


# 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 %}

| Chain                         | Squid Intents | Chainflip | Axelar |
| ----------------------------- | ------------- | --------- | ------ |
| Arbitrum                      | ✅             | ✅         | ✅      |
| Avalanche                     | ✅             | ✅         | ✅      |
| Base                          | ✅             | ✅         | ✅      |
| Berachain                     | ✅             | ✅         | ✅      |
| Binance                       | ✅             | ✅         | ✅      |
| Bitcoin                       | ☑️            | ✅         | ❌      |
| Blast                         | ✅             | ✅         | ✅      |
| Canton                        | ☑️            | ❌         | ❌      |
| 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 Squid Intents on your integrator ID.
{% endhint %}


# 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,
};

// 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 Squid Intents, 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.


# 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 ---------- |                     |                      |
```


# Contracts

Squid deploys router contracts on every supported EVM chain. Most chains share the same contract address, but some newer chains use a different deployment.

{% hint style="info" %}
**Dynamic Lookup:** You can always retrieve the correct contract address for any chain programmatically using the `/v2/sdk-info` or `/v2/chains` endpoints. Each chain object includes a `squidContracts.squidRouter` field with the correct router address.
{% endhint %}

## **Mainnet**

### **SquidRouter — Primary**

Used on the majority of EVM chains:

| Chain         | Address                                                                                                                   |
| ------------- | ------------------------------------------------------------------------------------------------------------------------- |
| All (default) | `0xce16F69375520ab01377ce7B88f5BA8C48F8D666`                                                                              |
| Blast         | [0x492751eC3c57141deb205eC2da8bFcb410738630](https://blastexplorer.io/address/0xDC3D8e1Abe590BCa428a8a2FC4CfDbD1AcF57Bd9) |
| Fraxtal       | [0xDC3D8e1Abe590BCa428a8a2FC4CfDbD1AcF57Bd9](https://fraxscan.com/address/0xdc3d8e1abe590bca428a8a2fc4cfdbd1acf57bd9)     |

### **SquidRouter — Alternate**

The following chains use an alternate router address:

| Address | `0x2B4d4Cf15dAD79D3426D19674Bd237C1dc9144aa` |
| ------- | -------------------------------------------- |

| Chain     | Chain ID |
| --------- | -------- |
| Berachain | 80094    |
| Citrea    | 4114     |
| Gnosis    | 100      |
| Hedera    | 295      |
| HyperEVM  | 999      |
| Mantra    | 5887     |
| Monad     | 143      |
| Peaq      | 3338     |
| SagaEVM   | 5464     |
| Soneium   | 1868     |
| Sonic     | 146      |
| Tempo     | 4217     |

{% hint style="warning" %}
**Always use the contract address returned by the API** for the chain you are targeting. Do not hardcode router addresses — use the `/v2/sdk-info` or `/v2/chains` endpoint to fetch the correct `squidContracts.squidRouter` dynamically.
{% endhint %}

### How to look up the router address

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

```bash
curl -H "x-integrator-id: YOUR_ID" \
  "https://v2.api.squidrouter.com/v2/chains?chainId=295" | jq '.chain.squidContracts.squidRouter'
```

{% endtab %}

{% tab title="SDK" %}

```typescript
const squid = new Squid({ integratorId: "YOUR_ID" });
await squid.init();

const hedera = squid.chains.find(c => c.chainId === "295");
console.log(hedera.squidContracts.squidRouter);
// "0x2b4d4cf15dad79d3426d19674bd237c1dc9144aa"
```

{% endtab %}
{% endtabs %}

### **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 %}

###




---

[Next Page](/llms-full.txt/1)

