# Claiming & Swapping Accumulated Fees

Swap fees are accumulated on the fee collector contract and should be claimed by the `operator` set on deployment of the fee collector.

Keep in mind that the fees are taken in the tokens being swapped so to claim all these tokens to the `fee_destination` address the latter must have all the trustlines.

There is a method to claim and immediately swap everything in 1 token, then settle to `fee_destination`. "Raw" claiming is also available though.

Below there are examples of these operations. Claims can be executed as frequently as necessary.

### Option 1: Claim & Immediately Swap

* **Function:** `claim_fees_and_swap(e, operator: Address, swaps_chain: Vec<…>, token: Address, out_min: u128) -> u128`
* **Effect:**
  1. Claims all of `token`.
  2. Swaps via your router along `swaps_chain`.
  3. Sends resulting tokens to `fee_destination`.
* **Returns:**\
  Final output amount in the target asset.
* **Function:** `claim_fees_and_swap(e, operator: Address, swaps_chain: Vec<…>, token: Address, out_min: u128) -> u128`
* **Effect:**
  1. Claims all of `token`.
  2. Swaps via your router along `swaps_chain`.
  3. Sends resulting tokens to `fee_destination`.
* **Returns:**\
  Final output amount in the target asset.

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

```python
import requests
from stellar_sdk import Asset, Keypair, Network, scval, Server, SorobanServer, TransactionBuilder
from stellar_sdk.xdr import Int128Parts, SCVal, TransactionMeta, UInt128Parts

# =========================================
# Configuration & Setup
# =========================================

# swap provider contract operator
operator_secret_key = "SA..........."
keypair = Keypair.from_secret(operator_secret_key)

# Input and output tokens
token_to_claim = Asset("AQUA", "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA")
token_out = Asset.native()  # XLM
slippage = "0.005"  # 0.5% slippage

# swap provider contract for AMM swaps on mainnet
# IMPORTANT: Replace with your deployed contract ID. This contract address is only for test purposes.
provider_swap_contract_id = "CDJCVXFIT2UIVNLC22OWCHABTWKXUSYYLPKKBLJW67ISMIWX56YJBGLS"

# Soroban and Horizon servers
soroban_server = SorobanServer("https://mainnet.sorobanrpc.com")
horizon_server = Server("https://horizon.stellar.org/")
network = Network.PUBLIC_NETWORK_PASSPHRASE

# AQUA AMM API endpoint
base_api = 'https://amm-api.aqua.network/api/external/v2'


# =========================================
# Utility Function
# =========================================

def u128_to_int(value: UInt128Parts) -> int:
    """Convert Uint128Parts to Python int."""
    return (value.hi.uint64 << 64) + value.lo.uint64


def i128_to_int(value: Int128Parts) -> int:
    """Convert int128Parts to Python int."""
    return (value.hi.int64 << 64) + value.lo.uint64


# =========================================
# Functions
# =========================================

def find_swap_path(base_api: str, token_in_address: str, token_out_address: str, amount: int, is_send: bool) -> (int, str):
    """
    Call the Find Path API to retrieve the swap chain and estimated amount.
    """
    print("Requesting swap path from AMM API...")
    data = {
        'token_in_address': token_in_address,
        'token_out_address': token_out_address,
        'amount': amount,
        'slippage': slippage,
    }
    endpoint = '/find-path/' if is_send else '/find-path-strict-receive/'
    response = requests.post(f'{base_api}{endpoint}', json=data)
    swap_result = response.json()
    print(swap_result)
    """
        {
          'success': True,
          'swap_chain_xdr': 'AAAAEAAAAAEAAAABAAAAEAAAAAEAAAADAAAAEAAAAAEAAAACAAAAEgAAAAEltPzYWa7C+mNIQ4xImzw8EMmLbSG+T9PLMMtolT75dwAAABIAAAABKIUvaMGYSI40b7EhLtUCkFN2HMJPRTOS41OYIBsIJecAAAANAAAAILLgL8/KbJb4rVy9hOd4Snd7NtnJaiRZQCxPRYRiqrfwAAAAEgAAAAEohS9owZhIjjRvsSEu1QKQU3Ycwk9FM5LjU5ggGwgl5w==',
          'pools': [
            'CDE57N6XTUPBKYYDGQMXX7E7SLNOLFY3JEQB4MULSMR2AKTSAENGX2HC'
          ],
          'tokens': [
            'native',
            'AQUA:GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA'
          ],
          'amount': 3627808902,
          'amount_with_fee': 3627808002,
        }
    """

    if not swap_result.get('success', False):
        raise Exception("Failed to retrieve swap path from the API.")

    print("Swap path retrieved. Estimated amount:", swap_result['amount'])
    print("Estimated amount with fee:", swap_result['amount_with_fee'])
    return int(swap_result['amount_with_fee']), swap_result['swap_chain_xdr']


def get_contract_balance(
        network: str,
        soroban_rpc_server: SorobanServer,
        keypair: Keypair,
        contract_address: str,
        token_address: str,
) -> int:
    """
    Retrieves the balance of a specific token for the given account.
    """
    tx = (
        TransactionBuilder(
            source_account=soroban_rpc_server.load_account(keypair.public_key),
            network_passphrase=network,
            base_fee=10000
        )
        .set_timeout(300)
        .append_invoke_contract_function_op(
            contract_id=token_address,
            function_name="balance",
            parameters=[
                scval.to_address(contract_address),
            ],
        )
        .build()
    )
    simulation = soroban_rpc_server.simulate_transaction(tx)
    return i128_to_int(SCVal.from_xdr(simulation.results[0].xdr).i128)


def execute_claim_with_swap(
        network: str,
        soroban_rpc_server: SorobanServer,
        horizon_server: Server,
        keypair: Keypair,
        contract_id: str,
        token_in_address: str,
        amount_with_slippage: int,
        swap_path: str,
) -> int:
    """
    Executes the chained swap transaction on Soroban and returns the final amount out.
    """
    print("Preparing and building swap transaction...")
    source_account = horizon_server.load_account(keypair.public_key)

    # Build the transaction to invoke `swap_chained`
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=network,
            base_fee=10000
        )
        .set_timeout(300)
        .append_invoke_contract_function_op(
            contract_id=contract_id,
            function_name='claim_fees_and_swap',
            parameters=[
                scval.to_address(keypair.public_key),
                SCVal.from_xdr(swap_path),
                scval.to_address(token_in_address),
                scval.to_uint128(amount_with_slippage),
            ],
        )
        .build()
    )

    # Prepare transaction to get Soroban-specific data (footprint, etc.)
    print("Preparing transaction on Soroban...")
    prepared_tx = soroban_rpc_server.prepare_transaction(tx)

    # Sign the prepared transaction
    print("Signing transaction...")
    prepared_tx.sign(keypair)

    # Submit the transaction to Horizon
    print("Submitting transaction to Horizon...")
    submit_response = horizon_server.submit_transaction(prepared_tx)

    if not submit_response.get('successful', False):
        raise Exception("Transaction failed: " + str(submit_response))

    print("Transaction submitted successfully. Fetching result...")

    # Get the transaction result from Soroban server to access Soroban metadata
    tx_info = soroban_server.get_transaction(submit_response['id'])
    if not tx_info or not tx_info.result_meta_xdr:
        raise Exception("No transaction metadata found.")

    # Extract the result from the Soroban metadata
    transaction_meta = TransactionMeta.from_xdr(tx_info.result_meta_xdr)
    return_val = transaction_meta.v3.soroban_meta.return_value
    final_amount = u128_to_int(return_val.u128)
    print("Swap executed successfully.")
    return final_amount


# =========================================
# Entry Point
# =========================================

print("Starting claim process...")
print(f"Swapping {token_to_claim.code} for {token_out.code}...")

# 0. Get the balance of the token to claim
amount = get_contract_balance(
    network,
    soroban_server,
    keypair,
    provider_swap_contract_id,
    token_to_claim.contract_id(network),
)

# 1. Find the swap path and estimated output
amount_with_slippage, swap_path_xdr = find_swap_path(
    base_api,
    token_to_claim.contract_id(network),
    token_out.contract_id(network),
    amount,
    True,
)

# 2. Execute the claim
amount = execute_claim_with_swap(
    network,
    soroban_server,
    horizon_server,
    keypair,
    provider_swap_contract_id,
    token_to_claim.contract_id(network),
    amount_with_slippage,
    swap_path_xdr,
)

print("Claim with swap completed successfully!")
print(f"Amount out: {amount / 10 ** 7} {token_out.code}")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const {
    Horizon,
    Keypair,
    Asset,
    Networks,
    TransactionBuilder,
    nativeToScVal,
    Address,
    Operation,
    xdr,
    rpc
} = require('@stellar/stellar-sdk');

// =========================================
// Configuration
// =========================================

// swap provider contract operator
const operatorSecretKey = 'SA...........'; // Replace with actual secret
const keypair = Keypair.fromSecret(operatorSecretKey);
const publicKey = keypair.publicKey();

// Input and output tokens
const tokenToClaim = new Asset('AQUA', 'GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA');
const tokenOut = Asset.native(); // XLM
const slippage = '0.005';


// swap provider contract for AMM swaps on mainnet
// IMPORTANT: Replace with your deployed contract ID. This contract address is only for test purposes.
const providerSwapContractId = 'CDJCVXFIT2UIVNLC22OWCHABTWKXUSYYLPKKBLJW67ISMIWX56YJBGLS';

// Soroban and Horizon servers
const sorobanServer = new rpc.Server('https://mainnet.sorobanrpc.com');
const horizonServer = new Horizon.Server('https://horizon.stellar.org');
const networkPassphrase = Networks.PUBLIC;

// AQUA AMM API endpoint
const baseApi = 'https://amm-api.aqua.network/api/external/v2';

// =========================================
// Helpers
// =========================================

function u128ToInt(value) {
    const result = (BigInt(value.hi()._value) << 64n) + BigInt(value.lo()._value);
    if (result <= BigInt(Number.MAX_SAFE_INTEGER)) {
        return Number(result);
    } else {
        console.warn("Value exceeds JS safe integer range");
        return result;
    }
}

// Retrieves the balance of a specific token for the given account.
async function getContractTokenBalance(tokenAddress) {
    const sourceAccount = await horizonServer.loadAccount(publicKey);
    const tx = new TransactionBuilder(sourceAccount, {
        fee: '10000',
        networkPassphrase
    })
        .setTimeout(300)
        .addOperation(
            Operation.invokeContractFunction({
                contract: tokenAddress,
                function: 'balance',
                args: [nativeToScVal(new Address(providerSwapContractId))],
            })
        )
        .build();

    const sim = await sorobanServer.simulateTransaction(tx);
    return u128ToInt(sim.result.retval.value());
}

// Call the Find Path API to retrieve the swap chain and estimated amount.
async function findSwapPath(tokenIn, tokenOut, amount) {
    const endpoint = `${baseApi}/find-path/`;
    const response = await fetch(endpoint, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            token_in_address: tokenIn,
            token_out_address: tokenOut,
            amount,
            slippage
        })
    });

    const data = await response.json();
    if (!data.success) throw new Error('Failed to retrieve swap path');
    return {
        amountWithFee: data.amount_with_fee,
        swapPathXDR: data.swap_chain_xdr
    };
}

// Executes the chained swap transaction on Soroban and returns the final amount out.
async function executeClaimAndSwap(tokenIn, amountWithSlippage, swapPathXDR) {
    const account = await horizonServer.loadAccount(publicKey);
    
    // Build the transaction to invoke `swap_chained`
    const tx = new TransactionBuilder(account, {
        fee: '10000',
        networkPassphrase
    })
        .setTimeout(300)
        .addOperation(
            Operation.invokeContractFunction({
                contract: providerSwapContractId,
                function: 'claim_fees_and_swap',
                args: [
                    nativeToScVal(new Address(publicKey)),
                    xdr.ScVal.fromXDR(swapPathXDR, 'base64'),
                    nativeToScVal(new Address(tokenIn)),
                    nativeToScVal(amountWithSlippage, { type: 'u128' })
                ]
            })
        )
        .build();

    // Prepare transaction to get Soroban-specific data (footprint, etc.)
    const preparedTx = await sorobanServer.prepareTransaction(tx);
    // Sign the prepared transaction
    preparedTx.sign(keypair);

    // Submit the transaction to Horizon
    const submitResponse = await horizonServer.submitTransaction(preparedTx);
    if (!submitResponse.successful) {
        throw new Error('Transaction submission failed: ' + JSON.stringify(submitResponse));
    }

    // Get the transaction result from Soroban server to access Soroban metadata
    const txInfo = await sorobanServer.getTransaction(submitResponse.hash);
    const metaXdr = txInfo.resultMetaXdr;
    if (!metaXdr) throw new Error('No metadata');

    // Extract the result from the Soroban metadata
    const returnVal = metaXdr.v3().sorobanMeta().returnValue();
    return u128ToInt(returnVal.u128());
}

// =========================================
// Main
// =========================================

(async () => {
    try {
        console.log(`Swapping ${tokenToClaim.code} for ${tokenOut.code}...`);

        const tokenInAddress = tokenToClaim.contractId(networkPassphrase);
        const tokenOutAddress = tokenOut.contractId(networkPassphrase);

        // 1. Get the balance of the token to claim
        const balance = await getContractTokenBalance(tokenInAddress);
        console.log(`Token balance to claim: ${balance / 1e7} ${tokenToClaim.code}`);

        // 2. Find the swap path and estimated output
        const { amountWithFee, swapPathXDR } = await findSwapPath(tokenInAddress, tokenOutAddress, balance);
        console.log(`Swap path found. Final amount with slippage: ${amountWithFee / 1e7}`);

        // 3. Execute the claim
        const resultAmount = await executeClaimAndSwap(tokenInAddress, amountWithFee, swapPathXDR);
        console.log(`Claim + swap successful. Amount received: ${resultAmount / 1e7} ${tokenOut.code}`);
    } catch (err) {
        console.error('Error:', err.message || err);
    }
})();
```

{% endtab %}
{% endtabs %}

### Option 2: Claim Raw Fees

* **Function:** `claim_fees(e, operator: Address, token: Address) -> u128`
* **Effect:** Transfers entire `token` balance from the contract to `fee_destination`.

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

```python
from stellar_sdk import Asset, Keypair, Network, scval, Server, SorobanServer, TransactionBuilder
from stellar_sdk.xdr import Int128Parts, TransactionMeta, UInt128Parts

# =========================================
# Configuration & Setup
# =========================================

# swap provider contract operator
operator_secret_key = "SA..........."
keypair = Keypair.from_secret(operator_secret_key)

# Input and output tokens
token_to_claim = Asset.native()

# swap provider contract for AMM swaps on mainnet
# IMPORTANT: Replace with your deployed contract ID. This contract address is only for test purposes.
provider_swap_contract_id = "CDJCVXFIT2UIVNLC22OWCHABTWKXUSYYLPKKBLJW67ISMIWX56YJBGLS"

# Soroban and Horizon servers
soroban_server = SorobanServer("https://mainnet.sorobanrpc.com")
horizon_server = Server("https://horizon.stellar.org/")
network = Network.PUBLIC_NETWORK_PASSPHRASE


# =========================================
# Utility Function
# =========================================

def u128_to_int(value: UInt128Parts) -> int:
    """Convert Uint128Parts to Python int."""
    return (value.hi.uint64 << 64) + value.lo.uint64


def i128_to_int(value: Int128Parts) -> int:
    """Convert int128Parts to Python int."""
    return (value.hi.int64 << 64) + value.lo.uint64


# =========================================
# Entry Point
# =========================================

print("Starting claim process...")
print(f"Claiming {token_to_claim.code}...")

tx = (
    TransactionBuilder(
        source_account=horizon_server.load_account(keypair.public_key),
        network_passphrase=network,
        base_fee=10000
    )
    .set_timeout(300)
    .append_invoke_contract_function_op(
        contract_id=provider_swap_contract_id,
        function_name='claim_fees',
        parameters=[
            scval.to_address(keypair.public_key),
            scval.to_address(token_to_claim.contract_id(network)),
        ],
    )
    .build()
)

# Prepare transaction to get Soroban-specific data (footprint, etc.)
print("Preparing transaction on Soroban...")
prepared_tx = soroban_server.prepare_transaction(tx)

# Sign the prepared transaction
print("Signing transaction...")
prepared_tx.sign(keypair)

# Submit the transaction to Horizon
print("Submitting transaction to Horizon...")
submit_response = horizon_server.submit_transaction(prepared_tx)

if not submit_response.get('successful', False):
    raise Exception("Transaction failed: " + str(submit_response))

print("Transaction submitted successfully. Fetching result...")

# Get the transaction result from Soroban server to access Soroban metadata
tx_info = soroban_server.get_transaction(submit_response['id'])
if not tx_info or not tx_info.result_meta_xdr:
    raise Exception("No transaction metadata found.")

# Extract the result from the Soroban metadata
transaction_meta = TransactionMeta.from_xdr(tx_info.result_meta_xdr)
return_val = transaction_meta.v3.soroban_meta.return_value
final_amount = u128_to_int(return_val.u128)

print("Claim completed successfully!")
print(f"Amount out: {final_amount / 10 ** 7} {token_to_claim.code}")
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
const {
    Horizon,
    Keypair,
    Asset,
    Networks,
    TransactionBuilder,
    nativeToScVal,
    Address,
    Operation,
    xdr,
    rpc
} = require('@stellar/stellar-sdk');

// =========================================
// Config & Setup
// =========================================

const operatorSecretKey = 'SA...........'; // your real key
const keypair = Keypair.fromSecret(operatorSecretKey);

const tokenToClaim = Asset.native();

// swap provider contract for AMM swaps on mainnet
// IMPORTANT: Replace with your deployed contract ID. This contract address is only for test purposes.
const providerSwapContractId = 'CDJCVXFIT2UIVNLC22OWCHABTWKXUSYYLPKKBLJW67ISMIWX56YJBGLS';

const sorobanServer = new rpc.Server('https://mainnet.sorobanrpc.com');
const horizonServer = new Horizon.Server('https://horizon.stellar.org');
const networkPassphrase = Networks.PUBLIC;

// =========================================
// Helpers
// =========================================

function u128ToInt(value) {
    const result = (BigInt(value.hi()._value) << 64n) + BigInt(value.lo()._value);
    if (result <= BigInt(Number.MAX_SAFE_INTEGER)) {
        return Number(result);
    } else {
        console.warn("Value exceeds JavaScript's safe integer range");
        return null;
    }
}

// =========================================
// Main
// =========================================

(async () => {
    try {
        console.log(`Claiming ${tokenToClaim.code} fees...`);

        const account = await horizonServer.loadAccount(keypair.publicKey());

        // Build transaction
        const tx = new TransactionBuilder(account, {
            fee: '10000',
            networkPassphrase
        })
            .setTimeout(300)
            .addOperation(
                Operation.invokeContractFunction({
                    contract: providerSwapContractId,
                    function: 'claim_fees',
                    args: [
                        nativeToScVal(new Address(keypair.publicKey())),
                        nativeToScVal(new Address(tokenToClaim.contractId(networkPassphrase)))
                    ],
                })
            )
            .build();

        // Prepare transaction to get Soroban-specific data (footprint, etc.)
        console.log('Preparing transaction...');
        const preparedTx = await sorobanServer.prepareTransaction(tx);

        // Sign the prepared transaction
        console.log('Signing...');
        preparedTx.sign(keypair);

        // Submit the transaction to Horizon
        console.log('Submitting...');
        const submitResponse = await horizonServer.submitTransaction(preparedTx);

        if (!submitResponse.successful) {
            throw new Error('Transaction failed: ' + JSON.stringify(submitResponse));
        }

        console.log('Transaction submitted. Fetching result...');

        // Get the transaction result from Soroban server to access Soroban metadata
        const txInfo = await sorobanServer.getTransaction(submitResponse.hash);
        const metaXdr = txInfo.resultMetaXdr;

        if (!metaXdr) {
            throw new Error('No result metadata.');
        }

        // Extract the result from the Soroban metadata
        const returnVal = metaXdr.v3().sorobanMeta().returnValue();
        const u128 = returnVal.u128();
        const finalAmount = u128ToInt(u128);

        console.log('Claim successful!');
        console.log(`Amount claimed: ${finalAmount / 1e7} ${tokenToClaim.code}`);
    } catch (err) {
        console.error('Error:', err.message || err);
    }
})();

```

{% endtab %}
{% endtabs %}


---

# 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/add-fees-to-swap/claiming-and-swapping-accumulated-fees.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.
