docs(specs): persist individual fills and expose per-order / per-account trade feeds#170
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new development spec (DEFI-2901) documenting the planned design for persisting individual fills in stable memory, extending OrderRecord with cumulative execution scalars, and exposing owner-scoped per-order and per-account trade feeds.
Changes:
- Introduces the DEFI-2901 spec with requirements (R1–R12), non-goals, and design decisions for order-level scalars plus per-fill persistence.
- Details the proposed storage layout (stable-memory regions + indices), new query endpoints (
get_order_fills,get_my_trades), and cursor/pagination behavior. - Defines a test/benchmark plan including a canbench-based hot-path cost acceptance gate.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| - **R10 — Bounded pages.** The feed caps `length` at `MAX_FILLS_PER_RESPONSE`; an absent / | ||
| larger value is clamped. An unknown `after` cursor yields an empty page (malformed cursors are | ||
| rejected per R5). |
There was a problem hiding this comment.
🤖 Fixed in b3fc8f1. You're right — length is mandatory (nat32) in the filter records, so there is no "absent" case. R10 now reads: "length is mandatory in the filter; a value above MAX_FILLS_PER_RESPONSE is clamped down to it." (Only after is optional.)
| 2. **Per-fill records in their own stable-memory regions** — the granular feed, behind one new | ||
| `get_my_trades` endpoint that filters either by order or account-wide. |
There was a problem hiding this comment.
🤖 Good catch — the PR description was stale. Updated it to describe the single get_my_trades endpoint with the ByOrder | ByAccount filter (the spec was collapsed to one endpoint in an earlier revision); there is no longer a get_order_fills.
| micro-benchmark, with vs. without fill persistence, to characterize the per-fill insert cost | ||
| against the timer chunk's instruction budget. | ||
|
|
||
| ## Worked example |
There was a problem hiding this comment.
Format the worked example as a table
- 1 row per fill
- 1 column per side (maker/taker)
in each cell bullet list, one bullet per parameter.
Change the examples to have 2 fills, use a bit more realistic example (ICP/ckUSDT, use 8/6 decimals, can use price of 10 ckUSDT per ICP to keep it easy)
There was a problem hiding this comment.
🤖 Reformatted in 0b2aaa8. The worked example is now a table — one row per fill, a Taker-leg and a Maker-leg column, each cell a bullet list of the Trade parameters. Switched to ICP/ckUSDT (8/6 decimals, prices in ckUSDT/ICP) and to two fills: a taker buy of 5 ICP @ limit 12 sweeping Maker A (2 ICP @ 10) and Maker B (3 ICP @ 11). Added a setup note showing the smallest-unit scaling (price = ckUSDT/ICP·10⁶, quantity = ICP·10⁸, notional = price·quantity/10⁸) worked once for Fill 1, plus order-level rollups (taker: filled_quote 53, VWAP 10.6, fee 0.005 ICP, 7 ckUSDT released; makers: 0.01 / 0.0165 ckUSDT fee). Updated the state/tests.rs plan to assert these numbers.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the DEFI-2901 spec for persisting individual fills and exposing them through a query endpoint.
The spec separates two distinct deliverables that should not be conflated:
OrderRecord— cumulative realizedfilled_quote(always quote-denominated) andfilled_fee(denominated in the order's receive token), folded into the existing single per-order write. VWAP is derived client-side rather than stored, since an integer price cannot represent a fractional average exactly.get_my_trades, filterable either by order (ByOrder) or account-wide (ByAccount).Key decisions captured in the spec: store realized amounts and never fee rates (robust to future rate changes); denormalized side-projected records over a normalized canonical-plus-pointers layout (fewer settlement hot-path inserts, no read indirection); compute per-fill values in settlement where the base-token scale is in scope; and a canbench measurement of the settlement path as an acceptance gate on the persistence PR. Includes a worked ICP/ckUSDT example and a comparison of the proposed surface against Binance, Coinbase Advanced, and Kraken.
Delivered as three stacked PRs: order-level scalars, fill store + per-order filter, then the account-wide filter.
🤖 Generated with Claude Code