@openzeppelin/miden-multisig-client 0.17.0-rc.2 → 0.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. package/README.md +172 -47
  2. package/dist/account/builder.d.ts +2 -2
  3. package/dist/account/builder.d.ts.map +1 -1
  4. package/dist/account/builder.js +49 -24
  5. package/dist/account/builder.js.map +1 -1
  6. package/dist/connectivity.d.ts +2 -0
  7. package/dist/connectivity.d.ts.map +1 -1
  8. package/dist/connectivity.js +7 -4
  9. package/dist/connectivity.js.map +1 -1
  10. package/dist/index.d.ts +8 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +7 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/multisig/authArgErrors.d.ts +59 -0
  15. package/dist/multisig/authArgErrors.d.ts.map +1 -0
  16. package/dist/multisig/authArgErrors.js +115 -0
  17. package/dist/multisig/authArgErrors.js.map +1 -0
  18. package/dist/multisig/helpers.d.ts +5 -0
  19. package/dist/multisig/helpers.d.ts.map +1 -1
  20. package/dist/multisig/helpers.js +7 -2
  21. package/dist/multisig/helpers.js.map +1 -1
  22. package/dist/multisig.d.ts +140 -0
  23. package/dist/multisig.d.ts.map +1 -1
  24. package/dist/multisig.js +419 -12
  25. package/dist/multisig.js.map +1 -1
  26. package/dist/procedures.d.ts +1 -1
  27. package/dist/procedures.js +1 -1
  28. package/dist/recovery/proposalNoteImport.d.ts +173 -0
  29. package/dist/recovery/proposalNoteImport.d.ts.map +1 -0
  30. package/dist/recovery/proposalNoteImport.js +411 -0
  31. package/dist/recovery/proposalNoteImport.js.map +1 -0
  32. package/dist/recovery/publicNoteBackfill.d.ts +168 -0
  33. package/dist/recovery/publicNoteBackfill.d.ts.map +1 -0
  34. package/dist/recovery/publicNoteBackfill.js +368 -0
  35. package/dist/recovery/publicNoteBackfill.js.map +1 -0
  36. package/dist/recovery/recoverNotes.d.ts +147 -0
  37. package/dist/recovery/recoverNotes.d.ts.map +1 -0
  38. package/dist/recovery/recoverNotes.js +163 -0
  39. package/dist/recovery/recoverNotes.js.map +1 -0
  40. package/dist/recovery/transportDrain.d.ts +124 -0
  41. package/dist/recovery/transportDrain.d.ts.map +1 -0
  42. package/dist/recovery/transportDrain.js +262 -0
  43. package/dist/recovery/transportDrain.js.map +1 -0
  44. package/dist/transaction/consumeNotes.d.ts.map +1 -1
  45. package/dist/transaction/consumeNotes.js +4 -1
  46. package/dist/transaction/consumeNotes.js.map +1 -1
  47. package/dist/transaction/p2id.d.ts.map +1 -1
  48. package/dist/transaction/p2id.js +4 -1
  49. package/dist/transaction/p2id.js.map +1 -1
  50. package/dist/transaction/summary.d.ts +10 -4
  51. package/dist/transaction/summary.d.ts.map +1 -1
  52. package/dist/transaction/summary.js +13 -7
  53. package/dist/transaction/summary.js.map +1 -1
  54. package/dist/transaction/updateGuardian.js +4 -1
  55. package/dist/transaction/updateGuardian.js.map +1 -1
  56. package/dist/transaction/updateProcedureThreshold.js +4 -1
  57. package/dist/transaction/updateProcedureThreshold.js.map +1 -1
  58. package/dist/transaction/updateSigners.js +4 -1
  59. package/dist/transaction/updateSigners.js.map +1 -1
  60. package/dist/transaction.d.ts +1 -1
  61. package/dist/transaction.d.ts.map +1 -1
  62. package/dist/transaction.js +1 -1
  63. package/dist/transaction.js.map +1 -1
  64. package/package.json +14 -10
  65. package/src/account/builder.ts +87 -35
  66. package/src/connectivity.ts +9 -4
  67. package/src/index.ts +34 -1
  68. package/src/multisig/authArgErrors.ts +138 -0
  69. package/src/multisig/helpers.ts +7 -2
  70. package/src/multisig.ts +513 -20
  71. package/src/procedures.ts +1 -1
  72. package/src/recovery/proposalNoteImport.ts +548 -0
  73. package/src/recovery/publicNoteBackfill.ts +502 -0
  74. package/src/recovery/recoverNotes.ts +288 -0
  75. package/src/recovery/transportDrain.ts +330 -0
  76. package/src/transaction/consumeNotes.ts +4 -1
  77. package/src/transaction/p2id.ts +4 -1
  78. package/src/transaction/summary.ts +13 -7
  79. package/src/transaction/updateGuardian.ts +4 -1
  80. package/src/transaction/updateProcedureThreshold.ts +4 -1
  81. package/src/transaction/updateSigners.ts +4 -1
  82. package/src/transaction.ts +1 -1
  83. package/dist/account/builder.test.d.ts +0 -2
  84. package/dist/account/builder.test.d.ts.map +0 -1
  85. package/dist/account/builder.test.js +0 -166
  86. package/dist/account/builder.test.js.map +0 -1
  87. package/dist/account/masm/account-components/auth.d.ts +0 -2
  88. package/dist/account/masm/account-components/auth.d.ts.map +0 -1
  89. package/dist/account/masm/account-components/auth.js +0 -46
  90. package/dist/account/masm/account-components/auth.js.map +0 -1
  91. package/dist/account/masm/index.d.ts +0 -2
  92. package/dist/account/masm/index.d.ts.map +0 -1
  93. package/dist/account/masm/index.js +0 -4
  94. package/dist/account/masm/index.js.map +0 -1
  95. package/dist/account/masm.d.ts +0 -2
  96. package/dist/account/masm.d.ts.map +0 -1
  97. package/dist/account/masm.js +0 -4
  98. package/dist/account/masm.js.map +0 -1
  99. package/dist/account/storage.test.d.ts +0 -2
  100. package/dist/account/storage.test.d.ts.map +0 -1
  101. package/dist/account/storage.test.js +0 -73
  102. package/dist/account/storage.test.js.map +0 -1
  103. package/dist/client.test.d.ts +0 -2
  104. package/dist/client.test.d.ts.map +0 -1
  105. package/dist/client.test.js +0 -380
  106. package/dist/client.test.js.map +0 -1
  107. package/dist/connectivity.test.d.ts +0 -2
  108. package/dist/connectivity.test.d.ts.map +0 -1
  109. package/dist/connectivity.test.js +0 -61
  110. package/dist/connectivity.test.js.map +0 -1
  111. package/dist/inspector.test.d.ts +0 -2
  112. package/dist/inspector.test.d.ts.map +0 -1
  113. package/dist/inspector.test.js +0 -425
  114. package/dist/inspector.test.js.map +0 -1
  115. package/dist/lookupAuth.test.d.ts +0 -2
  116. package/dist/lookupAuth.test.d.ts.map +0 -1
  117. package/dist/lookupAuth.test.js +0 -138
  118. package/dist/lookupAuth.test.js.map +0 -1
  119. package/dist/multisig/consumeNotesErrors.test.d.ts +0 -2
  120. package/dist/multisig/consumeNotesErrors.test.d.ts.map +0 -1
  121. package/dist/multisig/consumeNotesErrors.test.js +0 -28
  122. package/dist/multisig/consumeNotesErrors.test.js.map +0 -1
  123. package/dist/multisig/helpers.test.d.ts +0 -2
  124. package/dist/multisig/helpers.test.d.ts.map +0 -1
  125. package/dist/multisig/helpers.test.js +0 -94
  126. package/dist/multisig/helpers.test.js.map +0 -1
  127. package/dist/multisig.test.d.ts +0 -2
  128. package/dist/multisig.test.d.ts.map +0 -1
  129. package/dist/multisig.test.js +0 -4112
  130. package/dist/multisig.test.js.map +0 -1
  131. package/dist/proposal/factory.test.d.ts +0 -2
  132. package/dist/proposal/factory.test.d.ts.map +0 -1
  133. package/dist/proposal/factory.test.js +0 -32
  134. package/dist/proposal/factory.test.js.map +0 -1
  135. package/dist/proposal/metadata.test.d.ts +0 -2
  136. package/dist/proposal/metadata.test.d.ts.map +0 -1
  137. package/dist/proposal/metadata.test.js +0 -193
  138. package/dist/proposal/metadata.test.js.map +0 -1
  139. package/dist/prover/config.test.d.ts +0 -2
  140. package/dist/prover/config.test.d.ts.map +0 -1
  141. package/dist/prover/config.test.js +0 -54
  142. package/dist/prover/config.test.js.map +0 -1
  143. package/dist/prover/errors.test.d.ts +0 -2
  144. package/dist/prover/errors.test.d.ts.map +0 -1
  145. package/dist/prover/errors.test.js +0 -29
  146. package/dist/prover/errors.test.js.map +0 -1
  147. package/dist/prover/retry.test.d.ts +0 -2
  148. package/dist/prover/retry.test.d.ts.map +0 -1
  149. package/dist/prover/retry.test.js +0 -20
  150. package/dist/prover/retry.test.js.map +0 -1
  151. package/dist/prover/workflow.test.d.ts +0 -2
  152. package/dist/prover/workflow.test.d.ts.map +0 -1
  153. package/dist/prover/workflow.test.js +0 -105
  154. package/dist/prover/workflow.test.js.map +0 -1
  155. package/dist/raw-client.test.d.ts +0 -2
  156. package/dist/raw-client.test.d.ts.map +0 -1
  157. package/dist/raw-client.test.js +0 -111
  158. package/dist/raw-client.test.js.map +0 -1
  159. package/dist/rpc/config.test.d.ts +0 -2
  160. package/dist/rpc/config.test.d.ts.map +0 -1
  161. package/dist/rpc/config.test.js +0 -24
  162. package/dist/rpc/config.test.js.map +0 -1
  163. package/dist/rpc/errors.test.d.ts +0 -2
  164. package/dist/rpc/errors.test.d.ts.map +0 -1
  165. package/dist/rpc/errors.test.js +0 -34
  166. package/dist/rpc/errors.test.js.map +0 -1
  167. package/dist/rpc/retry.test.d.ts +0 -2
  168. package/dist/rpc/retry.test.d.ts.map +0 -1
  169. package/dist/rpc/retry.test.js +0 -98
  170. package/dist/rpc/retry.test.js.map +0 -1
  171. package/dist/signers/ecdsa.test.d.ts +0 -2
  172. package/dist/signers/ecdsa.test.d.ts.map +0 -1
  173. package/dist/signers/ecdsa.test.js +0 -88
  174. package/dist/signers/ecdsa.test.js.map +0 -1
  175. package/dist/signers/falcon.test.d.ts +0 -2
  176. package/dist/signers/falcon.test.d.ts.map +0 -1
  177. package/dist/signers/falcon.test.js +0 -161
  178. package/dist/signers/falcon.test.js.map +0 -1
  179. package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts +0 -2
  180. package/dist/signers/miden-wallet.ecdsa-recovery.test.d.ts.map +0 -1
  181. package/dist/signers/miden-wallet.ecdsa-recovery.test.js +0 -148
  182. package/dist/signers/miden-wallet.ecdsa-recovery.test.js.map +0 -1
  183. package/dist/signers/miden-wallet.test.d.ts +0 -2
  184. package/dist/signers/miden-wallet.test.d.ts.map +0 -1
  185. package/dist/signers/miden-wallet.test.js +0 -164
  186. package/dist/signers/miden-wallet.test.js.map +0 -1
  187. package/dist/signers/para.test.d.ts +0 -2
  188. package/dist/signers/para.test.d.ts.map +0 -1
  189. package/dist/signers/para.test.js +0 -146
  190. package/dist/signers/para.test.js.map +0 -1
  191. package/dist/transaction/index.d.ts +0 -8
  192. package/dist/transaction/index.d.ts.map +0 -1
  193. package/dist/transaction/index.js +0 -7
  194. package/dist/transaction/index.js.map +0 -1
  195. package/dist/transaction/p2id.test.d.ts +0 -2
  196. package/dist/transaction/p2id.test.d.ts.map +0 -1
  197. package/dist/transaction/p2id.test.js +0 -246
  198. package/dist/transaction/p2id.test.js.map +0 -1
  199. package/dist/transaction/rpoRandomCoin.test.d.ts +0 -2
  200. package/dist/transaction/rpoRandomCoin.test.d.ts.map +0 -1
  201. package/dist/transaction/rpoRandomCoin.test.js +0 -52
  202. package/dist/transaction/rpoRandomCoin.test.js.map +0 -1
  203. package/dist/transaction/summary.test.d.ts +0 -2
  204. package/dist/transaction/summary.test.d.ts.map +0 -1
  205. package/dist/transaction/summary.test.js +0 -26
  206. package/dist/transaction/summary.test.js.map +0 -1
  207. package/dist/transaction.test.d.ts +0 -2
  208. package/dist/transaction.test.d.ts.map +0 -1
  209. package/dist/transaction.test.js +0 -122
  210. package/dist/transaction.test.js.map +0 -1
  211. package/dist/types/proposal.test.d.ts +0 -2
  212. package/dist/types/proposal.test.d.ts.map +0 -1
  213. package/dist/types/proposal.test.js +0 -56
  214. package/dist/types/proposal.test.js.map +0 -1
  215. package/dist/utils/digest.test.d.ts +0 -2
  216. package/dist/utils/digest.test.d.ts.map +0 -1
  217. package/dist/utils/digest.test.js +0 -48
  218. package/dist/utils/digest.test.js.map +0 -1
  219. package/dist/utils/ecdsa.test.d.ts +0 -2
  220. package/dist/utils/ecdsa.test.d.ts.map +0 -1
  221. package/dist/utils/ecdsa.test.js +0 -131
  222. package/dist/utils/ecdsa.test.js.map +0 -1
  223. package/dist/utils/encoding.test.d.ts +0 -2
  224. package/dist/utils/encoding.test.d.ts.map +0 -1
  225. package/dist/utils/encoding.test.js +0 -185
  226. package/dist/utils/encoding.test.js.map +0 -1
  227. package/dist/utils/key.test.d.ts +0 -2
  228. package/dist/utils/key.test.d.ts.map +0 -1
  229. package/dist/utils/key.test.js +0 -82
  230. package/dist/utils/key.test.js.map +0 -1
  231. package/dist/utils/signature.test.d.ts +0 -2
  232. package/dist/utils/signature.test.d.ts.map +0 -1
  233. package/dist/utils/signature.test.js +0 -164
  234. package/dist/utils/signature.test.js.map +0 -1
  235. package/dist/utils/word.test.d.ts +0 -2
  236. package/dist/utils/word.test.d.ts.map +0 -1
  237. package/dist/utils/word.test.js +0 -54
  238. package/dist/utils/word.test.js.map +0 -1
  239. package/masm/account_components/auth/guarded_multisig.masm +0 -42
  240. package/src/account/builder.test.ts +0 -238
  241. package/src/account/masm/account-components/auth.ts +0 -46
  242. package/src/account/masm/index.ts +0 -4
  243. package/src/account/masm.ts +0 -4
  244. package/src/account/storage.test.ts +0 -90
  245. package/src/client.test.ts +0 -473
  246. package/src/connectivity.test.ts +0 -67
  247. package/src/inspector.test.ts +0 -542
  248. package/src/lookupAuth.test.ts +0 -185
  249. package/src/multisig/consumeNotesErrors.test.ts +0 -43
  250. package/src/multisig/helpers.test.ts +0 -114
  251. package/src/multisig.test.ts +0 -5008
  252. package/src/proposal/factory.test.ts +0 -40
  253. package/src/proposal/metadata.test.ts +0 -235
  254. package/src/prover/config.test.ts +0 -90
  255. package/src/prover/errors.test.ts +0 -61
  256. package/src/prover/retry.test.ts +0 -38
  257. package/src/prover/workflow.test.ts +0 -145
  258. package/src/raw-client.test.ts +0 -171
  259. package/src/rpc/config.test.ts +0 -45
  260. package/src/rpc/errors.test.ts +0 -69
  261. package/src/rpc/retry.test.ts +0 -144
  262. package/src/signers/ecdsa.test.ts +0 -111
  263. package/src/signers/falcon.test.ts +0 -197
  264. package/src/signers/miden-wallet.ecdsa-recovery.test.ts +0 -201
  265. package/src/signers/miden-wallet.test.ts +0 -206
  266. package/src/signers/para.test.ts +0 -186
  267. package/src/transaction/index.ts +0 -13
  268. package/src/transaction/p2id.test.ts +0 -371
  269. package/src/transaction/rpoRandomCoin.test.ts +0 -64
  270. package/src/transaction/summary.test.ts +0 -32
  271. package/src/transaction.test.ts +0 -142
  272. package/src/types/proposal.test.ts +0 -68
  273. package/src/utils/digest.test.ts +0 -55
  274. package/src/utils/ecdsa.test.ts +0 -164
  275. package/src/utils/encoding.test.ts +0 -233
  276. package/src/utils/key.test.ts +0 -91
  277. package/src/utils/signature.test.ts +0 -210
  278. package/src/utils/word.test.ts +0 -64
@@ -0,0 +1,368 @@
1
+ /**
2
+ * Historical public-note backfill by tag.
3
+ *
4
+ * Public notes addressed to an account are on chain, but normal forward sync
5
+ * starts from the store's **global** cursor: in a shared dirty store the
6
+ * cursor may already be past blocks containing a recovered account's notes,
7
+ * and a fresh store has no efficient path to them at all. This module
8
+ * rescans a historical block range with the account's standard note tag and
9
+ * imports what it finds with on-chain inclusion proofs, without ever
10
+ * touching the global sync height.
11
+ */
12
+ import { AccountId, Endpoint, NoteScript, NoteTag, NoteType, RpcClient, } from '@miden-sdk/miden-sdk';
13
+ import { errorMessage } from '../connectivity.js';
14
+ import { collectExistingRecords, detailsKeyOf, errorDetail, importNoteWithProof, reclassifyConsumedImports, } from './proposalNoteImport.js';
15
+ import { getRawMidenClient, requireMidenRpcEndpoint } from '../raw-client.js';
16
+ import { resolveRpcConfig } from '../rpc/config.js';
17
+ import { isTransientRpcError } from '../rpc/errors.js';
18
+ import { retryRpcRead } from '../rpc/retry.js';
19
+ import { normalizeHexWord } from '../utils/encoding.js';
20
+ /**
21
+ * `RpcError::PaginationError`'s Display prefix in the WASM error chain: the
22
+ * node caps internal pagination per `syncNotes` request, and the scan splits
23
+ * the range client-side when it trips. Exported for the drift-guard test,
24
+ * which pins it against the shipped WASM binary.
25
+ */
26
+ export const RPC_PAGINATION_FRAGMENT = 'rpc pagination error';
27
+ /**
28
+ * Upper bound on `syncNotes` requests per backfill. Splitting around the
29
+ * node's pagination cap halves ranges, so the budget is only approachable
30
+ * when nearly every sub-range is dense enough to trip the cap; exhausting it
31
+ * reports the remaining ranges as uncovered instead of scanning forever.
32
+ */
33
+ const MAX_SCAN_REQUESTS = 128;
34
+ /** Block numbers are u32 on chain; out-of-range JS numbers would silently
35
+ * wrap modulo 2^32 at the WASM boundary and scan the wrong range. */
36
+ const MAX_BLOCK_NUMBER = 4_294_967_295;
37
+ /**
38
+ * The requested scan range is invalid (out-of-range bound, or inverted
39
+ * against the resolved chain tip) — a caller error that retrying cannot fix,
40
+ * as opposed to the transient chain-tip-lookup failures this function also
41
+ * throws. `Multisig.recoverNotes` keys its problem retryability on this,
42
+ * mirroring the Rust orchestrator's `InvalidConfig` check.
43
+ */
44
+ export class BackfillRangeError extends Error {
45
+ }
46
+ function requireBlockNumber(name, value) {
47
+ if (!Number.isInteger(value) || value < 0 || value > MAX_BLOCK_NUMBER) {
48
+ throw new BackfillRangeError(`${name} must be an integer in [0, ${MAX_BLOCK_NUMBER}], got ${value}`);
49
+ }
50
+ }
51
+ /**
52
+ * Static relevance screen for a discovered public note. The Rust SDK screens
53
+ * with the execution-based `NoteScreener` normal sync uses; the WASM surface
54
+ * does not expose it, so this mirrors its verdict for the well-known note
55
+ * scripts: a note is `relevant` when it is a P2ID/P2IDE note whose target
56
+ * (or P2IDE reclaimer) is the scanned account, and `irrelevant` when it is
57
+ * one of those scripts addressed at someone else. Notes with other scripts
58
+ * are `unscreenable` — this screen cannot judge them, and they are
59
+ * conservatively not imported (tags are shared, truncated filters, and
60
+ * importing unscreened tag matches would let anyone pollute the store), but
61
+ * the report counts them separately so "screened out" and "not screenable"
62
+ * stay distinguishable. Exported for the drift-guard test, which pins the
63
+ * root and storage-layout assumptions against real WASM-built notes.
64
+ */
65
+ export function screenNoteForAccount(note, account) {
66
+ const root = normalizeHexWord(note.script().root().toHex());
67
+ const items = note.recipient().storage().items();
68
+ const prefix = account.prefix().asInt();
69
+ const suffix = account.suffix().asInt();
70
+ const accountAt = (index) => items.length > index + 1 &&
71
+ items[index].asInt() === suffix &&
72
+ items[index + 1].asInt() === prefix;
73
+ if (root === normalizeHexWord(NoteScript.p2id().root().toHex())) {
74
+ // P2ID note storage: [target.suffix, target.prefix].
75
+ return accountAt(0) ? 'relevant' : 'irrelevant';
76
+ }
77
+ if (root === normalizeHexWord(NoteScript.p2ide().root().toHex())) {
78
+ // P2IDE note storage: [reclaimer.suffix, reclaimer.prefix,
79
+ // target.suffix, target.prefix, reclaim, timelock].
80
+ return accountAt(2) || accountAt(0) ? 'relevant' : 'irrelevant';
81
+ }
82
+ return 'unscreenable';
83
+ }
84
+ /**
85
+ * Scans a historical block range for public notes addressed at an account's
86
+ * standard note tag and imports what it finds with their on-chain inclusion
87
+ * proofs. Counterpart of
88
+ * `MultisigClient::backfill_public_notes_by_tag` in the Rust SDK.
89
+ *
90
+ * Use after account recovery: normal forward sync starts from the store's
91
+ * **global** cursor, so in a shared dirty store the cursor may already be
92
+ * past blocks containing the recovered account's notes, and a fresh store
93
+ * would need to replay the whole chain state to see them. The scan is
94
+ * tag-scoped and its cost grows with the number of matching notes, not the
95
+ * range length, which makes genesis an acceptable default lower
96
+ * bound. The global sync height is never touched — run normal sync
97
+ * afterwards to verify the imported notes. The store must have synced at
98
+ * least once (`Multisig.recoverNotes` syncs the chain before this strategy
99
+ * runs): importing a proof into a store that has never seen the chain
100
+ * fails, and such failures surface as `failed` outcomes.
101
+ *
102
+ * Notes are discovered by tag only — a best-effort filter: notes sent with
103
+ * unrelated custom tags are outside this scan's guarantee, and, like normal
104
+ * sync, every new discovery is screened for relevance before import —
105
+ * tag-colliding notes the account cannot consume are counted as
106
+ * `skippedIrrelevant` instead of polluting the store. This SDK screens
107
+ * statically against the well-known P2ID/P2IDE scripts (the WASM surface
108
+ * does not expose the execution-based screener the Rust SDK uses), so notes
109
+ * with custom scripts are conservatively not imported and counted as
110
+ * `skippedUnscreenable`. Only public notes can be
111
+ * rebuilt from chain data; private matches are counted as `skippedPrivate`
112
+ * and are covered by the transport drain and proposal-import primitives
113
+ * instead.
114
+ *
115
+ * A range dense enough to trip the node's internal pagination cap is split
116
+ * client-side and rescanned as narrower requests; ranges that still cannot
117
+ * be covered are reported in {@link PublicBackfillReport.uncovered} rather
118
+ * than failing the recovery flow. This function throws only when the scan
119
+ * range itself cannot be established (chain-tip lookup failed, an invalid
120
+ * account ID, a block bound that is not a u32 integer, or
121
+ * `fromBlock > toBlock`).
122
+ *
123
+ * Prefer the `Multisig.backfillPublicNotesByTag` convenience method, which
124
+ * reuses the client's endpoint and retry configuration.
125
+ *
126
+ * @example
127
+ * ```typescript
128
+ * const report = await multisig.backfillPublicNotesByTag();
129
+ * console.log(report.discovered, 'discovered,', report.outcomes.length, 'public');
130
+ * await multisig.syncState(); // verifies the imported notes
131
+ * ```
132
+ */
133
+ export async function backfillPublicNotesByTag(midenClient, options) {
134
+ const midenRpcEndpoint = requireMidenRpcEndpoint(options.midenRpcEndpoint);
135
+ const rpcConfig = resolveRpcConfig(options.rpc);
136
+ const webClient = await getRawMidenClient(midenClient, midenRpcEndpoint);
137
+ const rpcClient = new RpcClient(new Endpoint(midenRpcEndpoint));
138
+ // Parse eagerly so a malformed account ID throws before any network work.
139
+ AccountId.fromHex(options.accountId);
140
+ const from = options.fromBlock ?? 0;
141
+ requireBlockNumber('fromBlock', from);
142
+ let to;
143
+ if (options.toBlock !== undefined) {
144
+ requireBlockNumber('toBlock', options.toBlock);
145
+ to = options.toBlock;
146
+ }
147
+ else {
148
+ try {
149
+ const tip = await retryRpcRead(() => rpcClient.getBlockHeaderByNumber(), rpcConfig);
150
+ to = tip.blockNum();
151
+ }
152
+ catch (error) {
153
+ throw new Error(`failed to resolve the chain tip for the backfill scan: ${errorDetail(error)}`);
154
+ }
155
+ }
156
+ if (from > to) {
157
+ throw new BackfillRangeError(`backfill range is inverted: fromBlock ${from} > toBlock ${to}`);
158
+ }
159
+ // Work queue of inclusive sub-ranges, split in half whenever the node
160
+ // reports its pagination cap for one of them. WASM call arguments are
161
+ // consumed by the bridge, so the tag is rebuilt per request.
162
+ const scanTag = () => NoteTag.withAccountTarget(AccountId.fromHex(options.accountId));
163
+ const queue = [[from, to]];
164
+ const discovered = new Map();
165
+ const uncovered = [];
166
+ const scanReasons = [];
167
+ let retryable = false;
168
+ let requests = 0;
169
+ let budgetExhausted = false;
170
+ while (queue.length > 0) {
171
+ const [lo, hi] = queue.shift();
172
+ if (requests >= MAX_SCAN_REQUESTS) {
173
+ budgetExhausted = true;
174
+ uncovered.push({ from: lo, to: hi });
175
+ continue;
176
+ }
177
+ requests += 1;
178
+ try {
179
+ const info = await retryRpcRead(() => rpcClient.syncNotes(lo, hi, [scanTag()]), rpcConfig);
180
+ for (const committed of info.notes()) {
181
+ const idHex = normalizeHexWord(committed.noteId().toString());
182
+ if (!discovered.has(idHex)) {
183
+ // The wrapper is kept (not a one-shot accessor result) so fresh
184
+ // NoteId handles can be minted per body-fetch attempt below.
185
+ discovered.set(idHex, committed);
186
+ }
187
+ }
188
+ }
189
+ catch (error) {
190
+ // The node caps internal pagination per request rather than
191
+ // truncating; a single-block range cannot be split further (and
192
+ // cannot realistically hold that many pages), so only splittable
193
+ // ranges take this branch.
194
+ if (errorMessage(error).toLowerCase().includes(RPC_PAGINATION_FRAGMENT) && lo < hi) {
195
+ const mid = lo + Math.floor((hi - lo) / 2);
196
+ queue.unshift([lo, mid], [mid + 1, hi]);
197
+ continue;
198
+ }
199
+ retryable ||= isTransientRpcError(error);
200
+ scanReasons.push(`blocks [${lo}, ${hi}]: ${errorDetail(error)}`);
201
+ uncovered.push({ from: lo, to: hi });
202
+ }
203
+ }
204
+ if (budgetExhausted) {
205
+ retryable = true;
206
+ scanReasons.push(`scan budget of ${MAX_SCAN_REQUESTS} requests exhausted while splitting around the node's pagination cap; rerun the backfill over the uncovered ranges`);
207
+ }
208
+ const publicNotes = [];
209
+ for (const [idHex, committed] of discovered) {
210
+ if (committed.noteType() === NoteType.Public) {
211
+ publicNotes.push({ idHex, committed });
212
+ }
213
+ }
214
+ const skippedPrivate = discovered.size - publicNotes.length;
215
+ let skippedIrrelevant = 0;
216
+ let skippedUnscreenable = 0;
217
+ const outcomes = [];
218
+ const buildReport = () => {
219
+ let reason;
220
+ if (scanReasons.length > 0) {
221
+ reason =
222
+ scanReasons.length <= 3
223
+ ? scanReasons.join('; ')
224
+ : `${scanReasons.slice(0, 3).join('; ')}; …and ${scanReasons.length - 3} more`;
225
+ }
226
+ return {
227
+ scannedFrom: from,
228
+ scannedTo: to,
229
+ discovered: discovered.size,
230
+ skippedPrivate,
231
+ skippedIrrelevant,
232
+ skippedUnscreenable,
233
+ outcomes,
234
+ uncovered,
235
+ // Rerunning can help when scan ranges were left uncovered OR when any
236
+ // per-note outcome is itself retryable — surface both at report level
237
+ // so orchestration keyed on the report alone reruns when it should.
238
+ retryable: retryable || outcomes.some((outcome) => outcome.retryable === true),
239
+ ...(reason === undefined ? {} : { reason }),
240
+ };
241
+ };
242
+ const pending = [];
243
+ if (publicNotes.length > 0) {
244
+ try {
245
+ // One batched body fetch — the upstream client chunks internally by
246
+ // the node's negotiated note-ids limit, and the node returns full
247
+ // bodies for public notes, so the scan's ID + proof is all this path
248
+ // needs. The WASM bridge consumes call arguments, so fresh NoteId
249
+ // handles are minted from the kept wrappers on every retry attempt.
250
+ const fetchedNotes = await retryRpcRead(() => rpcClient.getNotesById(publicNotes.map((candidate) => candidate.committed.noteId())), rpcConfig);
251
+ const bodies = new Map();
252
+ for (const fetched of fetchedNotes) {
253
+ if (fetched.note) {
254
+ bodies.set(normalizeHexWord(fetched.noteId.toString()), {
255
+ note: fetched.note,
256
+ proof: fetched.inclusionProof,
257
+ });
258
+ }
259
+ }
260
+ for (const { idHex } of publicNotes) {
261
+ const body = bodies.get(idHex);
262
+ if (body) {
263
+ pending.push({
264
+ idHex,
265
+ note: body.note,
266
+ proof: body.proof,
267
+ detailsKey: detailsKeyOf(normalizeHexWord(body.note.recipient().digest().toHex()), body.note.assets()),
268
+ });
269
+ }
270
+ else {
271
+ // Discovered as public by the scan but returned without a body —
272
+ // not expected for a committed public note.
273
+ outcomes.push({
274
+ identifier: idHex,
275
+ source: 'backfill',
276
+ status: 'failed',
277
+ retryable: true,
278
+ reason: 'the node did not return a body for this public note',
279
+ });
280
+ }
281
+ }
282
+ }
283
+ catch (error) {
284
+ const fetchRetryable = isTransientRpcError(error);
285
+ const reason = `failed to fetch note bodies: ${errorDetail(error)}`;
286
+ for (const { idHex } of publicNotes) {
287
+ outcomes.push({
288
+ identifier: idHex,
289
+ source: 'backfill',
290
+ status: 'failed',
291
+ retryable: fetchRetryable,
292
+ reason,
293
+ });
294
+ }
295
+ }
296
+ }
297
+ if (pending.length === 0) {
298
+ return buildReport();
299
+ }
300
+ let existing;
301
+ try {
302
+ existing = await collectExistingRecords(webClient);
303
+ }
304
+ catch (error) {
305
+ const reason = `failed to read local store: ${errorDetail(error)}`;
306
+ for (const candidate of pending) {
307
+ outcomes.push({
308
+ identifier: candidate.idHex,
309
+ source: 'backfill',
310
+ status: 'failed',
311
+ reason,
312
+ });
313
+ }
314
+ return buildReport();
315
+ }
316
+ // Provisionally `imported` outcomes, re-classified in one batched
317
+ // post-import state check below.
318
+ const screenAccount = AccountId.fromHex(options.accountId);
319
+ const imported = [];
320
+ for (const candidate of pending) {
321
+ // Skip decisions key on an exact note-ID match only: a details-key
322
+ // match is a lossy approximation (see {@link detailsKeyOf} in the
323
+ // proposal-import module), and the upstream import dedupes exactly by
324
+ // the real details commitment, so importing "again" is safe while
325
+ // pre-skipping on the approximation could silently drop a genuinely
326
+ // new note. Unlike the proposal import, a proof-less (expected) record
327
+ // is NOT skipped here even on an ID match: this primitive exists
328
+ // because forward sync will never revisit the note's block, so the
329
+ // freshly fetched proof is applied to upgrade the record in place (the
330
+ // WASM import handles existing records).
331
+ const record = existing.get(candidate.idHex);
332
+ if (record && (record.isConsumed() || record.inclusionProof() !== undefined)) {
333
+ outcomes.push({
334
+ identifier: candidate.idHex,
335
+ source: 'backfill',
336
+ status: record.isConsumed() ? 'already-consumed' : 'already-present',
337
+ });
338
+ continue;
339
+ }
340
+ // Screen genuinely new discoveries for relevance, exactly like normal
341
+ // sync does before it stores a tag match. Records the store already
342
+ // tracks (by ID, or a metadata-less record matching on details) are
343
+ // material the user chose to track and skip the screen.
344
+ if (!record && !existing.has(candidate.detailsKey)) {
345
+ const verdict = screenNoteForAccount(candidate.note, screenAccount);
346
+ if (verdict === 'irrelevant') {
347
+ skippedIrrelevant += 1;
348
+ continue;
349
+ }
350
+ if (verdict === 'unscreenable') {
351
+ skippedUnscreenable += 1;
352
+ continue;
353
+ }
354
+ }
355
+ const { outcome, wasImported } = await importNoteWithProof(webClient, 'backfill', candidate.idHex, candidate.note, candidate.proof);
356
+ if (wasImported) {
357
+ imported.push({
358
+ index: outcomes.length,
359
+ idHex: candidate.idHex,
360
+ detailsKey: candidate.detailsKey,
361
+ });
362
+ }
363
+ outcomes.push(outcome);
364
+ }
365
+ await reclassifyConsumedImports(webClient, imported, outcomes);
366
+ return buildReport();
367
+ }
368
+ //# sourceMappingURL=publicNoteBackfill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publicNoteBackfill.js","sourceRoot":"","sources":["../../src/recovery/publicNoteBackfill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,147 @@
1
+ /**
2
+ * Wallet-facing orchestration of the note-recovery primitives.
3
+ *
4
+ * After key-based recovery the local Miden store starts empty (or, in a
5
+ * shared store, its global cursors may already be past this account's
6
+ * notes). Each recovery primitive rescans one source normal forward sync
7
+ * would skip: the private-note transport backlog, the notes embedded in
8
+ * pending consume-notes proposals, and the chain's historical public notes
9
+ * for the account's tag. `Multisig.recoverNotes` runs them as a single flow
10
+ * and finishes with a normal sync so recovered notes are verified and ready
11
+ * to consume.
12
+ *
13
+ * The TS counterpart of the Rust SDK's `MultisigClient::recover_notes`,
14
+ * with matching semantics and report shape.
15
+ */
16
+ import type { NoteImportOutcome } from './proposalNoteImport.js';
17
+ import { type PublicBackfillReport } from './publicNoteBackfill.js';
18
+ import type { TransportRecoveryReport } from './transportDrain.js';
19
+ /** One step of the note-recovery flow, used to attribute problems. */
20
+ export type RecoveryStep = 'transport-drain' | 'proposal-import' | 'public-backfill' | 'sync';
21
+ /**
22
+ * A step of the recovery flow that could not run (or, for the final sync,
23
+ * did not finish). The flow always continues with the remaining steps; a
24
+ * problem here means the corresponding report field is absent (or `synced`
25
+ * is `false`) and rerunning the flow may recover more.
26
+ */
27
+ export interface RecoveryStepProblem {
28
+ /** The step that failed. */
29
+ step: RecoveryStep;
30
+ /** Human-readable cause. */
31
+ reason: string;
32
+ /**
33
+ * Whether rerunning the flow can plausibly make this step succeed.
34
+ * Failures reaching this level are I/O failures against GUARDIAN, the
35
+ * node, or the local store; all but local-store failures are marked
36
+ * retryable. The flow is idempotent, so retrying is always safe.
37
+ */
38
+ retryable: boolean;
39
+ }
40
+ /**
41
+ * Result of `Multisig.recoverNotes`.
42
+ *
43
+ * Each strategy's field holds its primitive's own report and is present
44
+ * exactly when the strategy was enabled and ran; an enabled strategy that
45
+ * could not run at all is a {@link RecoveryStepProblem} instead. Step
46
+ * problems never abort the flow.
47
+ */
48
+ export interface NoteRecoveryReport {
49
+ /** Report of the transport backlog drain, when that strategy ran. */
50
+ transport?: TransportRecoveryReport;
51
+ /**
52
+ * Per-note outcomes of the proposal-embedded import, when that strategy
53
+ * ran.
54
+ */
55
+ proposalImport?: NoteImportOutcome[];
56
+ /** Report of the historical public-note backfill, when that strategy ran. */
57
+ backfill?: PublicBackfillReport;
58
+ /** Steps that could not run or finish. Empty on a fully clean flow. */
59
+ problems: RecoveryStepProblem[];
60
+ /** Whether the final verifying sync completed. */
61
+ synced: boolean;
62
+ /**
63
+ * Total note records newly added to the local store by this flow: the
64
+ * drain's imports plus every `imported` outcome from the proposal import
65
+ * and the backfill.
66
+ */
67
+ imported: number;
68
+ /**
69
+ * Whether rerunning the flow can plausibly recover more: any step
70
+ * problem, per-note outcome, or strategy report marked retryable.
71
+ */
72
+ retryable: boolean;
73
+ }
74
+ /**
75
+ * Options for `Multisig.recoverNotes`. The default runs every strategy over
76
+ * the full chain history and syncs afterwards.
77
+ */
78
+ export interface RecoverNotesOptions {
79
+ /**
80
+ * Rescan the private-note transport backlog (the standalone
81
+ * `drainPrivateNoteBacklog`). Default `true`.
82
+ */
83
+ transportDrain?: boolean;
84
+ /**
85
+ * Import the notes embedded in pending consume-notes proposals
86
+ * (`Multisig.importNotesFromProposals`). Default `true`.
87
+ */
88
+ proposalImport?: boolean;
89
+ /**
90
+ * Scan chain history for public notes addressed at the account's tag
91
+ * (`Multisig.backfillPublicNotesByTag`). Default `true`.
92
+ */
93
+ publicBackfill?: boolean;
94
+ /** First block of the backfill scan; defaults to genesis. */
95
+ fromBlock?: number;
96
+ /** Last block of the backfill scan; defaults to the current chain tip. */
97
+ toBlock?: number;
98
+ /**
99
+ * Run a normal sync after the strategies so imported notes are verified
100
+ * and show up as consumable. Default `true`.
101
+ */
102
+ syncAfter?: boolean;
103
+ }
104
+ /**
105
+ * The guardian-switch slice of {@link RecoverNotesOptions}: only the
106
+ * proposal-embedded note import runs. Internal — the public entry point is
107
+ * `Multisig.preservePreSwitchProposalNotes`, which adds the switch-specific
108
+ * safety contract (timeout, cancellation, warnings) around this slice. The
109
+ * `satisfies` clause forces every non-range option to be listed, so adding
110
+ * a recovery strategy fails to compile until the switch path decides on it.
111
+ */
112
+ export declare const GUARDIAN_SWITCH_RECOVERY_OPTIONS: {
113
+ transportDrain: false;
114
+ proposalImport: true;
115
+ publicBackfill: false;
116
+ syncAfter: false;
117
+ };
118
+ /**
119
+ * The strategy implementations `runNoteRecovery` orchestrates. `Multisig`
120
+ * wires these to the SDK primitives; tests can substitute stubs.
121
+ */
122
+ export interface NoteRecoverySteps {
123
+ /** Drain the private-note transport backlog. */
124
+ transportDrain: () => Promise<TransportRecoveryReport>;
125
+ /** Import notes embedded in pending consume-notes proposals. */
126
+ proposalImport: () => Promise<NoteImportOutcome[]>;
127
+ /** Backfill historical public notes by tag. */
128
+ publicBackfill: () => Promise<PublicBackfillReport>;
129
+ /** Run the final verifying sync. */
130
+ sync: () => Promise<void>;
131
+ }
132
+ /**
133
+ * Runs the enabled recovery strategies in order — transport drain, proposal
134
+ * import, public backfill, final sync — folding each strategy-level throw
135
+ * into a {@link RecoveryStepProblem} so no step failure aborts the flow.
136
+ *
137
+ * The optional `cancelled` token makes the run cooperatively cancellable:
138
+ * the orchestrator checks it before each step, and a
139
+ * {@link RecoveryCancelledError} from inside a step is recorded as one
140
+ * non-retryable problem on the interrupted step, after which no further
141
+ * step runs — cancellation never masquerades as a GUARDIAN or node outage.
142
+ *
143
+ * Throws only for an inverted backfill range (a caller error). See
144
+ * `Multisig.recoverNotes` for the wallet-facing entry point.
145
+ */
146
+ export declare function runNoteRecovery(options: RecoverNotesOptions, steps: NoteRecoverySteps, cancelled?: () => boolean): Promise<NoteRecoveryReport>;
147
+ //# sourceMappingURL=recoverNotes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recoverNotes.d.ts","sourceRoot":"","sources":["../../src/recovery/recoverNotes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAsB,KAAK,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AACxF,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,sEAAsE;AACtE,MAAM,MAAM,YAAY,GACpB,iBAAiB,GACjB,iBAAiB,GACjB,iBAAiB,GACjB,MAAM,CAAC;AAEX;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,4BAA4B;IAC5B,IAAI,EAAE,YAAY,CAAC;IACnB,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,SAAS,CAAC,EAAE,uBAAuB,CAAC;IACpC;;;OAGG;IACH,cAAc,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,uEAAuE;IACvE,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,kDAAkD;IAClD,MAAM,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6DAA6D;IAC7D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,gCAAgC;;;;;CAK2B,CAAC;AAEzE;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,gDAAgD;IAChD,cAAc,EAAE,MAAM,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACvD,gEAAgE;IAChE,cAAc,EAAE,MAAM,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IACnD,+CAA+C;IAC/C,cAAc,EAAE,MAAM,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACpD,oCAAoC;IACpC,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,mBAAmB,EAC5B,KAAK,EAAE,iBAAiB,EACxB,SAAS,CAAC,EAAE,MAAM,OAAO,GACxB,OAAO,CAAC,kBAAkB,CAAC,CAwH7B"}