{"id":"412f234e5559d79208938c15a60e9684689b84fb91bc224bd8b0eb702918df88","pubkey":"2c917bfcfe4f3777ccacb4c968d6a3e9266d39a22db65c2cf2ca0c09fddf8638","created_at":1783579201,"kind":30817,"tags":[["d","nip-xx-dutch-auctions-reverse-procurement"],["title","NIP-XX: Dutch Auctions & Reverse Procurement"],["alt","Nostr Implementation Possibility: NIP-XX: Dutch Auctions & Reverse Procurement"],["client","NostrHub"]],"content":"# NIP-XX: Dutch Auctions & Reverse Procurement\n\n`draft` `optional`\n\nThis NIP defines time-based price discovery mechanisms for Nostr: **descending** (Dutch) auctions where a seller's price ticks down from a start price toward a floor, and **ascending** (reverse-Dutch/procurement) auctions where a buyer's offered price ticks up toward a ceiling. In both modes the price schedule is published once as a signed event; any client computes the current price deterministically from the clock. First valid commit clears the auction.\n\n## Motivation\n\nNIP-15 covers fixed-price stalls and traditional ascending bid auctions (kind 30020/1021/1022). This NIP adds a fundamentally different primitive: **deterministic, time-based price curves** where no live bidding occurs. The seller/buyer publishes a schedule; the first counterparty to commit at the current price wins. This is settlement-light (one payment, one winner), manipulation-resistant (no sniping, no gas wars), and requires no server to referee bids.\n\n## Event Kinds\n\n### `kind 30402` — Auction Listing (addressable, replaceable)\n\nAn addressable event that defines a complete auction schedule.\n\n**Tags (required):**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `d` | `<string>` | Unique auction identifier |\n| `title` | `<string>` | Auction title |\n| `mode` | `descending` \\| `ascending` | Descending = seller's price falls; ascending = buyer's price rises |\n| `start_price` | `<int msats>` | Starting price in millisatoshis |\n| `end_price` | `<int msats>` | Floor (descending) or ceiling (ascending) in millisatoshis |\n| `start_at` | `<int unix>` | Auction start timestamp |\n| `end_at` | `<int unix>` | Auction end timestamp |\n| `curve` | `linear` \\| `stepped` \\| `exponential` | Price curve type |\n| `settle` | `lightning` \\| `onchain` \\| `fiat` | Settlement method |\n| `alt` | `<string>` | NIP-31 human-readable description |\n\n**Tags (optional):**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `summary` | `<string>` | Short description |\n| `image` | `<url>` | Cover image URL |\n| `t` | `<string>` | Category tag (multiple allowed) |\n| `step` | `<int seconds>` | Step interval for stepped curves |\n| `step_amount` | `<int msats>` | Price change per step |\n| `trust` | `reputation` \\| `hold-invoice` \\| `escrow-2of3` | Trust/settlement tier |\n| `p` | `<hex pubkey>` | Arbiter pubkey (for escrow-2of3) |\n| `requirements` | `<string>` | Requirements for ascending (provider eligibility) |\n| `min_reputation` | `<int>` | Minimum cleared deals for eligibility |\n| `tribe` | `<string>` | Community/tribe scope identifier |\n| `currency` | `<string>` | Display currency code (default: `sat`) |\n\n**Content:** Human-readable description of the auction item or commission.\n\n### `kind 1402` — Clearing Commit (regular)\n\nPublished by the winner to clear the auction. For descending auctions this is the buyer; for ascending this is the accepting provider.\n\n**Tags:**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `a` | `30402:<pubkey>:<d-tag>` | Reference to the auction listing |\n| `p` | `<hex pubkey>` | Counterparty (auction creator) |\n| `price` | `<int msats>` | Computed price at commit time |\n| `commit_at` | `<int unix>` | Timestamp of commitment |\n| `bolt11` | `<string>` | Lightning invoice (if applicable) |\n| `alt` | `<string>` | NIP-31 fallback |\n\n**Content:** Optional message from the committer.\n\n**Validation:** A commit is valid if and only if `price` matches the deterministic price function evaluated at `commit_at` within a ±30 second clock-skew tolerance. First valid commit (by `created_at`) wins; later commits for the same auction are void.\n\n### `kind 1403` — Deal Acknowledgement / State (regular)\n\nPublished by the auction creator to acknowledge and track deal state transitions.\n\n**Tags:**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `a` | `30402:<pubkey>:<d-tag>` | Reference to the auction listing |\n| `e` | `<event id>` | Reference to the clearing commit (kind 1402) |\n| `p` | `<hex pubkey>` | Counterparty |\n| `status` | `committed` \\| `funded` \\| `delivered` \\| `released` \\| `refunded` \\| `disputed` | Current deal state |\n| `alt` | `<string>` | NIP-31 fallback |\n\n**Content:** Optional status message or notes.\n\n### `kind 1404` — Cancellation / No-clear (regular)\n\nPublished by the auction creator to cancel an auction or mark it as expired without clearing.\n\n**Tags:**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `a` | `30402:<pubkey>:<d-tag>` | Reference to the auction listing |\n| `reason` | `cancelled` \\| `expired` \\| `withdrawn` | Reason for cancellation |\n| `alt` | `<string>` | NIP-31 fallback |\n\n**Content:** Optional explanation.\n\n### `kind 1986` — Deal Review (regular)\n\nPublished by either party after a deal is released. Provides on-graph reputation.\n\n**Tags:**\n\n| Tag | Value | Description |\n|-----|-------|-------------|\n| `p` | `<hex pubkey>` | The reviewed counterparty |\n| `a` | `30402:<pubkey>:<d-tag>` | Reference to the auction listing |\n| `e` | `<event id>` | Reference to the clearing commit |\n| `rating` | `1` \\| `2` \\| `3` \\| `4` \\| `5` | Star rating |\n| `role` | `buyer` \\| `provider` | Role of the reviewer in this deal |\n| `alt` | `<string>` | NIP-31 fallback |\n\n**Content:** Review text (optional).\n\n## Deterministic Price Function (normative)\n\nAll clients MUST compute the current price using the same pure function. Given an auction's parameters, the current price at time `now` is:\n\n### Linear Curve\n\n```\nelapsed = clamp(now - start_at, 0, end_at - start_at)\nprogress = elapsed / (end_at - start_at)\n\nFor descending:\n  current_price = start_price - progress * (start_price - end_price)\n\nFor ascending:\n  current_price = start_price + progress * (end_price - start_price)\n```\n\n### Stepped Curve\n\n```\nelapsed = clamp(now - start_at, 0, end_at - start_at)\nsteps_elapsed = floor(elapsed / step)\n\nFor descending:\n  current_price = max(end_price, start_price - steps_elapsed * step_amount)\n\nFor ascending:\n  current_price = min(end_price, start_price + steps_elapsed * step_amount)\n```\n\n### Exponential Curve\n\n```\nelapsed = clamp(now - start_at, 0, end_at - start_at)\nprogress = elapsed / (end_at - start_at)\n\nFor descending:\n  current_price = end_price + (start_price - end_price) * (1 - progress)^2\n\nFor ascending:\n  current_price = start_price + (end_price - start_price) * progress^2\n```\n\nAll prices are rounded to the nearest integer (millisatoshi). After `end_at`, the price rests at `end_price`.\n\n## Protocol Invariants\n\n1. **Deterministic price** — pure function of signed schedule + time. Clients reject commits whose price doesn't match (±30s tolerance).\n2. **First-commit-wins** — earliest validly-signed kind 1402 whose price matches clears the auction.\n3. **Reputation on-graph** — cleared-deal history and reviews as public Nostr events. No proprietary scores.\n4. **No sealed bids** — only settlement details (invoices) may use NIP-44 encryption where needed.\n5. **Non-custodial** — funds flow directly between parties or through named arbiter keys. The marketplace client never custodies.\n\n## Clock Skew Tolerance\n\nCommits are valid if the claimed `commit_at` is within ±30 seconds of the relay's received timestamp (`created_at`). Clients SHOULD use NTP-synchronized clocks and SHOULD warn users when their system clock appears to be significantly off.","sig":"2acfaa881e7b081dad9872fb9acdc2e8574c67c7c22cd873b36bce3d15c59459e40aeac4b3e8a575efae9b4c1af0da2e59d6cbedec684c9120c6c7b7c1b89351"}