Proof, not promises.
Every number here is generated from an evidence file in the repository and carries the strongest label it has earned: local reproduction, simulation, testnet or mainnet. Unmeasured results say PENDING, never zero.
Headline results
An over-limit (6.00x) order sent directly to Desk.trade() on Monad testnet was mined and reverted by the contract with LeverageExceeded
A desk earned +2% over two closed trades on Monad testnet, graduated to tier 1 and was funded by the pool
A flat desk was closed on Monad testnet and its residual AUSD was paid by contract; the trader's higher balance was read back on an independent RPC
Completed Monad testnet results, each with its transaction. Mainnet results are not claimed; they are listed under “Not yet proven” and in the mainnet section below.
1. Testnet mechanism proof
Method
Real testnet transaction; receipt and post-state read on an independent RPC at the receipt block
source: scripts/src/testnet-demo.ts
Method
receipt, Graduated event and desk state read on the independent RPC at the receipt block
source: scripts/src/verify-graduation.ts
Method
sender 0x9c4f9b38ce13a1552aa6fcb505cffb3e70fafcc0 is the keeper wallet; receipt success and tier 1 read on the independent RPC; gas 518571
source: scripts/src/verify-graduation.ts
Method
Relayer simulated, then submitted with gas 698427; position lots read on the verification RPC at the receipt block (359) equal the TradeExecuted lotsAfter
source: scripts/src/graduation-attempt.ts
Method
Real testnet transaction; receipt and post-state read on an independent RPC at the receipt block
source: scripts/src/testnet-demo.ts
Method
read-only eth_call at a pinned block on two independent RPC providers; readbacks agree
source: scripts/src/gate0.ts
Method
read-only eth_call getExchangeInfo() and ERC20 symbol() at a pinned block on two RPCs
source: scripts/src/gate0.ts
Method
read-only eth_call getMinAccountOpenCNS() at a pinned block on two RPCs
source: scripts/src/gate0.ts
Method
read-only eth_call getPerpetualInfo at sampled historical blocks; age = block.timestamp - markTimestamp; window blocks 68991040-68993265, stride 25
source: scripts/src/mark-staleness.ts
Mark age on testnet over the sampled window: median 20s, max 49s (BTC). Desks refuse new risk whenever the mark is older than 60 s.
Not yet proven
Pending items are shown as pending, never as zero. Nothing here is forced: a profit claim needs genuine realized profit above the high-water mark.
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
2. Contract deployments
- Network
- Monad testnet (chain 10143)
- Mainnet
- not deployed
3. Guarded order rejection
Frontend validation explains a block before signing. The contract rejection below is the one that matters: the order goes straight to Desk.trade() with no UI involved.
Method
Direct Desk.trade() call bypassing any frontend; Perpl bytecode harness
source: contracts/test/unit/DeskPolicy.t.sol::test_leverage_oneUnitOverCapRejected
Method
Real testnet transaction; receipt and post-state read on an independent RPC at the receipt block
source: scripts/src/testnet-demo.ts
4. Live venue integration
Method
cd contracts && FORK_TESTNET=true forge test --match-contract TestnetFork -vv
source: contracts/test/perpl/TestnetFork.t.sol
Fork run log
[PASS] test_fork_deskOpensRealPerplAccountAndPolicyHolds() (gas: 6535834) Logs: live testnet BTC mark (PNS): 829935 mark valid at fork block: true fork block.timestamp: 1791386710 fork block.number: 69005251 perp markTimestamp: 1791386680 perp oracleTimestampSec: 1791386662 lots filled against live testnet book: 100 desk equity after fill (base units): 99968366 lots after reduce-only close: 0
5. Claim verification
A payout counts only when an independent RPC reads the higher balance. The forced mismatch fixture proves an unverified state can never become success: it ends in verification failed. See packages/core/test/core.test.ts, "forced mismatch fixture ends in verification_failed".
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
6. Accounting
Method
Independent Fraction-based model of PRD v3 rules vs outputs observed from real desk executions on Perpl exchange bytecode rc_v1.1.7-203.
source: proof/reference_model/run_reference.py
7. Security and invariant tests
Method
cd contracts && forge test --json --no-match-contract TestnetFork
source: contracts/test
Method
forge invariant runs; coverage: 1300 desks, 723 random trades, 491 graduations, 741 settlements, 1 claims
source: contracts/test/invariant/PoolInvariant.t.sol
ReferenceVectorsTest3/3
- test_vectors_accrual()
- test_vectors_claims()
- test_vectors_settlements()
SettlementMathTest8/8
- testFuzz_accrue_chunkedEqualsSingle(uint256,uint256,uint256)(512 runs)
- testFuzz_accrue_neverExceedsCap(uint256,uint256,uint256,uint256)(512 runs)
- testFuzz_claimSplit_conservesGross(uint256,uint256,uint256,uint16,uint16)(512 runs)
- testFuzz_waterfall_conservesCashAndOrdersPriority(uint256,uint256,uint256,uint256)(512 runs)
- test_accrue_prdTier1Month()
- test_claimSplit_prdIllustrativeMonth()
- test_waterfall_prdExampleExactTradingLoss()
- test_waterfall_severeGapExhaustsResidual()
PoolInvariantTest6/6
- invariant_cashBasisIdentity()(64 runs)
- invariant_closedDesksHoldNothing()(64 runs)
- invariant_feeSubledgerAndCap()(64 runs)
- invariant_idleBackedByCash()(64 runs)
- invariant_principalAndExposureLedgers()(64 runs)
- test_handlerCanTrade()
PerplProbeTest8/8
- test_probe_closeAndWithdrawEverything()
- test_probe_contractOwnedAccountOpensAndTrades()
- test_probe_deltaPnlTracksMark()
- test_probe_fokNoLiquidityReverts()
- test_probe_iocNoLiquidityDoesNotRevert()
- test_probe_markGoesStaleAfterMaxAge()
- test_probe_maxNegPnlRejectsOffMarketOpen()
- test_probe_venueClampsLeverageAboveListing()
GasProfileTest1/1
- test_gas_profile()
AttacksTest24/24
- test_attack_offMarketCloseIntoAccompliceBidRefused()
- test_caps_bootstrapImmediateOnlyBeforeFactoryWiring()
- test_caps_evaluationDesksDoNotTouchPoolExposure()
- test_caps_grossCapAcrossDesksCannotBeBypassed()
- test_caps_increaseIsTimelocked()
- test_caps_perDeskNotionalCap()
- test_caps_reductionAlwaysPossibleEvenOverCap()
- test_keeper_cannotGraduateIneligibleOrEnforceHealthy()
- test_lp_cannotWithdrawDeployedPrincipal()
- test_relay_alteredFieldsRejected()
- test_relay_expiredDeadlineRejected()
- test_relay_lowerNonceRejected()
- test_relay_malleableHighSRejected()
- test_relay_signatureForAnotherDeskRejected()
- test_relay_signedOrderStillPolicyChecked()
- test_relay_validSignedOrderExecutesOnce()
- test_relay_wrongSignerRejected()
- test_unauth_deskCannotDrawCreditForAnotherDesk()
- test_unauth_deskCannotUnderReportExposure()
- test_unauth_operatorCannotMoveFunds()
- test_unauth_poolMoneyPathsRequireRegisteredDesk()
- test_unauth_strangerCannotTradeClaimClose()
- test_venue_haltedExchangeBlocksTradingButEnforceStatePersists()
- test_venue_perplErrorsSurfaceNamed()
PairedDeskTest8/8
- test_paired_calm()
- test_paired_gap15_cap1000()
- test_paired_gap15_cap1500()
- test_paired_gap15_cap2500()
- test_paired_gap8_cap2500()
- test_paired_gapDown15_cap2500()
- test_paired_trend_delayedKeeper()
- test_paired_trend_keeperEachStep()
ReentrancyTest5/5
- test_reentry_claimDuringTrade()
- test_reentry_closeDuringTrade()
- test_reentry_enforceDuringTrade()
- test_reentry_graduateDuringTrade()
- test_reentry_tradeDuringTrade()
DeskLifecycleTest4/4
- test_evaluationTrade_opensAndClosesPosition()
- test_fullLifecycle_demoCohort_graduateTradeClaimClose()
- test_openDesk_ownsPerplAccountWithFullStake()
- test_predictDesk_matchesDeployment()
DeskPolicyTest28/28
- testFuzz_leverage_aboveCapAlwaysRejected(uint256)(512 runs)
- testFuzz_priceBand(uint256)(512 runs)
- test_control_healthyTraderFiftyTradesNoEnforcement()
- test_dailyLoss_breachBlocksNewRiskButAboveFloor()
- test_dailyLoss_measuredFromFirstTradeOfDay()
- test_dailyLoss_resetsNextUtcDay()
- test_floor_breachedDeskRejectsNewRiskAndReduce()
- test_floor_postTradeBreachRevertsWholeTransaction()
- test_leverage_exactlyAtCapAccepted()
- test_leverage_oneUnitOverCapRejected()
- test_leverage_zeroRejected()
- test_lots_zeroRejected()
- test_market_notAllowlistedRejected()
- test_negPnlStamp_perplRejectsFillFarFromMarkWithinBand()
- test_negPnlStamp_venueRefusesAddingToUnderwaterPosition()
- test_orderType_fokStampedAndRevertsAtomicallyWithoutLiquidity()
- test_orderType_iocWithoutLiquidityLeavesNoPosition()
- test_orderType_stampIsAlwaysImmediate()
- test_priceBand_appliesToClosesToo()
- test_priceBand_exactlyAtBandAccepted()
- test_priceBand_oneTickOutsideRejected()
- test_reduceOnly_largerThanPositionRejected()
- test_reduceOnly_withoutPositionRejected()
- test_reduceOnly_wrongSideRejected()
- test_side_invalidRejected()
- test_staleMark_enforceWaits()
- test_staleMark_refusesNewRiskAllowsReduceOnly()
- test_stamp_negPnlAndExecutionBlock()
DeskSettlementTest25/25
- test_claim_feesNettedFirstAndBookedOnce()
- test_claim_hwmPreventsReclaimAfterLossAndRecovery()
- test_claim_onlyTrader()
- test_claim_unrealizedProfitCannotBeWithdrawn()
- test_close_onlyTrader()
- test_close_voluntaryPaysNoKeeperAndRequiresFlat()
- test_enforce_bankruptPositionWithoutVenueInsuranceStaysEnforcing()
- test_enforce_breachSettlesWaterfallAndPaysKeeperOnce()
- test_enforce_dailyLossReason()
- test_enforce_gapPastStakeRecordsPrincipalLossAndZeroKeeper()
- test_enforce_healthyDeskRejected()
- test_enforce_partialCloseDoesNotSettleAndPaysNothing()
- test_factoryPause_blocksNewDesksOnly()
- test_fees_capStopsAccrualAndNewRiskButAllowsReduceAndEnforce()
- test_fees_chunkedCheckpointsCannotRoundFeesAway()
- test_fees_evaluationDeskAccruesNothing()
- test_fees_exposedIntervalAccruesExactlyOnceDespitePositionsAndCheckpoints()
- test_fees_externalLiquidationCannotEraseExposureTime()
- test_fees_flatFundedDeskAccruesNothingForAMonth()
- test_graduation_pausedPoolBlocksButCloseStillWorks()
- test_graduation_prematureRejectsOnchain()
- test_graduation_requiresFlat()
- test_graduation_requiresTradeCount()
- test_graduation_standardCohortRequires24h()
- test_settledDeskIsInert()
8. Paired-desk self-attack
One actor runs a long desk and a short desk, both graduated, scored together. This measures a scenario envelope; it is not a universal loss bound. Imprest makes no Sybil-resistance claim; it caps the damage with onchain gross-exposure and per-desk notional limits.
Data table: scroll sideways to see every column.
| Scenario | Move | Desk cap | Actor net | Principal loss | Pool profit share | Keeper | Pool net |
|---|---|---|---|---|---|---|---|
| calm_cap2500 | 0.5% | 2500.00 | 9.90 | 0.00 | 1.32 | 0.00 | 1.32 |
| gap15pct_cap1000 | 15.0% | 1000.00 | 6.73 | 18.03 | 18.62 | 0.00 | 0.60 |
| gap15pct_cap1500 | 15.0% | 1500.00 | 56.40 | 80.82 | 27.94 | 0.00 | -52.88 |
| gap15pct_cap2500 | 15.0% | 2500.00 | 155.73 | 206.39 | 46.56 | 0.00 | -159.83 |
| gap8pct_cap2500 | 8.0% | 2500.00 | 39.23 | 60.65 | 24.72 | 0.00 | -35.94 |
| gapdown15pct_cap2500 | -15.0% | 2500.00 | 156.08 | 206.30 | 46.60 | 0.00 | -159.70 |
| trend3pct_atomic_keeper_cap2500 | 3.0% | 2500.00 | 46.46 | 0.00 | 9.24 | 0.50 | 9.24 |
| trend3pct_delayed_keeper_cap2500 | 3.0% | 2500.00 | -1.21 | 0.00 | 9.24 | 0.50 | 9.24 |
All rows: LOCAL_REPRODUCTION on Perpl exchange bytecode, 100 AUSD stakes, 500 AUSD funded desks, AUSD units. Finding: under a 15% instantaneous gap, a per-desk notional cap of 2x desk size kept the pool net near zero; the deployment script uses that ratio. Early keeper enforcement acted as a free stop for the losing leg in the trend scenario.
Replay experiment: atomic enforcement vs keeper
Pre-registered before the first run: if the median overshoot gap against a 1-second keeper is under 10 bps, the atomic-enforcement headline is dropped. It was. In-transaction checks stop limit-breaking orders, but a pure price move still needs a keeper in both arms, and the tested order flow rarely produced an order one arm refused and the other accepted. The advantage shows only in the tail against slow keepers.
Method
Python simulation of PROTOCOL.md on real Binance 1 s BTC/ETH history; not the Perpl-bytecode harness. Breaches per arm: treatment 48, 1 s 48, 5 s 48, 10 s 48; max overshoot treatment 94.624 bps vs 10 s keeper 150.866 bps; pool loss beyond stake 0 in every arm.
source: proof/experiments/replay/replay.py
Data table: scroll sideways to see every column.
| Arm | Breaches | Median overshoot | P90 | Max | Pool loss beyond stake |
|---|---|---|---|---|---|
| Atomic (in-transaction) | 48/51 | 24.917 bps | 44.788 bps | 94.624 bps | 0 |
| Keeper 1 s | 48/51 | 24.917 bps | 44.788 bps | 94.624 bps | 0 |
| Keeper 5 s | 48/51 | 23.474 bps | 71.703 bps | 142.975 bps | 0 |
| Keeper 10 s | 48/51 | 24.634 bps | 69.506 bps | 150.866 bps | 0 |
9. Local Perpl reproduction
Perpl's own exchange bytecode (perpl-sdk, revision rc_v1.1.7-203-g0e5902dd) runs on a local EVM with Monad's 128 KiB contract limit. Findings recorded by the probe suite: a contract can own a Perpl account; IOC with no liquidity leaves no position while FOK reverts; Perpl clamps order leverage to the listing maximum instead of rejecting it, so the desk's 5x check is load-bearing; the stamped 50 bps negative-PnL cap refuses adding to a position under water.
Method
gasleft() delta around Desk.trade in contracts/test/perpl/GasProfile.t.sol
source: contracts/test/perpl/GasProfile.t.sol
forge Version: 1.5.1-stable · solc 0.8.28 (foundry.toml) · exchange sha256 9f0d259dd45bda91…
10. Mainnet dependency status
Method
read-only eth_call at a pinned block on two independent RPC providers; readbacks agree
source: scripts/src/gate0.ts
Method
read-only eth_call getExchangeInfo() and ERC20 symbol() at a pinned block on two RPCs
source: scripts/src/gate0.ts
Method
read-only eth_call getMinAccountOpenCNS() at a pinned block on two RPCs
source: scripts/src/gate0.ts
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Not yet measured. See docs/FINAL_STATUS.md for the gate that produces it.
source: pending
Method
Python simulation of PROTOCOL.md on real Binance 1 s BTC/ETH history; not the Perpl-bytecode harness. Breaches per arm: treatment 48, 1 s 48, 5 s 48, 10 s 48; max overshoot treatment 94.624 bps vs 10 s keeper 150.866 bps; pool loss beyond stake 0 in every arm.
source: proof/experiments/replay/replay.py
What needs mainnet, why, and what it costs is listed in Known limitations and Final status.