@bananapus/nana-sdk-core 4.0.0 → 6.0.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 (244) hide show
  1. package/bin/wallet-check.mjs +7 -1
  2. package/dist/cjs/generated/abi/jbBuybackHookAbi.d.ts +8 -0
  3. package/dist/cjs/generated/abi/jbBuybackHookAbi.d.ts.map +1 -1
  4. package/dist/cjs/generated/abi/jbBuybackHookAbi.js +5 -0
  5. package/dist/cjs/generated/abi/jbBuybackHookAbi.js.map +1 -1
  6. package/dist/cjs/generated/abi/jbBuybackHookPreviousAbi.d.ts +12 -0
  7. package/dist/cjs/generated/abi/jbBuybackHookPreviousAbi.d.ts.map +1 -1
  8. package/dist/cjs/generated/abi/jbBuybackHookPreviousAbi.js +8 -0
  9. package/dist/cjs/generated/abi/jbBuybackHookPreviousAbi.js.map +1 -1
  10. package/dist/cjs/generated/abi/jbBuybackHookV2Abi.d.ts +1175 -0
  11. package/dist/cjs/generated/abi/jbBuybackHookV2Abi.d.ts.map +1 -0
  12. package/dist/cjs/generated/abi/jbBuybackHookV2Abi.js +832 -0
  13. package/dist/cjs/generated/abi/jbBuybackHookV2Abi.js.map +1 -0
  14. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookAbi.d.ts +214 -113
  15. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookAbi.d.ts.map +1 -1
  16. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookAbi.js +176 -82
  17. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookAbi.js.map +1 -1
  18. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.d.ts +1 -1
  19. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.js +1 -1
  20. package/dist/cjs/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.js.map +1 -1
  21. package/dist/cjs/generated/abi/jbp6FeeLpSplitHookAbi.d.ts +214 -113
  22. package/dist/cjs/generated/abi/jbp6FeeLpSplitHookAbi.d.ts.map +1 -1
  23. package/dist/cjs/generated/abi/jbp6FeeLpSplitHookAbi.js +176 -82
  24. package/dist/cjs/generated/abi/jbp6FeeLpSplitHookAbi.js.map +1 -1
  25. package/dist/cjs/generated/addresses/jbContractAddress.d.ts +42 -42
  26. package/dist/cjs/generated/addresses/jbContractAddressHistory.d.ts +75 -0
  27. package/dist/cjs/generated/addresses/jbContractAddressHistory.d.ts.map +1 -0
  28. package/dist/cjs/generated/addresses/jbContractAddressHistory.js +80 -0
  29. package/dist/cjs/generated/addresses/jbContractAddressHistory.js.map +1 -0
  30. package/dist/cjs/generated/addresses/jbV6ContractAddress.d.ts +42 -42
  31. package/dist/cjs/generated/addresses/jbV6ContractAddress.js +42 -42
  32. package/dist/cjs/generated/juicebox.d.ts +13 -45
  33. package/dist/cjs/generated/juicebox.d.ts.map +1 -1
  34. package/dist/cjs/generated/juicebox.js +29 -48
  35. package/dist/cjs/generated/juicebox.js.map +1 -1
  36. package/dist/cjs/review/confirm.d.ts +4 -0
  37. package/dist/cjs/review/confirm.d.ts.map +1 -1
  38. package/dist/cjs/review/confirm.js +14 -3
  39. package/dist/cjs/review/confirm.js.map +1 -1
  40. package/dist/cjs/review/contractWrite.d.ts.map +1 -1
  41. package/dist/cjs/review/contractWrite.js +2 -1
  42. package/dist/cjs/review/contractWrite.js.map +1 -1
  43. package/dist/cjs/review/decodeCall.d.ts.map +1 -1
  44. package/dist/cjs/review/decodeCall.js +7 -0
  45. package/dist/cjs/review/decodeCall.js.map +1 -1
  46. package/dist/cjs/review/heldWrite.d.ts +4 -0
  47. package/dist/cjs/review/heldWrite.d.ts.map +1 -1
  48. package/dist/cjs/review/heldWrite.js +31 -28
  49. package/dist/cjs/review/heldWrite.js.map +1 -1
  50. package/dist/cjs/review/index.d.ts +1 -1
  51. package/dist/cjs/review/index.d.ts.map +1 -1
  52. package/dist/cjs/review/index.js +6 -2
  53. package/dist/cjs/review/index.js.map +1 -1
  54. package/dist/cjs/review/lineError.d.ts +38 -0
  55. package/dist/cjs/review/lineError.d.ts.map +1 -1
  56. package/dist/cjs/review/lineError.js +35 -1
  57. package/dist/cjs/review/lineError.js.map +1 -1
  58. package/dist/cjs/review/plan.d.ts +0 -2
  59. package/dist/cjs/review/plan.d.ts.map +1 -1
  60. package/dist/cjs/review/plan.js +0 -6
  61. package/dist/cjs/review/plan.js.map +1 -1
  62. package/dist/cjs/review/react/useHeldSend.js +3 -4
  63. package/dist/cjs/review/react/useHeldSend.js.map +1 -1
  64. package/dist/cjs/review/react/useHeldWrite.d.ts.map +1 -1
  65. package/dist/cjs/review/react/useHeldWrite.js +2 -1
  66. package/dist/cjs/review/react/useHeldWrite.js.map +1 -1
  67. package/dist/cjs/review/react/useReviewedRun.d.ts +29 -3
  68. package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -1
  69. package/dist/cjs/review/react/useReviewedRun.js +219 -37
  70. package/dist/cjs/review/react/useReviewedRun.js.map +1 -1
  71. package/dist/cjs/review/receipt.d.ts +33 -0
  72. package/dist/cjs/review/receipt.d.ts.map +1 -1
  73. package/dist/cjs/review/receipt.js +69 -0
  74. package/dist/cjs/review/receipt.js.map +1 -1
  75. package/dist/cjs/review/relayr.d.ts.map +1 -1
  76. package/dist/cjs/review/relayr.js +1 -0
  77. package/dist/cjs/review/relayr.js.map +1 -1
  78. package/dist/cjs/review/relayrSend.d.ts +3 -32
  79. package/dist/cjs/review/relayrSend.d.ts.map +1 -1
  80. package/dist/cjs/review/relayrSend.js +78 -226
  81. package/dist/cjs/review/relayrSend.js.map +1 -1
  82. package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
  83. package/dist/cjs/review/safeRelayr.js +4 -8
  84. package/dist/cjs/review/safeRelayr.js.map +1 -1
  85. package/dist/cjs/review/safeSend.js +3 -5
  86. package/dist/cjs/review/safeSend.js.map +1 -1
  87. package/dist/cjs/review/send.d.ts +38 -7
  88. package/dist/cjs/review/send.d.ts.map +1 -1
  89. package/dist/cjs/review/send.js +267 -121
  90. package/dist/cjs/review/send.js.map +1 -1
  91. package/dist/cjs/review/sign.d.ts +6 -4
  92. package/dist/cjs/review/sign.d.ts.map +1 -1
  93. package/dist/cjs/review/sign.js +22 -18
  94. package/dist/cjs/review/sign.js.map +1 -1
  95. package/dist/cjs/review/wallet.d.ts +18 -2
  96. package/dist/cjs/review/wallet.d.ts.map +1 -1
  97. package/dist/cjs/review/wallet.js +127 -50
  98. package/dist/cjs/review/wallet.js.map +1 -1
  99. package/dist/cjs/review/writeHold.d.ts +38 -1
  100. package/dist/cjs/review/writeHold.d.ts.map +1 -1
  101. package/dist/cjs/review/writeHold.js +37 -5
  102. package/dist/cjs/review/writeHold.js.map +1 -1
  103. package/dist/cjs/review/writeRecovery.d.ts +11 -0
  104. package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
  105. package/dist/cjs/review/writeRecovery.js +38 -5
  106. package/dist/cjs/review/writeRecovery.js.map +1 -1
  107. package/dist/cjs/v6/cashOut.d.ts.map +1 -1
  108. package/dist/cjs/v6/cashOut.js +8 -14
  109. package/dist/cjs/v6/cashOut.js.map +1 -1
  110. package/dist/cjs/v6/feeBuyback.d.ts.map +1 -1
  111. package/dist/cjs/v6/feeBuyback.js +2 -7
  112. package/dist/cjs/v6/feeBuyback.js.map +1 -1
  113. package/dist/cjs/v6/pay.d.ts.map +1 -1
  114. package/dist/cjs/v6/pay.js +36 -37
  115. package/dist/cjs/v6/pay.js.map +1 -1
  116. package/dist/cjs/v6/terminals.d.ts.map +1 -1
  117. package/dist/cjs/v6/terminals.js +2 -8
  118. package/dist/cjs/v6/terminals.js.map +1 -1
  119. package/dist/cjs/v6/types.d.ts +10 -0
  120. package/dist/cjs/v6/types.d.ts.map +1 -1
  121. package/dist/cjs/v6/types.js +20 -0
  122. package/dist/cjs/v6/types.js.map +1 -1
  123. package/dist/esm/generated/abi/jbBuybackHookAbi.d.ts +8 -0
  124. package/dist/esm/generated/abi/jbBuybackHookAbi.d.ts.map +1 -1
  125. package/dist/esm/generated/abi/jbBuybackHookAbi.js +5 -0
  126. package/dist/esm/generated/abi/jbBuybackHookAbi.js.map +1 -1
  127. package/dist/esm/generated/abi/jbBuybackHookPreviousAbi.d.ts +12 -0
  128. package/dist/esm/generated/abi/jbBuybackHookPreviousAbi.d.ts.map +1 -1
  129. package/dist/esm/generated/abi/jbBuybackHookPreviousAbi.js +8 -0
  130. package/dist/esm/generated/abi/jbBuybackHookPreviousAbi.js.map +1 -1
  131. package/dist/esm/generated/abi/jbBuybackHookV2Abi.d.ts +1175 -0
  132. package/dist/esm/generated/abi/jbBuybackHookV2Abi.d.ts.map +1 -0
  133. package/dist/esm/generated/abi/jbBuybackHookV2Abi.js +829 -0
  134. package/dist/esm/generated/abi/jbBuybackHookV2Abi.js.map +1 -0
  135. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookAbi.d.ts +214 -113
  136. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookAbi.d.ts.map +1 -1
  137. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookAbi.js +176 -82
  138. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookAbi.js.map +1 -1
  139. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.d.ts +1 -1
  140. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.js +1 -1
  141. package/dist/esm/generated/abi/jbUniswapV4LpSplitHookDeployerAbi.js.map +1 -1
  142. package/dist/esm/generated/abi/jbp6FeeLpSplitHookAbi.d.ts +214 -113
  143. package/dist/esm/generated/abi/jbp6FeeLpSplitHookAbi.d.ts.map +1 -1
  144. package/dist/esm/generated/abi/jbp6FeeLpSplitHookAbi.js +176 -82
  145. package/dist/esm/generated/abi/jbp6FeeLpSplitHookAbi.js.map +1 -1
  146. package/dist/esm/generated/addresses/jbContractAddress.d.ts +42 -42
  147. package/dist/esm/generated/addresses/jbContractAddressHistory.d.ts +75 -0
  148. package/dist/esm/generated/addresses/jbContractAddressHistory.d.ts.map +1 -0
  149. package/dist/esm/generated/addresses/jbContractAddressHistory.js +77 -0
  150. package/dist/esm/generated/addresses/jbContractAddressHistory.js.map +1 -0
  151. package/dist/esm/generated/addresses/jbV6ContractAddress.d.ts +42 -42
  152. package/dist/esm/generated/addresses/jbV6ContractAddress.js +42 -42
  153. package/dist/esm/generated/juicebox.d.ts +13 -45
  154. package/dist/esm/generated/juicebox.d.ts.map +1 -1
  155. package/dist/esm/generated/juicebox.js +22 -45
  156. package/dist/esm/generated/juicebox.js.map +1 -1
  157. package/dist/esm/review/confirm.d.ts +4 -0
  158. package/dist/esm/review/confirm.d.ts.map +1 -1
  159. package/dist/esm/review/confirm.js +13 -3
  160. package/dist/esm/review/confirm.js.map +1 -1
  161. package/dist/esm/review/contractWrite.d.ts.map +1 -1
  162. package/dist/esm/review/contractWrite.js +3 -2
  163. package/dist/esm/review/contractWrite.js.map +1 -1
  164. package/dist/esm/review/decodeCall.d.ts.map +1 -1
  165. package/dist/esm/review/decodeCall.js +7 -0
  166. package/dist/esm/review/decodeCall.js.map +1 -1
  167. package/dist/esm/review/heldWrite.d.ts +4 -0
  168. package/dist/esm/review/heldWrite.d.ts.map +1 -1
  169. package/dist/esm/review/heldWrite.js +30 -27
  170. package/dist/esm/review/heldWrite.js.map +1 -1
  171. package/dist/esm/review/index.d.ts +1 -1
  172. package/dist/esm/review/index.d.ts.map +1 -1
  173. package/dist/esm/review/index.js +1 -1
  174. package/dist/esm/review/index.js.map +1 -1
  175. package/dist/esm/review/lineError.d.ts +38 -0
  176. package/dist/esm/review/lineError.d.ts.map +1 -1
  177. package/dist/esm/review/lineError.js +33 -1
  178. package/dist/esm/review/lineError.js.map +1 -1
  179. package/dist/esm/review/plan.d.ts +0 -2
  180. package/dist/esm/review/plan.d.ts.map +1 -1
  181. package/dist/esm/review/plan.js +0 -5
  182. package/dist/esm/review/plan.js.map +1 -1
  183. package/dist/esm/review/react/useHeldSend.js +3 -4
  184. package/dist/esm/review/react/useHeldSend.js.map +1 -1
  185. package/dist/esm/review/react/useHeldWrite.d.ts.map +1 -1
  186. package/dist/esm/review/react/useHeldWrite.js +2 -1
  187. package/dist/esm/review/react/useHeldWrite.js.map +1 -1
  188. package/dist/esm/review/react/useReviewedRun.d.ts +29 -3
  189. package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -1
  190. package/dist/esm/review/react/useReviewedRun.js +220 -38
  191. package/dist/esm/review/react/useReviewedRun.js.map +1 -1
  192. package/dist/esm/review/receipt.d.ts +33 -0
  193. package/dist/esm/review/receipt.d.ts.map +1 -1
  194. package/dist/esm/review/receipt.js +66 -0
  195. package/dist/esm/review/receipt.js.map +1 -1
  196. package/dist/esm/review/relayr.d.ts.map +1 -1
  197. package/dist/esm/review/relayr.js +2 -1
  198. package/dist/esm/review/relayr.js.map +1 -1
  199. package/dist/esm/review/relayrSend.d.ts +3 -32
  200. package/dist/esm/review/relayrSend.d.ts.map +1 -1
  201. package/dist/esm/review/relayrSend.js +85 -232
  202. package/dist/esm/review/relayrSend.js.map +1 -1
  203. package/dist/esm/review/safeRelayr.d.ts.map +1 -1
  204. package/dist/esm/review/safeRelayr.js +4 -8
  205. package/dist/esm/review/safeRelayr.js.map +1 -1
  206. package/dist/esm/review/safeSend.js +4 -6
  207. package/dist/esm/review/safeSend.js.map +1 -1
  208. package/dist/esm/review/send.d.ts +38 -7
  209. package/dist/esm/review/send.d.ts.map +1 -1
  210. package/dist/esm/review/send.js +270 -125
  211. package/dist/esm/review/send.js.map +1 -1
  212. package/dist/esm/review/sign.d.ts +6 -4
  213. package/dist/esm/review/sign.d.ts.map +1 -1
  214. package/dist/esm/review/sign.js +24 -20
  215. package/dist/esm/review/sign.js.map +1 -1
  216. package/dist/esm/review/wallet.d.ts +18 -2
  217. package/dist/esm/review/wallet.d.ts.map +1 -1
  218. package/dist/esm/review/wallet.js +128 -51
  219. package/dist/esm/review/wallet.js.map +1 -1
  220. package/dist/esm/review/writeHold.d.ts +38 -1
  221. package/dist/esm/review/writeHold.d.ts.map +1 -1
  222. package/dist/esm/review/writeHold.js +37 -6
  223. package/dist/esm/review/writeHold.js.map +1 -1
  224. package/dist/esm/review/writeRecovery.d.ts +11 -0
  225. package/dist/esm/review/writeRecovery.d.ts.map +1 -1
  226. package/dist/esm/review/writeRecovery.js +38 -5
  227. package/dist/esm/review/writeRecovery.js.map +1 -1
  228. package/dist/esm/v6/cashOut.d.ts.map +1 -1
  229. package/dist/esm/v6/cashOut.js +10 -16
  230. package/dist/esm/v6/cashOut.js.map +1 -1
  231. package/dist/esm/v6/feeBuyback.d.ts.map +1 -1
  232. package/dist/esm/v6/feeBuyback.js +2 -7
  233. package/dist/esm/v6/feeBuyback.js.map +1 -1
  234. package/dist/esm/v6/pay.d.ts.map +1 -1
  235. package/dist/esm/v6/pay.js +37 -38
  236. package/dist/esm/v6/pay.js.map +1 -1
  237. package/dist/esm/v6/terminals.d.ts.map +1 -1
  238. package/dist/esm/v6/terminals.js +4 -10
  239. package/dist/esm/v6/terminals.js.map +1 -1
  240. package/dist/esm/v6/types.d.ts +10 -0
  241. package/dist/esm/v6/types.d.ts.map +1 -1
  242. package/dist/esm/v6/types.js +18 -0
  243. package/dist/esm/v6/types.js.map +1 -1
  244. package/package.json +1 -1
@@ -4,12 +4,16 @@ exports.SAFE_BATCH_UNFOLLOWABLE_LINE = exports.SAFE_BATCH_UNSUPPORTED_LINE = voi
4
4
  exports.reviewPlan = reviewPlan;
5
5
  exports.sendReviewed = sendReviewed;
6
6
  exports.resumeReviewed = resumeReviewed;
7
+ exports.completeReviewedStep = completeReviewedStep;
7
8
  const lineError_js_1 = require("./lineError.js");
8
9
  const viem_1 = require("viem");
9
10
  const confirm_js_1 = require("./confirm.js");
10
11
  const contractWrite_js_1 = require("./contractWrite.js");
11
12
  const constants_js_1 = require("../constants.js");
12
13
  const gas_js_1 = require("./gas.js");
14
+ const heldWrite_js_1 = require("./heldWrite.js");
15
+ const reviewQueue_js_1 = require("./reviewQueue.js");
16
+ const pause_js_1 = require("../pause.js");
13
17
  const safeService_js_1 = require("../safeService.js");
14
18
  const messages_js_1 = require("./messages.js");
15
19
  const model_js_1 = require("./model.js");
@@ -194,14 +198,15 @@ funded) {
194
198
  if (!(0, simulation_js_1.isRevert)(error))
195
199
  return { status: "unavailable", message: SIMULATION_UNAVAILABLE };
196
200
  const reason = (0, simulation_js_1.revertReason)(error);
197
- return {
201
+ // A sequence's failure is the SDK's line naming its call.
202
+ const failure = error instanceof lineError_js_1.ReviewLineError
203
+ ? error
204
+ : (0, simulation_js_1.simulationFailure)(`${labelOf(calls[steps[0]], steps[0])} cannot run on ${chainName}: ${reason ?? simulation_js_1.REVERT_UNKNOWN_LINE}`, error);
205
+ return (0, confirm_js_1.failedSimulation)({
198
206
  status: "failed",
199
- // A sequence's failure is the SDK's line naming its call.
200
- message: error instanceof lineError_js_1.ReviewLineError
201
- ? error.message
202
- : `${labelOf(calls[steps[0]], steps[0])} cannot run on ${chainName}: ${reason ?? simulation_js_1.REVERT_UNKNOWN_LINE}`,
207
+ message: failure.message,
203
208
  explained: reason !== null,
204
- };
209
+ }, failure);
205
210
  }
206
211
  });
207
212
  // A revert on one chain is reported at once, whatever the others still wait on.
@@ -243,8 +248,8 @@ async function promptSimulated(model, fromOf, calls, run, blocks, clientFor, sig
243
248
  * One review of calls an app then sends one by one, across chains and
244
249
  * paths: core's prompt over exactly `action.calls`, simulated as their
245
250
  * senders, and nothing else. The plan it returns lets {@link sendReviewed},
246
- * `signReviewed`, `proposeReviewedSafeTransaction`, `payRelayrReviewed` and
247
- * `runRelayrReviewed` skip their prompt for a call identical to one of its
251
+ * `signReviewed`, `proposeReviewedSafeTransaction` and `payRelayrReviewed`
252
+ * skip their prompt for a call identical to one of its
248
253
  * calls (account, chain, sender, target, data, value and gas: a call's
249
254
  * exact gas limit, or a forward request's signed gas, is set before the
250
255
  * review), each spent once, for {@link REVIEWED_PLAN_TTL_MS} after confirm.
@@ -381,38 +386,21 @@ async function resumeReviewed(record, action, deps) {
381
386
  // wallet") or nothing was sent: then the step is reviewed and sent again.
382
387
  if (!state.settled && !handle.released(reservation))
383
388
  throw new lineError_js_1.ReviewLineError(sequence_js_1.REVIEWED_SEQUENCE_UNCERTAIN_LINE);
384
- delete saved.sending;
385
- delete saved.proposed;
386
389
  const { settled } = state;
387
- if (settled?.result === "success") {
388
- // This sequence's own step: it is recorded, never offered again.
390
+ // Read before anything advances: a failed read leaves the step to resume again.
391
+ const receipt = await confirmedReceipt(settled, deps.clientFor(call.chainId));
392
+ // This sequence's own step: it is recorded, told, and only then
393
+ // acknowledged, so it is never offered again.
394
+ const kept = await recordSending(saved, settled, storage, expected);
395
+ await tellConfirmed(action, handle, call, step, settled, receipt);
396
+ if (settled?.result === "success")
389
397
  await handle.acknowledge(settled);
390
- saved.completed.push(settled.hash);
391
- }
392
- /** Tells the site of the step that went through while away, once saved and when its receipt reads. */
393
- const told = async () => {
394
- if (settled?.result !== "success" || !action.onConfirmed)
395
- return;
396
- try {
397
- const receipt = await deps
398
- .clientFor(call.chainId)
399
- .getTransactionReceipt({ hash: settled.hash });
400
- if (receipt.status === "success")
401
- await action.onConfirmed(call, step, receipt);
402
- }
403
- catch {
404
- /* The step went through whatever the read or the site's callback does. */
405
- }
406
- };
407
- if (saved.completed.length === saved.calls.length) {
408
- await (0, sequence_js_1.removeReviewedSequence)(saved, storage, expected);
409
- await told();
398
+ if (kept === null) {
410
399
  const total = saved.calls.length;
411
- deps.onProgress?.({ step: total - 1, total, phase: "done" });
400
+ (0, receipt_js_1.tell)(deps.onProgress, { step: total - 1, total, phase: "done" });
412
401
  return { status: "done", hashes: saved.completed, receipts: [] };
413
402
  }
414
- expected = await (0, sequence_js_1.saveReviewedSequence)(saved, storage, expected);
415
- await told();
403
+ expected = kept;
416
404
  }
417
405
  return send({
418
406
  ...action,
@@ -421,8 +409,133 @@ async function resumeReviewed(record, action, deps) {
421
409
  scope: saved.scope,
422
410
  }, deps, { record: saved, storage, raw: expected });
423
411
  }
412
+ /**
413
+ * Ends `saved`'s step in flight as its hold settled it: a success is
414
+ * recorded as completed. Removes a finished sequence (null) or saves it over
415
+ * `expected`, returning the value written.
416
+ */
417
+ async function recordSending(saved, settled, storage, expected) {
418
+ delete saved.sending;
419
+ delete saved.proposed;
420
+ if (settled?.result === "success")
421
+ saved.completed.push(settled.hash);
422
+ if (saved.completed.length < saved.calls.length)
423
+ return (0, sequence_js_1.saveReviewedSequence)(saved, storage, expected);
424
+ await (0, sequence_js_1.removeReviewedSequence)(saved, storage, expected);
425
+ return null;
426
+ }
427
+ /**
428
+ * The receipt of a step its hold settled ({@link heldReceipt}), checked
429
+ * before anything advances: a read that fails or disagrees with the hold
430
+ * throws. Null when the settlement has no transaction (an expiry).
431
+ */
432
+ async function confirmedReceipt(settled, client, given) {
433
+ return settled && "hash" in settled
434
+ ? (0, receipt_js_1.heldReceipt)(settled, client, given)
435
+ : null;
436
+ }
437
+ /**
438
+ * Tells `onConfirmed` of a step's verified success, once per settlement:
439
+ * only the completion (a run, `completeReviewedStep`, `resumeReviewed`, in
440
+ * any tab) that claims its notice on the hold tells it.
441
+ */
442
+ async function tellConfirmed(action, handle, call, step, settled, receipt) {
443
+ if (settled?.result === "success" &&
444
+ receipt &&
445
+ (await handle.claimConfirmed(settled)))
446
+ await (0, receipt_js_1.tell)(action.onConfirmed, call, step, receipt);
447
+ }
448
+ /**
449
+ * A sent step's settlement by its own reservation, and the receipt its hold
450
+ * verified ({@link heldReceipt}), read again until it reads. Null on `follow`'s
451
+ * timeout or signal, or when the hold cleared without settling it (its exit).
452
+ */
453
+ async function followSent(handle, client, reserved, follow) {
454
+ const stop = new AbortController();
455
+ const timer = setTimeout(() => stop.abort(), follow.timeoutMs ?? heldWrite_js_1.FOLLOW_MS);
456
+ const signal = follow.signal
457
+ ? AbortSignal.any([stop.signal, follow.signal])
458
+ : stop.signal;
459
+ // Every read races the follow's end: a read that answers after it is ignored.
460
+ const ended = new Promise((resolve) => {
461
+ signal.addEventListener("abort", () => resolve(null), { once: true });
462
+ });
463
+ const read = (work) => Promise.race([work, ended]);
464
+ try {
465
+ while (!signal.aborted) {
466
+ const state = await read((0, heldWrite_js_1.followHeldWrite)(handle, client, { signal }));
467
+ if (signal.aborted)
468
+ return null;
469
+ if (state?.status !== "clear" ||
470
+ state.reservation !== reserved ||
471
+ !state.settled ||
472
+ !("hash" in state.settled))
473
+ return null;
474
+ const { settled } = state;
475
+ try {
476
+ const receipt = await read((0, receipt_js_1.heldReceipt)(settled, client));
477
+ return signal.aborted || !receipt ? null : { settled, receipt };
478
+ }
479
+ catch {
480
+ await (0, pause_js_1.pause)(heldWrite_js_1.RECEIPT_RETRY_MS, signal, () => null).catch(() => null);
481
+ }
482
+ }
483
+ return null;
484
+ }
485
+ finally {
486
+ clearTimeout(timer);
487
+ }
488
+ }
489
+ /**
490
+ * Completes a sent step (one a run left at its receipt,
491
+ * {@link ReviewedReceiptUnverifiedError}, or a proposal: its step and its
492
+ * `held` call and reservation) once its hold settled that send, as the run
493
+ * itself would have: the saved sequence under `scope` records it, a success
494
+ * is told to `onConfirmed` with the receipt its hold verified (`receipt`,
495
+ * the hold view's, say, when it is that one) and only then acknowledged, the
496
+ * one acknowledgement of a followed step. Returns the settlement and that
497
+ * checked receipt (a failure's too); null until then. A read that fails or disagrees with the hold throws with
498
+ * nothing advanced: call it again. Call it once per settlement:
499
+ * `onConfirmed` is told each time.
500
+ */
501
+ async function completeReviewedStep(unverified, action, deps, receipt) {
502
+ const { step, held } = unverified;
503
+ if (!held)
504
+ return null;
505
+ const { call, reservation } = held;
506
+ const client = deps.clientFor(call.chainId);
507
+ const handle = (0, writeHold_js_1.openStepHold)(deps.hold, action.account, false, call);
508
+ const state = await handle.state(client);
509
+ if (state.status !== "clear" ||
510
+ state.reservation !== reservation ||
511
+ !state.settled)
512
+ return null;
513
+ const { settled } = state;
514
+ const confirmed = await confirmedReceipt(settled, client, receipt);
515
+ if (action.scope !== undefined) {
516
+ const storage = deps.storage ?? (0, writeRecovery_js_1.createHeldWriteStorage)();
517
+ const { raw, record } = (0, sequence_js_1.readReviewedSequence)(action.scope, action.account, storage);
518
+ if (record?.sending?.step === step &&
519
+ record.sending.reservation === reservation)
520
+ await recordSending(record, settled, storage, raw);
521
+ }
522
+ await tellConfirmed(action, handle, call, step, settled, confirmed);
523
+ if (settled.result === "success")
524
+ await handle.acknowledge(settled);
525
+ return { settled, receipt: confirmed };
526
+ }
527
+ /**
528
+ * The hash a wallet returned, even when the site's record of it failed
529
+ * afterwards: the step was sent.
530
+ */
531
+ function sentHash(error) {
532
+ if (error instanceof contractWrite_js_1.SubmittedContractWriteError)
533
+ return error.hash;
534
+ throw error;
535
+ }
424
536
  async function send(action, deps, resuming) {
425
- const { adapter, clientFor, hold, onProgress } = deps;
537
+ const { adapter, clientFor, hold } = deps;
538
+ const onProgress = (progress) => (0, receipt_js_1.tell)(deps.onProgress, progress);
426
539
  action.guard?.();
427
540
  const { account } = action;
428
541
  const calls = [...action.calls];
@@ -433,14 +546,7 @@ async function send(action, deps, resuming) {
433
546
  /** Each step's simulation block, read once; a resumed run's prerequisites are long confirmed. */
434
547
  const blocks = calls.map((call) => resuming ? undefined : call.simulationBlockNumber);
435
548
  /** A site's release callback never stops core's own release. */
436
- const tellUnsent = async (call, step) => {
437
- try {
438
- await action.onUnsent?.(call, step);
439
- }
440
- catch {
441
- /* The step is released whatever the site's callback does. */
442
- }
443
- };
549
+ const tellUnsent = (call, step) => (0, receipt_js_1.tell)(action.onUnsent, call, step);
444
550
  const connected = adapter.account();
445
551
  if (!connected)
446
552
  throw new lineError_js_1.ReviewLineError("Connect a wallet first.");
@@ -495,20 +601,12 @@ async function send(action, deps, resuming) {
495
601
  await tellUnsent(call, step);
496
602
  throw error;
497
603
  }
498
- // Every step is told; a site's failure to record it never reads as unsent.
499
- const failures = [];
604
+ // Every step is told; a site's failure to record it never changes what was sent.
500
605
  for (const [step, call] of calls.entries())
501
- try {
502
- await action.onSubmitted?.(call, step, hash, {
503
- safe: false,
504
- adopted: false,
505
- });
506
- }
507
- catch (error) {
508
- failures.push(error);
509
- }
510
- if (failures.length)
511
- throw new contractWrite_js_1.SubmittedContractWriteError(hash, failures[0]);
606
+ await (0, receipt_js_1.tell)(action.onSubmitted, call, step, hash, {
607
+ safe: false,
608
+ adopted: false,
609
+ });
512
610
  return { status: "done", hashes: [hash], receipts: [] };
513
611
  }
514
612
  const { scope } = action;
@@ -549,6 +647,10 @@ async function send(action, deps, resuming) {
549
647
  if (state.status !== "clear")
550
648
  throw new writeHold_js_1.WriteHeldError(state);
551
649
  }
650
+ // So is one whose last success nothing showed: a resend may pay twice.
651
+ const away = handles[handles.length - 1].unacknowledgedSuccess();
652
+ if (away)
653
+ throw new writeHold_js_1.WriteHoldUnacknowledgedSuccessError(away);
552
654
  /**
553
655
  * Each step's latest reservation as the review opened. Another prompt of
554
656
  * the same action that reserved meanwhile, whether or not it has settled,
@@ -621,7 +723,7 @@ async function send(action, deps, resuming) {
621
723
  if (!sameCall(now, sent[step]))
622
724
  throw new lineError_js_1.ReviewLineError(CHANGED);
623
725
  });
624
- const progress = (phase, hash) => onProgress?.({
726
+ const progress = (phase, hash) => onProgress({
625
727
  step: 0,
626
728
  total: calls.length,
627
729
  phase,
@@ -629,7 +731,8 @@ async function send(action, deps, resuming) {
629
731
  });
630
732
  /** The steps whose `beforeWallet` began. */
631
733
  let began = 0;
632
- const hash = await handles[0].send(client, (gate) => {
734
+ const hash = await handles[0]
735
+ .send(client, (gate) => {
633
736
  if (generation(handles[0]) !== reviewedGenerations[0]) {
634
737
  throw new writeHold_js_1.WriteHoldStaleReviewError();
635
738
  }
@@ -692,19 +795,11 @@ async function send(action, deps, resuming) {
692
795
  onWriteSubmitted: async (submitted) => {
693
796
  gate.afterSubmit(submitted);
694
797
  // Every step went: each is told, whatever an earlier callback does.
695
- const failures = [];
696
798
  for (const [step, call] of calls.entries())
697
- try {
698
- await action.onSubmitted?.(call, step, submitted, {
699
- safe: true,
700
- adopted: false,
701
- });
702
- }
703
- catch (error) {
704
- failures.push(error);
705
- }
706
- if (failures.length)
707
- throw failures[0];
799
+ await (0, receipt_js_1.tell)(action.onSubmitted, call, step, submitted, {
800
+ safe: true,
801
+ adopted: false,
802
+ });
708
803
  },
709
804
  write: async () => {
710
805
  const id = await adapter.sendCalls(batched.chainId, sent.map(({ to, data, value }) => ({ to, data, value })));
@@ -716,7 +811,8 @@ async function send(action, deps, resuming) {
716
811
  onPhase: (phase) => progress(phase),
717
812
  guard: action.guard,
718
813
  });
719
- });
814
+ })
815
+ .catch(sentHash);
720
816
  progress("proposed", hash);
721
817
  return { status: "proposed", step: 0, safeTxHash: hash, ...signed };
722
818
  }
@@ -765,7 +861,7 @@ async function send(action, deps, resuming) {
765
861
  const reviewed = sent[step];
766
862
  /** This step's index in the whole action. */
767
863
  const at = offset + step;
768
- const progress = (phase, hash) => onProgress?.({ step: at, total, phase, ...(hash ? { hash } : {}) });
864
+ const progress = (phase, hash) => onProgress({ step: at, total, phase, ...(hash ? { hash } : {}) });
769
865
  const unchanged = () => {
770
866
  let now;
771
867
  try {
@@ -792,20 +888,20 @@ async function send(action, deps, resuming) {
792
888
  const done = resuming?.record;
793
889
  if (step > 0 || !done?.completed.length)
794
890
  return undefined;
795
- const { chainId } = done.calls[done.completed.length - 1];
796
- // One read: a receipt that can't be read now (a repriced original) is no block.
797
- const receipt = await clientFor(chainId)
798
- .getTransactionReceipt({
799
- hash: done.completed[done.completed.length - 1],
800
- })
801
- .catch(() => undefined);
802
- return receipt
803
- ? {
804
- chainId,
805
- blockNumber: receipt.blockNumber,
806
- blockHash: receipt.blockHash,
807
- }
808
- : undefined;
891
+ const last = done.calls[done.completed.length - 1];
892
+ const hash = done.completed[done.completed.length - 1];
893
+ // Its hold's settlement, while it is still the call's latest, kept
894
+ // the block it verified; else the hash's receipt, canonical and final.
895
+ const held = (0, writeHold_js_1.openStepHold)(hold, account, adapter.isSafe(), last).peek();
896
+ const settled = held.status === "clear" &&
897
+ held.settled &&
898
+ "hash" in held.settled &&
899
+ held.settled.hash.toLowerCase() === hash.toLowerCase()
900
+ ? held.settled
901
+ : { result: "success", hash };
902
+ // One try: a block that can't be read or verified now is no block.
903
+ const block = await (0, receipt_js_1.heldBlock)(settled, clientFor(last.chainId)).catch(() => undefined);
904
+ return block && { chainId: last.chainId, ...block };
809
905
  };
810
906
  const priorBlock = call.dependsOnPrior &&
811
907
  prior &&
@@ -816,7 +912,12 @@ async function send(action, deps, resuming) {
816
912
  let reserved;
817
913
  /** A proposal of exactly this call its Safe already queued, sent in its place. */
818
914
  let queued;
819
- const hash = await handles[step].send(client, (gate) => {
915
+ /** The caller's end of the run, once this run sent a step. */
916
+ const runEnd = hashes.length ? action.follow?.signal : undefined;
917
+ /** The site's failed record of this step's hash: the step was sent, and is held unverified. */
918
+ let unrecorded;
919
+ const hash = await handles[step]
920
+ .send(client, (gate) => {
820
921
  // Under the hold's own check of the call, before anything reserves.
821
922
  if (generation(handles[step]) !== reviewedGenerations[step]) {
822
923
  throw new writeHold_js_1.WriteHoldStaleReviewError();
@@ -907,6 +1008,10 @@ async function send(action, deps, resuming) {
907
1008
  }
908
1009
  },
909
1010
  beforeSend: () => {
1011
+ // The caller ended the run (a reset, an unmount) after it sent a
1012
+ // step: nothing more is sent.
1013
+ if (hashes.length && action.follow?.signal?.aborted)
1014
+ throw new reviewQueue_js_1.TransactionReviewCancelledError();
910
1015
  action.assertWriteState?.();
911
1016
  unchanged();
912
1017
  if (adapter.isSafe() !== safe) {
@@ -925,16 +1030,32 @@ async function send(action, deps, resuming) {
925
1030
  // An adopted proposal's nonce lets the hold prove its execution onchain.
926
1031
  onWriteSubmitted: async (submitted) => {
927
1032
  gate.afterSubmit(submitted, queued?.tx);
928
- await action.onSubmitted?.(call, at, submitted, {
1033
+ await (0, receipt_js_1.tell)(action.onSubmitted, call, at, submitted, {
929
1034
  safe,
930
1035
  adopted: !!queued,
931
1036
  });
932
1037
  },
933
1038
  write: async ({ chainId, to, data, value, gas }) => queued?.proposalHash ??
934
- adapter.sendTransaction({ chainId, to, data, value, gas }),
1039
+ adapter.sendTransaction({
1040
+ chainId,
1041
+ to,
1042
+ data,
1043
+ value,
1044
+ gas,
1045
+ // After a step was sent, the run's end refuses this one, unsent,
1046
+ // as late as the wallet's own last check.
1047
+ ...(runEnd ? { signal: runEnd } : {}),
1048
+ }),
935
1049
  onPhase: (phase) => progress(phase),
936
1050
  guard: action.guard,
937
1051
  });
1052
+ })
1053
+ .catch((error) => {
1054
+ // Refused unsent because the caller ended the run: a cancel, not a failure.
1055
+ if (runEnd?.aborted && error instanceof lineError_js_1.WalletNotInvokedError)
1056
+ throw new reviewQueue_js_1.TransactionReviewCancelledError();
1057
+ unrecorded = error;
1058
+ return sentHash(error);
938
1059
  });
939
1060
  hashes.push(hash);
940
1061
  // A later step held under this step's key (the same call, or the same
@@ -956,21 +1077,56 @@ async function send(action, deps, resuming) {
956
1077
  progress("proposed", hash);
957
1078
  return { status: "proposed", step: at, safeTxHash: hash, ...signed };
958
1079
  }
959
- progress("receipt", hash);
960
- const receipt = await (0, receipt_js_1.waitForTrackedReceipt)(client, hash);
961
- // The hold checks the receipt itself and settles, so the same call (or
962
- // intent) can be reviewed and sent again without waiting on a view.
963
- // Only this send's own reservation's settlement speaks for it: a later
964
- // send of the same call or intent may have settled since.
965
- const settled = await handles[step]
966
- .state(client)
967
- .then((state) => state.status === "clear" &&
968
- reserved !== undefined &&
969
- state.reservation === reserved
970
- ? state.settled
971
- : undefined)
972
- .catch(() => undefined);
973
- if (receipt.status === "success" && settled?.result === "failed") {
1080
+ // From here the step was sent: it ends done, failed as its hold
1081
+ // verified, or unverified with what resumes it, never any other way.
1082
+ const unverified = (cause) => new lineError_js_1.ReviewedReceiptUnverifiedError(at, hash, (0, safeService_js_1.isSafeExecTransaction)(reviewed.data)
1083
+ ? messages_js_1.WRITE_HOLD_SAFE_UNCONFIRMED_LINE
1084
+ : undefined, {
1085
+ call,
1086
+ reservation: reserved,
1087
+ // This run's sends, its own last: only the steps before it completed.
1088
+ hashes: journal ? [...journal.completed] : hashes.slice(0, -1),
1089
+ ...signed,
1090
+ }, cause === undefined ? {} : { cause });
1091
+ // The site could not record the hash: held as sent, for it to resume.
1092
+ if (unrecorded !== undefined)
1093
+ throw unverified(unrecorded);
1094
+ // Its hold's verified settlement is the only word on how it ended: its
1095
+ // result, its transaction (a speed-up's, when the wallet replaced the
1096
+ // send) and that transaction's receipt in the block the hold verified.
1097
+ // A watcher's receipt only says when to ask.
1098
+ let receipt;
1099
+ let settled;
1100
+ try {
1101
+ progress("receipt", hash);
1102
+ const seen = await (0, receipt_js_1.waitForTrackedReceipt)(client, hash);
1103
+ // Only this send's own reservation's settlement speaks for it: a later
1104
+ // send of the same call or intent may have settled since.
1105
+ settled = await handles[step]
1106
+ .state(client)
1107
+ .then((state) => state.status === "clear" &&
1108
+ reserved !== undefined &&
1109
+ state.reservation === reserved &&
1110
+ state.settled &&
1111
+ "hash" in state.settled
1112
+ ? state.settled
1113
+ : undefined)
1114
+ .catch(() => undefined);
1115
+ receipt = settled
1116
+ ? await (0, receipt_js_1.heldReceipt)(settled, client, seen).catch(() => undefined)
1117
+ : undefined;
1118
+ if (!receipt && action.follow) {
1119
+ (0, receipt_js_1.tell)(action.follow.onConfirming, at);
1120
+ const ended = await followSent(handles[step], client, reserved, action.follow);
1121
+ ({ settled, receipt } = ended ?? { settled, receipt });
1122
+ }
1123
+ }
1124
+ catch (error) {
1125
+ throw unverified(error);
1126
+ }
1127
+ if (!settled || !receipt)
1128
+ throw unverified();
1129
+ if (settled.result === "failed" && receipt.status === "success") {
974
1130
  // It ran, and the hold proved it failed: a Safe's call that failed.
975
1131
  if (journal) {
976
1132
  delete journal.sending;
@@ -978,35 +1134,25 @@ async function send(action, deps, resuming) {
978
1134
  }
979
1135
  throw new lineError_js_1.ReviewLineError(messages_js_1.WRITE_HOLD_CALL_FAILED_LINE);
980
1136
  }
981
- // A Safe's execTransaction is done only once its hold proved the Safe's
982
- // own success; until then the step stays in flight, held and journaled.
983
- if (receipt.status === "success" &&
984
- (0, safeService_js_1.isSafeExecTransaction)(reviewed.data) &&
985
- settled?.result !== "success") {
986
- throw new lineError_js_1.ReviewLineError(messages_js_1.WRITE_HOLD_SAFE_UNCONFIRMED_LINE);
987
- }
1137
+ const mined = settled.hash;
1138
+ hashes[hashes.length - 1] = mined;
988
1139
  if (receipt.status !== "success") {
989
1140
  // It ran and reverted: nothing of it to resume.
990
1141
  if (journal) {
991
1142
  delete journal.sending;
992
1143
  await keep();
993
1144
  }
994
- throw new lineError_js_1.ReviewedCallRevertedError(at, hash, receipt);
1145
+ throw new lineError_js_1.ReviewedCallRevertedError(at, mined, receipt);
995
1146
  }
996
1147
  receipts.push(receipt);
997
1148
  if (journal) {
998
1149
  delete journal.sending;
999
- journal.completed.push(hash);
1150
+ journal.completed.push(mined);
1000
1151
  await keep();
1001
1152
  }
1002
- try {
1003
- await action.onConfirmed?.(call, at, receipt);
1004
- }
1005
- catch {
1006
- /* The step went through whatever the site's callback does. */
1007
- }
1153
+ await tellConfirmed(action, handles[step], call, at, settled, receipt);
1008
1154
  }
1009
- onProgress?.({ step: total - 1, total, phase: "done" });
1155
+ onProgress({ step: total - 1, total, phase: "done" });
1010
1156
  return {
1011
1157
  status: "done",
1012
1158
  hashes: journal ? [...journal.completed] : hashes,