> 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

Deploy your own fee collector contract and configure its fee parameters.

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 %}
