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();