Endpoints
The aggregator boundary
Theswap argument is an opaque Bytes payload (ScVal XDR). The controller
does not decode it or validate its route structure. It forwards the bytes
verbatim to the configured aggregator:
sender is the controller’s own address. total_in is the exact amount the
controller commits to spend. The aggregator pulls total_in of the input token
from the controller, runs the swap, and returns how much output it delivered.
Inside the aggregator the XDR decodes to a StrategyPayload. It is a compact
program, not a list of routes:
u8 index, so an address or amount
used by several hops is carried exactly once. Each hop is a fixed 5-byte
record rather than a full XDR struct.
The ops blob starts with a 10-byte header:
Split weights are
u24 big-endian parts-per-million and sum to 1_000_000.
Building the swap payload
You do not hand-assemble the XDR. Request a route from the swap aggregator’s quote service, which returns the encodedStrategyPayload bytes for the
input/output pair and amount. Pass those bytes straight into the strategy call.
See Stellar Aggregator for the quote API and
token coverage.
When the route is multi-hop or split across venues, that complexity is entirely
inside the bytes; the controller and your transaction see only swap: Bytes.
Position mode
PositionMode tags what the account is for: Normal = 0, Multiply = 1,
Long = 2, Short = 3.
multiply and flash_position accept only Multiply, Long, or Short. They
reject Normal with #111 InvalidPositionMode.
The mode is fixed when the account is created and never changes. swap_debt,
swap_collateral, and repay_debt_with_collateral do not touch it.
Multiply
- Collect any
initial_paymentfromcaller. - Borrow
debt_to_flash_loanofdebtfrom the pool as strategy debt. - Swap it — plus any debt-denominated payment — into
collateralthroughexecute_strategy. - Supply the combined collateral to the account.
- Re-check the LTV gate, health factor, and the minimum-borrow floor.
modeisMultiply,Long, orShort(#111otherwise); the collateral and debt assets must differ (#7 AssetsAreTheSame).account_id = 0creates the account. Otherwise the passedmodemust equal the account’s stored mode (#25 AccountModeMismatch) and the spoke must match (#310 SpokeMismatch).initial_paymentmay be in the collateral asset (added directly), the debt asset (added to the flash amount), or a third asset — which requiresconvert_swapto convert it to the collateral asset, else#500 ConvertStepsRequired. Supplying one emitsInitialMultiplyPaymentEvent.- Indexer note: the leverage borrow leg is tagged
Multiply(6); the deposit leg is taggedSupply(0).
Swap debt
amount of new_debt, swaps to existing_debt, repays the old debt;
over-repayment is refunded to caller. The two assets must differ and
existing_debt’s hub must be active.
Indexer note: both legs carry SwDebtR (8) — the new borrow and the old
repay.
Swap collateral
amount of current, swaps to new, redeposits. The two assets must
differ and current’s hub must be active. The new collateral must pass the
deposit preflight (collateralizable on the account’s spoke, caps and position
limits). Legs are tagged SwColWd (9) and Supply (0).
Repay debt with collateral
collateral_amount, swaps to debt, repays. When collateral and
debt are the same market the position is netted directly on the pool — no swap,
no router trust boundary, and the single leg is tagged RpColNet (14). Otherwise
the legs are RpColWd (10) and RpColR (11).
close_position = true also withdraws all remaining collateral to caller once
no debt remains, giving a one-call full exit (CloseWd, 12). It reverts
#122 CannotCloseWithRemainingDebt if borrow positions are still open.
Migrate from Blend
blend_pool must be governance-approved. Solvency is checked at
strategy_finalize, not during the Blend calls.
This flow does not use the flash-loan receiver pattern. See
Blend migration for the two-phase submit
model, refund reconciliation, and parameter guide.
Strategy borrow vs flash loan
Strategy finalization
Every strategy ends instrategy_finalize: restamp listed collateral risk
parameters from the current spoke config, apply the post-pool risk gates (LTV
coverage, health factor, and the minimum-borrow-collateral floor), persist, and
emit the position batch. All strategy entrypoints are pause-gated and require
account owner or delegate authority.
Reentry and trust
Strategy swaps and Blendsubmit calls reuse the flash-loan reentrancy guard.
While either is running, any mutating controller entrypoint reverts with
#400 FlashLoanOngoing. A compromised or misconfigured aggregator cannot call
back into the protocol mid-swap.
The controller authorizes exactly one token pull — total_in of the input token
— and checks its own balance deltas afterward. It never trusts the router’s
return value.
Failure modes
Next
Blend migration
Atomic Blend V2 to XOXNO position migration.
Flash loans
The single-asset flash loan receiver pattern.
Swap aggregator ABI
The router contract itself:
execute_strategy, fees, and referrals.Stellar Aggregator
The quote service that produces the swap bytes.

