mirror of
https://github.com/Such-Software/smirk-backend-core.git
synced 2026-10-17 07:21:32 +02:00
feat(lws): balance as a verification passthrough (spent_outputs + mempool pending)
POST /wallet/lws/balance returned a server-summarized {unlocked, locked} where
unlocked = total_received - locked OVER-COUNTED: a non-custodial backend cannot
verify spends without the spend key, so it never subtracted them. Reshape to the
wallet's verification-passthrough contract — aggregate get_address_info +
get_address_txs (parallel) and return total_received, locked_balance,
pending_balance (0-conf summed directly from mempool rows: webhook-free, cleaner
than the private backend's DB table), and spent_outputs[] for client-side
key-image verification. The wallet nets its own spends (privacy-correct).
spent_outputs fixes the over-count immediately; pending_balance activates once
the parity LWS mempool feature is deployed. Adversarially reviewed (3 lenses,
0 confirmed findings).
This commit is contained in:
+25
-10
@@ -2566,15 +2566,17 @@
|
||||
},
|
||||
"LwsBalanceResponse": {
|
||||
"type": "object",
|
||||
"description": "Balance + scan state. `total_received` is the balance (an LWS cannot confirm\nspends without the spend key; the wallet subtracts its own known spends).",
|
||||
"description": "Balance + scan state, as a **verification passthrough**. The backend holds no\nspend key, so it cannot net out spends; the wallet computes the true spendable\nbalance client-side: `total_received − sum(spent_outputs it verifies with the\nspend key) − locked_balance`. `spent_outputs` are therefore CANDIDATES (some\nare ring decoys of the user's own outputs); `pending_balance` is the 0-conf\n(mempool) received.",
|
||||
"required": [
|
||||
"asset",
|
||||
"total_received",
|
||||
"unlocked",
|
||||
"locked",
|
||||
"locked_balance",
|
||||
"pending_balance",
|
||||
"start_height",
|
||||
"scanned_height",
|
||||
"blockchain_height",
|
||||
"transaction_count"
|
||||
"transaction_count",
|
||||
"spent_outputs"
|
||||
],
|
||||
"properties": {
|
||||
"asset": {
|
||||
@@ -2585,16 +2587,34 @@
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"locked": {
|
||||
"locked_balance": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"pending_balance": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"description": "Unconfirmed (mempool) received — 0-conf. `0` until the LWS reports mempool\nrows (the monero-lws mempool feature); never negative.",
|
||||
"minimum": 0
|
||||
},
|
||||
"scanned_height": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"spent_outputs": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/SpentOutputDto"
|
||||
},
|
||||
"description": "Candidate spent outputs (confirmed + mempool) for client-side key-image\nverification with the spend key. Never authoritative server-side."
|
||||
},
|
||||
"start_height": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"total_received": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
@@ -2604,11 +2624,6 @@
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
},
|
||||
"unlocked": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user