> For the complete documentation index, see [llms.txt](https://docs.squidrouter.exchange/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.squidrouter.exchange/api-and-sdk-integration/chain-integration-guides/stellar-integration.md).

# 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.md) — 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.exchange/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.exchange/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.exchange",
    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.exchange/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.md) 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.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.squidrouter.exchange/api-and-sdk-integration/chain-integration-guides/stellar-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
