Current protocol fee as (numerator, denominator).
fn get_fee(env: soroban_sdk::Env) -> (i128, i128)
Set the protocol fee (per 100,000 of the taker's payment). Admin only, hard-capped at MAX_FEE_PER_100K (0.5 bps) — the ceiling is compile-time; 0 is valid (fee holiday).
fn set_fee(env: soroban_sdk::Env, fee_per_100k: i128) -> Result<(), SwapBookError>
Get a specific order by ID.
fn get_order(env: soroban_sdk::Env, order_id: u64) -> Result
Fill an order completely. The taker provides amount_out of token_out,
and receives the maker's escrowed token_in.
fn fill_order(
env: soroban_sdk::Env,
taker: soroban_sdk::Address,
order_id: u64,
amount_out: i128,
) -> Result<(), SwapBookError>
Get all open order IDs for a token pair.
fn get_orders(
env: soroban_sdk::Env,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
) -> soroban_sdk::Vec
Quote a fill from the TAKER's perspective.
The taker wants to acquire token_buy and pay with token_pay.
Scans orders where makers sell token_buy for token_pay
(i.e. PairIndex(token_buy, token_pay)) and greedily computes how much
token_buy the taker receives for spending up to amount_pay
(before protocol fee).
Returns (amount_bought, amount_paid).
fn quote_fill(
env: soroban_sdk::Env,
token_buy: soroban_sdk::Address,
token_pay: soroban_sdk::Address,
amount_pay: i128,
) -> (i128, i128)
Set the authorized router address (admin only). The router MUST be the Router contract, which claims timer-expired orders and settles the maker atomically.
fn set_router(
env: soroban_sdk::Env,
router: soroban_sdk::Address,
) -> Result<(), SwapBookError>
Place a new swap order.
price_mode: 0 = Fixed (uses min_amount_out), 1 = Oracle (uses live price)
max_slippage_bps: Oracle mode only — must be 1..=MAX_SLIPPAGE_BPS
auto_route_after: ledger sequence after which router can claim for DEX.
0 = no auto-route (sit on book until expiry).
excluded: addresses that may not fill this order (≤ MAX_EXCLUDED);
pass an empty Vec for none.
fn place_order(
env: soroban_sdk::Env,
maker: soroban_sdk::Address,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
amount_in: i128,
min_amount_out: i128,
expiry: u32,
price_mode: u32,
max_slippage_bps: u32,
auto_route_after: u32,
excluded: soroban_sdk::Vec,
) -> Result
Cancel an open order. Only the maker can cancel. Returns escrowed tokens to the maker.
fn cancel_order(env: soroban_sdk::Env, order_id: u64) -> Result<(), SwapBookError>
Permissionless cleanup: refund and close an order whose expiry has passed. Anyone may call (keeper-friendly); funds always go to the maker.
fn expire_order(env: soroban_sdk::Env, order_id: u64) -> Result<(), SwapBookError>
Partially fill an order.
fill_amount_in is the portion of the maker's token_in the taker wants.
amount_out is what the taker pays in token_out.
fn partial_fill(
env: soroban_sdk::Env,
taker: soroban_sdk::Address,
order_id: u64,
fill_amount_in: i128,
amount_out: i128,
) -> Result<(), SwapBookError>
Deploy-time constructor — atomic with deployment, cannot be front-run.
fn __constructor(
env: soroban_sdk::Env,
admin: soroban_sdk::Address,
fee_vault: soroban_sdk::Address,
)
Register the SEP-40 asset feed for a token. Admin only.
fn set_sep40_feed(
env: soroban_sdk::Env,
token: soroban_sdk::Address,
feed: OracleAsset,
) -> Result<(), SwapBookError>
Atomically fill reverse-side orders and escrow the remainder as a new sitting order — the whole plan lands in ONE invocation, so the book cannot move between the fills and the placement.
Each FillSpec targets an order selling token_out for token_in
(the reverse side of the new order). The maker acts as taker on
those fills, paying amount_out of their token_in per fill. The
payments plus the escrowed remainder must not exceed amount_in.
Returns the new order's id, or 0 if the fills consumed the full amount and nothing was placed. Placement params mirror place_order.
fn match_and_place(
env: soroban_sdk::Env,
maker: soroban_sdk::Address,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
amount_in: i128,
min_amount_out: i128,
expiry: u32,
price_mode: u32,
max_slippage_bps: u32,
auto_route_after: u32,
excluded: soroban_sdk::Vec,
fills: soroban_sdk::Vec,
) -> Result
Read the current oracle price for a pair.
fn get_oracle_price(
env: soroban_sdk::Env,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
) -> Result<(i128, i128, u32), SwapBookError>
Set the authorized oracle admin (contract admin only).
fn set_oracle_admin(
env: soroban_sdk::Env,
oracle_admin: soroban_sdk::Address,
) -> Result<(), SwapBookError>
Configure the SEP-40 oracle (e.g. Reflector) and the max price age in seconds. Admin only. Once set, pairs where BOTH tokens have a registered feed price exclusively off the SEP-40 oracle (fail closed); other pairs keep using the pushed price.
fn set_sep40_oracle(
env: soroban_sdk::Env,
oracle: soroban_sdk::Address,
max_age_secs: u64,
) -> Result<(), SwapBookError>
Remove a token's SEP-40 feed (pairs including it fall back to the pushed price). Admin only.
fn remove_sep40_feed(
env: soroban_sdk::Env,
token: soroban_sdk::Address,
) -> Result<(), SwapBookError>
Claim a timer-expired order. Only the authorized Router CONTRACT can
call this (invoker auth). The escrowed tokens transfer to the router,
which must — within the same invocation — execute the DEX route and
pay the maker at least min_out of token_out.
min_out is derived on-chain from the order's own price terms:
Fixed → pro-rata min_amount_out over the remaining amount
Oracle → current fresh oracle fair value minus max_slippage_bps
fn claim_expired_timer(
env: soroban_sdk::Env,
order_id: u64,
) -> Result
Update an oracle price for a token pair. Only the oracle admin can call.
Hardening:
fn update_oracle_price(
env: soroban_sdk::Env,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
price_num: i128,
price_den: i128,
) -> Result<(), SwapBookError>
Get all orders whose auto_route_after timer has expired.
fn get_expired_timer_orders(
env: soroban_sdk::Env,
token_in: soroban_sdk::Address,
token_out: soroban_sdk::Address,
) -> soroban_sdk::Vec