DevelopersSmart contract
Resource limits and costs
What AXIS operations consume under Soroban's per-transaction limits, which limit binds first, and what each operation costs in fees and rent.
Note
Network limits and fee rates on this page are a snapshot of Stellar mainnet in September 2026 (protocol 23 or later). The measurements come from the contract's test host (contract v0.6.0, soroban-sdk 28), not from sampled network transactions. Validators retune network limits through Stellar Limits Proposals (SLPs), so read the live values before relying on them.
Network limits#
| Limit per transaction | Value | What it means for AXIS |
|---|---|---|
| Contract events and return value | 16,384 B | Binds first: 20 fills or about 110 order updates per call |
| Read-write ledger entries | 200 | 4 per fill plus 5 per trade, so about 48 fills if events did not bind first |
| Footprint entries | 400 | Counts every declared entry once, read-write ones included (the Reads column below), so about 97 fills. The read-write cap binds first. |
| CPU instructions | 400,000,000 | About 1M to 1.5M per fill, growing with the number of fills, far from binding |
| Write bytes | 132,096 B | A 20-fill trade writes about 15.8 KB |
| Disk-read entries | 200 | Classic-account makers add two trustline reads each |
Per ledger the network allows 1,000 written entries and 286,720 written bytes. Persistent entries are created with a minimum TTL of 2,073,600 ledgers (about 120 days) on mainnet and 120,960 ledgers (7 days) on Testnet, and no entry can live more than 3,110,400 ledgers (about 180 days) ahead.
| Fee component | Rate |
|---|---|
| Instructions | 7 stroops per 10,000 |
| Write ledger entry | 2,500 stroops per entry |
| Write bytes | 875 stroops per KB |
| Rent | 1,000 stroops per KB at the floor, rising toward 10,000 as live state grows |
| Disk read (classic or archived entries only) | 1,563 stroops per entry plus 447 per KB |
| Contract events | 5,000 stroops per KB |
| Transaction size | About 4.4 stroops per byte |
Reading live state is free. A key declared read-write pays the write-entry fee even if the call never writes it, so the read-write declarations the JS client adds cost something for unmatched orders too.
Measured operation shapes#
The contract's resource tests (src/tests/lib/resources.rs) measure one call per shape in the test host. Instructions are a lower bound (no Wasm overhead), makers are contract addresses (no classic disk reads), and writes include the 72-byte authorization nonce. "Created" is the size of new persistent entries, the basis of rent.
| Operation | Reads | Writes | Write B | Event B | Instructions | Created B |
|---|---|---|---|---|---|---|
trade Limit, order stored, no fills |
13 | 2 | 320 | 268 | 0.34M | 247 |
trade Fill, 1 order |
14 | 9 | 1,776 | 1,028 | 1.09M | 671 |
trade Fill, 8 orders of 8 makers |
42 | 37 | 6,956 | 6,572 | 7.97M | 2,239 |
trade Fill, 8 orders of 1 maker |
21 | 16 | 1,776 | 3,268 | 1.54M | 671 |
trade Fill, 20 orders of 20 makers |
90 | 85 | 15,836 | 16,076 | 25.4M | 4,927 |
trade Fill, 20 orders plus 3 skipped makers |
102 | 85 | 15,836 | 16,328 | 27.7M | 4,927 |
trade Fill, 21 orders of 21 makers |
94 | 89 | 16,576 | 16,868, over the cap | 27.2M | 5,151 |
trade Limit, 8 fills plus a stored remainder |
46 | 38 | 7,204 | 6,840 | 8.33M | 2,487 |
trade Fill over 8 unbacked orders, all skipped |
38 | 1 | 72 | 672 | 1.88M | 0 |
update removing 1 order |
5 | 2 | 72 | 148 | 0.09M | 0 |
update changing 1 order |
13 | 2 | 320 | 148 | 0.34M | 0 |
update changing 8 orders |
20 | 9 | 2,056 | 1,184 | 1.62M | 0 |
swap Sell, 2 hops of 1 order |
20 | 14 | 2,740 | 2,056 | 2.62M | 1,119 |
swap Sell, 3 hops of 1 order |
26 | 19 | 3,704 | 2,848 | 3.90M | 1,567 |
swap Sell, 2 hops of 4 orders |
44 | 38 | 7,180 | 6,808 | 10.9M | 2,463 |
crossfill, 8 maker orders |
44 | 38 | 6,956 | 6,892 | 8.59M | 2,239 |
subsidize, new market |
12 | 6 | 2,524 | 536 | 1.21M | 464 |
requote, two price fetches |
8 | 3 | 1,536 | 152 | 0.60M | 0 |
Buy trades and swaps measure like their Sell rows, except that a Buy swap needs fewer instructions because it skips the forward planning pass (2.22M for 2 hops of 1 order). The created bytes of fills are first-time token balances of the test accounts. They include the contract's own balance of each asset a trade buys, an entry that only the first trade buying that asset creates.
Per-fill formulas#
With N fills from distinct makers:
| Operation | Reads | Writes | Write bytes | Event bytes |
|---|---|---|---|---|
trade Fill, N fills plus S skipped makers |
4N + 4S + 10 | 4N + 5 | 1,036 + 740N | 236 + 792N + 84S |
trade Fill, N fills of one maker |
N + 13 | N + 8 | About 1,780 | 708 + 320N |
trade Limit, N fills plus a remainder |
4N + 14 | 4N + 6 | 1,284 + 740N | 504 + 792N |
update removing N orders of one owner |
N + 4 | N + 1 | 72 | 148N |
update changing N orders selling one asset |
N + 12 | N + 1 | 72 + 248N | 148N |
swap, H hops of K orders |
8 + H(4K + 2) | 4 + H(4K + 1) | 812 + 740HK + 224H | 472 + 792HK |
crossfill, N maker orders |
4N + 12 | 4N + 6 | About 1,040 + 740N | 556 + 792N |
A fill against a distinct maker writes 4 entries: the maker's order, both of the maker's balances and the maker's allowance. Its 792 event bytes are one trade event (about 320 B) and the two transfer events of the legs (about 236 B each). One maker's orders share one transfer per leg, hence 320 B per extra fill in the single-maker row. On top of the fills, every trade forwards what the makers delivered from the contract to the trader in one transfer (236 B), which also writes the contract's balance of the bought asset. Every swap hop writes the contract's balance of the asset it buys, and the swap ends with the same forward plus its own swap event. Other events: new 268 B, mod 148 B, skip 84 B, refresh 152 B, swap 236 B. A crossfill pays the taker order's owner instead of forwarding, and a surplus adds one transfer event to its row.
Which cap binds first#
| Cap per transaction | Value | Fills per trade |
Orders per update |
|---|---|---|---|
| Contract events | 16,384 B | 20 | About 110 |
| Read-write entries | 200 | 48 | 199 |
| Footprint entries | 400 | About 97 | About 388 changes or 396 removals |
| Write bytes | 132,096 B | About 177 | About 530 changes, removals unbounded |
| Instructions, lower bound | 400M | About 115 | About 700 removals or 2,000 changes |
Event bytes bind first, by a factor of about 2.4. The constants routers must respect:
MAX_FILLS = 20pertrade. The resource tests pin it: 20 fills from distinct makers fit, 21 do not.- The skip budget. 20 fills use 16,076 B, leaving room for 3
skipevents (252 B), not 4, so routers budget listed orders, not only fills. Silent skips cost no event bytes. - About 110 orders per
update, changed or removed.AxisAccountsends batches of 90, whileAxisContractClient.updateandcancelsend the whole list in one transaction. - 20 fills per
swapacross all hops, since theswapevent and the forward to the trader add 472 B. - 19 maker fills per
crossfill, derived from its formula: the taker order's owntradeevent and the payouts add up to 792 B with a surplus.
The two transfer events per fill (472 B) are 60% of a fill's event budget and come from the token, so the AXIS contract cannot lower them.
Fee estimates#
Execution fees at the snapshot rates, without rent and transaction size:
| Operation | Execution fee | About | Plus |
|---|---|---|---|
trade storing an order, no fills |
~6,900 stroops | 0.0007 XLM | 0.041 XLM order rent |
update removing 1 order |
~5,900 stroops | 0.0006 XLM | |
update changing 1 order |
~6,300 stroops | 0.0006 XLM | |
update changing 8 orders |
~31,400 stroops | 0.0031 XLM | |
trade Fill, 1 order |
~30,000 stroops | 0.003 XLM | New balances |
trade Fill, 8 orders of 8 makers |
~137,000 stroops | 0.014 XLM | New balances |
trade Fill, 20 orders |
~324,200 stroops | 0.032 XLM | New balances |
swap, 2 hops of 1 order |
~49,500 stroops | 0.005 XLM | New balances |
crossfill, 8 maker orders |
~141,500 stroops | 0.014 XLM | New balances |
ExtendFootprintTTL of the contract instance and code (not a contract call) |
~0 | ~0 XLM | Rent of the extension: about 67 XLM from 3 to 30 days on Testnet, see Running a keeper |
"New balances" is the rent of first-time token balances, if the call creates any. About two thirds of a multi-fill trade's fee is the write-entry fee (4 entries per maker at 2,500 stroops), and about a quarter the event fee. Not included: transaction size (several KB for a 20-fill envelope), read-write entries declared for orders that end up unmatched, resource safety margins and the inclusion fee, which the JS client bids up to 100,000 stroops by default (see Contract client).
Rent at the floor rate is about 1,667 stroops per byte for 120 days: about 0.041 XLM for an order entry, and about 0.037 XLM for the first token balance of a contract address. Order lifecycle and rent covers who pays which rent.
Requote economics#
Only new entries pay rent. A maker who refreshes quotes by removing orders and creating new ones pays about 0.042 XLM per order each time. update rewrites the same entries in place and pays the execution fee, plus a small TTL extension proportional to the time since the last update.
| Refreshing a 40-order ladder | Per refresh | Per day, every minute | Per day, every hour |
|---|---|---|---|
| Remove and recreate | About 1.7 XLM | About 2,400 XLM | About 40 XLM |
update in place |
About 0.016 XLM | About 23 XLM | About 0.4 XLM |
A 40-order update stays well within the event cap and keeps its orders from archiving. See Market making.
Adapting to limit changes#
The contract stores no caps: every loop it runs is bounded by a list the client passes. When an SLP changes a limit, nothing changes on-chain, and clients adapt:
- Read live limits. Take the per-transaction limits from the network configuration over RPC instead of hard-coding
MAX_FILLS, and derive the fill budget from the event cap, the 792 B per fill and the 236 B forward per trade. - Chunk large sweeps into several transactions, each racing the book on its own.
- Expect the effects. A higher event cap raises fills per transaction until the read-write cap takes over near 48, while a higher read-write cap alone changes nothing. A higher rent rate makes new orders dearer but barely affects
update, which pays only a small extension.
Concurrency#
Since protocol 23, transactions that write no common ledger entry can execute in parallel.
- A
tradewrites the orders it fills, each maker's balances and allowance, the taker's balances and allowance, the taker's authorization nonce, and the AXIS contract's own balance of the asset it buys. It writes no instance entry or counter. Trades that buy the same asset share that contract balance entry and serialize, whatever their pair or makers. Trades that buy different assets from disjoint makers are independent. - An
updatewrites only the owner's orders, plus the owner's allowances when it grants approvals. swapandcrossfillroute tokens through the AXIS contract's own balance in every hop asset or the bought asset, the same entry the trades buying that asset write.requoteandsubsidizewrite the market and the price cache only when something changed, so a refresh with nothing new does not serialize with the trades and updates that read them.