> For the complete documentation index, see [llms.txt](https://docs.aqua.network/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.aqua.network/developers/code-examples/executing-swaps-through-specific-pool.md).

# Executing swaps through specific pool

Swap against one pool you choose, bypassing path-finding entirely. `pool.quote()` asks the router's on-chain `estimate_swap` for that pool's hash, and `execute()` submits the router's single-pool swap with a minimum-out guard derived from the quote. The only network dependency is the RPC — for your own routing, a single-market integration, or isolation from other pools.

{% hint style="info" %}
This page uses the [official SDKs](/developers/integrating-with-aquarius.md) (0.4.0 or later). The [contract-level flow](#contract-level-flow-any-language) below covers other languages and contract sub-invocations.
{% endhint %}

{% hint style="warning" %}
Make sure the account has an established trustline for the asset to receive — otherwise the swap will fail until the trustline is created. See the [Stellar documentation on trustlines](https://developers.stellar.org/docs/learn/fundamentals/stellar-data-structures/accounts#trustlines).
{% endhint %}

### 1. Set up the client and pick the pool

A pair can have several pools — different types and fee tiers. Pick the exact one you trust:

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

```python
from stellar_sdk import Keypair
from aquarius import AquariusClient, Asset, XLM

AQUA = Asset.classic("AQUA", "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA")

aqua = AquariusClient(network="mainnet", signer=Keypair.from_secret("S..."))

pools = aqua.pools_for_pair(XLM, AQUA)
pool = next(p for p in pools if p.type == "volatile" and p.fee_bps == 30)
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
import { Keypair } from "@stellar/stellar-sdk";
import { AquariusClient, Asset, XLM } from "@aquariusdefi/sdk";

const AQUA = Asset.classic("AQUA", "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA");

const aqua = new AquariusClient({ network: "mainnet", signer: Keypair.fromSecret("S...") });

const pools = await aqua.pools.forPair(XLM, AQUA);
const pool = pools.find(p => p.type === "volatile" && p.feeBps === 30);
```

{% endtab %}
{% endtabs %}

### 2. Quote against this pool only

The quote runs the router's `estimate_swap` for this pool's hash — no signer required, no path-finding API involved:

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

```python
quote = pool.quote(XLM, AQUA, amount_in=1000000, slippage=0.01)   # 0.1 XLM in stroops

print(f"estimated out: {quote.amount_out}")   # base units
print(f"guaranteed minimum: {quote.guard}")   # estimate reduced by slippage
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const quote = await pool.quote({ from: XLM, to: AQUA, amountIn: 1000000n, slippage: 0.01 });   // 0.1 XLM in stroops

console.log(`estimated out: ${quote.amountOut}`);    // base units
console.log(`guaranteed minimum: ${quote.guard}`);   // estimate reduced by slippage
```

{% endtab %}
{% endtabs %}

### 3. Execute

`execute()` submits the router's single-pool `swap` pinned to this pool, with the quote's guard as the on-chain minimum. If the pool moves past the guard between quote and inclusion, the transaction fails with a `SlippageError` whose `requote()` re-reads the same pool. For bots, `pool.swap()` combines quote, execute, and retries:

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

```python
receipt = pool.swap(XLM, AQUA, amount_in=1000000, slippage=0.01, retries=3)

print(f"swapped: {receipt.amount_in} -> {receipt.amount_out}")
print(f"transaction: {receipt.tx_hash}")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const receipt = await pool.swap({ from: XLM, to: AQUA, amountIn: 1000000n, slippage: 0.01, retries: 3 });

console.log(`swapped: ${receipt.amountIn} -> ${receipt.amountOut}`);
console.log(`transaction: ${receipt.txHash}`);
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
Single-pool swaps are exact-input only: the router has no single-pool strict-receive. For an exact output amount, use the routed path described in [Executing swaps through optimal path](/developers/code-examples/executing-swaps-through-optimal-path.md).
{% endhint %}

### Contract-level flow (any language)

The SDK methods above wrap the router's single-pool entry points. The steps below call the pool contract directly — useful from other languages and for contract sub-invocations, where a direct pool call costs fewer resources than a chained swap.

To perform a swap, you need to follow these steps:

1\. **Identify pool address**: This part was covered earlier, please check [corresponding article](/developers/code-examples/prerequisites-and-basics.md#get-pool-contract-id-and-pool-hash).

2\. **Specify user secret key, pool address, amount in, input and output token indices**: You need to specify pool address, the amount of the input token you want to swap in stroops and swap direction by in and out tokens.

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

```python
# Your Secret Key (keep it secure!)
user_secret_key = "S......."
# XLM/AQUA pool address
pool_address = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV"

# Amount in (0.1 XLM), in stroops (1 XLM = 10^7 stroops)
amount_in = 1000000
# tokens are [XLM, AQUA], so XLM index is 0
in_idx = 0
out_idx = 1
# slippage percent
slippage_percent = 1
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// Your Secret Key (keep it secure!)
const userSecretKey = "S.......";
// XLM/AQUA pool address
const poolAddress = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV";
// 0.1 XLM in stroops
const amountIn = 1000000;
// tokens are [XLM, AQUA], so XLM index is 0
const inIdx = 0;
const outIdx = 1;
// slippage percent
const slippagePercent = 1;
```

{% endtab %}
{% endtabs %}

3\. **Calculate minimum amount of token to receive**: This can be achieved by simulating *estimate\_swap* pool method.

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

```python
def estimate_swap():
    print("Estimating swap amount...")
    soroban_server = SorobanServer(soroban_server_url)
    keypair = Keypair.from_secret(user_secret_key)

    source_account = soroban_server.load_account(keypair.public_key)
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE,
            base_fee=100
        )
        .append_invoke_contract_function_op(
            contract_id=pool_address,
            function_name="estimate_swap",
            parameters=[
                scval.to_uint32(in_idx),
                scval.to_uint32(out_idx),
                scval.to_uint128(amount_in),
            ]
        )
        .set_timeout(300)
        .build()
    )

    print("Simulating 'estimate_swap' transaction...")
    sim_result = soroban_server.simulate_transaction(tx)
    if not sim_result or sim_result.error:
        print("Simulation failed.", sim_result.error if sim_result else "")
        return math.nan

    retval = xdr.SCVal.from_xdr(sim_result.results[0].xdr)
    estimated = u128_to_int(retval.u128)
    print(f"Estimated result: {estimated / 1e7}")
    return estimated
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function estimateSwap() {
    const sorobanServer = new rpc.Server(sorobanServerUrl);

    const amount = new XdrLargeInt("u128", amountIn.toFixed()).toU128();

    const inIdxSCVal = xdr.ScVal.scvU32(inIdx);
    const outIdxSCVal = xdr.ScVal.scvU32(outIdx);

    const keypair = Keypair.fromSecret(userSecretKey);
    // Load the user account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the deposit transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
        // Append the invoke_contract_function operation for deposit
        .addOperation(
            contract.call(
                "estimate_swap",
                inIdxSCVal,
                outIdxSCVal,
                amount,
            ),
        )
        .setTimeout(TimeoutInfinite)
        .build();

    // Simulate the result
    const simulateResult = await sorobanServer.simulateTransaction(tx);

    if (!simulateResult.result) {
        console.log(simulateResult.error);
        console.log("Unable to simulate transaction");
        return NaN;
    }

    const result = u128ToInt(simulateResult.result.retval.value());

    console.log(`Estimated result: ${result}`);

    return result;
}
```

{% endtab %}
{% endtabs %}

4\. **Perform swap operation by submitting corresponding transaction.**

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

```python
def execute_swap():
    print("Executing swap...")
    soroban_server = SorobanServer(soroban_server_url)
    horizon_server = Server(horizon_server_url)
    keypair = Keypair.from_secret(user_secret_key)

    estimated_result = estimate_swap()
    if math.isnan(estimated_result):
        print("Estimation failed. Cannot proceed with swap.")
        return

    # Calculate minimum out after slippage
    slippage_coefficient = (100 - slippage_percent) / 100.0
    minimum_out = math.floor(estimated_result * slippage_coefficient)

    # Build swap transaction
    source_account = soroban_server.load_account(keypair.public_key)
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE,
            base_fee=100
        )
        .append_invoke_contract_function_op(
            contract_id=pool_address,
            function_name="swap",
            parameters=[
                scval.to_address(keypair.public_key),
                scval.to_uint32(in_idx),
                scval.to_uint32(out_idx),
                scval.to_uint128(amount_in),
                scval.to_uint128(minimum_out),
            ]
        )
        .set_timeout(300)
        .build()
    )

    print("Preparing transaction for submission...")
    prepared_tx = soroban_server.prepare_transaction(tx)
    prepared_tx.sign(keypair)

    print("Submitting transaction to Horizon...")
    response = horizon_server.submit_transaction(prepared_tx)
    if 'result_meta_xdr' not in response:
        print("Transaction failed.")
        return

    meta = xdr.TransactionMeta.from_xdr(response['result_meta_xdr'])
    meta_body = meta.v4 if meta.v == 4 else meta.v3
    if meta_body and meta_body.soroban_meta:
        out_value = u128_to_int(meta_body.soroban_meta.return_value.u128)
        print("Swap successful!")
        print(f"Received token out: {out_value / 1e7}")
    else:
        print("No result returned by the contract.")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
async function executeSwap() {
    const sorobanServer = new rpc.Server(sorobanServerUrl);
    const horizonServer = new Horizon.Server(horizonServerUrl);

    const amount = new XdrLargeInt("u128", amountIn.toFixed()).toU128();

    const slippageCoefficient = (100 - slippagePercent) / 100;
    const estimatedResult = await estimateSwap();
    const estimateWithSlippage = Math.floor(estimatedResult * slippageCoefficient);
    const minimumOut = new XdrLargeInt("u128", estimateWithSlippage.toFixed()).toU128();

    const inIdxSCVal = xdr.ScVal.scvU32(inIdx);
    const outIdxSCVal = xdr.ScVal.scvU32(outIdx);

    const keypair = Keypair.fromSecret(userSecretKey);
    // Load the user account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the swap transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
        // Append the invoke_contract_function operation for swap
        .addOperation(
            contract.call(
                "swap",
                xdr.ScVal.scvAddress(
                    Address.fromString(keypair.publicKey()).toScAddress(),
                ),
                inIdxSCVal,
                outIdxSCVal,
                amount,
                minimumOut,
            ),
        )
        .setTimeout(TimeoutInfinite)
        .build();

    // Prepare and sign the transaction
    const preparedTx = await sorobanServer.prepareTransaction(tx);
    preparedTx.sign(keypair);

    // Submit the transaction to the Horizon server
    const result = await horizonServer.submitTransaction(preparedTx);

    // Parse the transaction metadata to extract results
    const meta = (await sorobanServer.getTransaction(result.id)).resultMetaXdr;
    const returnValue = meta.value().sorobanMeta().returnValue();

    // Extract swapped amount
    const outValue = u128ToInt(returnValue.value());

    console.log("Swap successful!");
    console.log(`Received token out: ${outValue / 1e7}`);
}
```

{% endtab %}
{% endtabs %}

### Complete code examples

This code swaps 0.1 XLM to AQUA with Aquarius AMM on mainnet.

To successfully execute the code, provide the secret key of a Stellar account with at least 3 XLM and an established trustline for AQUA.

<details>

<summary>Copy the full code Python</summary>

```python
from stellar_sdk import (
    Keypair,
    TransactionBuilder,
    Network,
    Server,
    xdr,
    scval,
    SorobanServer,
)
import math

# =========================================
# Configuration and Input Variables
# =========================================

user_secret_key = "S......"  # Keep this secret
pool_address = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV"

# 0.1 XLM in stroops (1 XLM = 10^7 stroops)
amount_in = 1000000

# Token indices: [XLM, AQUA]
in_idx = 0
out_idx = 1

# Slippage in percent
slippage_percent = 1

# Servers
soroban_server_url = "https://mainnet.sorobanrpc.com"
horizon_server_url = "https://horizon.stellar.org"


# =========================================
# Utility Functions
# =========================================
def u128_to_int(parts: xdr.UInt128Parts) -> int:
    """Convert Uint128Parts to Python int."""
    return (parts.hi.uint64 << 64) + parts.lo.uint64


# =========================================
# Soroban Functions
# =========================================
def estimate_swap():
    print("Estimating swap amount...")
    soroban_server = SorobanServer(soroban_server_url)
    keypair = Keypair.from_secret(user_secret_key)

    source_account = soroban_server.load_account(keypair.public_key)
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE,
            base_fee=100
        )
        .append_invoke_contract_function_op(
            contract_id=pool_address,
            function_name="estimate_swap",
            parameters=[
                scval.to_uint32(in_idx),
                scval.to_uint32(out_idx),
                scval.to_uint128(amount_in),
            ]
        )
        .set_timeout(300)
        .build()
    )

    print("Simulating 'estimate_swap' transaction...")
    sim_result = soroban_server.simulate_transaction(tx)
    if not sim_result or sim_result.error:
        print("Simulation failed.", sim_result.error if sim_result else "")
        return math.nan

    retval = xdr.SCVal.from_xdr(sim_result.results[0].xdr)
    estimated = u128_to_int(retval.u128)
    print(f"Estimated result: {estimated / 1e7}")
    return estimated


def execute_swap():
    print("Executing swap...")
    soroban_server = SorobanServer(soroban_server_url)
    horizon_server = Server(horizon_server_url)
    keypair = Keypair.from_secret(user_secret_key)

    estimated_result = estimate_swap()
    if math.isnan(estimated_result):
        print("Estimation failed. Cannot proceed with swap.")
        return

    # Calculate minimum out after slippage
    slippage_coefficient = (100 - slippage_percent) / 100.0
    minimum_out = math.floor(estimated_result * slippage_coefficient)

    # Build swap transaction
    source_account = soroban_server.load_account(keypair.public_key)
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=Network.PUBLIC_NETWORK_PASSPHRASE,
            base_fee=100
        )
        .append_invoke_contract_function_op(
            contract_id=pool_address,
            function_name="swap",
            parameters=[
                scval.to_address(keypair.public_key),
                scval.to_uint32(in_idx),
                scval.to_uint32(out_idx),
                scval.to_uint128(amount_in),
                scval.to_uint128(minimum_out),
            ]
        )
        .set_timeout(300)
        .build()
    )

    print("Preparing transaction for submission...")
    prepared_tx = soroban_server.prepare_transaction(tx)
    prepared_tx.sign(keypair)

    print("Submitting transaction to Horizon...")
    response = horizon_server.submit_transaction(prepared_tx)
    if 'result_meta_xdr' not in response:
        print("Transaction failed.")
        return

    meta = xdr.TransactionMeta.from_xdr(response['result_meta_xdr'])
    meta_body = meta.v4 if meta.v == 4 else meta.v3
    if meta_body and meta_body.soroban_meta:
        out_value = u128_to_int(meta_body.soroban_meta.return_value.u128)
        print("Swap successful!")
        print(f"Received token out: {out_value / 1e7}")
    else:
        print("No result returned by the contract.")


# =========================================
# Entry Point
# =========================================
if __name__ == "__main__":
    execute_swap()

```

</details>

<details>

<summary>Copy the full code JavaScript</summary>

```javascript
const StellarSdk = require("@stellar/stellar-sdk");
const {
    Address,
    Contract,
    TransactionBuilder,
    rpc,
    Horizon,
    BASE_FEE,
    Networks,
    xdr,
    TimeoutInfinite,
    XdrLargeInt,
    Keypair,
} = StellarSdk;

// Step 1. Specify user secret key, pool address, amount in and direction

// User secret key (ensure this is kept secure)
const userSecretKey = "S.......";
// XLM/AQUA pool address
const poolAddress = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV";
// 0.1 XLM in stroops
const amountIn = 1000000;
// tokens are [XLM, AQUA], so XLM index is 0
const inIdx = 0;
const outIdx = 1;
// slippage percent
const slippagePercent = 1;

// ==========================
// Configuration Variables
// ==========================

// Soroban and Horizon server RPC endpoints
const sorobanServerUrl = "https://mainnet.sorobanrpc.com";
const horizonServerUrl = "https://horizon.stellar.org";

// ==========================
// Utility Functions
// ==========================

function u128ToInt(value) {
    /**
     * Converts UInt128Parts from Stellar's XDR to a JavaScript number.
     *
     * @param {Object} value - UInt128Parts object from Stellar SDK, with `hi` and `lo` properties.
     * @returns {number|null} Corresponding JavaScript number, or null if the number is too large.
     */
    const result =
        (BigInt(value.hi()._value) << 64n) + BigInt(value.lo()._value);

    // Check if the result is within the safe integer range for JavaScript numbers
    if (result <= BigInt(Number.MAX_SAFE_INTEGER)) {
        return Number(result);
    } else {
        console.warn("Value exceeds JavaScript's safe integer range");
        return null;
    }
}

// ==========================
// Swap Function
// ==========================

async function estimateSwap() {
    const sorobanServer = new rpc.Server(sorobanServerUrl);

    const amount = new XdrLargeInt("u128", amountIn.toFixed()).toU128();

    const inIdxSCVal = xdr.ScVal.scvU32(inIdx);
    const outIdxSCVal = xdr.ScVal.scvU32(outIdx);

    const keypair = Keypair.fromSecret(userSecretKey);
    // Load the user account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the deposit transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
        // Append the invoke_contract_function operation for deposit
        .addOperation(
            contract.call(
                "estimate_swap",
                inIdxSCVal,
                outIdxSCVal,
                amount,
            ),
        )
        .setTimeout(TimeoutInfinite)
        .build();

    // Simulate the result
    const simulateResult = await sorobanServer.simulateTransaction(tx);

    if (!simulateResult.result) {
        console.log(simulateResult.error);
        console.log("Unable to simulate transaction");
        return NaN;
    }

    const result = u128ToInt(simulateResult.result.retval.value());

    console.log(`Estimated result: ${result}`);

    return result;
}

// Step 3. Make a contract call to the pool's "swap" method.
async function executeSwap() {
    const sorobanServer = new rpc.Server(sorobanServerUrl);
    const horizonServer = new Horizon.Server(horizonServerUrl);

    const amount = new XdrLargeInt("u128", amountIn.toFixed()).toU128();

    const slippageCoefficient = (100 - slippagePercent) / 100;
    const estimatedResult = await estimateSwap();
    const estimateWithSlippage = Math.floor(estimatedResult * slippageCoefficient);
    const minimumOut = new XdrLargeInt("u128", estimateWithSlippage.toFixed()).toU128();

    const inIdxSCVal = xdr.ScVal.scvU32(inIdx);
    const outIdxSCVal = xdr.ScVal.scvU32(outIdx);

    const keypair = Keypair.fromSecret(userSecretKey);
    // Load the user account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the swap transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
        // Append the invoke_contract_function operation for swap
        .addOperation(
            contract.call(
                "swap",
                xdr.ScVal.scvAddress(
                    Address.fromString(keypair.publicKey()).toScAddress(),
                ),
                inIdxSCVal,
                outIdxSCVal,
                amount,
                minimumOut,
            ),
        )
        .setTimeout(TimeoutInfinite)
        .build();

    // Prepare and sign the transaction
    const preparedTx = await sorobanServer.prepareTransaction(tx);
    preparedTx.sign(keypair);

    // Submit the transaction to the Horizon server
    const result = await horizonServer.submitTransaction(preparedTx);

    // Parse the transaction metadata to extract results
    const meta = (await sorobanServer.getTransaction(result.id)).resultMetaXdr;
    const returnValue = meta.value().sorobanMeta().returnValue();

    // Extract swapped amount
    const outValue = u128ToInt(returnValue.value());

    console.log("Swap successful!");
    console.log(`Received token out: ${outValue / 1e7}`);
}

// ==========================
// Entry Point
// ==========================
executeSwap();

```

</details>
