Skip to content

Security: a16k-lab/highlow-contracts

Security

SECURITY.md

Security model and accepted findings

HighLow binds one immutable Flare FTSOv2 source and one owner-rotatable oracle signer. FTSOv2 supplies every opening price and every timely closing price. The oracle has one explicit trusted fallback: after a missed 10-second live close window, it may type the nonzero closing price that settles the blocked round.

Required operating assumptions

  1. The oracle submits finalizeFromFtso(id) during [roundEnd, roundEnd + 10 seconds) and monitors confirmation, not only transaction submission.
  2. A missed live close is resolved by an authorized operator calling finalizeWithManualPrice(id, closePrice). Until that succeeds, funds remain unclaimable and no later round can start.
  3. After a close exists, the oracle calls startNextRound(id) at or after roundEnd + 10 seconds. Failure leaves the closed round claimable but stops all later trading.
  4. Operations monitor the selected FTSOv2 feed. FastUpdater exposes a batch submission timestamp, not proof that every selected feed changed in that submission.
  5. The owner is trusted with immediate economic configuration, pause, oracle rotation, automatic liquidity, and fee withdrawal authority. The owner cannot replace the immutable FTSOv2 source.
  6. Trading clients set meaningful minShares and minOut values.
  7. autoVL stays disabled unless its gross-volume input and selected bounds are intentionally accepted.

Lifecycle trust boundary

The timely close path reads live FTSOv2 and accepts no caller-supplied price:

round close = current FTSOv2 price during [roundEnd, roundEnd + 10s)
next open   = current FTSOv2 price at startNextRound submission

The live adapter stores no historical samples. It rejects future timestamps, stale updater timestamps, feed-index mismatches, malformed return data, invalid decimals, zero, and overflow. HighLow applies the configured opening-to-closing deviation guard to the timely FTSOv2 close.

At roundEnd + 10 seconds, the live closing path permanently closes and the manual oracle path opens. The manual path intentionally bypasses the deviation guard so a genuine large price move cannot make recovery impossible. It records MANUAL provenance on chain. The next opening remains FTSOv2-only.

If startNextRound registers an opening anchor during the second 10-second interval, the anchor is held until the scheduled opening at roundEnd + 20 seconds. It can be up to 10 seconds old when trading opens, so its horizon to the next close-window start is 100 to 110 seconds. The actual closing feed publication may land during the following 10-second live window. A later registration starts the round immediately and restores a 100-second scheduled horizon.

There is no permissionless timeout, automatic VOID, skipped round, or stale anchor carry-forward. This is a deliberate liveness tradeoff: oracle failure can lock an unsettled round until the owner rotates the oracle or the oracle acts.

Current finding decisions

ID Finding Current severity Decision
H1 A privileged reporter can choose a manual post-deadline result. High, accepted trust assumption Intentionally restored only after the live FTSOv2 window. Every manual close is marked on chain.
H2 Missing required lifecycle calls can halt later rounds and can lock an unsettled round. High, accepted operational risk Deliberate hard gate. Deploy only with redundant automation, confirmation monitoring, oracle rotation, and a manual runbook.
H3 The owner can replace settlement authority. Medium, accepted governance power The owner can rotate the operational oracle but cannot replace FTSOv2.
M1 Reusing a closing price as the next opening changes the intended measurement interval. Resolved Closing and next opening are separate calls. The next opening always reads live FTSOv2.
M2 A trader can sell and then buy through different addresses in one block around an unprotected victim sell. Low Accepted MEV risk. Clients must use minOut.
M3 Optional auto-VL uses gross buy volume, so repeated buy and sell cycles can influence future depth. Informational while disabled, Medium if enabled Accepted. Keep disabled unless explicitly enabled and monitored.
L1 Fixed-point LMSR rounding is not perfectly monotonic in extremely small dust states. Low Accepted numerical edge case.
L2 sell and claim pay only msg.sender; a wallet that rejects native currency cannot redirect proceeds. Low Accepted interface limitation. Supported wallets need a payable receive path.
L3 Four-decimal reference prices can be too coarse for very low-priced feeds. Low Accepted listing constraint. Use feeds with adequate resolution.
I1 Some owner setters do not emit dedicated change events. Informational Accepted. Operations read current state directly.
I2 The inherited owner can renounce ownership. Informational Accepted governance responsibility. Production operations must not renounce accidentally.
I3 Integer division can leave negligible claim dust. Informational Accepted accounting dust.

Reassessment triggers

  • The oracle is operated by one key, one process, or one RPC endpoint.
  • Confirmation monitoring or the manual close runbook is unavailable.
  • The selected FTSOv2 feed is inactive, economically weak, or unsuitable for four-decimal storage.
  • Frontends submit trades with zero slippage protection.
  • autoVL is enabled in production.
  • Owner or oracle authority is described as trustless.

Executable assumptions live under test/security/. End-to-end lifecycle behavior is covered by test/integration/FtsoV2Finalization.t.sol, source behavior by test/feeds/FtsoV2PriceSource.t.sol, and stateful accounting by test/invariant/HighLowInvariant.t.sol.

Security contact: a16k-lab, info@a16.com.

There aren't any published security advisories