生き甲斐 · test results

Every test, on the record

This is everything I tested on the vault contract, version 3.0.1, before freezing it for launch: the review layers, the test suite, and a series of 16 attacks. Each attack transaction links to HashScan, so you can check it on the chain yourself.

This is my own testing, not an audit. An independent, professional audit comes before the vault ever handles real money. The background is in my story.

6
review layers
577
tests, all green
16
attacks
13
held cleanly
78
transactions on HashScan

Of the 16 attacks, 13 held on the frozen v3.0.1 code. One held on the previous version, on code that didn't change, and was not repeated. Two are known trade-offs, described under known limits. No internal check broke in any attack.

The contracts

Where the tests ran

All attacks ran on Hedera testnet, against vaults deployed from the same frozen v3.0.1 code (tag testnet-v3.0.1, commit 74b45c6). The attack vaults were set up to be broken on purpose; the vault you can try is C.

VaultContractRole
Vault B0.0.10764329v2.0.7.1, used for ATT-14
Vault C0.0.10974199the testnet vault you can try
Vault D0.0.10975125attack vault, wound down by ATT-21
Vault E0.0.11022200attack vault for ATT-13 and ATT-16
Before the attacks

Six review layers and 577 tests

LayerWhat it coversOutcome
Dependency scanAikido: dependencies and infrastructureTwo dependency CVEs fixed; contract clean
Static analysisSlither121 findings, each triaged; no real vulnerability
Self-reviewManual review, proven with mutation testingThree issues (M1, M2, M3) found and fixed
AI contract reviewsGemini on HbarVault, and separately on the pricing and swap librariesRail-snapshot isolation confirmed, M1/M2 corrections applied; fee math matches Uniswap V3 exactly; nothing Critical or High
Mathematical verificationHalmos, symbolic proofs of key propertiesThree properties proven; two left undecided by solver limits, covered by fuzzing and on-chain runs
48-hour live runThe dead-man switch on the real chainM2 confirmed and verified on-chain
The test suite. forge test on the released v3.0.1 code: 577 of 577 green, in both token orderings, once with the default profile and once with the CI profile (10,000 fuzz runs per test, invariants 256 × 100). Contract size 23,748 bytes, under Hedera's 24,576-byte limit.
The attack series

16 attacks, each one on the chain

An attacker agent came at the vault the way real attackers have come at vaults over the past ten years. Each attack checked seven internal invariants before and after. Open an attack to read what it tried, why it was stopped, and its transactions; each one opens on HashScan. Two attacks needed no transaction: they were read-only checks against the contract.

ATT-01 Access control (all protected entry points)Protected calls revert (16 calls) Held16 tx

The attack. A stranger's wallet tries all 16 functions that only the owner, the operator or a depositor themselves may call: opening and closing positions, changing settings, cancelling someone's deposit.

Why it held. Every one of those functions checks who is calling. All 16 calls were refused (NotOwner, NotOperator, NotEntryOwner).

Recorded result: PASS. Vault D.

ATT-04 Owner rug (reserve/fee/cap limits)Owner rug (reserve withdrawal, fee flip, cap manipulation) Held8 tx

The attack. The owner, me, tries to use its own legitimate powers to get at participants' money: withdrawing the operational reserve, pointing the fee at itself, and setting the deposit cap to 1 to trap people in.

Why it held. The reserve is a separate gas pot, so withdrawing it touched nothing of the participants. Changing the fee recipient created no shares, because a fee only arises on real profit at withdrawal. The deposit cap only limits new deposits: a withdrawal went through while the cap was 1. Vault value and total shares stayed the same.

Recorded result: PASS — owner power bounded, NAV-for-users unchanged. Vault D.

ATT-05 Queue-griefingQueue griefing (dust, empty push, foreign cancel, invalid index) Held4 tx

The attack. Clogging the deposit queue so other people can't get through: dust deposits of 1 tinybar, empty deposits, cancelling someone else's entry, and pointing at a queue position that doesn't exist.

Why it held. There is a minimum deposit, an empty deposit is refused, only the person who queued an entry can cancel it, and an invalid position is rejected. All four calls were refused.

Recorded result: PASS. Vault D.

ATT-06 Reentrancy (v3.0.1 cancel-refund path)Reentrancy on payout paths (incl. the new cancel refund) Held6 tx

The attack. Re-entrancy, the pattern behind some of the largest hacks: a hostile contract receives a refund and, during that payout, calls back into the vault to cancel, claim or withdraw again, hoping to be paid twice.

Why it held. Every payout function is locked while it runs. All three call-backs were rejected, and the contract received exactly one payout of 5 HBAR.

Recorded result: PASS — nonReentrant, single payout. Vault D.

ATT-07 Cross-user isolationCross-user (another user's shares, deposit, claimable) Held5 tx

The attack. One participant tries to reach another participant's money: cancel their deposit, withdraw more shares than they own, or claim someone else's payout.

Why it held. Shares and payouts are kept per wallet. You can only cancel your own entry, withdraw your own shares and claim your own balance. All five calls were refused.

Recorded result: PASS. Vault D.

ATT-08 Dead-man → fee-free emergency exitDead-man mechanism (M2) Heldread-only

The attack. The other way round: does the emergency exit really open when the bot goes silent, and can an ordinary participant use it without me?

Why it held. Before the 48 hours were up, the emergency functions were refused. After 48 hours without a heartbeat, a participant who isn't the owner could start closing positions herself, without a fee. Checked with a read-only call, so nothing was changed.

Recorded result: PASS — emergency exit opens for non-owners, proven non-destructively. Vault D.

No transaction: a read-only call against the contract, nothing was broadcast.

ATT-11 Cancel timing / delayFree look / cancel delay Held2 tx

The attack. A free bet: queue a deposit, watch for an hour whether the price moves your way, and cancel if it doesn't. The other participants would pay for that option.

Why it held. A deposit can't be cancelled during its first hour. The immediate cancel was refused (CancelNotYetAllowed).

Recorded result: PASS — DEPOSIT_CANCEL_DELAY enforced. Vault D.

ATT-13 Fee dodging via pool skewBypassing the fee gate via a skewed pool Held1 tx

The attack. Dodging the 15% fee by pushing the pool price just before your withdrawal is processed, so your profit looks smaller than it is.

Why it held. The vault only processes the queue when the live price is close to its 30-minute average. With the price pushed 253 ticks away (the limit is 200), processing was refused. A manipulated pool makes the withdrawal wait; it doesn't give it a better price.

Recorded result: PASS — processQueue reverts TwapSpotDeviationTooHigh. Vault E.

ATT-14 Reward-pool manipulation + 97% floorReward floor Held, carried over5 tx

The attack. Manipulating the pool of the reward token so the vault sells its SAUCE rewards at a bad price.

Why it held. A reward swap must return at least 97% of the averaged price, and the pool price must be within its band. It held live on v2.0.7.1, and that code is byte-identical in v3.0.1.

Recorded result: PASS-INHERITED (see §4.3). Vault B (v2.0.7.1).

ATT-16 Inheritance after full exit (R-1/M2)R-3 bucket inheritance after a full exit Known trade-off13 tx

The attack. After everyone has left, a newcomer deposits into the nearly empty vault and collects the rewards that were still being released to the people before them.

How it is contained. The contract doesn't prevent this. My operations do: no fresh deposits into an emptied vault while rewards are still being released.

Recorded result: FINDING-BY-DESIGN (see §4.2). Vault E.

ATT-17 Solvency gate (v3.0.1-specific)Bypassing the solvency gate Held3 tx

The attack. Forcing withdrawals the vault can't cover, to cause short payouts or a stuck queue.

Why it held. You can only withdraw your own shares, so an attacker's withdrawal is small compared with what the vault holds free. The contract also refuses to process a withdrawal it can't pay in full. Three full withdrawals were processed cleanly.

Recorded result: PASS — withdrawals capped at own shares, wallet covers. Vault D.

ATT-18 Rail snapshot (v3.0.1-specific)Manipulating the rail snapshot Held1 tx

The attack. Feeding the vault an old or false snapshot of its positions, so it prices deposits wrongly.

Why it held. Anyone may refresh the snapshot, but it can only record the live position amounts, and it is wiped on every position change. Pricing always reads the live positions.

Recorded result: PASS — snapshot cleared on position change, price always live. Vault D.

ATT-19 collectFees abusecollectFees abuse Held1 tx

The attack. Calling the function that collects the trading fees the positions earned, to grab them or send them elsewhere.

Why it held. Only the operator may call it. The call was refused (NotOperator).

Recorded result: PASS — onlyOperator. Vault D.

ATT-20 Child records / position capChild records beyond the 50 limit Heldread-only

The attack. Driving up the number of positions until one processing step needs more work than Hedera allows, so the vault gets stuck.

Why it held. Only the operator can open positions, with a hard limit of 8. A ninth was refused, and each step stays well under Hedera's limit (14 of 50 child records).

Recorded result: PASS — cap of 8 positions, 9th reverts TooManyPositions; processQueue(50)@8 = 1 child record. Vault D.

No transaction: a read-only call against the contract, nothing was broadcast.

ATT-21 M3 permissionless forceWindDownM3 permissionless wind-down Held1 tx

The attack. With the bot gone for 48 hours plus seven days, can a stranger wind the whole vault down, and can they profit from doing it?

Why it held. Anyone can wind it down, but it only opens the exit. Nothing was drained, no one's shares changed, and the caller received exactly her own share and paid the gas.

Recorded result: PASS (see §4.1). Vault D.

ATT-22 Depeg + stolen operator key (R-9)R-9 depeg + stolen operator key Known trade-off, bounded12 tx

The attack. Someone steals the operator key and, during a sustained stablecoin de-peg, swaps the vault's HBAR into USDC at a bad rate.

How it is contained. This is a known limit, not fully blocked. The daily swap cap in the contract bounds the damage, a short spike is refused, the bot halts swaps during a de-peg, and the monitor raises an alarm. Four swaps went through, the fifth was refused.

Recorded result: BOUNDED-LOSS (see §4.4). Vault D.

The four outcomes that matter most

The exit, and the known limits

ATT-21 · held

Anyone can open the exit

After 48 hours without the bot plus seven days of grace, a wallet that wasn't mine called the wind-down. It only opened the exit: no positions were drained, no one's shares changed, and the caller paid only gas (−0.202 HBAR). Her share of the payout was exactly her 17.24% pro-rata, the same formula as everyone. 11 of 11 checks green.

The wind-down on HashScan

ATT-22 · bounded

Stolen operator key during a de-peg

During a sustained stablecoin de-peg, someone holding the operator key could swap HBAR to USDC at a bad rate. Measured on vault D: four swaps went through and rotated 83.8% of the daily cap; a fifth was refused by the contract. A short price spike is caught; only a de-peg that lasts at least 30 minutes gets through.

Bound: damage per day ≤ de-peg × daily-cap fraction × vault value, and never beyond the amount rotated. Three mitigations: the daily cap in the contract, a de-peg halt in the bot, and the independent monitor.

ATT-16 · trade-off

Rewards left in an emptied vault

If everyone leaves and a new depositor comes in while rewards are still vesting, that newcomer inherits those rewards. On vault E a 10 HBAR deposit inherited about 14.98 HBAR. The contract doesn't prevent this; an operational rule does: no fresh deposits into an emptied vault while rewards remain.

ATT-14 · carried over

The reward floor

Held live on v2.0.7.1 (vault B). The attacked code is byte-identical in v3.0.1, and repeating it on testnet isn't possible: it needs about 40,000 SAUCE through the pool, and only about 263 exist there. So it counts as carried over, not as one of the 13.

The monitor. A monitor runs around the clock, separate from the bot, with six detectors and a hash-chained journal. During ATT-21 it raised a critical alert on the wind-down by a wallet that wasn't mine, so a real action like that on mainnet would be seen right away.
Before mainnet

What still comes first

Each transaction can also be read straight from the Hedera mirror node: testnet.mirrornode.hedera.com/api/v1/transactions/<id> or /api/v1/contracts/results/<0x-hash>.