Audit · 10 September 2026

What we checked, and what we found.

A self-audit of the site and the contract, published as is. It is not a third-party security audit and does not replace one. Items marked fixed were changed on the day of the audit; items marked open are still true. Revised the same evening after the market list grew from five to ten and two of the original pools were found drained.

Scope

Everything a user touches: the four public pages, the JavaScript that reads the chain and talks to a wallet, the TremoVol contract on Robinhood Chain, the keeper that marks prices, and the way the site is served. Method: reading the code, running the contract test suite on an in-process EVM, reading the live contract and pools, fetching the live site's headers, and measuring what the browser downloads.

Out of scope: the Uniswap v4 PoolManager and the USDG token, both of which are third-party contracts this product depends on but does not control.

Summary

AreaFoundFixed todayOpen
Contract505 (by design or awaiting a third party)
Price oracle31 (mitigated)2 (inherent to the design)
Front end321
Transport220
Operations312
Performance211
Accessibility211
Discoverability220

The one thing to take away: the contract works as specified and its tests pass, but it has not been reviewed by anyone who did not write it. Until it has, treat any escrow you post as money you can lose to a bug.

Contract

TremoVol, Solidity 0.8.24, about 350 lines. Twelve tests cover pricing orientation, escrow accounting, the capped transfer, voiding, mark timing and listing. What was looked at and what stands out:

SeverityFindingStatus
HighNo independent audit. The code has a test suite, which is not a review. A single arithmetic or accounting mistake would be shared by every position.Open. Needs a third party.
MediumThe listing is not frozen. The owner can still add markets. Adding a market cannot touch existing positions or escrow, but it is a power the owner holds.Open. Will be frozen once the list is final; the freeze is irreversible.
MediumFunds are held in one contract with no pause, no upgrade path and no admin withdrawal. That removes rug risk, and also removes the ability to rescue funds if a bug is found.By design. Stated here so it is not a surprise.
LowReturns are simple, not logarithmic. For hourly moves the two agree to well inside a vol point; for a market that gaps 30% in an hour they diverge.By design, documented in Mechanics.
LowSettlement, cancel and accept are guarded against re-entry and follow checks-effects-interactions; the quote token's transfer return value is checked. ERC-20s that do not return a bool would revert; USDG returns one.No action.

Price oracle

Every number the contract settles on comes from the storage of one Uniswap v4 pool per market, read once an hour. That is transparent and manipulation-resistant in the way Mechanics describes, and it carries its own risks:

SeverityFindingStatus
MediumOne pool per market. If that pool's liquidity leaves, marks stop (carry-forward) and a term can void. The depth floor protects against thin marks, not against a market going quiet.Inherent. Depth is shown on the front page for this reason.
HighThe pools that price AAPL (#2) and TTWO (#3) drained after listing to under 200 USDG of depth per percent of price. A pool that thin can be pushed for pennies, and the contract's liquidity floor, which is fixed at deployment, sat far below it. A market cannot be re-pointed once listed.Mitigated Both markets are retired on the desk and in the ticker; they stay on the contract so anything open settles. AAPL is listed again on the deepest pool. A future contract should carry a floor in quote terms and let the owner retire a market on chain.
LowThe read depends on the PoolManager's storage layout. The PoolManager is immutable, so the layout cannot change under us.No action.

Front end

No server-side logic, no accounts, no analytics, no third-party scripts. Signing stays inside the wallet extension; the site never sees a key. Findings:

SeverityFindingStatus
MediumWallet names and icons announced by browser extensions were written into the page as HTML. A hostile extension could have injected markup into the connect dialog.Fixed Rendered as text and attributes; icons limited to data: and https: URLs.
LowTwo pages carried inline scripts, which prevents a strict content security policy.Fixed Moved to files.
LowABI encoding is hand-written rather than from a library. It is covered by tests against the compiled contract, and the selectors are checked to match at test time. It is still one more thing to get wrong when the contract changes.Open. Accepted for now.

Transport

SeverityFindingStatus
MediumNo content security policy and no framing protection were sent.Fixed Scripts and styles from this origin only, fonts from Google, connections only to the chain RPC, framing denied.
LowNo nosniff, referrer or permissions policy headers.Fixed

TLS is terminated by the host. The site talks to one external service, the chain's public RPC, over HTTPS.

Operations

SeverityFindingStatus
MediumHourly marks depend on one keeper process. If it stops for more than a day, open terms lose observations; a term with fewer than 24 voids and refunds both sides, so nobody loses escrow, only the trade.Open. A public health endpoint at /keeper.json shows its last pass; a second keeper anywhere in the world can run the same script, marking is permissionless.
LowThe keeper wallet holds only gas and is topped up by hand; running dry stops marks silently.Partly The health endpoint reports its balance; a low-balance warning is logged.
LowOne RPC endpoint, no fallback. If the public node is down the site shows prices as unavailable and the keeper waits.Open.

Performance

SeverityFindingStatus
LowThe logo shipped at 1254 pixels and 425 KB for a 22-pixel slot.Fixed Now 128 pixels.
LowThe text fields are drawn on canvas at 8 to 12 frames per second. They pause off-screen and in background tabs, and are static under reduced-motion settings. On a weak phone the home page still costs a few percent of CPU while visible.Open. Accepted.

Total JavaScript is about 85 KB uncompressed with no framework and no bundler; the only external requests are two font files and the RPC.

Accessibility

SeverityFindingStatus
MediumKeyboard focus was not visible on buttons and links.Fixed A visible focus ring on every focusable element.
LowThe desk's payoff chart is an SVG with a single label; its numbers are also in the table beneath it, which is how a screen reader gets them.Open. Accepted.

Text contrast is at least 5.9:1 everywhere; the canvases carry labels; motion honours the system reduce-motion setting.

Discoverability

SeverityFindingStatus
LowNo social preview tags, so a shared link rendered without a card.Fixed Open Graph and Twitter tags with an image on every page.
LowNo robots.txt or sitemap.Fixed

Still open

  • Third-party audit of the contract. The only item on this page that matters more than all the others together.
  • Freeze the market list once it is final. Two of the first five pools drained within a day of listing, so the list is held open for now.
  • A second contract version with a depth floor in USDG rather than raw liquidity, and an owner call that retires a market on chain instead of only on the desk.
  • A second keeper run by someone else, so marks do not depend on one machine.
  • A fallback RPC for the site and the keeper.

This page will be updated when any of these changes. The date at the top is the date of the last revision.

Open the desk+