nips/88.md

8.5 KiB

NIP-88

Discreet Log Contracts over nostr

draft optional

This NIP describes a way to use Discreet Log Contracts (DLCs) over Nostr. This comes in four main components: kind:8_888 for sending DLC messages between wallets. kind:30088 for posting DLC offers to the global market. kind:88 and kind:89 for publishing DLC oracle announcements and attestations. And kind:90 for a DLC "receipt" that can publish the result of a DLC for social interaction.

DLC Messages

DLCs typically use BOLT 8 for sending messages but this has various problems: it requires the ability to accept incoming connections and an always-on node. Nostr provides a unique opportunity to use a different transport layer for DLCs. This NIP proposes a new kind:8_888 message that acts like a mailbox for DLC messages. The DLC messages are sent over nostr and available for the user the next time they open their wallet. This allows for a more mobile-friendly DLC experience.

DLC protocol messages are binary-serialized messages described concretely in this document. Whenever embedding DLC messages inside Nostr events (which are encoded as JSON), we serialize those DLC messages in base64.

kind:8_888

Kind 8_888 is a simple message that contains a NIP04 encrypted DLC message and is tagged with the recipient's public key with a p tag and if it is in reply to another event, that event should be tagged with an e tag. The DLC message is first serialized in binary, and then encrypted with NIP04.

A DLC wallet should only process messages that are tagged with their public key and that are in reply to a message they sent unless it is an offer. This is to prevent spam and to prevent a malicious actor from sending a message to a user that looks like it is from a different user.

{
  "kind": 8888,
  "content": "TJob1dQrf2ndsmdbeGU+05HT5GMnBSx3fx8QdDY/g3NvCa7klfzgaQCmRZuo1d3WQjHDOjzSY1+MgTK5WjewFFumCcOZniWtOMSga9tJk1ky00tLoUUzyLnb1v9x95h/iT/KpkICJyAwUZ+LoJBUzLrK52wNTMt8M5jSLvCkRx8C0BmEwA/00pjOp4eRndy19H4WUUehhjfV2/VV/k4hMAjJ7Bb5Hp9xdmzmCLX9+64+MyeIQQjQAHPj8dkSsRahP7KS3MgMpjaF8nL48Bg5suZMxJayXGVp3BLtgRZx5z5nOk9xyrYk+71e2tnP9IDvSMkiSe76BcMct+m7kGVrRcavDI4n62goNNh25IpghT+a1OjjkpXt9me5wmaL7fxffV1pchdm+A7KJKIUU3kLC7QbUifF22EucRA9xiEyxETusNludBXN24O3llTbOy4vYFsq35BeZl4v1Cse7n2htZicVkItMz3wjzj1q1I1VqbnorNXFgllkRZn4/YXfTG/RMnoK/bDogRapOV+XToZ+IvsN0BqwKSUDx+ydKpci6htDRF2WDRkU+VQMqwM0CoLzy2H6A2cqyMMMD9SLRRzBg==?iv=S3rFeFr1gsYqmQA7bNnNTQ==",
  "tags": [
    [
      "p",
      "04c915daefee38317fa734444acee390a8269fe5810b2241e5e6dd343dfbecc9"
    ],
    [
      "e",
      "9ae37aa68f48645127299e9453eb5d908a0cbb6058ff340d528ed4d37c8994fb"
    ]
  ],
  "pubkey": "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322",
  "created_at": 1679673265,
  "id": "30efed56a035b2549fcaeec0bf2c1595f9a9b3bb4b1a38abaf8ee9041c4b7d93",
  "sig": "f2cb581a84ed10e4dc84937bd98e27acac71ab057255f6aa8dfa561808c981fe8870f4a03c1e3666784d82a9c802d3704e174371aa13d63e2aeaf24ff5374d9d"
}

DLC Offers

DLCs are done between two parties and Nostr provides a unique opportunity to create a global market for DLCs. This market can be constructed with a simple list of DLC offers that can be filtered by the user's wallet. The user can then select an offer and send a message to the offerer to begin the DLC process. kind:30088 is an event that contains a DLC offer.

A parameterized replaceable event is used to allow the offerer to update the offer or remove it from the market. The d tag should be the Offer's id to allow replacement of the offer. If the user wishes to remove the offer from the market, they can replace the event with an expires tag that is in the past. The relays tag indicates the relays on which to contact the offerer.

The content field must be the base64-encoding of a binary-serialized contract_info object.

kind:30_088

{
  "kind": 30088,
  "content": "base64 contract_info",
  "tags": [
    [
      "relays",
      "wss://nostr.mutinywallet.com",
      "wss://relay.damus.io"
    ],
    [
      "expires",
      "1695327657"
    ],
    [
      "d",
      "6423394a32f37a4f0590e74f9308f5aee06e59e14f50c4cd6d59365caed13cb7"
    ],
  ],
  "pubkey": "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322",
  "created_at": 1679673265,
  "id": "30efed56a035b2549fcaeec0bf2c1595f9a9b3bb4b1a38abaf8ee9041c4b7d93",
  "sig": "f2cb581a84ed10e4dc84937bd98e27acac71ab057255f6aa8dfa561808c981fe8870f4a03c1e3666784d82a9c802d3704e174371aa13d63e2aeaf24ff5374d9d"
}

DLC Oracle Gossip

DLCs require an oracle to attest to the outcome of real world events. This is done by the oracle signing a message containing the outcome of the event. Before they attest to the outcome, they must create an announcement where they publish the intent to sign the future event. This announcement is then used by the DLC participants to create the contract. Here we define two events, kind:88 and kind:89 that are used to publish the oracle's announcement and attestations respectively.

kind:88

{
  "kind": 88,
  "content": "base64 oracle_annoucement",
  "tags": [
    [
      "relays", // the relays the oracle will publish attestations to
      "wss://nostr.mutinywallet.com",
      "wss://relay.damus.io"
    ],
    [
      "title",
      "Optional Event Title"
    ],
    [
      "description",
      "An optional human-readable description of the event which the oracle will attest to, in plain text."
    ]
  ],
  "pubkey": "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322",
  "created_at": 1679673265,
  "id": "30efed56a035b2549fcaeec0bf2c1595f9a9b3bb4b1a38abaf8ee9041c4b7d93",
  "sig": "f2cb581a84ed10e4dc84937bd98e27acac71ab057255f6aa8dfa561808c981fe8870f4a03c1e3666784d82a9c802d3704e174371aa13d63e2aeaf24ff5374d9d"
}

The content field must be the base64-encoding of a binary-serialized oracle_annoucement object.

The optional title tag gives observers a short human-readable title with which to display the announcement in cards, hyperlinks, etc. It should be at most 100 characters of UTF8 text. Clients should ignore or truncate titles longer than 100 characters. This tag must NOT be parsed as markdown or HTML.

The optional description tag provides a human-readable summary of the real-world event which this announcement is for. The description should give observers context, so that they know how the real-world event in question will be reflected in the oracle's final attestation. This tag must NOT be parsed as markdown or HTML.

kind:89

{
  "kind": 89,
  "content": "base64 oracle_attestation",
    "tags": [
    [
      "e", // the Nostr event id of the announcement
      "30efed56a035b2549fcaeec0bf2c1595f9a9b3bb4b1a38abaf8ee9041c4b7d93",
    ],
  ],
  "pubkey": "97c70a44366a6535c145b333f973ea86dfdc2d7a99da618c40c64705ad98e322",
  "created_at": 1679673265,
  "id": "30efed56a035b2549fcaeec0bf2c1595f9a9b3bb4b1a38abaf8ee9041c4b7d93",
  "sig": "f2cb581a84ed10e4dc84937bd98e27acac71ab057255f6aa8dfa561808c981fe8870f4a03c1e3666784d82a9c802d3704e174371aa13d63e2aeaf24ff5374d9d"
}

The content field must be the base64-encoding of a binary-serialized oracle_attestation object.

Note that the e tag is the Nostr event identifier for the kind:88 announcement event, which is distinct from the identifier embedded in the announcement or in the attestation itself. The e tag is intended to be used to look up the corresponding announcement event.

Upon receiving an attestation, clients should validate that the event_id field inside the oracle_announcement object matches the event_id field in the oracle_attestation object.

DLC Receipts

DLCs can be fun, social events. This NIP proposes a kind:90 event that can be used to publish the result of a DLC contract. This event can be used to show off the result of a DLC to the user's followers, similar Zaps but for DLC bets.

kind:90

todo I still need to think about this one