# Withdraw Liquidity

In this section, we demonstrate how to withdraw 1 share from a specific Aquarius AMM pool. For this example, we will use this [this XLM-AQUA pool](https://aqua.network/pools/CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV/).

Scroll [here](#complete-code-examples) to see the complete code.

### Executing Withdraw: Step by Step Guide

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

1. **Specify user secret key, share amount for withdraw and pool address**: To withdraw from a pool, you need your **user secret key**, the **amount for withdraw** (specified in stroops), and the **pool address**.  \
   You need to already have a share in this pool, make a [deposit](/developers/code-examples/deposit-liquidity.md) beforehand.

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

```python
# Distributor's secret key (ensure this is kept secure)
user_secret_key = "S..."
# XLM/AQUA pool address 
pool_address = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV"
# 1 share in stroops
share_amount = 1_0000000
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
// Distributor's secret key (ensure this is kept secure)
const userSecretKey = "S...";
// XLM/AQUA pool address 
const poolAddress = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV";
// 1 share in stroops
const shareAmount = 10000000;
```

{% endtab %}
{% endtabs %}

2. **Make a contract call to the pool's "withdraw" method.**

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

```python
def execute_withdraw():
   # Initialize Soroban and Horizon servers
   server = SorobanServer(SOROBAN_SERVER_RPC)
   horizon_server = Server(HORIZON_SERVER)

   # Load distributor's keypair using the secret key
   keypair = Keypair.from_secret(user_secret_key)

   # Load the distributor's account information from Soroban server
   account = server.load_account(keypair.public_key)

   # Build the withdraw transaction
   tx_builder = TransactionBuilder(
       source_account=account,
       network_passphrase=NETWORK_PASSPHRASE,
       base_fee=1000000  # Set base fee; adjust as necessary
   ).set_timeout(3600)  # Set transaction timeout

   # Append the invoke_contract_function operation for withdraw
   tx = tx_builder.append_invoke_contract_function_op(
       contract_id=pool_address,
       function_name="withdraw",
       parameters=[
           Address(keypair.public_key).to_xdr_sc_val(),  # Distributor's address
           scval.to_uint128(share_amount),  # Amount of shares to redeem
           scval.to_vec([
               scval.to_uint128(1),  # Minimum amount of XLM to receive
               scval.to_uint128(1),  # Minimum amount of AQUA to receive
           ]),
       ],
   )
   tx = server.prepare_transaction(tx.build())
   tx.sign(keypair)

   tx_response = horizon_server.submit_transaction(tx)
   transaction_meta = xdr.TransactionMeta.from_xdr(tx_response['result_meta_xdr'])
   tx_result = transaction_meta.v3.soroban_meta.return_value
   if not tx_result:
       raise RuntimeError

   amount_a, amount_b = map(u128_to_int, [r.u128 for r in tx_result.vec.sc_vec])
   print("Withdrawal successful!")
   print(f"Received Amounts: Token A = {amount_a}, Token B = {amount_b}")
```

{% endtab %}

{% tab title="JavaScript" %}

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

    const sharesToRedeemU128 = new XdrLargeInt('u128', shareAmount.toFixed()).toU128();
    const minimumAmount = new XdrLargeInt('u128', '1').toU128(); // 0.0000001

    // Load distributor's keypair using the secret key
    const keypair = Keypair.fromSecret(userSecretKey);
    
    // Load the distributor's account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the withdraw transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
    // Append the invoke_contract_function operation for withdraw
    .addOperation(contract.call(
        'withdraw',
        xdr.ScVal.scvAddress(Address.fromString(keypair.publicKey()).toScAddress()), // Distributor's address
        sharesToRedeemU128, // Amount of shares to redeem
        xdr.ScVal.scvVec([minimumAmount, minimumAmount]), // Minimum amounts of Token A and Token B to receive
    )).setTimeout(TimeoutInfinite).build();

    const preparedTx = await sorobanServer.prepareTransaction(tx);

    preparedTx.sign(keypair);

    const result = await horizonServer.submitTransaction(preparedTx);

    const meta = (await sorobanServer.getTransaction(result.id)).resultMetaXdr;

    const returnValue = meta.v3().sorobanMeta().returnValue();

    const [withdrawalA, withdrawalB] = returnValue.value().map(value => u128ToInt(value.value()));

    console.log('Withdrawal successful!');
    console.log(`Received Amounts: Token A = ${withdrawalA / 1e7}, Token B = ${withdrawalB / 1e7}`);
}
```

{% endtab %}
{% endtabs %}

## Complete Code Examples

This code withdraw 1 share from the pool with Aquarius AMM on mainnet.

To successfully execute the code, provide the secret key of a Stellar account with at least 1 share in the [pool XLM / AQUA](https://aqua.network/pools/CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV/).

<details>

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

```python
# withdraw.py

from typing import List

from stellar_sdk import Address, Keypair, scval, SorobanServer, xdr, TransactionBuilder, Server, Network
from stellar_sdk.xdr import UInt128Parts

# Step 1. Specify user secret key, amount for withdraw and pool address
# Distributor's secret key (ensure this is kept secure)
user_secret_key = "S..."
# XLM/AQUA pool address 
pool_address = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV"
# 1 share in stroops
share_amount = 1_0000000

# ==========================
# Configuration Variables
# ==========================

# Soroban and Horizon server RPC endpoints
SOROBAN_SERVER_RPC = 'https://mainnet.sorobanrpc.com'
HORIZON_SERVER = 'https://horizon.stellar.org'

# Stellar network passphrase
NETWORK_PASSPHRASE = Network.PUBLIC_NETWORK_PASSPHRASE

# ==========================
# Utility Functions
# ==========================

def u128_to_int(value: UInt128Parts) -> int:
   """
   Converts UInt128Parts from Stellar's XDR to a Python integer.

   Args:
       value (UInt128Parts): UInt128Parts object from Stellar SDK.

   Returns:
       int: Corresponding Python integer.
   """
   return int(value.hi.uint64 << 64) + value.lo.uint64


# ==========================
# Withdraw Function
# ==========================

# Step 2. Make a contract call to the pool's "withdraw" method.
def execute_withdraw():
   # Initialize Soroban and Horizon servers
   server = SorobanServer(SOROBAN_SERVER_RPC)
   horizon_server = Server(HORIZON_SERVER)

   # Load distributor's keypair using the secret key
   keypair = Keypair.from_secret(user_secret_key)

   # Load the distributor's account information from Soroban server
   account = server.load_account(keypair.public_key)

   # Build the withdraw transaction
   tx_builder = TransactionBuilder(
       source_account=account,
       network_passphrase=NETWORK_PASSPHRASE,
       base_fee=1000000  # Set base fee; adjust as necessary
   ).set_timeout(3600)  # Set transaction timeout

   # Append the invoke_contract_function operation for withdraw
   tx = tx_builder.append_invoke_contract_function_op(
       contract_id=pool_address,
       function_name="withdraw",
       parameters=[
           Address(keypair.public_key).to_xdr_sc_val(),  # Distributor's address
           scval.to_uint128(share_amount),  # Amount of shares to redeem
           scval.to_vec([
               scval.to_uint128(1),  # Minimum amount of XLM to receive
               scval.to_uint128(1),  # Minimum amount of AQUA to receive
           ]),
       ],
   )
   tx = server.prepare_transaction(tx.build())
   tx.sign(keypair)

   tx_response = horizon_server.submit_transaction(tx)
   transaction_meta = xdr.TransactionMeta.from_xdr(tx_response['result_meta_xdr'])
   tx_result = transaction_meta.v3.soroban_meta.return_value
   if not tx_result:
       raise RuntimeError

   amount_a, amount_b = map(u128_to_int, [r.u128 for r in tx_result.vec.sc_vec])
   print("Withdrawal successful!")
   print(f"Received Amounts: Token A = {amount_a}, Token B = {amount_b}")


# ==========================
# Entry Point
# ==========================
if __name__ == "__main__":
   execute_withdraw()
```

</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, amount for withdraw and pool addresss
// Distributor's secret key (ensure this is kept secure)
const userSecretKey = "S...";
// XLM/AQUA pool address 
const poolAddress = "CCY2PXGMKNQHO7WNYXEWX76L2C5BH3JUW3RCATGUYKY7QQTRILBZIFWV";
// 1 share in stroops
const shareAmount = 10000000;

// ==========================
// 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;
    }
}

// ==========================
// Withdraw Function
// ==========================

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

    const sharesToRedeemU128 = new XdrLargeInt('u128', shareAmount.toFixed()).toU128();
    const minimumAmount = new XdrLargeInt('u128', '1').toU128(); // 0.0000001

    // Load distributor's keypair using the secret key
    const keypair = Keypair.fromSecret(userSecretKey);
    
    // Load the distributor's account information from Soroban server
    const account = await sorobanServer.getAccount(keypair.publicKey());

    const contract = new Contract(poolAddress);

    // Build the withdraw transaction
    const tx = new TransactionBuilder(account, {
        fee: BASE_FEE,
        networkPassphrase: Networks.PUBLIC,
    })
    // Append the invoke_contract_function operation for withdraw
    .addOperation(contract.call(
        'withdraw',
        xdr.ScVal.scvAddress(Address.fromString(keypair.publicKey()).toScAddress()), // Distributor's address
        sharesToRedeemU128, // Amount of shares to redeem
        xdr.ScVal.scvVec([minimumAmount, minimumAmount]), // Minimum amounts of Token A and Token B to receive
    )).setTimeout(TimeoutInfinite).build();

    const preparedTx = await sorobanServer.prepareTransaction(tx);

    preparedTx.sign(keypair);

    const result = await horizonServer.submitTransaction(preparedTx);

    const meta = (await sorobanServer.getTransaction(result.id)).resultMetaXdr;

    const returnValue = meta.v3().sorobanMeta().returnValue();

    const [withdrawalA, withdrawalB] = returnValue.value().map(value => u128ToInt(value.value()));

    console.log('Withdrawal successful!');
    console.log(`Received Amounts: Token A = ${withdrawalA / 1e7}, Token B = ${withdrawalB / 1e7}`);
}

// ==========================
// Entry Point
// ==========================
executeWithdraw();
```

</details>


---

# Agent Instructions: 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.aqua.network/developers/code-examples/withdraw-liquidity.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.
