Audit status
This page is the honest read on the security posture of the current SealedIP deployment.
Prototype build, testnet only
The current deployment is unaudited. It runs on Story Aeneid testnet (chain id 1315), with testnet WIP, against contracts that were deployed and redeployed multiple times during the CDR Hackathon (May 27 to June 5, 2026). Do not assume mainnet security guarantees.
What's on-chain
| Item | Value |
|---|---|
| SealedAuction | 0xb41B87f2E58E3f6139d6B6D2323C7AdFd47FC9ee |
| AuctionRevealCondition | 0x1A3cCd475CCFb47D1353f62F3bca6DEfAC3D69bC |
| CDR (Story system contract) | 0xCCCcCC0000000000000000000000000000000005 (not verified on Storyscan) |
| Source license | MIT |
| Solidity version | 0.8.26 |
| Optimizer runs | 200 |
What's covered by tests
43 Foundry tests passing across three suites.
BidPayload
- Encoding / decoding round-trip preserves all fields
recoverSignerreturns the correct address for valid signaturesrecoverSignerrejects tampered amountsrecoverSignerrejects tampered nonces- High-s signatures rejected (EIP-2 low-s enforcement)
- Invalid payload length reverts with
InvalidPayloadLength - Invalid signature length reverts with
InvalidSignatureLength
AuctionRevealCondition
checkReadConditionreturns false before the deadlinecheckReadConditionreturns false at deadline but before triggercheckReadConditionreturns true once deadline elapsed AND auction triggeredregisterreverts when called by a non-registrarregistersucceeds when called by the registrar
SealedAuction — creation and reserve
createAuctionemitsAuctionCreatedevent and stores record- Rejects past deadlines (
DeadlineInPast) submitEncryptedReservestores ciphertext and setsreserveHasCiphertextsubmitEncryptedReservereverts on double-write (ReserveAlreadyWritten)submitEncryptedReservereverts when called by non-seller (NotSeller)
SealedAuction — bidding
allocateBidSlotpulls deposit and allocates a CDR vault slot- Reverts past deadline (
BiddingClosed) - Reverts on zero deposit (
ZeroDeposit) submitEncryptedBidblocks non-bidder writes (NotBidder)- Blocks double-write of ciphertext (
CiphertextAlreadyWritten)
SealedAuction — trigger / settle
triggerflips state at deadline only (DeadlineNotReachedrevert otherwise)settlepicks highest valid bid, verifies reserve reveal, mints license, pays out, refunds loserssettleskips amount-exceeds-deposit attackssettleskips bad signaturessettleskips slots without ciphertextsettlereverts withInvalidReserveRevealon a bad reserve reveal whenreserveHasCiphertextis true- No-winner path (no bid clears reserve) refunds all deposits and emits
AuctionExpiredNoWinner
Run locally:
cd contracts && forge build && forge test
Source-line coverage for production contracts is gated at 90%:
npm run coverage
Verified live end-to-end on Aeneid
Beyond the Foundry suite, the full lifecycle has been run against the real CDR threshold network on testnet: list, seal reserve, two sealed bids, trigger, CDR threshold-decryption of both bids AND the sealed reserve, and an atomic settle that mints a Story PIL license to the winner. This exercises the one leg the Foundry tests mock: real CDR decryption at settle.
| Step | On-chain evidence (auction #2) |
|---|---|
| Trigger | 0xe18035c9ef7cc4cd2d15ca46ffa7ad49fd9240bea25c1ca45549b321dd3ab89c |
| CDR decrypt bid A (0.5 WIP) | read tx 0xf4a3f7c1a75ad2d020f86c024ee5428c43b2f10ac17c4faf2b70f8b442393b57 |
| CDR decrypt bid B (1.0 WIP) | read tx 0x2540b9b58b34ef1e2843e85c01d3c3b4f5bb2f1ef04b19168c811837f632a116 |
| CDR decrypt sealed reserve (0.1 WIP) | read tx 0x57a79e48b5593ddef982e604c7d7fe4776649304a0ba52d6b6456bb71bb0e8f3 |
| Settle | 0x15003bbcfad735a4222cc2b20e7684d8906c8f1c75e14d9374b111f9c4e5be04 (status 1) |
| Outcome | winner bidder B at 1.0 WIP; license token #72662 minted to the winner |
The harness is sdk/scripts/live-settle-test.ts (places two bids, then runs the
orchestrator: wait, trigger, decrypt every vault, settle). Every hash above is
checkable on Storyscan.
What's NOT covered by tests
- Gas-limit boundary tests — what happens when settling with hundreds of bidders
- Reentrancy fuzzing — manual code review covers the patterns, but no fuzz suite
- End-to-end with real CDR (automated) — the Foundry suite mocks the CDR contract. The real CDR network has been exercised manually and settles correctly (see Verified live end-to-end), but there is no automated integration suite against live CDR
- Story Protocol contract behavior changes — if Story redeploys
PILicenseTemplate or changes the mint signature,
settlecould revert. No automated integration tests run against live Story contracts. - Floor-0 default edge cases — the behavior when no reserve is sealed is tested; extreme bid values near zero are not fuzz-tested.
Static analysis
No automated static analysis (Slither, Mythril, Echidna) has been run on the contracts. These are typically the first step of a professional audit.
What passing tests don't prove
The tests verify the documented behavior of the contract. They do not prove:
- Threshold cryptography correctness. The TDH2 implementation lives in CDR, not SealedIP. We trust CDR's implementation.
- Validator set integrity. A colluding validator set can defeat the protocol regardless of contract correctness.
- Off-chain encryption service correctness. The encryption service is a TypeScript wrapper around a Rust WASM module. Bugs there could leak plaintext.
- Front-end correctness. The marketplace UI handles wallet flows; bugs there could mislead users.
- PIL terms semantics. We mint a Story PIL license at settle. The legal effect of that license depends on Story Protocol's enforcement, not ours.
- CDR reveal-integrity. The contract verifies the seller and bidder signatures on revealed amounts, but cannot verify that the revealed amount matches what was originally encrypted in the CDR vault.
Path to audit-readiness
If you wanted to deploy SealedIP to mainnet, the things to do first:
- Static analysis pass — Slither and Mythril against
SealedAuction.solandBidPayload.sol. Address findings. - Reentrancy reordering — move state transitions before external calls
in
settle()(currently state is written after transfers). - Gas-limit fuzzing — fuzz settlement with varying bid counts; document the practical max or add a pull-payment fallback.
- Real-CDR integration tests — run end-to-end against an Aeneid CDR fork.
- Independent audit — engage a security firm familiar with threshold-crypto-adjacent systems.
None of this is hard. It is not in scope for the hackathon.
Reporting issues
See Reporting vulnerabilities for the disclosure path.