> 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/add-fees-to-swap/deploying-a-new-fee-collector.md).

# Deploying a new fee collector

To receive fees from swaps, deploy your own fee collector instance through the Provider Swap Fee Factory. With the SDK it is one call — the signer becomes the collector's `operator`:

{% hint style="info" %}
This page uses the [official SDKs](/developers/integrating-with-aquarius.md) (0.5.0 or later). The factory address lives in [Addresses and networks](/developers/reference/addresses-and-networks.md); the [contract-level flow](#contract-level-flow-any-language) below covers other languages.
{% endhint %}

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

```python
from stellar_sdk import Keypair
from aquarius import AquariusClient

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

collector = aqua.deploy_fee_collector(
    max_fee_fraction=100,        # per-swap fee_fraction cap: 100 / 10_000 -> up to 1%
    fee_denominator=10_000,      # basis points; raise for finer fee resolution
    fee_destination="G...",      # optional — defaults to the operator (the signer)
)
print(f"collector deployed: {collector.address}")
```

{% endtab %}

{% tab title="JavaScript" %}

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

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

const collector = await aqua.deployFeeCollector({
  maxFeeFraction: 100,        // per-swap feeFraction cap: 100 / 10000 -> up to 1%
  feeDenominator: 10_000,     // basis points; raise for finer fee resolution
  feeDestination: "G...",     // optional — defaults to the operator (the signer)
});
console.log(`collector deployed: ${collector.address}`);
```

{% endtab %}
{% endtabs %}

Parameters, fixed at deploy time:

| Parameter          | Description                                                                                                                                        |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `operator`         | The signer. The only address that can [claim fees](/developers/code-examples/add-fees-to-swap/claiming-and-swapping-accumulated-fees.md).          |
| `fee_destination`  | Where every claim pays out. Cannot be changed later — not even by the operator.                                                                    |
| `max_fee_fraction` | Upper bound for the per-swap `fee_fraction` this collector accepts.                                                                                |
| `fee_denominator`  | The fraction's denominator. 10,000 (basis points) works well; record it — the contract has no getter, and every `ProviderFeeConfig` must match it. |

The operator and the fee destination can be the same address; separate addresses are safer. The destination needs trustlines for any asset the operator claims raw — or convert claims into one asset with [`claim_and_swap`](/developers/code-examples/add-fees-to-swap/claiming-and-swapping-accumulated-fees.md).

Verify the deployment with the collector's read methods:

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

```python
print(collector.fee_destination())
print(collector.max_fee_fraction())
```

{% endtab %}

{% tab title="JavaScript" %}

```javascript
console.log(await collector.feeDestination());
console.log(await collector.maxFeeFraction());
```

{% endtab %}
{% endtabs %}

Charge fees on swaps with `collector.fee_config(fee_fraction)` — see [Executing swaps with provider fees](/developers/code-examples/add-fees-to-swap/executing-swaps-with-provider-fees.md).

### Contract-level flow (any language)

The factory function behind `deploy_fee_collector`:

* **Function:**\
  `deploy_swap_fee_contract(operator: Address, fee_destination: Address, max_swap_fee_fraction: u32, swap_fee_fraction_denominator: u32) -> Address`
* **Returns:**\
  Address of the newly deployed **ProviderSwapFeeCollector**.

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

```python
import binascii

from stellar_sdk import Keypair, Network, scval, Server, SorobanServer, StrKey, TransactionBuilder, xdr


def main():
    # =========================================
    # Configuration & Setup
    # =========================================
    # Operator account to be assigned as the fee contract operator
    operator_secret_key = "SA..........."
    operator_keypair = Keypair.from_secret(operator_secret_key)

    # Address to receive the swap fees
    fee_destination_address = "GC..........."

    # Factory contract for provider swap fee contracts (already deployed on network)
    provider_fee_factory_contract_id = "CA4Q2T6FRAFYJYSMDJV7F6B7RL5PS6QS2UOZHBMCT2KSMGQRAAKP2MKO"

    # Maximum allowed swap fee in basis points
    #   (depends on denominator, e.g. 100 bps with 10000 denominator = 1% fee)
    max_swap_fee_bps = 100    # 100 bps = 1% = 100 / 10000
    swap_fee_bps_denominator = 10000

    # Soroban and Horizon server endpoints (adjust for your network)
    soroban_server = SorobanServer("https://mainnet.sorobanrpc.com")
    horizon_server = Server("https://horizon.stellar.org/")
    network_passphrase = Network.PUBLIC_NETWORK_PASSPHRASE

    # =========================================
    # Build Transaction to Deploy Provider Swap Fee Contract
    # =========================================
    # This transaction calls:
    #   deploy_swap_fee_contract(
    #       operator: Address,
    #       fee_destination: Address,
    #       swap_fee_bps: u32,
    #       swap_fee_fraction_denominator: u32,
    #   )
    # on the provider fee factory contract; it returns the address of the newly deployed fee contract.

    # Load operator account from Horizon (must have sufficient XLM)
    source_account = horizon_server.load_account(operator_keypair.public_key)

    # Build transaction
    tx = (
        TransactionBuilder(
            source_account=source_account,
            network_passphrase=network_passphrase,
            base_fee=10000
        )
        .set_timeout(300)
        .append_invoke_contract_function_op(
            contract_id=provider_fee_factory_contract_id,
            function_name="deploy_swap_fee_contract",
            parameters=[
                # operator address (as an SCVal address)
                scval.to_address(operator_keypair.public_key),
                # fee destination address (as an SCVal address)
                scval.to_address(fee_destination_address),
                # max swap fee in basis points (as a uint32)
                scval.to_uint32(max_swap_fee_bps),
                # swap fee bps denominator (as a uint32)
                scval.to_uint32(swap_fee_bps_denominator),
            ]
        )
        .build()
    )

    prepared_tx = soroban_server.prepare_transaction(tx)

    # Sign the transaction with the operator keypair
    prepared_tx.sign(operator_keypair)

    print("Submitting transaction to Horizon...")
    horizon_response = horizon_server.submit_transaction(prepared_tx)
    if not horizon_response['successful']:
        print("Transaction submission failed.")
        return

    response = soroban_server.get_transaction(horizon_response['hash'])
    if not response.result_meta_xdr:
        print("No meta in response.")
        return

    meta = xdr.TransactionMeta.from_xdr(response.result_meta_xdr)
    if meta.v3 and (meta.v4 if meta.v == 4 else meta.v3).soroban_meta:
        address = StrKey.encode_contract(
            binascii.unhexlify((meta.v4 if meta.v == 4 else meta.v3).soroban_meta.return_value.address.contract_id.hash.hex()))
        print("Deploy successful!")
        print(f"Deployed address: {address}")
    else:
        print("No result returned by the contract.")


if __name__ == "__main__":
    main()

```

{% endtab %}

{% tab title="JavaScript" %}

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

async function main() {
    // =========================================
    // Configuration & Setup
    // =========================================
    
    // Operator account to be assigned as the fee contract operator
    const operatorSecretKey = 'SA...........';
    // Address to receive the swap fees
    const feeDestinationAddress = 'GC...........';
    // Factory contract for provider swap fee contracts (already deployed on network)
    const providerFeeFactoryContractId = 'CA4Q2T6FRAFYJYSMDJV7F6B7RL5PS6QS2UOZHBMCT2KSMGQRAAKP2MKO';
    // Maximum allowed swap fee in basis points
    //   (depends on denominator, e.g. 100 bps with 10000 denominator = 1% fee)
    const maxSwapFeeBps = 100;
    const swapFeeBpsDenominator = 10000;

    // Soroban and Horizon server endpoints (adjust for your network)
    const sorobanServer = new rpc.Server('https://mainnet.sorobanrpc.com');
    const horizonServer = new Horizon.Server('https://horizon.stellar.org');
    const networkPassphrase = Networks.PUBLIC;

    const operatorKeypair = Keypair.fromSecret(operatorSecretKey);

    // =========================================
    // Load operator account
    // =========================================
    const account = await horizonServer.loadAccount(operatorKeypair.publicKey());

    // =========================================
    // Build transaction
    // =========================================
    
    // This transaction calls:
    //   deploy_swap_fee_contract(
    //       operator: Address,
    //       fee_destination: Address,
    //       swap_fee_bps: u32,
    //       swap_fee_fraction_denominator: u32,
    //   )
    // on the provider fee factory contract; it returns the address of the newly deployed fee contract.

    // Build transaction
    const tx = new TransactionBuilder(account, {
        fee: '10000',
        networkPassphrase,
    })
        .setTimeout(300)
        .addOperation(
            Operation.invokeContractFunction({
                contract: providerFeeFactoryContractId,
                function: 'deploy_swap_fee_contract',
                args: [
                    nativeToScVal(new Address(operatorKeypair.publicKey())),
                    nativeToScVal(new Address(feeDestinationAddress)),
                    nativeToScVal(maxSwapFeeBps, { type: 'u32' }),
                    nativeToScVal(swapFeeBpsDenominator, { type: 'u32' }),
                ]
            }),
        )
        .build();

    const preparedTx = await sorobanServer.prepareTransaction(tx);

    // Sign the transaction with the operator keypair
    preparedTx.sign(operatorKeypair);

    console.log('Submitting transaction to Horizon...');
    try {
        const txResponse = await horizonServer.submitTransaction(preparedTx);

        if (!txResponse.successful) {
            console.error('Transaction failed.');
            return;
        }

        const txStatus = await sorobanServer.getTransaction(txResponse.hash);
        if (!txStatus?.resultMetaXdr) {
            console.log('No meta in response.');
            return;
        }

        const resultValue = txStatus.returnValue;

        if (resultValue.value().value()) {
            const contractId = StrKey.encodeContract(resultValue.value().value());
            console.log('Deploy successful!');
            console.log(`Deployed address: ${contractId}`);
        } else {
            console.log('No result returned by the contract.');
        }
    } catch (err) {
        console.error('Transaction error:', err.response?.data || err.message);
    }
}

main();


```

{% endtab %}
{% endtabs %}
