> loading_
# Walkthrough: Validating trustline capacity before a vault withdrawal
# and constructing a compliant multi-send with aggregate MaximumAmount.
# Tested against rippled amendments as of 2026-04-05.
# -------------------------------------------------------
# 1. CHECK TRUSTLINE CAPACITY BEFORE VAULT WITHDRAWAL
# -------------------------------------------------------
# Before submitting a share-denominated vault withdrawal,
# query the recipient's trustline to confirm capacity.
import xrpl
from xrpl.clients import JsonRpcClient
from xrpl.models.requests import AccountLines
client = JsonRpcClient("https://s.altnet.rippletest.net:51234")
# Replace with your recipient account and the vault asset issuer
recipient_address = "rRecipientAddressHere"
vault_asset_issuer = "rVaultIssuerAddressHere"
vault_asset_currency = "USD"
# Fetch trustlines for the recipient
response = client.request(AccountLines(
account=recipient_address,
peer=vault_asset_issuer
))
# Find the relevant trustline and check remaining capacity
for line in response.result.get("lines", []):
if line["currency"] == vault_asset_currency:
limit = float(line["limit"]) # max the recipient will hold
balance = float(line["balance"]) # current balance on the line
remaining_capacity = limit - balance
print(f"Trustline capacity remaining: {remaining_capacity} {vault_asset_currency}")
# Only proceed with withdrawal if remaining_capacity >= withdrawal_amount
# The protocol now enforces this — but checking client-side gives better UX
break
else:
print("No trustline found. Recipient must create one before withdrawing.")
# -------------------------------------------------------
# 2. CONSTRUCT A MULTI-SEND WITH AGGREGATE MaximumAmount
# -------------------------------------------------------
# The aggregate MaximumAmount is now enforced across ALL
# payments in the batch. Set it to your true spending cap.
# NOTE: Multi-send (batch payments) API shape may vary by
# SDK version. This illustrates the conceptual structure.
multi_send_tx = {
"TransactionType": "MultiSend", # hypothetical tx type name
"Account": "rSenderAddressHere",
"MaximumAmount": { # AGGREGATE cap — now enforced
"currency": "XRP",
"value": "1000" # total across all payments
},
"Payments": [
{"Destination": "rAlice", "Amount": {"currency": "XRP", "value": "400"}},
{"Destination": "rBob", "Amount": {"currency": "XRP", "value": "350"}},
{"Destination": "rCarol", "Amount": {"currency": "XRP", "value": "250"}},
# Sum = 1000. If any payment pushes aggregate > MaximumAmount, tx fails.
# Previously the aggregate was not enforced — now it is. Plan accordingly.
]
}
# -------------------------------------------------------
# 3. DELEGATE PAYMENTS: RESERVE ≠ FEE (BREAKING CHANGE)
# -------------------------------------------------------
# Previously, some apps inferred reserve from fee or vice versa.
# Now they are independent. Query each separately.
from xrpl.models.requests import ServerInfo, Fee
# Get current base fee
fee_response = client.request(Fee())
current_fee = fee_response.result["drops"]["open_ledger_fee"]
print(f"Current open ledger fee: {current_fee} drops")
# Get current owner reserve (for delegate payment objects)
server_info = client.request(ServerInfo())
reserve_inc = server_info.result["info"]["validated_ledger"]["reserve_inc_xrp"]
print(f"Owner reserve increment: {reserve_inc} XRP")
# IMPORTANT: Do NOT derive one from the other.
# Set fee and reserve independently in your transaction builder.
# If your app previously coupled these, update your logic now.