Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
[Unreleased]
0.4.0 - 2026-08-14
First release since the canister went live on mainnet: the Candid interface and the persisted state are backward compatible, so an upgrade from 0.3.0 needs no migration and no client change (see Changed).
Added
- Separate funding and trading accounts: a funding account can whitelist trading-account principals via
add_trading_account/remove_trading_account/get_my_trading_accounts. A trading account places and cancels orders on the funding account’s balance but can never deposit or withdraw (deposit/withdraware denied with aTradingAccountForbiddenrequest-error variant). Orders and reads by a trading account resolve to the funding account, and each order records the acting key via the newplaced_by/canceled_byfields onOrderRecord. Grants require a registered granter, target a fresh principal that can actually be exercised by a single keyholder — the anonymous principal and the management canister are rejected — and are rate-limited by a per-account cooldown; revocation is never rate-limited. All additions are backward-compatible Candid (#207, #208, #209, #219, #222, #223, #226, #230, #238) max_settlement_units_per_event, an optional init/upgrade argument capping how much settlement work a single settling event carries; absent, it falls back to the conservative production default (#216)
Changed
- No break for clients or for persisted state. Every Candid addition is backward compatible: new record fields are ignored by older decoders, and the new
TradingAccountForbiddenleaves sit underRequestError : opt variant, which the disposition contract has older clients decode asnull. Every persisted-state addition is a new optional CBOR field at a fresh index or a new event variant, and the trading-account maps live in fresh stable-memory regions, so a canister upgraded from state persisted by 0.3.0 decodes and replays it unchanged. This is now checked against production: a test replays the live mainnet event log and asserts the reconstructed balances, order history, trades, user registry, and order-book depth match the mainnet snapshot (#229) - A matching round now emits several bounded settling events instead of one per chunk, so
get_eventsreaders see more, smaller settling events for the same settlement; the debug event stream also gains the trading-account grant/revoke events and theplaced_by/canceled_byattribution (#216, #207, #223, #226) - Render principals textually in canister logs (#203)
- Finalize the ckBTC/ckUSDT tick and lot sizing, and document the live production listings (#246)
Fixed
- Cancel applies only its own settlement: a cancellation used to drain the whole global settlement backlog, inheriting the instruction debt of unrelated matching rounds. On a large backlog it could exceed the per-message instruction limit and trap, leaving the order uncanceled and its reservation locked, so the user could not exit (#240)
- Bound the settlement work applied per message: a single fill-or-kill order sweeping many resting makers produced one oversized settling event whose apply cost, past roughly 23,000 fills, exceeded the per-message instruction limit and froze matching. Settlement is now partitioned into bounded events at construction (#216, #210)
- Validate the deposit/withdraw amount before rendering it: the handlers formatted the caller-controlled unbounded
natinto a diagnostic string ahead of authorization and validation, and that super-linear conversion alone could exhaust a message’s instruction budget and trap the call (#237)
0.3.0 - 2026-07-02
Added
- Per-fill trade history and the
get_my_tradesquery: persist each fill individually in stable memory and expose a caller’s trades newest-first — a per-orderByOrderfeed and an account-wideByAccountfeed — built on realized per-order quote/fee scalars, shared composite-id/sequence machinery, and a dedicated trade store (#171, #192, #193, #179, #186, #180)
Changed
- BREAKING (pre-launch persisted state only): the trade-history work changes the stable-memory / event-log encoding — order ids now encode as a bare CBOR
u64instead of a 1-element array,OrderBookSnapshotgains a non-Optionnext_fillfield, and the settling event carries a lean per-fill record — so a canister upgraded from state persisted before this release cannot decode it. Acceptable because the canister is pre-launch with no deployed state to migrate; the Candid/public API is unchanged (#192, #179) - Extract a dedicated settlement module and harden the fill-persistence tests, with a
get_my_tradesaccount-wide pagination benchmark (#195, #196) - Render prices and amounts as human-readable floats (#182)
0.2.0 - 2026-06-26
Added
- Fill-or-kill (FOK) orders: a time-in-force on order submission with an
Expiredorder status, enforced as a matching gate and through execution (#164, #169)
Changed
- BREAKING: rework the error types returned by the user-facing endpoints into a disposition contract — each error is categorized as a request error (client-side, do not retry), a temporary error (safe to retry), or an internal canister error;
get_my_ordersno longer traps and returns distinctInvalidOrderIdandOrderNotFounderrors. Impacted endpoints:add_limit_order,cancel_limit_order,deposit,withdraw,get_balances,get_fee_balances,get_my_orders,get_order_book_ticker,get_order_book_depth(#158, #168, #172)
0.1.0 - 2026-06-16
Added
- Limit orders: submit and query order status, with validation on submission (#11, #19); cancel orders (#76, #77)
- Order matching: order book with a timer-driven matching engine, plus a configurable execution policy and chunked execution of pending orders (#15, #18, #90, #89)
- Deposit and withdrawal flows (#17, #45)
- Balances: per-user free/reserved balances, reserved on order placement and updated on settlement, with
get_balancesandlist_supported_tokensqueries (#27, #28, #30, #99, #98) - Trading pairs:
add_trading_pairandget_trading_pairs, with token metadata (#22, #21, #32) - Per-pair maker/taker fees: configuration and pair plumbing, per-token fee pools, deduction at fill time, and fee visibility — including the per-pair rates in
get_trading_pairsand the dashboard (#107, #108, #109, #105, #153) - Order history and queries: order-lifecycle history, a per-user order index with submission timestamps, and a
get_my_ordersquery; order-book ticker and depth queries (#41, #110, #111, #115, #74) - Audit and event log for state replay, with deposit, withdrawal, trading-pair, limit-order, and matching/settlement events (#38, #42, #44, #47, #66, #68)
- Trading halts: global and per-pair halt, on a permission layer (#125, #126, #127)
- State persistence: order history and balances persisted in stable memory and restored across upgrades (#62, #63, #64)
- Observability: operation logging, canister metrics, and a dashboard with trading-pair details (#23, #52, #79, #80)
Changed
- Settlement exactness: enforce the tick·lot settlement invariant, settle fills in quote units per whole base token, and widen price and tick size to u128 (#119, #121, #122)
- Add a min/max notional filter per trading pair (#131)
- Expand order records with partial-fill information (#133)
- Rename the project from DEX to OISY TRADE (#138)