Skip to content

NUT-07: Token state check

optional

used in: NUT-17


With the token state check, wallets can ask the mint whether a specific proof is already spent and whether it is in-flight in a transaction. Wallets can also request the witness data that was used to spend a proof.

Token states

A proof can be in one of the following states

  • A proof is UNSPENT if it has not been spent yet
  • A proof is PENDING if it is being processed in a transaction (in an ongoing payment). A PENDING proof cannot be used in another transaction until it is live again.
  • A proof is SPENT if it has been redeemed and its secret is in the list of spent secrets of the mint.

Note: Before deleting spent proofs from their database, wallets can check if the proof is SPENT to make sure that they don't accidentally delete an unspent proof. Beware that this behavior can make it easier for the mint to correlate the sender to the receiver.

Important: Mints MUST remember which proofs are currently PENDING to avoid reuse of the same token in multiple concurrent transactions. This can be achieved with for example mutex lock whose key is the Proof's Y.

Use cases

Example 1: Ecash transaction

When Alice prepares a token to be sent to Carol, she can mark these tokens in her database as pending. She can then, periodically or upon user input, check with the mint if the token is UNSPENT or whether it has been redeemed by Carol already, i.e., is SPENT. If the proof is not spendable anymore (and, thus, has been redeemed by Carol), she can safely delete the proof from her database.

Example 2: Lightning payments

If Alice's melt operation takes a long time to complete (for example if she requests a very slow Lightning payment) and she closes her wallet in the meantime, the next time she comes online, she can check all proofs marked as pending in her database to determine whether the payment is still in flight (mint returns PENDING), it has succeeded (mint returns SPENT), or it has failed (mint returns UNSPENT).

Example

Request of Alice:

POST https://mint.host:3338/v1/checkstate

With the data being of the form PostCheckStateRequest:

{
  "Ys": <Array[hex_str]>,
}

Where the elements of the array in Ys are the hexadecimal representation of the compressed point Y = hash_to_curve(secret) of the Proof to check (see NUT-00).

Response of Bob:

Bob will respond with a PostCheckStateResponse

{
  "states": [
    {
      "Y": <hex_str>,
      "state": <str_enum[STATE]>,
      "witness": <str|null>,
    },
    ...
  ]
}
  • Y corresponds to the Proof checked in the request.
  • state is an enum string field with possible values "UNSPENT", "PENDING", "SPENT"
  • witness is the serialized witness data that was used to spend the Proof if the token required it such as in the case of P2PK (see NUT-11).

With curl:

Request of Alice:

curl -X POST https://mint.host:3338/v1/checkstate -H 'Content-Type: application/json' -d '{
  "Ys": [
    "02599b9ea0a1ad4143706c2a5a4a568ce442dd4313e1cf1f7f0b58a317c1a355ee"
  ]
}'

Response of Bob:

{
  "states": [
    {
      "Y": "02599b9ea0a1ad4143706c2a5a4a568ce442dd4313e1cf1f7f0b58a317c1a355ee",
      "state": "SPENT",
      "witness": "{\"signatures\": [\"b2cf120a49cb1ac3cb32e1bf5ccb6425e0a8372affdc1d41912ca35c13908062f269c0caa53607d4e1ac4c8563246c4c8a869e6ee124ea826fd4746f3515dc1e\"]}"
    }
  ]
}

Where Y belongs to the provided Proof to check in the request, state indicates its state, and witness is the witness data that was potentially provided in a previous spend operation (can be empty).