{"id":"ae2e2d6d3c5e9b864b9b07312766d04742b926bcf6cd5c2f8b139373c0a9d690","pubkey":"d1678e7ef965374bbea308a1215609a78376dc158277a7d657680f9d5efd5c38","created_at":1731684898,"kind":30817,"tags":[["d","nut-07"],["title","NUT-07: Token state check"],["summary","How a wallet asks the mint whether a proof is unspent, pending, or already spent."],["s","optional"],["t","cashu"],["t","ecash"],["t","nut"],["alt","A specification: NUT-07: Token state check"],["client","openspecs-import"],["published_at","1678379954"],["proxy","https://github.com/cashubtc/nuts/blob/a845dfc998abae501fc3419592d53dc995d34b12/07.md","web"],["x","aa5bd7b193265a207ecf74f0afd68112d7eacb0f175457b0fa19dbe5d0158009"]],"content":"# NUT-07: Token state check\n\n`optional`\n\n`used in: NUT-17, NUT-11, NUT-14`\n\n---\n\nWith 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.\n\n### Token states\n\nA proof can be in one of the following states\n\n- A proof is `UNSPENT` if it has not been spent yet\n- 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.\n- A proof is `SPENT` if it has been redeemed and its secret is in the list of spent secrets of the mint.\n\n**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.\n\n**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`.\n\n## Use cases\n\n#### Example 1: Ecash transaction\n\nWhen `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.\n\n#### Example 2: Lightning payments\n\nIf `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`).\n\n## Example\n\n**Request** of `Alice`:\n\n```http\nPOST https://mint.host:3338/v1/checkstate\n```\n\nWith the data being of the form `PostCheckStateRequest`:\n\n```json\n{\n  \"Ys\": <Array[hex_str]>,\n}\n```\n\nWhere 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][00]).\n\n**Response** of `Bob`:\n\n`Bob` responds with a `PostCheckStateResponse`:\n\n```json\n{\n  \"states\": [\n    {\n      \"Y\": <hex_str>,\n      \"state\": <str_enum[STATE]>,\n      \"witness\": <str|null>,\n    },\n    ...\n  ]\n}\n```\n\nThe elements of the `states` array MUST be returned in the same order as the corresponding `Ys` checked in the request.\n\n- `Y` corresponds to the `Proof` checked in the request.\n- `state` is an enum string field with possible values `\"UNSPENT\"`, `\"PENDING\"`, `\"SPENT\"`\n- `witness` is the serialized witness data that was used to spend the `Proof` if the token has a [NUT-10][10] spending condition that requires a witness such as in the case of P2PK ([NUT-11][11]) or HTLCs ([NUT-14][14]).\n\nWith curl:\n\n**Request** of `Alice`:\n\n```bash\ncurl -X POST https://mint.host:3338/v1/checkstate -H 'Content-Type: application/json' -d '{\n  \"Ys\": [\n    \"02599b9ea0a1ad4143706c2a5a4a568ce442dd4313e1cf1f7f0b58a317c1a355ee\"\n  ]\n}'\n```\n\n**Response** of `Bob`:\n\n```json\n{\n  \"states\": [\n    {\n      \"Y\": \"02599b9ea0a1ad4143706c2a5a4a568ce442dd4313e1cf1f7f0b58a317c1a355ee\",\n      \"state\": \"SPENT\",\n      \"witness\": \"{\\\"signatures\\\": [\\\"b2cf120a49cb1ac3cb32e1bf5ccb6425e0a8372affdc1d41912ca35c13908062f269c0caa53607d4e1ac4c8563246c4c8a869e6ee124ea826fd4746f3515dc1e\\\"]}\"\n    }\n  ]\n}\n```\n\nWhere `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).\n\n## Mint info setting\n\nThe [NUT-06][06] `MintMethodSetting` indicates support for this feature:\n\n```json\n{\n  \"7\": {\n    \"supported\": true\n  }\n}\n```\n\n[00]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crqqpd6d9\n[01]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crznyve7g\n[02]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cry0t0uzl\n[03]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crxuwwl3j\n[04]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crg74fknc\n[05]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cr2dsg4q4\n[06]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crv3ltsuz\n[07]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crwz62n00\n[08]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crs4q9zck\n[09]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595crjx9yptm\n[10]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnqx5tye7\n[11]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnz43282n\n[12]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cnyf7fzky\n[14]: nostr:naddr1qvzqqqrcvypzp5t83el0jefhfwl2xz9py9tqnfurwmwptqnh5lt9w6q0n4006hpcqqrxuat595cngcq0g8r\n","sig":"86d81e3fafe440b7979fe842d2b809eb2a9381edb8de6cb6c13bdba5fca50c2aaaa86eee0448f5230bd9f9b69c74bc1c8051d71be81c511f6d234726e2dfec82"}