nips/88.md
2023-06-29 11:58:37 +01:00

4.4 KiB

NIP-88

Nostr Cash (simple Nostr ecash)

draft optional author:benarc

Nostr Cash is not blinded by default.

Ecash is useful and relays should have the option to offer ecash mints. Other mints could exist as stand-alone clients, but relays are ideally placed to package in with their service offerings.

Users can use relays offering mints they trust, or relays they don't trust but for smaller amounts.

Relays offering mints must have a keypair and an additional nostr keypair for its mint.

Nostr Cash uses derived keys, much like NIP26.

All communication between the relay and user happen over NIP04.

The mints ledger is two tables active and spent:

active:
    key: <integer, keypair deriviation number from master>, 
    amount: <integer BTC millisat denomination>, 
    user: <string, public-key of user>,
    timestamp: <integer timestamp>

spent:
    key: <integer, keypair deriviation number from master>, 
    amount: <integer BTC millisat denomination>, 
    user: <string, public-key of user>,
    timestamp: <integer timestamp>

User client ecash wallet stores:

active:
    key: <string, derived private key/ecash>, 
    amount: <integer BTC millisat denomination>, 
    relay: <string, relay ws address>,
    relaykey: <string, public-key of relay>,
    timestamp: <integer timestamp>

spent:
    key: <string, derived private key/ecash>, 
    amount: <integer BTC millisat denomination>, 
    relay: <string, relay ws address>,
    relaykey: <string, public-key of relay>,
    timestamp: <integer timestamp> 

Workflows

Mint details

User DMs the relay:

{
    "mint": <bool true>
}

Relay DMs user (maybe after a check if the relays mint has restricted access):

{
    "title": <string mints title>,
    "description": <string mints description>,
    "liquiity": <integer optional public millisat balance of mint>,
    "type": <list different offered payment types bolt11 bolt12 onchain stripe paypal shitcoin etc>,
    "fee": <integer millisat fee for internal nostr payments>,
}

Minting

User DMs the relay:

{
  "amount": <integer millisats>
}

Relay responds with payment request, which user pays:

{
  "request": <string payment request bolt11 bolt12 onchain stripe paypal shitcoin etc>
}

Once paid the mint generates derived keypair from the mints private key, storing in table active:

{
  "key": <integer derived keypair number>,
  "amount": <integer BTC millisat denomination>, 
  "user": <string public-key of user>
}

Mint replies:

{
  "key": <string derived private key/ecash>,
  "amount": <integer BTC millisat denomination>
}

User client stores:

{
  "key": <string derived private key/ecash>,
  "amount": <integer BTC millisat denomination>,
  "relay": <string relay ws address>,
  "relaykey": <string public-key of relay>,
  "timestamp": <integer timestamp>
}

Claiming

User DMs relay:

{
  "key": <String, derived private key/ecash>,
  "amount": <Integer, BTC millisat denomination>,
  "type": <String, preffered payment method bolt11 bolt12 onchain stripe paypal shitcoin etc>
}

Relay DMs user:

{
  "type": <String, bolt11 bolt12 onchain stripe paypal shitcoin etc>
}

User DMs relay:

{
   "request": <String, payment-request bolt11 bolt12 onchain stripe paypal shitcoin etc>,
}

Sending

User DMs relay:

{
  "key": <String, derived private key/ecash>,
  "amount": <Integer, BTC millisat denomination>,
  "type": <String, public key of recipient>
}

Mint burns the old record for the ecash and creates a new record(s), depending on if sending user is owed change (the old record from active to spent table). The mint creates a new record in active and DMs the recipient user the private-key/ecash. If change is due, another record is created in active and sent back to the sender user.

Relay DMs user(s):

{
  "key": <string derived private key/ecash>,
  "amount": <integer BTC millisat denomination>
}

User(s) client stores:

{
  "key": <string derived private key/ecash>,
  "amount": <integer BTC millisat denomination>,
  "relay": <string, relay ws address>,
  "relaykey": <string public-key of relay>,
  "timestamp": <integer timestamp>
}