# auco
**Sealed-bid auctions for Solana, powered by [Arcium](https://arcium.com) MPC.**
Spin up a Vickrey or first-price auction in ~10 lines.
```ts
import { createAuction, configure } from 'auco-sdk';
configure({ connection });
const auction = await createAuction({
type: 'vickrey', // second-price sealed bid
asset: nftMint,
reservePrice: 1 * LAMPORTS_PER_SOL,
duration: 86_400,
authority: sellerKeypair,
});
// Bidders submit encrypted bids — never revealed to anyone, ever.
await auction.bid(bidderKeypair, 5 * LAMPORTS_PER_SOL);
// On settlement, MPC reveals only the winner + winning price.
// Losing bids stay encrypted forever.
await auction.settle(sellerKeypair);
```
That's the whole pitch.
---
## Why this exists
Every "sealed-bid" auction shipping on Solana today is sealed in name only.
The auctioneer (a backend, a relayer, a privileged account) holds the bids in
plaintext and is trusted to settle honestly. The mechanic only works if you
believe nobody peeks.
Vickrey auctions — second-price sealed-bid — are the textbook gold standard
because the dominant strategy is to bid your true valuation. **But that
property only holds if bids are actually sealed.** Otherwise rational bidders
shade down, and the mechanic degrades to a worse version of first-price.
Auco uses [Arcium MPC](https://arcium.com) so that:
- Bids are encrypted in the bidder's browser before they leave.
- The on-chain account stores ciphertext, not amounts.
- A multi-party computation cluster compares bids inside MPC and reveals
only the winner + winning price.
- **Losing bids are never decrypted. Ever.**
## Comparison
| | Auco (this SDK) | Commit-reveal | Off-chain "sealed" backend |
| ---------------------------- | ----------------------- | ------------------- | -------------------------- |
| Trust model | Arcium MPC threshold | Honest reveals | Trust the operator |
| Reveal phase required | **No** | Yes | No |
| Bidders must come back? | **No** | Yes (else forfeit) | No |
| Losing bids stay private? | **Yes, forever** | No (revealed) | Trust the operator |
| Sealed reserve? | **Yes** (optional) | No | No |
| Lines of code for a dev | **~10** | ~200 (custom) | N/A |
| vs raw Arcium examples (LOC) | **~10 vs ~200** | — | — |
## Install
```bash
pnpm add auco-sdk
```
Peer deps: `@solana/web3.js`, `@coral-xyz/anchor`, `@arcium-hq/client`.
## API
### `createAuction(options)`
Creates a fresh auction PDA on chain.
| option | type | default | notes |
| --------------- | -------------------------- | ----------- | ----------------------------------------------------------- |
| `type` | `'vickrey'` \| `'first-price'` | `'vickrey'` | Mechanic. |
| `asset` | `PublicKey` | required | What's being auctioned. Opaque to the contract. |
| `reservePrice` | `number` \| `bigint` \| `BN` | required | Minimum acceptable bid (lamports). |
| `duration` | `number` | required | Seconds from creation until settlement is allowed. |
| `authority` | `Keypair` | required | Seller. Receives proceeds. |
| `sealedReserve` | `boolean` | `false` | **Novel**: encrypt the reserve itself. See below. |
| `client` | `AucoClient` | configured | Optional override for the global client. |
### `auction.bid(bidder, amountLamports)`
Encrypts `amountLamports` client-side and escrows it in a per-bid PDA.
### `auction.settle(authority)`
Queues the MPC settlement computation. Anyone can call after `endsAt`, but
typically the authority does. State transitions: `open` → `settling` →
`settled` / `no-winner`.
### `auction.claimPrize(winner, bidAccount)` / `auction.claimRefund(bidder, bidAccount)`
After settlement, the winner pays the seller (and recovers their Vickrey
rebate); losers reclaim their full escrow.
### `auction.onSettled(cb)`
Polling-based subscription. Resolves the first time the on-chain auction
transitions to `settled` or `no-winner`.
## The "sealed reserve" stretch
Set `sealedReserve: true` and the reserve itself is encrypted under the MXE
cluster. Public-bid auctions structurally cannot do this — comparing a public
bid against a hidden reserve requires revealing one or the other. MPC just
does it.
```ts
const auction = await createAuction({
type: 'vickrey',
asset: nftMint,
reservePrice: secretMinimum,
sealedReserve: true, // ← only revealed if no bid clears it
// ...
});
```
This is genuinely new. We don't know of any other Solana auction that ships
it.
## Architecture
```
┌────────────────────────────────────────────────────────────────────┐
│ Bidder browser │
│ 1. generate ephemeral x25519 keypair │
│ 2. fetch MXE cluster pubkey │
│ 3. ECDH → shared secret → RescueCipher.encrypt(amount) │
└────────────────────────────────────────────────────────────────────┘
│ encrypted bid (32 bytes)
▼
┌────────────────────────────────────────────────────────────────────┐
│ arena_auction (Anchor program — name preserved for on-chain id) │
│ • place_bid — escrow SOL, store ciphertext, queue MPC │
│ • settle — queue MPC settlement │
│ • claim_prize / claim_refund — pay seller, refund losers │
└────────────────────────────────────────────────────────────────────┘
│ ArgBuilder + queue_computation
▼
┌────────────────────────────────────────────────────────────────────┐
│ Arcium MXE cluster │
│ Runs encrypted-ixs/src/lib.rs: │
│ • submit_bid — streaming max & second-max over encrypted │
│ bids; constant on-chain state │
│ • settle_auction — reveals winner pubkey + both prices; │
│ program picks based on type │
│ Signs output; callback updates on-chain auction. │
└────────────────────────────────────────────────────────────────────┘
```
The MPC state is `(highest_amount, second_amount, highest_bidder_pubkey,
bid_count)` — all encrypted, constant size, updated obliviously per bid.
## Repo layout
```
auco/
├── packages/sdk/ # auco-sdk — the public TS API
├── apps/demo/ # Next.js showcase: expired-.sol auctions
├── programs/arena_auction/ # Anchor program (Rust) — original deploy name
├── encrypted-ixs/ # Arcis MPC circuits (Rust)
└── scripts/init-comp-defs.ts # One-shot computation-definition init
```
## Demo
`pnpm dev:demo` boots two surfaces:
- **`/`** — the SDK product page. The pitch, the 10-line snippet, the
comparison table, the API.
- **`/vault-drops`** — *VaultDrops*, a fictional third-party marketplace
for premium `.sol` drops, with its own branding, that integrated this
SDK in ~12 lines. Every page has a floating **</> view integration**
button that reveals the actual SDK calls behind it.
The point of the showcase: a site author writes only the frontend (and an
optional user DB). The contract, MPC, encryption, settlement, refunds —
all behind the SDK.
The demo runs in **simulation mode** by default — same UX flow, same
encryption boundary, but a local stand-in for the MXE cluster so it works
offline. Wire `configure({ connection, programId })` with a deployed program
address to switch to live mode.
## Deploy
```bash
# 1. Build everything (Anchor program + Arcis circuits)
anchor build
arcium compile encrypted-ixs
# 2. Upload circuits, get the IPFS URLs, paste into
# programs/arena_auction/src/instructions/init_comp_defs.rs
# 3. Deploy
anchor deploy
# 4. Initialize the three computation definitions
pnpm tsx scripts/init-comp-defs.ts \
--rpc https://devnet.helius-rpc.com/?api-key=... \
--keypair ~/.config/solana/id.json
```
## License
MIT.
---
Built for the Solana Graveyard Hack 2026. Honest pitch: the SDK is the
contribution — every NFT marketplace, domain registry, RWA platform, and
DAO doing public sales has the same auction problem. Auco solves it once.