Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NUT-18: Payment Requests #124

Merged
merged 27 commits into from
Oct 18, 2024
Merged
Changes from 2 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 103 additions & 0 deletions xx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# NUT-XX: Payment Requests

`optional`

---

This NUT introduces a standardised format for payment requests, that supply a sending wallet with all information necessary to complete the transaction. This enables many use-cases where a transaction is better initiated by the receiver (e.g. point of sale).

## Flow

1. Receiver creates a payment request, encodes it and displays it to the sender
2. Sender scans the request and constructs a matching token
3. Sender sends the token according to the transport specified in the payment request
4. Receiver receives the token and finalises the transaction

## Payment Request

A Payment Request is defined as follows

```go
type PaymentRequest struct {
A int `amount (optional)`
U string `unit`

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the unit also be optional and default to sats?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking that as well, however I can receivers run into compatibility issues quickly if they let users choose the unit.

R string `mint url (optional)`
D string `description (optional)`
M string `memo (optional)`
T []Transport `transport`
}
```

while Transport is defined as

```go
type Transport struct {
T string `type`
Ta string `target`
}
```
thesimplekid marked this conversation as resolved.
Show resolved Hide resolved

- amount: The amount of the requested token (payment amount)
- unit: The unit of the requested token (e.g. sats)
- mint: The mint to use to mint the token
- description: A human readable discription that the sending wallet will display after scanning the request
- transport: The method of transport chosen to transmit the created token to the sender (can be multiple, sorted by preference)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a use case where transport is empty? Or should there be a minimum of one element in the list?


## Encoded Request

Cashu Payment Requests can be encoded and displayed/sent as string or qr code. They underlying object is serialised using CBOR and finlly base64 encoded and prefixed with a version byte and standard prefix.

_Example_

```sh
cashrqAaVhQRVhVWNzYXRhTXgiaHR0cHM6Ly9taW50Lm1pbmliaXRzLmNhc2gvQml0Y29pbmFEeCNQbGVzYXNlIHBheSB0aGUgdmVyeSBmaXJzdCBjYXNodSBwcmFUgaJhVGVub3N0cmJUYXhGbnByb2ZpbGUxcXFzZG11cDZlMno2bWNwZXVlNno2a2wwOGhlNDloY2VuNXhucmMzdG5wdncwbWRndGplbWgwc3V4YTBrag
```

## Reference Implementation

```go
package main

import (
"encoding/base64"
"fmt"
"log"

"github.com/fxamacker/cbor/v2"
)

const (
pre = "cashrq"
version = byte(0x01)
)

type Transport struct {
T string
Ta string
}
type PaymentRequest struct {
A int
U string
M string
D string
T []Transport
}

func encodeRequest(pr PaymentRequest) string {
b, err := cbor.Marshal(pr)
if err != nil {
log.Fatal("CBOR encoding failed...")
}
b = append([]byte{version}, b...)
encodedString := base64.RawURLEncoding.EncodeToString(b)
res := pre + encodedString
return res
}

func main() {
t := Transport{T: "nostr", Ta: "nprofile1qqsdmup6e2z6mcpeue6z6kl08he49hcen5xnrc3tnpvw0mdgtjemh0suxa0kj"}
pr := PaymentRequest{A: 21, U: "sat", M: "https://mint.minibits.cash/Bitcoin", D: "Plesase pay the very first cashu pr", T: []Transport{t}}
res := encodeRequest(pr)
fmt.Printf("%s", res)
}
```