Deposit Liquidity
Example of code that deposits liquidity into Aquarius pool
# deposit.py
from typing import List
from stellar_sdk import Address, Keypair, scval, SorobanServer, xdr, TransactionBuilder, Server
from stellar_sdk.xdr import UInt128Parts
# ==========================
# Configuration Variables
# ==========================
# Soroban and Horizon server RPC endpoints
SOROBAN_SERVER_RPC = 'https://soroban-testnet.stellar.org:443/'
HORIZON_SERVER = 'https://horizon-testnet.stellar.org'
# Distributor's secret key (ensure this is kept secure)
SECRET = 'SCJF..........KTXQ'
# Contract IDs for the router and tokens
ROUTER_CONTRACT_ID = 'CDMSJQ4TPCTAYDRYN46FVMYIWV2A4ZTHCWWIN2NW3QZIFPJWBBEGDKDY'
TOKEN_A_CONTRACT_ID = 'CAZRY5GSFBFXD7H6GAFBA5YGYQTDXU4QKWKMYFWBAZFUCURN3WKX6LF5'
TOKEN_B_CONTRACT_ID = 'CBL6KD2LFMLAUKFFWNNXWOXFN73GAXLEA4WMJRLQ5L76DMYTM3KWQVJN'
# Stellar network passphrase and known pool hash
NETWORK_PASSPHRASE = 'Test SDF Network ; September 2015'
POOL_HASH = '8328b65c4d32886fb1876be01b4ad13ef5ff14719d7c735d4060da683315473d'
# ==========================
# Utility Functions
# ==========================
def order_token_ids(tokens: List[xdr.SCVal]) -> List[xdr.SCVal]:
"""
Orders token IDs based on their contract ID to maintain consistency.
Args:
tokens (List[xdr.SCVal]): List of token addresses as SCVal objects.
Returns:
List[xdr.SCVal]: Ordered list of token SCVal objects.
"""
return sorted(tokens, key=lambda token: int(token.address.contract_id.hash.hex(), 16))
def u128_to_int(value: UInt128Parts) -> int:
"""
Converts UInt128Parts from Stellar's XDR to a Python integer.
Args:
value (UInt128Parts): UInt128Parts object from Stellar SDK.
Returns:
int: Corresponding Python integer.
"""
return (value.hi.uint64 << 64) + value.lo.uint64
# ==========================
# Deposit Function
# ==========================
def execute_deposit(pool_hash: str):
"""
Executes the deposit operation to a specified AMM pool.
Args:
pool_hash (str): The known hash of the target AMM pool (32-byte hex string).
"""
# Initialize Soroban and Horizon servers
server = SorobanServer(SOROBAN_SERVER_RPC)
horizon_server = Server(HORIZON_SERVER)
# Load distributor's keypair using the secret key
keypair = Keypair.from_secret(SECRET)
print(f"Initiating deposit using router contract ID: {ROUTER_CONTRACT_ID}")
# Order token IDs to ensure consistency
token_a = scval.to_address(TOKEN_A_CONTRACT_ID)
token_b = scval.to_address(TOKEN_B_CONTRACT_ID)
ordered_tokens = order_token_ids([token_a, token_b])
token_a, token_b = ordered_tokens
# Define the amounts of tokens to deposit
# Adjust these values as necessary
BALANCE_A = 1_0000000 # Example: 1 token with 7 decimal places
BALANCE_B = 1_0000000 # Example: 1 token with 7 decimal places
print(f"Depositing to pool {pool_hash}")
# Load the distributor's account information from Soroban server
account = server.load_account(keypair.public_key)
# Build the deposit transaction
tx_builder = TransactionBuilder(
source_account=account,
network_passphrase=NETWORK_PASSPHRASE,
base_fee=1000000 # Set base fee; adjust as necessary
).set_timeout(3600) # Set transaction timeout
# Append the invoke_contract_function operation for deposit
tx = tx_builder.append_invoke_contract_function_op(
contract_id=ROUTER_CONTRACT_ID,
function_name="deposit",
parameters=[
Address(keypair.public_key).to_xdr_sc_val(), # Distributor's address
scval.to_vec([token_a, token_b]), # Token pair
scval.to_bytes(bytes.fromhex(pool_hash)), # Known pool hash as bytes
scval.to_vec([
scval.to_uint128(BALANCE_A), # Amount of Token A to deposit
scval.to_uint128(BALANCE_B), # Amount of Token B to deposit
]),
scval.to_uint128(0), # Additional parameter (e.g., minimum shares)
],
).build()
# Prepare and sign the transaction
prepared_tx = server.prepare_transaction(tx)
prepared_tx.sign(keypair)
# Submit the transaction to the Horizon server
tx_response = horizon_server.submit_transaction(prepared_tx)
# Parse the transaction metadata to extract results
transaction_meta = xdr.TransactionMeta.from_xdr(tx_response['result_meta_xdr'])
tx_result = transaction_meta.v3.soroban_meta.return_value
if not tx_result:
raise RuntimeError("Transaction did not return a result. Deposit failed.")
# Extract deposited amounts and shares from the transaction result
deposit_a, deposit_b = map(u128_to_int, [r.u128 for r in tx_result.vec.sc_vec[0].vec.sc_vec])
shares_amount = u128_to_int(tx_result.vec.sc_vec[1].u128)
print("Deposit successful!")
print(f"Deposited Amounts: Token A = {deposit_a}, Token B = {deposit_b}")
print(f"Received Shares: {shares_amount}")
# ==========================
# Entry Point
# ==========================
if __name__ == "__main__":
execute_deposit(POOL_HASH)
const binascii = require('binascii');
const StellarSdk = require('@stellar/stellar-sdk');
const {
Address,
Contract,
TransactionBuilder,
SorobanRpc,
Horizon,
BASE_FEE,
Networks,
xdr,
TimeoutInfinite,
StrKey,
XdrLargeInt,
Keypair,
} = StellarSdk;
// ==========================
// Configuration Variables
// ==========================
// Soroban and Horizon server RPC endpoints
const sorobanServerUrl = 'https://soroban-testnet.stellar.org:443/'; //testnet
const horizonServerUrl = 'https://horizon-testnet.stellar.org';
// Distributor's secret key (ensure this is kept secure)
const userSecretKey = 'S...';
// Contract IDs for the router and tokens
const routerContractId = 'CDMSJQ4TPCTAYDRYN46FVMYIWV2A4ZTHCWWIN2NW3QZIFPJWBBEGDKDY'; //testnet
const tokenAContractId = 'CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC'; // XLM
const tokenBContractId = 'CDNVQW44C3HALYNVQ4SOBXY5EWYTGVYXX6JPESOLQDABJI5FC5LTRRUE'; //AQUA
// Known pool hash
const poolHash = '9ac7a9cde23ac2ada11105eeaa42e43c2ea8332ca0aa8f41f58d7160274d718e' // XLM-AQUA
// ==========================
// Utility Functions
// ==========================
function orderTokensIds(tokensIds) {
/**
* Orders token IDs based on their contract ID to maintain consistency.
*
* @param {Array} tokensIds - List of token addresses as SCVal objects.
* @returns {Array} Ordered list of token SCVal objects.
*/
return tokensIds.sort((a, b) => {
const aHash = BigInt('0x' + a.address().contractId().toString('hex'));
const bHash = BigInt('0x' + b.address().contractId().toString('hex'));
// Compare BigInts directly without converting to number
if (aHash < bHash) return -1;
if (aHash > bHash) return 1;
return 0;
});
}
function u128ToInt(value) {
/**
* Converts UInt128Parts from Stellar's XDR to a JavaScript number.
*
* @param {Object} value - UInt128Parts object from Stellar SDK, with `hi` and `lo` properties.
* @returns {number|null} Corresponding JavaScript number, or null if the number is too large.
*/
const result = (BigInt(value.hi()._value) << 64n) + BigInt(value.lo()._value);
// Check if the result is within the safe integer range for JavaScript numbers
if (result <= BigInt(Number.MAX_SAFE_INTEGER)) {
return Number(result);
} else {
console.warn("Value exceeds JavaScript's safe integer range");
return null;
}
}
function contractIdToScVal(contractId) {
/**
* Converts a contract ID to a Stellar SCVal (Smart Contract Value) format.
*
* @param {string} contractId - The contract ID to convert.
* @returns {StellarSdk.xdr.ScVal} - The SCVal representation of the contract ID.
*
* @throws {Error} Throws an error if the contract ID is invalid or cannot be decoded.
*/
return StellarSdk.Address.contract(StrKey.decodeContract(contractId)).toScVal();
}
// ==========================
// Deposit Function
// ==========================
async function executeDeposit() {
const sorobanServer = new SorobanRpc.Server(sorobanServerUrl);
const horizonServer = new Horizon.Server(horizonServerUrl);
const [tokenA, tokenB] = orderTokensIds([
contractIdToScVal(tokenAContractId),
contractIdToScVal(tokenBContractId)
]);
// Define the amounts of tokens to deposit
// Adjust these values as necessary
const balanceA = 10000000; // Example: 1 token with 7 decimal places
const balanceB = 10000000; // Example: 1 token with 7 decimal places
const amountAU128 = new XdrLargeInt('u128', balanceA.toFixed()).toU128();
const amountBU128 = new XdrLargeInt('u128', balanceB.toFixed()).toU128();
const minimumShares = new XdrLargeInt('u128', '1').toU128(); // 0.0000001
const keypair = Keypair.fromSecret(userSecretKey);
// Load the distributor's account information from Soroban server
const account = await sorobanServer.getAccount(keypair.publicKey());
const contract = new Contract(routerContractId);
const tx = new TransactionBuilder(account, {
fee: BASE_FEE,
networkPassphrase: Networks.TESTNET,
}).addOperation(contract.call(
'deposit',
xdr.ScVal.scvAddress(Address.fromString(keypair.publicKey()).toScAddress()), // Distributor's address
xdr.ScVal.scvVec([tokenA, tokenB]), // Token pair
xdr.ScVal.scvBytes(Buffer.from(binascii.unhexlify(poolHash), 'ascii')), // Known pool hash as bytes
xdr.ScVal.scvVec([amountAU128, amountBU128]), // Amounts of Token A and Token B to deposit
minimumShares, // Additional parameter (e.g., minimum shares)
)).setTimeout(TimeoutInfinite).build();
const preparedTx = await sorobanServer.prepareTransaction(tx);
preparedTx.sign(keypair);
const result = await horizonServer.submitTransaction(preparedTx);
const meta = xdr.TransactionMeta.fromXDR(result.result_meta_xdr, 'base64');
const returnValue = meta.v3().sorobanMeta().returnValue();
const [deposited, share] = returnValue.value();
const [depositedA, depositedB] = deposited.value().map(value => u128ToInt(value.value()));
const shareValue = u128ToInt(share.value());
console.log('Deposit successful!');
console.log(`Deposited Amounts: Token A = ${depositedA}, Token B = ${depositedB}`);
console.log(`Received Shares: ${shareValue}`);
}
executeDeposit();
Last updated