Executing Swaps Through Optimal Path
Executing swaps is the most common use of Aquarius protocol. This article explains how to prepare, find the best path and execute swap.
This is the recommended way to execute swaps with Aquarius, as it provides the best swap results. It supports swaps through multiple pools (multi-hop, up to 4 pools).
In this example we will swap XLM to AQUA with Aquarius AMM. The swap will be executed using router and will be optimized for best results. The example will also demonstrate the ability to specify either the amount of the asset being sent or the amount of the asset to be received, similar to strict-send and strict-receive behavior.
☝️ Please make sure account has established trustline for asset to receive. Otherwise, swap will fail until trustline is created. For more information please refer to documentation on Stellar.org.
Scroll here to see the complete code.
Executing Swap: Step by Step Guide
To perform a swap, you need to follow these steps:
1. Specify user secret key, input token, output token, whether it’s a send or receive operation, and the token amount: You need to specify the input and output tokens and a single amount (in stroops) — either the amount of the token to send or to receive, depending on the selected mode.
# This account must have at least 3 XLM and a trustline to AQUA.
user_secret_key = "S..."
# XLM
token_in = Asset.native()
# AQUA
token_out = Asset("AQUA", "GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA")
# If True, the swap behaves like strict-send: the amount of the sending asset is fixed.
# If False, the swap behaves like strict-receive: the amount of the receiving asset is fixed.
is_send=True
# Amount of 1 XLM or 1 AQUA in stroops (depending on is_send)
amount = 1_0000000
2. Call the Find Path API to calculate the swap route and generate the XDR:
Send a POST
request to the appropriate endpoint — either /api/external/v1/find-path/
(for strict-send) or /api/external/v1/find-path-strict-receive/
(for strict-receive).
The request body must be a JSON object containing the following fields:
token_in_address
: The address of the token you want to swap from.token_out_address
: The address of the token you want to swap to.amount
: The amount of the token to be swapped, in stroops. This represents either the input amount (for send mode) or the output amount (for receive mode), depending on the endpoint used.
def find_swap_path(base_api: str, token_in_address: str, token_out_address: str, amount: int, is_send: bool) -> (int, str):) -> (int, str):
data = {
'token_in_address': token_in_address,
'token_out_address': token_out_address,
'amount': amount
}
endpoint = '/find-path/' if is_send else '/find-path-strict-receive/'
response = requests.post(f'{base_api}{endpoint}', json=data)
swap_result = response.json()
assert swap_result['success']
return int(swap_result['amount']), swap_result['swap_chain_xdr']
3. Execute the AMM Router smart contract call using the swap XDR:
Use the XDR generated by the Find Path API to perform a smart contract invocation on the AMM Router.
Depending on the swap type, call either the swap_chained
(for strict-send) or swap_chained_strict_receive
(for strict-receive) method.
This XDR contains all the necessary routing and pricing logic for the optimal swap execution.
def execute_swap(
network: str,
soroban_rpc_server: SorobanServer,
horizon_server: Server,
keypair: Keypair,
router_contract_id: str,
token_in_address: str,
amount: int,
amount_with_slippage: int,
swap_path: str,
is_send: bool,
) -> int:
function_name = 'swap_chained' if is_send else 'swap_chained_strict_receive'
tx = soroban_rpc_server.prepare_transaction(
TransactionBuilder(
horizon_server.load_account(keypair.public_key),
network_passphrase=network,
base_fee=10000
).set_timeout(300)
.append_invoke_contract_function_op(
contract_id=router_contract_id,
function_name=function_name,
parameters=[
scval.to_address(keypair.public_key),
SCVal.from_xdr(swap_path),
scval.to_address(token_in_address),
scval.to_uint128(amount),
scval.to_uint128(amount_with_slippage),
],
)
.build()
)
tx.sign(keypair)
submit_response = horizon_server.submit_transaction(tx)
assert submit_response['successful']
result_meta = soroban_server.get_transaction(submit_response['id']).result_meta_xdr
transaction_meta = TransactionMeta.from_xdr(result_meta)
result = transaction_meta.v3.soroban_meta.return_value
return u128_to_int(result.u128)
Complete Code Examples
This code performs a swap using Aquarius AMM on the Stellar mainnet. Depending on the is_send
parameter: if is_send
is True
, it swaps 1 XLM for AQUA; if is_send
is False
, it swaps XLM for 1 AQUA.
To successfully execute the code, provide the secret key of a Stellar account with at least 3 XLM and an established trustline for AQUA.
Swap Example Transactions
Last updated