The track record: what is guaranteed, and where it stops
How it works
- The strategy is registered before it trades.
registerStrategy(name, configHash)fixes its name, owner and creation time on chain. Registrations cannot be deleted: every registration by an address is listed bystrategiesOf(owner). (This does not cover strategies that were never registered, or were registered from another address.) - The engine writes each decision to an append-only journal within about a second: every entry and every exit, with time, token, side, amounts, price and the position number.
- A daemon commits them. It hashes each journal row the moment it appears (keccak-256 of the row with
sorted keys), and one minute after the first uncommitted row it commits a Merkle root of all pending rows with
commitBatch(strategyId, root, count, fromTs, toTs). The contract only accepts windows that start after the previous one ended, so the record of a strategy is one timeline that cannot be rewritten. - Anyone can check a decision. The public results page publishes each batch as JSON: every decision with its
hash and Merkle proof.
verifyDecision(strategyId, index, hash, proof)on the contract returnstrue; change any field of the decision and it returnsfalse.
What this guarantees
Scope: the decisions the engine writes to its journal for a registered strategy.
- A recorded entry cannot be dropped after the trade goes wrong. Each entry is sealed about 60–75 seconds after it happens, before the committed 120-second exit; the page checks that order against the committed exit time.
- Nothing recorded can be edited or added later. A decision that is not in a committed root cannot be proven, and a committed root cannot be replaced (windows are append-only per strategy).
- Gaps are visible. Position numbers of the public instance are one sequence shared by strategies #0 and #1; a missing number in the committed batches shows that a recorded trade was left out.
- No one can rewrite committed roots, including us. No contract-wide owner or admin, no upgrade path, no funds. Each strategy's owner can only add publishers, post snapshots or close that strategy.
What it does not guarantee is listed below and in the threat model: that the engine recorded every signal it saw (an operator could filter before the journal), that nothing was known in the 60–75 seconds before the seal, or that simulated fills were achievable.
Checking it without us
The results page at /record/ runs the checks in the visitor's own browser, against Robinhood Chain (public RPC first; this site's read-only relay only as a fallback):
- Entry sealed before the exit — each trade's entry decision is recomputed from the published file, its batch root is rebuilt and compared with the root stored on chain, and the batch must be committed before the trade ended.
- Result matches the record — the exit ("close") decision is on chain too; ETH in and ETH out shown on the page must equal the committed amounts, and the exit must come when the rule says (120 s after entry).
- Nothing left out ("Check all trades") — every batch ever committed for the public strategies is fetched and checked; every committed entry must be shown on the page, and position numbers must have no gaps.
A mismatch turns the summary red and marks the trade. The code is engine/tools/verify.js.
What it does not guarantee
- Paper fills are our model, not real trades. The chain proves what the engine decided and claimed at that
moment. It does not prove that the simulated price was achievable. Each decision names the token, time and
price, so the fill can be re-simulated against the chain state of that block by anyone (we do this ourselves
with
eth_callreplays; see Results). - An operator can stop committing. The contract cannot force a daemon to run. A stopped record is visible (no new batches), and a strategy can be closed on chain, but not silently.
- The rules are declared, not enforced.
configHashfixes a strategy's declared rules; the chain does not check that the engine followed them. For the public strategies the rules are published inengine/strategies-public.json. Strategy #0 was registered with a placeholder hash (keccak("config-v1")) before this file existed; #1 uses the keccak-256 of its JSON entry. - Batch
countis informational. Membership is proven by the root;countis not checked on chain.
Cost
A batch costs about 0.000003 ETH of gas on Robinhood Chain. With one-minute batches only when there are new decisions, a strategy that trades a few times an hour costs cents per day.
Scaling (TrackRecord v2, planned)
v1 commits one root per strategy per minute, so gas grows with the number of strategies: about 0.01 ETH a week for our two strategies today, and several ETH a week for 2,000 active strategies. v2 keeps the same guarantee and removes that growth:
- one root for all strategies per minute — the strategy id goes into each leaf, so every trade still has its own proof;
- root in storage, window in the event log — about 35–40k gas per commit instead of ~110k;
- entries within a minute, exits hourly — the exit follows from the rule and prices anyone can re-check at that block, so only entries are time-critical.
Estimated gas at today's prices: 0.005–0.01 ETH a week, roughly $700–1,400 a year, whether 10 or 10,000 strategies are recorded. Longer-horizon strategies (for example tokenized stocks held for days) can commit hourly.