Spec · HardeningBuilding now

How the Solidity holds up the math

The on-chain surface is deliberately minimal — the complex math lives off-chain in auditable libraries; the contract is an ERC-20-with-rules that enforces the invariants every downstream price depends on. This spec enumerates the surface, the invariants, the access-control posture, and the path to a formal audit.

Contract surface

A deployed covenant is a single contract on Base. It extends OpenZeppelin’s ERC-20 with three bounded extensions:

MethodCallerPurpose
constructor(R, s, T, e)Platform deployerMints 10,000 tokens to the treasury; sets the four immutable parameters
allocate(backer, amount)Platform-onlyRecords backer allocation against treasury tokens during the funding phase
distribute(teb)Platform-onlyRecords a quarterly TEB report; dividend = s × teb pro-rata; updates on-chain payout index
claim(holder)Holder or platformPulls accrued dividend to the holder's wallet (pull-payment pattern)
unlock()Platform-onlyIrreversibly enables token transfer once the three pre-IPO triggers clear
transitionToPersonToken()Platform-onlyAt year T, switches distribution logic from Phase 1 (s × TEB) to Phase 2 (e × TEB)
pause()Platform emergencyHalts transfers + distributions during investigation (see delisting framework)

That’s the whole surface. Everything else — forecast, conviction, pricing, cross-listing cap-check — runs off-chain in libraries covered by 75 passing tests. The contract is the arithmetic that absolutely has to be on-chain; the rest is an implementation detail of the platform.

On-chain invariants

Eight invariants that must hold across every block. Violation of any one is a critical-severity bug:

#InvariantEnforcement
I₁Token supply is exactly N=10,000N = 10{,}000 foreverNo mint() / burn() public; constructor mints once, never again
I₂Sum of holder balances + treasury balance = totalSupplyERC-20 default; checked by every transfer path
I₃funded_amount monotonic non-decreasing until unlock()allocate() guards against negative or zero amounts; no withdrawal path pre-unlock
I₄No transfer executable while lockedtransfer() reverts with LOCKED error if !unlocked; emits Locked event on attempt
I₅unlock() is one-wayOnce unlocked flag flips true, no path sets it back to false; no re-lock() method exists
I₆Phase transition is one-way, fires exactly once, at year TtransitionToPersonToken() checks both phase == ISA and block.timestamp >= T; storage flag prevents re-entry
I₇AON escrow returns funds if minimum threshold not metPer SEA Rule 15c2-4. settle() validates clearing; on failure refundAll() releases every escrowed bid atomically.
I₈Cap-ledger 25% invariant cross-validated by two algorithmsAnalytic transition-scan + monthly-bucket scan; both must agree before any new obligation is admitted. See /spec/cross-listing-math.

Why it mattersEach invariant has a Solidity unit test plus an invariant-fuzzing test (via Foundry) that attempts randomized call sequences to break it. The invariants are the foundation every off-chain price depends on — if the on-chain supply can be inflated, every price on the secondary market is wrong by the same factor.

Access control

Three roles, each with strictly bounded authority:

RoleAuthorized actionsHow assigned
Platform adminallocate(), distribute(), unlock(), transitionToPersonToken(), pause()Multi-sig (3-of-5) controlled by Preflop operations; rotateable
IssuerView-only on their covenant; initiate the quarterly report flow off-chain which the platform ratifies on-chainBound to the issuer wallet in constructor
Holderclaim() for their own accrued dividend; transfer() once unlockedHeld by any wallet with a non-zero balance

Platform admin is the only privileged role. The multi-sig means no single key compromise enables unauthorized allocate / distribute / unlock. Transitions (unlock, Phase 2) require an explicit multi-sig execution trail recorded on-chain.

Upgrade posture · immutable

Deployed covenants are immutable. No proxy, no upgrade path, no admin-callable logic swap. Every operational parameter that could change (timing, thresholds, fee routing) is off-chain. The on-chain contract is a 400-LOC frozen artifact.

The tradeoff is explicit: we give up flexibility in exchange for a simpler audit surface and a guarantee to holders that the terms at issuance cannot be retroactively modified. If a bug is discovered, the path is:

  • Minor (cosmetic / event emission): accept, document, fix in next vintage.
  • Moderate (auxiliary feature): pause() affected contracts, deploy a parallel migration path, holders opt-in to migrate.
  • Critical (invariant-breaking): pause() all affected contracts, governance-approved emergency migration plan with mandatory holder notification.

Audit roadmap

StageTarget horizonStatus
Internal review + Foundry invariant suiteDone75+ tests + fuzzing across all six invariants
Slither + Mythril static analysisDoneNo high-severity findings outstanding
External security audit (tier-1 firm)Pre-mainnet launchPlanned; budget earmarked
Bug bounty (live)Mainnet launchImmunefi program planned; scales with TVL
Formal verification (Certora or equivalent)Post-launch, 12 monthsLong-term goal; targeted at the six invariants specifically

Why it mattersFormal verification on six named invariants is a realistic target for a contract this small. Most DeFi protocols stop at audit + bounty because the surface is too large; Preflop’s minimal-surface design means the invariants are tractable to prove mechanically.

Known risks & mitigations

RiskSeverityMitigation
Platform multi-sig key compromiseHigh3-of-5 threshold; keys rotated quarterly; HSM for primary signers; incident response playbook
Issuer dispute over TEB reportingMediumOff-chain arbitration; on-chain record of every report with content hash; delisting framework for uncured disputes
Layer-1 (Base) chain-level incidentLow-MediumBase is Ethereum L2 secured by Ethereum mainnet; Preflop tokens are portable if Base migrates/sunsets (escape hatch in the platform, not in the covenant contract)
Oracle dependenceLowMinimal — distribute() takes TEB as input from the platform (which derives it off-chain from Plaid + tax attestations); no external oracle dependency in the hot path
Reentrancy on claim()LowPull-payment pattern; OpenZeppelin ReentrancyGuard applied; state mutations precede transfers
Front-running of allocate()LowAllocations are platform-only via signed authorization; no public allocate() for backers to front-run

Related specs