diff --git a/61.md b/61.md index 5842d6b3fd..148aaf79ae 100644 --- a/61.md +++ b/61.md @@ -6,14 +6,14 @@ Nutzaps `draft` `optional` -A Nutzap is a P2PK Cashu token in which the payment itself is the receipt. +A Nutzap is an event containing a [P2PK-locked](https://github.com/cashubtc/nuts/blob/main/11.md) Cashu token that is publicly verifiable. ## High-level flow -Alice wants to nutzap 1 sat to Bob because of an event `event-id-1` she liked. +Alice wants to nutzap 1 sat to Bob for an event `nutzapped-event-id` she liked. ### Alice nutzaps Bob 1. Alice fetches event `kind:10019` from Bob to see the mints Bob trusts. -2. She mints a token at that mint (or swaps some tokens she already had in that mint) P2PK-locked to the pubkey Bob has listed in his `kind:10019`. +2. She mints or swaps ecash at that mint with a P2PK lock that contains the pubkey Bob listed in his `kind:10019`, a `P` tag with the sender's pubkey, and an `e` tag of the event `nutzapped-event-id` to zap. 3. She publishes a `kind:9321` event to the relays Bob indicated with the proofs she minted. ### Bob receives the nutzap @@ -40,9 +40,29 @@ Alice wants to nutzap 1 sat to Bob because of an event `event-id-1` she liked. * `pubkey`: Public key that MUST be used to P2PK-lock receiving nutzaps -- implementations MUST NOT use the target user's main Nostr public key. This public key corresponds to the `privkey` field encrypted in a user's [nip-60](60.md) _wallet event_. ### Nutzap event -Event `kind:9321` is a nutzap event published by the sender, p-tagging the recipient. The outputs are P2PK-locked to the public key the recipient indicated in their `kind:10019` event. +Event `kind:9321` is a nutzap event published by the sender, p-tagging the recipient. The outputs are P2PK-locked to the public key the recipient indicated in their `kind:10019` event and with a P2PK secret that commits to the event id `nutzapped-event-id` to zap. -Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu compatibility). +##### Cashu proof +A NIP-61 zap contains one or more Cashu proofs with a [NUT-12](https://github.com/cashubtc/nuts/blob/main/11.md) P2PK lock. The proof's `secret` has the receiver's `p2pk-pubkey` in `data` field. The `tags` field of the `secret` contains a `P` tag with the sender's pubkey `sender-pubkey` and the zapped event's id `e`. The proof also contains a [NUT-12](https://github.com/cashubtc/nuts/blob/main/12.md) DLEQ field `dleq`. + +Clients MUST prefix the receiver's `p2pk-pubkey` with `"02"` (for nostr<>cashu compatibility). +```jsonc +{ + "amount":2, + "C":"0302f4aacbfa5da455b884501ebcbd4c9c3cc6640daa7269f640aa70522727b790", + "id":"00da2cc2b0016589", + "secret":"[\"P2PK\", {\"data\": \"029128d0918cd2241e92968c2d5f8eb6ba9b6adf3cd7bd0a5c82c64400470f9a86\", \"nonce\": \"43e0d7c14e20616850f540b5dec96006\", \"tags\": [[\"e\", \"nutzapped-event-id\"], [\"P\", \"sender-pubkey\"]]}]", + "dleq":{ + "r":"e5f0c29513ef7e0b0b1798be8f7ca7940296833a7e723e16ba2162299c77d183", + "s":"12fdde66b4bc26fc76f11f88aae527fb1642c0fb4066d06db8a3c6976a224205", + "e":"9df01b6421926fd04521185d3264eed99a4c0951d8c247f0f8f1244d340d5e06" + } +} +``` + +##### Nostr event + +The nutzap event contains one or more serialized Cashu proofs. ```jsonc { @@ -50,7 +70,7 @@ Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu "content": "Thanks for this great idea.", "pubkey": "", "tags": [ - [ "proof", "{\"amount\":1,\"C\":\"02277c66191736eb72fce9d975d08e3191f8f96afb73ab1eec37e4465683066d3f\",\"id\":\"000a93d6f8a1d2c4\",\"secret\":\"[\\\"P2PK\\\",{\\\"nonce\\\":\\\"b00bdd0467b0090a25bdf2d2f0d45ac4e355c482c1418350f273a04fedaaee83\\\",\\\"data\\\":\\\"02eaee8939e3565e48cc62967e2fde9d8e2a4b3ec0081f29eceff5c64ef10ac1ed\\\"}]\"}" ], + [ "proof", "{\"amount\": 2, \"C\": \"0302f4aacbfa5da455b884501ebcbd4c9c3cc6640daa7269f640aa70522727b790\", \"id\": \"00da2cc2b0016589\", \"secret\": \"[\\\"P2PK\\\", {\\\"data\\\": \\\"029128d0918cd2241e92968c2d5f8eb6ba9b6adf3cd7bd0a5c82c64400470f9a86\\\", \\\"nonce\\\": \\\"43e0d7c14e20616850f540b5dec96006\\\", \\\"tags\\\": [[\\\"e\\\", \\\"nutzapped-event-id\\\"], [\\\"P\\\", \\\"sender-pubkey\\\"]]}]\", \"dleq\": {\"r\": \"e5f0c29513ef7e0b0b1798be8f7ca7940296833a7e723e16ba2162299c77d183\", \"s\": \"12fdde66b4bc26fc76f11f88aae527fb1642c0fb4066d06db8a3c6976a224205\", \"e\": \"9df01b6421926fd04521185d3264eed99a4c0951d8c247f0f8f1244d340d5e06\"}}"], [ "unit", "sat" ], [ "u", "https://stablenut.umint.cash" ], [ "e", "", "" ], @@ -62,12 +82,14 @@ Clients MUST prefix the public key they P2PK-lock with `"02"` (for nostr<>cashu * `.content` is an optional comment for the nutzap * `.tags`: - * `proof` is one or more proofs P2PK-locked to the public key the recipient specified in their `kind:10019` event and including a DLEQ proof. + * `proof` is one P2PK-locked proof to the public key the recipient specified in their `kind:10019` event, a `P` tag committing to the sender's pubkey `sender-pubkey`, an optional `e` tag committing to `nutzapped-event-id`, and a DLEQ proof. Multiple `proof` tags may be added - one proof per tag. * `unit` the base unit the proofs are denominated in (eg: `sat`, `usd`, `eur`). Default: `sat` if omitted. * `u` is the mint the URL of the mint EXACTLY as specified by the recipient's `kind:10019`. * `p` is the Nostr identity public key of nutzap recipient. * `e` is the event that is being nutzapped, if any. +Note that the optional `e` tag is contained in the Cashu proof's `secret` as well as in the Nostr event. The `P` tag in the Cashu proof is the `pubkey` in the nutzap event. + ## Sending a nutzap * The sender fetches the recipient's `kind:10019`. @@ -113,9 +135,11 @@ Events that redeem a nutzap SHOULD be published to the sender's [NIP-65](65.md) When listing or counting zaps received by any given event, observer clients SHOULD: * check that the receiving user has issued a `kind:10019` tagging the mint where the cashu has been minted. -* check that the token is locked to the pubkey the user has listed in their `kind:10019`. +* check that the Cashu proofs are locked to the pubkey the user has listed in their `kind:10019`. +* check that the Cashu proof's secret contains a `P` that equals the `pubkey` of the nutzap event. +* check that the Cashu proofs' secrets contain an `e` tag that equals the zapped event's id. * look at the `u` tag and check that the token is issued in one of the mints listed in the `kind:10019`. -* locally verify the DLEQ proof of the tokens being sent. +* verify the DLEQs of the proofs using the public keysets of the mint. All these checks can be done offline (as long as the observer has the receiver mints' keyset and their `kind:10019` event), so the process should be reasonably fast.