Threat model: what the TrackRecord proves, and what it does not
This is the precise claim behind "every trade committed before it ends". It is narrower than "results can't be faked", and we say so on purpose: a verification product has to be exact about its own limits.
Actors
- Operator — runs the engine and the commit daemon, holds the publisher key. Can be dishonest.
- Visitor / judge / allocator — wants to know whether the published record is complete and unedited.
- Robinhood Chain — orders transactions and timestamps blocks (100 ms blocks). Trusted for ordering and time.
What is proven (anyone can check, without trusting us)
| Claim | How it is checked | Where |
|---|---|---|
| A recorded decision has not been changed since it was sealed | leaf = keccak(0x00‖keccak(canonical JSON)), Merkle root stored on chain | verify.js, verifyDecision() |
| A recorded entry was sealed before its committed exit | block time of the entry's batch < time of the committed close decision | verify.js judge() |
| Every time, amount and net multiple shown on the page equals the committed decisions | entry/exit time (±5 s), ETH in, ETH out, net multiple from committed pnl_eth (so gas is included) |
verify.js judge(), page built from committed data |
| No recorded trade is missing from the page | all batches for the strategy ids are fetched (batchCount must be answered), each root and count checked, every committed entry must be shown, position numbers have no gaps |
verify.js completeness() |
| Committed history is append-only | windows per strategy must not overlap; no admin, no upgrade path | TrackRecord.sol |
Failures are loud: an RPC error or an unreadable batch count shows "Not verified", never a green summary. Warnings (seal later than 90 s after entry, exit outside the 120 ± 60 s rule, net result not committed) are counted separately and turn the summary yellow.
Measured on the public instance (snapshot 26 Sep 2026, 91 trades, 150 batches)
- Seal latency, entry → end of its commit window: median 60.5 s, p95 63.4 s, max 65.1 s.
- Margin between the seal and the committed exit: minimum 56.8 s, median 73.4 s. No entry was sealed after its exit.
- Holding time: 119–189 s (rule: 120 s; one exit at 189 s is shown as a warning).
What is NOT proven (and what would close each gap)
| Gap | Why it matters | Mitigation (status) |
|---|---|---|
| Signals the engine never recorded. The operator could filter decisions before they reach the journal. Position numbers catch gaps only after a number is assigned. | Selective recording is still possible for a dishonest operator. | The eligible universe is on chain (launchpad buys by the tracked wallets). Committing a hash of the wallet list at registration, plus the skip log (signals.csv, every signal with its skip reason), lets an auditor who is given the list replay a block range and find unrecorded signals. (planned) |
| The ~60 s before the seal. An operator sees 60 s of the price path before the entry is sealed and could drop bad entries in that window. | "Before the result is known" is only true relative to the exit. | Seal per block instead of per minute (cost is flat with the v2 single-root design); verifier fails entries sealed later than a fixed limit. (limit implemented as a warning at 90 s; per-block sealing planned) |
| Simulated fills. Paper prices come from our model of pool depth, fees and gas. | A committed number is not an executable number. | Each decision names token, time and price, so it can be re-simulated against block state. Live mode with signed transactions and receipts is the real guarantee. (re-simulation tooling in Results; public checker planned) |
Rules followed. configHash fixes the declared rules; the chain does not check the engine followed them. |
Hidden logic could deviate. | Public rules are published; strategy #0 was registered with a placeholder hash (keccak("config-v1")), so it is a legacy record. New registrations use the keccak of the canonical JSON manifest. (to be registered) |
Other addresses, unregistered strategies. strategiesOf(owner) lists one address's registrations only. |
"You can't hide twenty strategies" is true only per address. | Publish the operator's addresses; for external producers, bind registrations to a signed identity. (planned) |
| Operator stops committing. The contract cannot force the daemon to run. | Missing periods. | Visible as a gap in batch windows; the page shows the last commit time. |
Canonical manifests of the public strategies
keccak256 of the canonical JSON (keys sorted) of each entry in engine/strategies-public.json:
k2-early-120s:0x7ea8f46f1cc7c313fb01da29c2727abaee8d11231db103fb7f4d4f6dc4e9a8ffk2-all-120s:0xe0b3f38499d1f7c47cff579e89072395760be5b93f4cbaad7d5fa9a4ae63d166
Answers to the questions a jury will ask
- What is a mandatory event? Every entry/exit the engine journals for a registered strategy. The eligible universe (launchpad buys by tracked wallets) is on chain; committing the wallet-list hash and the skip log is next.
- Worst event→commit lag? 65 s on the snapshot above; the verifier warns above 90 s and fails if sealed after the exit.
- Why does commit-before-exit help if the operator sees the market first? It bounds the window for dropping trades to ~60 s instead of forever; per-block sealing reduces it to seconds.
- Secret strategies? A hash proves the rules did not change, not that they were followed. We publish rules; for private rules the options are later disclosure, TEE attestation or ZK — none is claimed today.
- Can every multiple be reproduced? Net multiple = (ETH in + committed pnl) / ETH in; the page recomputes it. Whether the fill was achievable needs re-simulation at the block (see Results).
- Why is #0 worse than the control? 29 vs 68 trades, overlapping samples, one day of data; no conclusion yet.
- Pre-registration? The protocol and registration date are on chain for #1; #0 is a legacy placeholder.
- Why not a broker statement / Dune / own signature? Those show what happened to money, or what the author says; this shows what was decided and when, before the outcome, in a form anyone can re-check.
- Why a contract rather than plain L2 timestamping? Per-strategy append-only windows, publisher permissions, registration history and on-chain verification in one place, with no admin.
- Which code is deployed? The repository tag submitted with the application; the contract source is verified (Blockscout + Sourcify, exact match).