Skip to content

sneg55/SealedIP

Repository files navigation

SealedIP

A trustless sealed-bid auction protocol for licensing IP on Story, built on Confidential Data Rails (CDR).

Live marketplace → sealedip.com · Documentation → docs.sealedip.com

Bidders encrypt their bids into CDR vaults. A custom on-chain read condition keeps every bid unreadable until the auction's deadline passes and the auction is triggered. At settlement the contract re-verifies each revealed bid, picks the winner, mints a Story PIL license token, pays the seller, and refunds every loser: all in a single transaction.

Built for the CDR Hackathon (Story Foundation), May 27 – June 5, 2026. Targeting Track 1: Technical Implementation.

Why

On-chain sealed-bid auctions usually use commit-reveal, which has a fatal flaw: a losing bidder can simply refuse to reveal and grief the auction. CDR's threshold decryption removes that escape hatch: bids are revealed at the deadline by a validator quorum regardless of bidder cooperation. Combine that with Story's license tokens and royalty rails and you get atomic, trustless settlement of an IP license auction: no operator ever touches the bid amount, and no single party can decrypt a bid early.

How CDR is used (the technical core)

  • One CDR vault per bid. allocateBidSlot calls CDR.allocate(...) to reserve a vault, escrows the bidder's deposit, and binds the vault to a read condition. submitEncryptedBid writes the TDH2-encrypted bid payload into that vault.

  • AuctionRevealCondition: a multi-step, cross-contract read condition (contracts/src/conditions/AuctionRevealCondition.sol). A vault becomes readable only when both gates pass:

    1. block.timestamp >= deadline, and
    2. SealedAuction.isTriggered(auctionId) == true.

    The second gate is a live state read into another contract, so a bid cannot be decrypted merely because the clock advanced: someone must also have called trigger(). The two gates are independent, gated entirely on-chain.

  • Composable, atomic settlement. settle(auctionId, reveals[]) re-verifies every bid signature (eth-signed-prefix ecrecover), rejects any reveal exceeding its deposit, selects the highest valid bid at or above reserve, mints a Story PIL license token to the winner, transfers the winning amount to the seller, and refunds the winner's overpayment plus every losing deposit. If any step would revert, the whole settlement reverts: partial settlement is impossible.

A malicious orchestrator can therefore only censor (which auto-refunds), never forge a winner or pay a non-winner.

Lifecycle

list  →  bid (allocate vault + encrypt + submit)  →  trigger at deadline  →  validators reveal  →  settle (mint + pay + refund), one tx

Full walkthrough: docs.sealedip.com/protocol/lifecycle and the in-app how-it-works page.

Live deployment (Story Aeneid testnet, chain 1315)

Contract Address
SealedAuction 0xb41B87f2E58E3f6139d6B6D2323C7AdFd47FC9ee
AuctionRevealCondition 0x1A3cCd475CCFb47D1353f62F3bca6DEfAC3D69bC
CDR (Story system contract) 0xCCCcCC0000000000000000000000000000000005
Story PIL license token 0xFe3838BFb30B34170F00030B52eA4893d8aAC6bC

The canonical list lives in sdk/src/constants.ts (redeployed 2026-05-29 for the multi-step reveal condition). A demo lot is seeded and live at sealedip.com.

Repository layout (monorepo)

SealedIP/
├── contracts/   # Solidity (Foundry): auction state machine + custom CDR conditions
│   ├── src/conditions/AuctionRevealCondition.sol   # the multi-step read condition
│   ├── src/SealedAuction.sol                        # state machine + atomic settle
│   ├── src/interfaces/ICDR.sol                      # minimal CDR interface we use
│   └── test/                                        # 43 Foundry tests
├── sdk/         # TypeScript: CDR encryption, bid submission, settlement helpers
├── web/         # Next.js + shadcn marketplace (bidder, seller, trust pages)
└── docs-site/   # Docusaurus protocol + contract + security docs

Run it

# From the repo root: shared TS dev tools (Biome + ESLint)
npm install

# Contracts (Foundry)
(cd contracts && forge build && forge test)      # 43 tests
npm run coverage                                 # 90%+ contract source-line gate

# Web (Next.js)
cd web && npm install && npm run dev              # http://localhost:3000

Deploying to Aeneid

Aeneid reports a near-zero EIP-1559 base fee, so an unpinned forge script broadcast goes out at ~15 wei and never mines. You must pin a legacy gas price on the CLI (neither vm.txGasPrice nor foundry.toml gas_price is honored by the script broadcaster):

cd contracts
DEPLOYER_PRIVATE_KEY=0x... forge script script/DeploySealedAuction.s.sol:DeploySealedAuction \
  --rpc-url https://aeneid.storyrpc.io --broadcast --legacy --gas-price 100000000000

A note on write conditions

CDR exposes both read and write conditions. We investigated a custom BidWriteCondition and deliberately did not ship it: an on-chain spike confirmed that the live CDR does not block writes for our writeConditionAddr = address(this) setup (a real submitEncryptedBid tx succeeds: 0x41c37e64…56f392e), so introducing a custom write condition carried regression risk with no functional gain. Write-access rules are enforced in SealedAuction Solidity instead.

Documentation & security

Full docs are published at docs.sealedip.com (source in docs-site/).

This is a hackathon prototype on testnet. It is covered by a Foundry test suite but is otherwise unaudited; do not assume mainnet-grade guarantees.

License

MIT.

About

Trustless two-sided sealed-bid auction protocol for licensing Story IP, built on CDR (Confidential Data Rails)

Resources

Stars

Watchers

Forks

Contributors