♒
Aquarius Guide
  • 👋Welcome to Aquarius
  • Developers
    • Integrating with Aquarius
    • Aquarius Soroban Functions
    • Code Examples
      • Prerequisites & Basics
      • Executing Swaps Through Optimal Path
      • Executing Swaps Through Specific Pool
      • Deposit Liquidity
      • Withdraw Liquidity
      • Get Pools Info
      • Claim LP Rewards
      • Add Fees To Swap
        • Deploying a New Fee Collector
        • Executing Swaps with Provider Fees
        • Claiming & Swapping Accumulated Fees
  • Ecosystem Overview
    • 🌐What is Stellar?
      • What are Lumens (XLM)?
      • What are Anchors?
      • What are Trustlines?
      • How much are network fees on Stellar?
      • What are network reserves?
      • Where to trade Stellar assets?
    • 🧮What is Soroban?
  • AQUA tokens
    • ♒What are AQUA tokens?
      • AQUAnomics
      • AQUA Wallets
      • Where can I buy AQUA?
  • ICE
    • 🧊ICE tokens: locking AQUA and getting benefits
    • ICE boosts - how to maximize LP rewards
  • Aquarius AMMs
    • 💱What are Aquarius AMMs?
      • Pools
        • Creating a Pool
        • Deposit & Withdraw Liquidity
      • Swap
      • System limitations
        • Aquarius AMM: Limitations in Support for Fee-on-Transfer, Rebasing, and Deflationary Tokens
        • Aquarius AMM: Token Address Migration Limitations and Mitigation Strategy
  • My Aquarius
    • 👤My Aquarius
      • Main Overview
      • Balances
      • My Liquidity
      • SDEX Rewards
      • Liquidity Votes
      • Governance Votes
      • Airdrop #2
      • ICE Locks
      • Payments History
  • Aquarius AQUA Rewards
    • 🗳️Aquarius voting
      • Aquarius voting: asset Flag Restrictions
    • 🪙SDEX Rewards
    • 🤖Aquarius AMM Rewards
  • Bribes
    • 🎁What are bribes?
      • What are the advantages of protocol level bribes?
  • Aquarius Governance
    • 🧑‍⚖️Aquarius Governance: Community-Led Decision Making
  • Airdrops
    • 1️⃣The Initial Airdrop
      • Am I Eligible For the Initial Airdrop?
      • How can I see if I am eligible?
      • What are Claimable Balances?
      • How is the Initial airdrop distributed?
      • Where can I find more information?
    • 🌠Airdrop #2
      • How could I have been eligible for Airdrop #2?
      • How can I see if I am eligible?
      • When was the Airdrop #2 snapshot?
      • Were there any CEX's taking part?
      • How big was Airdrop #2?
      • How will the airdrop be distributed and for how long?
      • Could I have increased my potential reward?
      • Where can I find more information?
  • Signers Guild
    • 📜What is the signers guild?
      • What percentage of the AQUA supply will be controlled by the Signers Guild?
      • Who will be in the Signers Guild?
      • How does the Signing process work?
      • What will be expected from a guild member?
      • How can I sign up for this position?
      • What are wallets that Guild members will manage?
      • How can I learn more about this?
  • Guides
    • ❔How to use AQUA Locker tool and get ICE tokens
    • ❔How to vote for markets on Aquarius
    • How to create bribes
    • ❔How to use Aquarius Governance
      • How to make a governance vote
      • How to create a proposal
    • ❔How to earn SDEX rewards
    • ❔How to earn AMM rewards
  • Technical Documents
    • 📜Audits
    • 🪲Bug Bounties
    • 🛄Claimable Balances
    • 🗳️The Aquarius Voting Mechanism
    • 🎁SDEX v2 proposal & algorithm
    • ⏩ICE Boost Formula
  • Useful Links
    • Aquarius Home
    • Liquidity Voting
    • Liquidity Rewards
    • Aquarius Bribes
    • ICE locker
    • Aquarius Governance
    • Airdrop #2
Powered by GitBook
On this page
  1. Developers
  2. Code Examples
  3. Add Fees To Swap

Deploying a New Fee Collector

PreviousAdd Fees To SwapNextExecuting Swaps with Provider Fees

Last updated 26 days ago

To start receiving fees from swaps you will need to deploy the fee collector contract instance using the Provider Swap Fee Factory:

Provider Swap Fee Factory address is CCEG2NHI3RO545HEMV4HQLIEPNXIBDOVXXD3DLOK727CMVBVNPOQJUFB

  • Function: deploy_swap_fee_contract(operator: Address, fee_destination: Address, max_swap_fee_fraction: u32) -> Address

  • Returns: Address of the newly deployed ProviderSwapFeeCollector.

Parameters explained:

  • operator- an address that will be able to

  • fee_destination - an address that will be able to receive the claimed fees.

  • max_swap_fee_fraction - maximum value of a swap fee that a given fee collector instance can accept.

Notes:

  • operator and fee_destination addresses can be the same but we recommend using different addresses for greater security.

  • fee_destination must have all the trustlines in case the operator withdraw "raw" fees accumulated in various currencies. Aquarius has a mechanism to settle fees in one single currency though.

  • on you can set a dynamic fee but not exceeding the max_swap_fee_fraction parameter.

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 (e.g. 100 bps = 1% fee)
    max_swap_fee_bps = 100

    # 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, swap_fee_bps: 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)
            ]
        )
        .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.v3.soroban_meta:
        address = StrKey.encode_contract(
            binascii.unhexlify(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()
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 (e.g. 100 bps = 1% fee)
    const maxSwapFeeBps = 100;

    // 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, swap_fee_bps: 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' }),
                ]
            }),
        )
        .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();

claim fees
executing swaps with fees