@bananapus/nana-sdk-core 3.5.2 → 5.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 (304) hide show
  1. package/bin/wallet-check.mjs +495 -0
  2. package/dist/cjs/actions/suckerPairs.d.ts +5 -3
  3. package/dist/cjs/actions/suckerPairs.d.ts.map +1 -1
  4. package/dist/cjs/actions/suckerPairs.js +6 -26
  5. package/dist/cjs/actions/suckerPairs.js.map +1 -1
  6. package/dist/cjs/pause.d.ts +2 -0
  7. package/dist/cjs/pause.d.ts.map +1 -1
  8. package/dist/cjs/pause.js +17 -0
  9. package/dist/cjs/pause.js.map +1 -1
  10. package/dist/cjs/review/confirm.d.ts +56 -0
  11. package/dist/cjs/review/confirm.d.ts.map +1 -0
  12. package/dist/cjs/review/confirm.js +99 -0
  13. package/dist/cjs/review/confirm.js.map +1 -0
  14. package/dist/cjs/review/contractWrite.d.ts +5 -3
  15. package/dist/cjs/review/contractWrite.d.ts.map +1 -1
  16. package/dist/cjs/review/contractWrite.js +10 -8
  17. package/dist/cjs/review/contractWrite.js.map +1 -1
  18. package/dist/cjs/review/decode.d.ts +19 -1
  19. package/dist/cjs/review/decode.d.ts.map +1 -1
  20. package/dist/cjs/review/decode.js +30 -11
  21. package/dist/cjs/review/decode.js.map +1 -1
  22. package/dist/cjs/review/decodeCall.d.ts +21 -0
  23. package/dist/cjs/review/decodeCall.d.ts.map +1 -0
  24. package/dist/cjs/review/decodeCall.js +183 -0
  25. package/dist/cjs/review/decodeCall.js.map +1 -0
  26. package/dist/cjs/review/heldWrite.d.ts +4 -0
  27. package/dist/cjs/review/heldWrite.d.ts.map +1 -1
  28. package/dist/cjs/review/heldWrite.js +35 -31
  29. package/dist/cjs/review/heldWrite.js.map +1 -1
  30. package/dist/cjs/review/index.d.ts +12 -1
  31. package/dist/cjs/review/index.d.ts.map +1 -1
  32. package/dist/cjs/review/index.js +29 -1
  33. package/dist/cjs/review/index.js.map +1 -1
  34. package/dist/cjs/review/intents.d.ts +10 -0
  35. package/dist/cjs/review/intents.d.ts.map +1 -1
  36. package/dist/cjs/review/intents.js +13 -0
  37. package/dist/cjs/review/intents.js.map +1 -1
  38. package/dist/cjs/review/lineError.d.ts +72 -0
  39. package/dist/cjs/review/lineError.d.ts.map +1 -0
  40. package/dist/cjs/review/lineError.js +76 -0
  41. package/dist/cjs/review/lineError.js.map +1 -0
  42. package/dist/cjs/review/messages.d.ts +15 -3
  43. package/dist/cjs/review/messages.d.ts.map +1 -1
  44. package/dist/cjs/review/messages.js +16 -4
  45. package/dist/cjs/review/messages.js.map +1 -1
  46. package/dist/cjs/review/model.d.ts +149 -0
  47. package/dist/cjs/review/model.d.ts.map +1 -0
  48. package/dist/cjs/review/model.js +750 -0
  49. package/dist/cjs/review/model.js.map +1 -0
  50. package/dist/cjs/review/plan.d.ts +61 -0
  51. package/dist/cjs/review/plan.d.ts.map +1 -0
  52. package/dist/cjs/review/plan.js +143 -0
  53. package/dist/cjs/review/plan.js.map +1 -0
  54. package/dist/cjs/review/react/index.d.ts +1 -0
  55. package/dist/cjs/review/react/index.d.ts.map +1 -1
  56. package/dist/cjs/review/react/index.js +1 -0
  57. package/dist/cjs/review/react/index.js.map +1 -1
  58. package/dist/cjs/review/react/useHeldSend.js +3 -4
  59. package/dist/cjs/review/react/useHeldSend.js.map +1 -1
  60. package/dist/cjs/review/react/useHeldWrite.d.ts.map +1 -1
  61. package/dist/cjs/review/react/useHeldWrite.js +2 -1
  62. package/dist/cjs/review/react/useHeldWrite.js.map +1 -1
  63. package/dist/cjs/review/react/useReviewedRun.d.ts +122 -0
  64. package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -0
  65. package/dist/cjs/review/react/useReviewedRun.js +443 -0
  66. package/dist/cjs/review/react/useReviewedRun.js.map +1 -0
  67. package/dist/cjs/review/receipt.d.ts +37 -1
  68. package/dist/cjs/review/receipt.d.ts.map +1 -1
  69. package/dist/cjs/review/receipt.js +76 -3
  70. package/dist/cjs/review/receipt.js.map +1 -1
  71. package/dist/cjs/review/relayr.d.ts +13 -4
  72. package/dist/cjs/review/relayr.d.ts.map +1 -1
  73. package/dist/cjs/review/relayr.js +52 -8
  74. package/dist/cjs/review/relayr.js.map +1 -1
  75. package/dist/cjs/review/relayrSend.d.ts +106 -0
  76. package/dist/cjs/review/relayrSend.d.ts.map +1 -0
  77. package/dist/cjs/review/relayrSend.js +795 -0
  78. package/dist/cjs/review/relayrSend.js.map +1 -0
  79. package/dist/cjs/review/reviewQueue.d.ts +10 -9
  80. package/dist/cjs/review/reviewQueue.d.ts.map +1 -1
  81. package/dist/cjs/review/reviewQueue.js +19 -29
  82. package/dist/cjs/review/reviewQueue.js.map +1 -1
  83. package/dist/cjs/review/reviewRequests.d.ts +86 -0
  84. package/dist/cjs/review/reviewRequests.d.ts.map +1 -0
  85. package/dist/cjs/review/reviewRequests.js +266 -0
  86. package/dist/cjs/review/reviewRequests.js.map +1 -0
  87. package/dist/cjs/review/safeRelayr.d.ts +3 -1
  88. package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
  89. package/dist/cjs/review/safeRelayr.js +9 -9
  90. package/dist/cjs/review/safeRelayr.js.map +1 -1
  91. package/dist/cjs/review/safeSend.d.ts +69 -0
  92. package/dist/cjs/review/safeSend.d.ts.map +1 -0
  93. package/dist/cjs/review/safeSend.js +306 -0
  94. package/dist/cjs/review/safeSend.js.map +1 -0
  95. package/dist/cjs/review/send.d.ts +272 -0
  96. package/dist/cjs/review/send.d.ts.map +1 -0
  97. package/dist/cjs/review/send.js +1163 -0
  98. package/dist/cjs/review/send.js.map +1 -0
  99. package/dist/cjs/review/sequence.d.ts +77 -0
  100. package/dist/cjs/review/sequence.d.ts.map +1 -0
  101. package/dist/cjs/review/sequence.js +232 -0
  102. package/dist/cjs/review/sequence.js.map +1 -0
  103. package/dist/cjs/review/sign.d.ts +111 -0
  104. package/dist/cjs/review/sign.d.ts.map +1 -0
  105. package/dist/cjs/review/sign.js +378 -0
  106. package/dist/cjs/review/sign.js.map +1 -0
  107. package/dist/cjs/review/simulation.d.ts +41 -2
  108. package/dist/cjs/review/simulation.d.ts.map +1 -1
  109. package/dist/cjs/review/simulation.js +99 -29
  110. package/dist/cjs/review/simulation.js.map +1 -1
  111. package/dist/cjs/review/transaction-message.d.ts +13 -0
  112. package/dist/cjs/review/transaction-message.d.ts.map +1 -1
  113. package/dist/cjs/review/transaction-message.js +25 -0
  114. package/dist/cjs/review/transaction-message.js.map +1 -1
  115. package/dist/cjs/review/transactionReview.d.ts +27 -19
  116. package/dist/cjs/review/transactionReview.d.ts.map +1 -1
  117. package/dist/cjs/review/transactionReview.js +22 -63
  118. package/dist/cjs/review/transactionReview.js.map +1 -1
  119. package/dist/cjs/review/wallet.d.ts +98 -0
  120. package/dist/cjs/review/wallet.d.ts.map +1 -0
  121. package/dist/cjs/review/wallet.js +234 -0
  122. package/dist/cjs/review/wallet.js.map +1 -0
  123. package/dist/cjs/review/writeHold.d.ts +138 -13
  124. package/dist/cjs/review/writeHold.d.ts.map +1 -1
  125. package/dist/cjs/review/writeHold.js +98 -18
  126. package/dist/cjs/review/writeHold.js.map +1 -1
  127. package/dist/cjs/review/writeRecovery.d.ts +17 -1
  128. package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
  129. package/dist/cjs/review/writeRecovery.js +146 -45
  130. package/dist/cjs/review/writeRecovery.js.map +1 -1
  131. package/dist/cjs/safeService.d.ts +27 -4
  132. package/dist/cjs/safeService.d.ts.map +1 -1
  133. package/dist/cjs/safeService.js +120 -3
  134. package/dist/cjs/safeService.js.map +1 -1
  135. package/dist/cjs/testing.d.ts +24 -0
  136. package/dist/cjs/testing.d.ts.map +1 -1
  137. package/dist/cjs/testing.js +26 -1
  138. package/dist/cjs/testing.js.map +1 -1
  139. package/dist/cjs/v6/defifa.d.ts.map +1 -1
  140. package/dist/cjs/v6/defifa.js +24 -23
  141. package/dist/cjs/v6/defifa.js.map +1 -1
  142. package/dist/cjs/v6/executionErrors.d.ts.map +1 -1
  143. package/dist/cjs/v6/executionErrors.js +3 -2
  144. package/dist/cjs/v6/executionErrors.js.map +1 -1
  145. package/dist/cjs/v6/pay.d.ts +25 -8
  146. package/dist/cjs/v6/pay.d.ts.map +1 -1
  147. package/dist/cjs/v6/pay.js +117 -23
  148. package/dist/cjs/v6/pay.js.map +1 -1
  149. package/dist/cjs/v6/suckers.d.ts +30 -0
  150. package/dist/cjs/v6/suckers.d.ts.map +1 -1
  151. package/dist/cjs/v6/suckers.js +69 -5
  152. package/dist/cjs/v6/suckers.js.map +1 -1
  153. package/dist/esm/actions/suckerPairs.d.ts +5 -3
  154. package/dist/esm/actions/suckerPairs.d.ts.map +1 -1
  155. package/dist/esm/actions/suckerPairs.js +7 -27
  156. package/dist/esm/actions/suckerPairs.js.map +1 -1
  157. package/dist/esm/pause.d.ts +2 -0
  158. package/dist/esm/pause.d.ts.map +1 -1
  159. package/dist/esm/pause.js +16 -0
  160. package/dist/esm/pause.js.map +1 -1
  161. package/dist/esm/review/confirm.d.ts +56 -0
  162. package/dist/esm/review/confirm.d.ts.map +1 -0
  163. package/dist/esm/review/confirm.js +93 -0
  164. package/dist/esm/review/confirm.js.map +1 -0
  165. package/dist/esm/review/contractWrite.d.ts +5 -3
  166. package/dist/esm/review/contractWrite.d.ts.map +1 -1
  167. package/dist/esm/review/contractWrite.js +10 -8
  168. package/dist/esm/review/contractWrite.js.map +1 -1
  169. package/dist/esm/review/decode.d.ts +19 -1
  170. package/dist/esm/review/decode.d.ts.map +1 -1
  171. package/dist/esm/review/decode.js +29 -14
  172. package/dist/esm/review/decode.js.map +1 -1
  173. package/dist/esm/review/decodeCall.d.ts +21 -0
  174. package/dist/esm/review/decodeCall.d.ts.map +1 -0
  175. package/dist/esm/review/decodeCall.js +180 -0
  176. package/dist/esm/review/decodeCall.js.map +1 -0
  177. package/dist/esm/review/heldWrite.d.ts +4 -0
  178. package/dist/esm/review/heldWrite.d.ts.map +1 -1
  179. package/dist/esm/review/heldWrite.js +34 -30
  180. package/dist/esm/review/heldWrite.js.map +1 -1
  181. package/dist/esm/review/index.d.ts +12 -1
  182. package/dist/esm/review/index.d.ts.map +1 -1
  183. package/dist/esm/review/index.js +12 -1
  184. package/dist/esm/review/index.js.map +1 -1
  185. package/dist/esm/review/intents.d.ts +10 -0
  186. package/dist/esm/review/intents.d.ts.map +1 -1
  187. package/dist/esm/review/intents.js +12 -0
  188. package/dist/esm/review/intents.js.map +1 -1
  189. package/dist/esm/review/lineError.d.ts +72 -0
  190. package/dist/esm/review/lineError.d.ts.map +1 -0
  191. package/dist/esm/review/lineError.js +68 -0
  192. package/dist/esm/review/lineError.js.map +1 -0
  193. package/dist/esm/review/messages.d.ts +15 -3
  194. package/dist/esm/review/messages.d.ts.map +1 -1
  195. package/dist/esm/review/messages.js +15 -3
  196. package/dist/esm/review/messages.js.map +1 -1
  197. package/dist/esm/review/model.d.ts +149 -0
  198. package/dist/esm/review/model.d.ts.map +1 -0
  199. package/dist/esm/review/model.js +746 -0
  200. package/dist/esm/review/model.js.map +1 -0
  201. package/dist/esm/review/plan.d.ts +61 -0
  202. package/dist/esm/review/plan.d.ts.map +1 -0
  203. package/dist/esm/review/plan.js +136 -0
  204. package/dist/esm/review/plan.js.map +1 -0
  205. package/dist/esm/review/react/index.d.ts +1 -0
  206. package/dist/esm/review/react/index.d.ts.map +1 -1
  207. package/dist/esm/review/react/index.js +1 -0
  208. package/dist/esm/review/react/index.js.map +1 -1
  209. package/dist/esm/review/react/useHeldSend.js +3 -4
  210. package/dist/esm/review/react/useHeldSend.js.map +1 -1
  211. package/dist/esm/review/react/useHeldWrite.d.ts.map +1 -1
  212. package/dist/esm/review/react/useHeldWrite.js +2 -1
  213. package/dist/esm/review/react/useHeldWrite.js.map +1 -1
  214. package/dist/esm/review/react/useReviewedRun.d.ts +122 -0
  215. package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -0
  216. package/dist/esm/review/react/useReviewedRun.js +439 -0
  217. package/dist/esm/review/react/useReviewedRun.js.map +1 -0
  218. package/dist/esm/review/receipt.d.ts +37 -1
  219. package/dist/esm/review/receipt.d.ts.map +1 -1
  220. package/dist/esm/review/receipt.js +72 -2
  221. package/dist/esm/review/receipt.js.map +1 -1
  222. package/dist/esm/review/relayr.d.ts +13 -4
  223. package/dist/esm/review/relayr.d.ts.map +1 -1
  224. package/dist/esm/review/relayr.js +51 -8
  225. package/dist/esm/review/relayr.js.map +1 -1
  226. package/dist/esm/review/relayrSend.d.ts +106 -0
  227. package/dist/esm/review/relayrSend.d.ts.map +1 -0
  228. package/dist/esm/review/relayrSend.js +787 -0
  229. package/dist/esm/review/relayrSend.js.map +1 -0
  230. package/dist/esm/review/reviewQueue.d.ts +10 -9
  231. package/dist/esm/review/reviewQueue.d.ts.map +1 -1
  232. package/dist/esm/review/reviewQueue.js +17 -26
  233. package/dist/esm/review/reviewQueue.js.map +1 -1
  234. package/dist/esm/review/reviewRequests.d.ts +86 -0
  235. package/dist/esm/review/reviewRequests.d.ts.map +1 -0
  236. package/dist/esm/review/reviewRequests.js +263 -0
  237. package/dist/esm/review/reviewRequests.js.map +1 -0
  238. package/dist/esm/review/safeRelayr.d.ts +3 -1
  239. package/dist/esm/review/safeRelayr.d.ts.map +1 -1
  240. package/dist/esm/review/safeRelayr.js +9 -9
  241. package/dist/esm/review/safeRelayr.js.map +1 -1
  242. package/dist/esm/review/safeSend.d.ts +69 -0
  243. package/dist/esm/review/safeSend.d.ts.map +1 -0
  244. package/dist/esm/review/safeSend.js +301 -0
  245. package/dist/esm/review/safeSend.js.map +1 -0
  246. package/dist/esm/review/send.d.ts +272 -0
  247. package/dist/esm/review/send.d.ts.map +1 -0
  248. package/dist/esm/review/send.js +1156 -0
  249. package/dist/esm/review/send.js.map +1 -0
  250. package/dist/esm/review/sequence.d.ts +77 -0
  251. package/dist/esm/review/sequence.d.ts.map +1 -0
  252. package/dist/esm/review/sequence.js +223 -0
  253. package/dist/esm/review/sequence.js.map +1 -0
  254. package/dist/esm/review/sign.d.ts +111 -0
  255. package/dist/esm/review/sign.d.ts.map +1 -0
  256. package/dist/esm/review/sign.js +372 -0
  257. package/dist/esm/review/sign.js.map +1 -0
  258. package/dist/esm/review/simulation.d.ts +41 -2
  259. package/dist/esm/review/simulation.d.ts.map +1 -1
  260. package/dist/esm/review/simulation.js +95 -29
  261. package/dist/esm/review/simulation.js.map +1 -1
  262. package/dist/esm/review/transaction-message.d.ts +13 -0
  263. package/dist/esm/review/transaction-message.d.ts.map +1 -1
  264. package/dist/esm/review/transaction-message.js +23 -0
  265. package/dist/esm/review/transaction-message.js.map +1 -1
  266. package/dist/esm/review/transactionReview.d.ts +27 -19
  267. package/dist/esm/review/transactionReview.d.ts.map +1 -1
  268. package/dist/esm/review/transactionReview.js +19 -56
  269. package/dist/esm/review/transactionReview.js.map +1 -1
  270. package/dist/esm/review/wallet.d.ts +98 -0
  271. package/dist/esm/review/wallet.d.ts.map +1 -0
  272. package/dist/esm/review/wallet.js +227 -0
  273. package/dist/esm/review/wallet.js.map +1 -0
  274. package/dist/esm/review/writeHold.d.ts +138 -13
  275. package/dist/esm/review/writeHold.d.ts.map +1 -1
  276. package/dist/esm/review/writeHold.js +96 -19
  277. package/dist/esm/review/writeHold.js.map +1 -1
  278. package/dist/esm/review/writeRecovery.d.ts +17 -1
  279. package/dist/esm/review/writeRecovery.d.ts.map +1 -1
  280. package/dist/esm/review/writeRecovery.js +149 -48
  281. package/dist/esm/review/writeRecovery.js.map +1 -1
  282. package/dist/esm/safeService.d.ts +27 -4
  283. package/dist/esm/safeService.d.ts.map +1 -1
  284. package/dist/esm/safeService.js +119 -4
  285. package/dist/esm/safeService.js.map +1 -1
  286. package/dist/esm/testing.d.ts +24 -0
  287. package/dist/esm/testing.d.ts.map +1 -1
  288. package/dist/esm/testing.js +23 -1
  289. package/dist/esm/testing.js.map +1 -1
  290. package/dist/esm/v6/defifa.d.ts.map +1 -1
  291. package/dist/esm/v6/defifa.js +24 -23
  292. package/dist/esm/v6/defifa.js.map +1 -1
  293. package/dist/esm/v6/executionErrors.d.ts.map +1 -1
  294. package/dist/esm/v6/executionErrors.js +3 -2
  295. package/dist/esm/v6/executionErrors.js.map +1 -1
  296. package/dist/esm/v6/pay.d.ts +25 -8
  297. package/dist/esm/v6/pay.d.ts.map +1 -1
  298. package/dist/esm/v6/pay.js +115 -22
  299. package/dist/esm/v6/pay.js.map +1 -1
  300. package/dist/esm/v6/suckers.d.ts +30 -0
  301. package/dist/esm/v6/suckers.d.ts.map +1 -1
  302. package/dist/esm/v6/suckers.js +67 -5
  303. package/dist/esm/v6/suckers.js.map +1 -1
  304. package/package.json +11 -2
@@ -0,0 +1,795 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RELAYR_FEE_MARKUP_BPS = exports.RELAYR_FEE_MARGIN_BPS = void 0;
4
+ exports.relayrFeeCap = relayrFeeCap;
5
+ exports.signReviewedForwardRequests = signReviewedForwardRequests;
6
+ exports.payRelayrReviewed = payRelayrReviewed;
7
+ exports.pollRelayrBundle = pollRelayrBundle;
8
+ exports.safeRelayrWalletDeps = safeRelayrWalletDeps;
9
+ const viem_1 = require("viem");
10
+ const accounts_1 = require("viem/accounts");
11
+ const juicebox_js_1 = require("../generated/juicebox.js");
12
+ const safe_js_1 = require("../safe.js");
13
+ const safeService_js_1 = require("../safeService.js");
14
+ const confirm_js_1 = require("./confirm.js");
15
+ const contractWrite_js_1 = require("./contractWrite.js");
16
+ const decodeCall_js_1 = require("./decodeCall.js");
17
+ const model_js_1 = require("./model.js");
18
+ const plan_js_1 = require("./plan.js");
19
+ const receipt_js_1 = require("./receipt.js");
20
+ const relayr_js_1 = require("./relayr.js");
21
+ const lineError_js_1 = require("./lineError.js");
22
+ const sign_js_1 = require("./sign.js");
23
+ const simulation_js_1 = require("./simulation.js");
24
+ const wallet_js_1 = require("./wallet.js");
25
+ const writeHold_js_1 = require("./writeHold.js");
26
+ const writeRecovery_js_1 = require("./writeRecovery.js");
27
+ const pause_js_1 = require("../pause.js");
28
+ const heldWrite_js_1 = require("./heldWrite.js");
29
+ /**
30
+ * The margin over an estimated Relayr fee that the review shows as its cap,
31
+ * in basis points (11,000 = the estimate plus 10%). Identical requests quoted
32
+ * minutes apart on every Relayr chain differed by at most 1.4%, so a signed
33
+ * quote above the cap, which asks again, should be rare.
34
+ */
35
+ exports.RELAYR_FEE_MARGIN_BPS = 11000n;
36
+ /**
37
+ * Relayr's fee over a request's gas limit at the chain's gas price, in basis
38
+ * points, for bounding a fee when no stand-in quote can be had: the highest
39
+ * ratio measured on a Relayr chain (7.95, Ethereum at 100,000 gas), rounded
40
+ * up. Most of a fee is fixed per chain, so the ratio falls as gas rises.
41
+ */
42
+ exports.RELAYR_FEE_MARKUP_BPS = 80000n;
43
+ /** The gas a forwarder's `execute` adds around the request's own. */
44
+ const FORWARDER_OVERHEAD_GAS = 100000n;
45
+ const QUOTE_TIMEOUT_MS = 45_000;
46
+ /** How long the review waits on a stand-in quote before it bounds the fee locally. */
47
+ const STAND_IN_TIMEOUT_MS = 10_000;
48
+ const POLL_INTERVAL_MS = 2_500;
49
+ const POLL_TIMEOUT_MS = 5 * 60_000;
50
+ const BALANCE_OF_ABI = [
51
+ {
52
+ type: "function",
53
+ name: "balanceOf",
54
+ stateMutability: "view",
55
+ inputs: [{ name: "owner", type: "address" }],
56
+ outputs: [{ type: "uint256" }],
57
+ },
58
+ ];
59
+ const RELAYR_PAYMENT_ABI = [
60
+ {
61
+ type: "function",
62
+ name: "prepayment",
63
+ stateMutability: "payable",
64
+ inputs: [
65
+ { name: "payment_uuid", type: "bytes16" },
66
+ { name: "deadline", type: "uint40" },
67
+ ],
68
+ outputs: [],
69
+ },
70
+ ];
71
+ const ACCOUNT_CHANGED = "The connected account changed. Review again.";
72
+ const ORDINARY_WALLET = "Pay for relayed transactions from an ordinary wallet. Nothing was sent.";
73
+ /** The quote's payment deadline passed before the wallet opened. */
74
+ class QuoteExpiredError extends Error {
75
+ constructor() {
76
+ super("This Relayr quote expired. Review the action again for a new quote.");
77
+ }
78
+ }
79
+ function forwarderOn(chainId) {
80
+ const forwarder = (0, relayr_js_1.relayrForwarder)(chainId);
81
+ if (!forwarder) {
82
+ throw new Error(`There is no Juicebox forwarder on chain ${chainId}.`);
83
+ }
84
+ return forwarder;
85
+ }
86
+ /** The connected wallet, as long as it is an ordinary one on `account` (or, with `safe`, a Safe app). */
87
+ async function requireOrdinaryWallet(adapter, account, safe = false) {
88
+ await (0, wallet_js_1.walletReady)(adapter);
89
+ if (adapter.kind !== "wallet")
90
+ throw (0, wallet_js_1.unsupportedWalletRequest)();
91
+ const connected = adapter.account();
92
+ if (!connected)
93
+ throw new Error("Connect a wallet first.");
94
+ if (connected.toLowerCase() !== account.toLowerCase()) {
95
+ throw new Error(ACCOUNT_CHANGED);
96
+ }
97
+ // Signed requests and their proof need an ordinary wallet's own transaction.
98
+ if (adapter.isSafe() && !safe)
99
+ throw new Error(ORDINARY_WALLET);
100
+ }
101
+ /** Whether `target` on `chainId` trusts the chain's canonical forwarder, so the real sender is kept. */
102
+ async function trustsForwarder(client, chainId, target) {
103
+ const forwarder = (0, relayr_js_1.relayrForwarder)(chainId);
104
+ if (!forwarder)
105
+ return false;
106
+ try {
107
+ const data = await (0, simulation_js_1.simulateStateChangingTransaction)(client, {
108
+ from: forwarder,
109
+ to: target,
110
+ data: (0, viem_1.encodeFunctionData)({
111
+ abi: relayr_js_1.TRUSTED_FORWARDER_ABI,
112
+ functionName: "isTrustedForwarder",
113
+ args: [forwarder],
114
+ }),
115
+ gas: 100000n,
116
+ });
117
+ return (0, viem_1.decodeFunctionResult)({
118
+ abi: relayr_js_1.TRUSTED_FORWARDER_ABI,
119
+ functionName: "isTrustedForwarder",
120
+ data,
121
+ });
122
+ }
123
+ catch {
124
+ return false;
125
+ }
126
+ }
127
+ /**
128
+ * The forward request each call is signed as: from `account`, with the
129
+ * forwarder nonce read now and the default deadline. Refuses more than one
130
+ * call per chain, chains outside one Relayr network family, a gas limit that
131
+ * is not positive, and a destination that does not trust the forwarder.
132
+ */
133
+ async function forwardRequests(calls, account, clientFor) {
134
+ const read = [...calls].map(({ chainId, target, data, value, gas }) => ({
135
+ chainId,
136
+ target,
137
+ data,
138
+ value: value ?? 0n,
139
+ gas,
140
+ }));
141
+ if (!read.length)
142
+ throw new Error("Choose at least one chain.");
143
+ const chainIds = read.map((call) => call.chainId);
144
+ if (!(0, relayr_js_1.relayrSupportsChains)(chainIds)) {
145
+ throw new Error("Relayr runs one call per supported destination, all mainnets or all testnets.");
146
+ }
147
+ if (read.some((call) => typeof call.gas !== "bigint" || call.gas <= 0n)) {
148
+ throw new Error("Each relayed call needs a positive gas limit.");
149
+ }
150
+ const deadline = (0, relayr_js_1.relayrForwarderDeadline)();
151
+ return Promise.all(read.map(async (call) => {
152
+ const client = clientFor(call.chainId);
153
+ if (!(await trustsForwarder(client, call.chainId, call.target))) {
154
+ throw new Error(`The target on chain ${call.chainId} does not trust the canonical forwarder. Send this action directly.`);
155
+ }
156
+ const nonce = await client.readContract({
157
+ address: forwarderOn(call.chainId),
158
+ abi: juicebox_js_1.erc2771ForwarderAbi,
159
+ functionName: "nonces",
160
+ args: [account],
161
+ });
162
+ return {
163
+ chainId: call.chainId,
164
+ request: {
165
+ from: account,
166
+ to: call.target,
167
+ value: call.value,
168
+ gas: call.gas,
169
+ nonce,
170
+ deadline,
171
+ data: call.data,
172
+ },
173
+ };
174
+ }));
175
+ }
176
+ /** The bundle entry that runs `request` with `signature` through the chain's forwarder. */
177
+ function entryOf(chainId, request, signature) {
178
+ const { from, to, value, gas, deadline, data } = request;
179
+ return {
180
+ chain: chainId,
181
+ target: forwarderOn(chainId),
182
+ data: (0, viem_1.encodeFunctionData)({
183
+ abi: juicebox_js_1.erc2771ForwarderAbi,
184
+ functionName: "execute",
185
+ args: [{ from, to, value, gas, deadline, data, signature }],
186
+ }),
187
+ value: value.toString(),
188
+ };
189
+ }
190
+ /** Post `entries` to Relayr and bind its quote to them (see {@link bindRelayrQuote}). */
191
+ async function postBundle(entries) {
192
+ const request = (0, relayr_js_1.relayrBundleRequest)(entries);
193
+ const response = await globalThis.fetch(`${relayr_js_1.RELAYR_API}/v1/bundle/prepaid`, {
194
+ method: "POST",
195
+ headers: { "Content-Type": "application/json" },
196
+ body: JSON.stringify(request),
197
+ signal: AbortSignal.timeout(QUOTE_TIMEOUT_MS),
198
+ });
199
+ return (0, relayr_js_1.bindRelayrQuote)(response, request);
200
+ }
201
+ /** Refuses while a payment held under `intent` may still land, or, for `paidOnce`, once one succeeded. */
202
+ function requireIntentClear(deps, account, intent) {
203
+ for (const chainId of intent.funding) {
204
+ const state = (0, writeHold_js_1.openStepHold)(deps.hold, account, false, {
205
+ chainId,
206
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
207
+ data: "0x",
208
+ intent: intent.key,
209
+ }).peek();
210
+ if (state.status !== "clear")
211
+ throw new writeHold_js_1.WriteHeldError(state);
212
+ if (intent.paidOnce && state.settled?.result === "success") {
213
+ throw new Error("This Relayr payment already succeeded. Do not pay again.");
214
+ }
215
+ }
216
+ }
217
+ /** The quote's authenticated payment on `chainId`. */
218
+ function paymentOn(quote, chainId) {
219
+ const destinationChainIds = quote.expectedTransactions.map((binding) => binding.chain);
220
+ const option = (0, relayr_js_1.relayrPaymentOptions)(quote, destinationChainIds).find((payment) => payment.chain === chainId);
221
+ if (!option &&
222
+ (0, relayr_js_1.relayrPaymentOptions)(quote, destinationChainIds, 0).some((payment) => payment.chain === chainId)) {
223
+ // Offered, but already too close to its deadline to pay.
224
+ throw new QuoteExpiredError();
225
+ }
226
+ if (!option) {
227
+ throw new Error(`Relayr returned no payment option on chain ${chainId}. Nothing was paid.`);
228
+ }
229
+ return (0, relayr_js_1.relayrPaymentDetails)(option, {
230
+ bundleUuid: quote.bundle_uuid,
231
+ destinationChainIds,
232
+ expectedTransactions: quote.expectedTransactions,
233
+ });
234
+ }
235
+ /** The calls a quote's bundle runs, as a plan holds them; a raw value that can't be read matches none. */
236
+ function quotedCalls(quote) {
237
+ return quote.expectedTransactions.map(({ chain, entry }) => {
238
+ const request = (0, relayr_js_1.relayrForwardRequest)(entry);
239
+ if (request) {
240
+ const { from, to, data, value, gas } = request;
241
+ return { chainId: chain, from, to, data, value, gas };
242
+ }
243
+ return {
244
+ chainId: chain,
245
+ from: "relayr",
246
+ to: entry.target,
247
+ data: entry.data,
248
+ value: /^\d+$/u.test(entry.value) ? BigInt(entry.value) : -1n,
249
+ };
250
+ });
251
+ }
252
+ function withMargin(fee) {
253
+ return (fee * exports.RELAYR_FEE_MARGIN_BPS + 9999n) / 10000n;
254
+ }
255
+ /**
256
+ * Relayr's fee for `calls` signed by a key made for this quote alone: the
257
+ * same chains, gas limits and values, so Relayr prices the same work. The key
258
+ * lives only in memory for this call and leaves it only inside the requests'
259
+ * signatures.
260
+ */
261
+ async function standInFee(calls, paymentChainId, deadline) {
262
+ const signer = (0, accounts_1.privateKeyToAccount)((0, accounts_1.generatePrivateKey)());
263
+ const entries = await Promise.all(calls.map(async ({ chainId, target, data, value, gas, raw }) => {
264
+ // Anyone may run a raw call: it is its own stand-in.
265
+ if (raw)
266
+ return { chain: chainId, target, data, value: value.toString() };
267
+ const request = {
268
+ from: signer.address,
269
+ to: target,
270
+ value,
271
+ gas,
272
+ deadline,
273
+ data,
274
+ };
275
+ const signature = await signer.signTypedData({
276
+ domain: {
277
+ name: "Juicebox",
278
+ version: "1",
279
+ chainId,
280
+ verifyingContract: forwarderOn(chainId),
281
+ },
282
+ types: relayr_js_1.FORWARD_REQUEST_TYPES,
283
+ primaryType: "ForwardRequest",
284
+ // A key made now has used no forwarder nonce.
285
+ message: { ...request, nonce: 0n },
286
+ });
287
+ return entryOf(chainId, request, signature);
288
+ }));
289
+ return paymentOn(await postBundle(entries), paymentChainId).amount;
290
+ }
291
+ /**
292
+ * The fee cap the review shows: Relayr's quote for stand-ins of `calls`, plus
293
+ * {@link RELAYR_FEE_MARGIN_BPS}. A call that runs only for the real sender
294
+ * (an owner's action) can't be stood in, so a call with the same chain, gas
295
+ * and calldata length that anyone can run (JBProjects' `balanceOf`) is quoted
296
+ * instead, with the calls' values added. Without either quote in time, the
297
+ * fee is bounded locally: each call's gas estimate through the forwarder as
298
+ * `account`, at the chain's gas price, times {@link RELAYR_FEE_MARKUP_BPS}.
299
+ */
300
+ async function relayrFeeCap(calls, account, paymentChainId, clientFor) {
301
+ const read = calls.map((call) => ({ ...call, value: call.value ?? 0n }));
302
+ const deadline = (0, relayr_js_1.relayrForwarderDeadline)();
303
+ const values = read.reduce((sum, call) => sum + call.value, 0n);
304
+ const quoted = await (0, pause_js_1.timeout)(standInFee(read, paymentChainId, deadline).catch(async () => {
305
+ const filler = (0, accounts_1.privateKeyToAccount)((0, accounts_1.generatePrivateKey)()).address;
306
+ return ((await standInFee(read.map((call) => {
307
+ const probe = (0, viem_1.encodeFunctionData)({
308
+ abi: BALANCE_OF_ABI,
309
+ functionName: "balanceOf",
310
+ args: [filler],
311
+ });
312
+ const bytes = Math.max((call.data.length - probe.length) / 2, 0);
313
+ return {
314
+ ...call,
315
+ raw: false,
316
+ target: juicebox_js_1.jbV6ContractAddress.JBProjects[call.chainId],
317
+ data: `${probe}${"00".repeat(bytes)}`,
318
+ value: 0n,
319
+ };
320
+ }), paymentChainId, deadline)) + values);
321
+ }), STAND_IN_TIMEOUT_MS).catch(() => null);
322
+ if (quoted !== null)
323
+ return withMargin(quoted);
324
+ let bound = values;
325
+ for (const call of read) {
326
+ const client = clientFor(call.chainId);
327
+ const estimate = await client
328
+ .estimateGas(call.raw
329
+ ? { to: call.target, data: call.data, value: call.value }
330
+ : {
331
+ account: forwarderOn(call.chainId),
332
+ to: call.target,
333
+ // ERC-2771: the forwarder appends the real sender.
334
+ data: (0, viem_1.concat)([call.data, account]),
335
+ value: call.value,
336
+ })
337
+ .catch(() => call.gas);
338
+ const gas = (estimate > call.gas ? estimate : call.gas) +
339
+ (call.raw ? 0n : FORWARDER_OVERHEAD_GAS);
340
+ bound +=
341
+ (gas * (await client.getGasPrice()) * exports.RELAYR_FEE_MARKUP_BPS) / 10000n;
342
+ }
343
+ return withMargin(bound);
344
+ }
345
+ /** The payment as the review shows it: one call to Relayr's pinned payment contract. */
346
+ function paymentReviewCall(details, account, safe = false) {
347
+ const { functionName, args } = (0, viem_1.decodeFunctionData)({
348
+ abi: RELAYR_PAYMENT_ABI,
349
+ data: details.calldata,
350
+ });
351
+ return {
352
+ chainId: details.chainId,
353
+ from: account,
354
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
355
+ data: details.calldata,
356
+ value: details.amount,
357
+ // A Safe signs the sent gas as safeTxGas; 0 makes a failed payment revert.
358
+ ...(safe ? { safeTxGas: 0n } : { gas: relayr_js_1.RELAYR_PAYMENT_GAS }),
359
+ abi: RELAYR_PAYMENT_ABI,
360
+ functionName,
361
+ args,
362
+ label: "Pay network fee",
363
+ contractName: "Relayr payment",
364
+ };
365
+ }
366
+ async function reviewPayment(details, account, action, safe = false) {
367
+ const model = (0, model_js_1.buildReviewModel)({
368
+ calls: [paymentReviewCall(details, account, safe)],
369
+ title: action.title ?? "Review network fee",
370
+ ...(action.context ? { context: action.context } : {}),
371
+ });
372
+ await (0, confirm_js_1.promptReview)(model, Promise.resolve({ status: "passed" }), Promise.resolve(model));
373
+ }
374
+ /**
375
+ * Send one reviewed payment without asking again: Relayr's pinned contract
376
+ * and selector only, from `account`, after the runtime and simulation checks,
377
+ * under the payment's write hold (or `intent`'s). The payment must be proven
378
+ * from the chain before the hash it was mined under comes back.
379
+ */
380
+ async function sendPayment(details, account, deps, hooks = {}) {
381
+ const { adapter } = deps;
382
+ const safe = hooks.safe ?? false;
383
+ await requireOrdinaryWallet(adapter, account, safe);
384
+ const client = deps.clientFor(details.chainId);
385
+ const call = {
386
+ chainId: details.chainId,
387
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
388
+ data: details.calldata,
389
+ value: details.amount,
390
+ ...(hooks.intent ? { intent: hooks.intent.key } : {}),
391
+ };
392
+ const handle = (0, writeHold_js_1.openStepHold)(deps.hold, account, safe, call);
393
+ /** The attempt is saved (`onSending`), and the wallet not yet asked. */
394
+ let saved = false;
395
+ let invoked = false;
396
+ /** The reservation this payment's send took. */
397
+ let reserved;
398
+ /** A proposal of exactly this payment its Safe already queued, sent in its place. */
399
+ let queued = null;
400
+ const attempt = () => {
401
+ const held = handle.peek();
402
+ if (held.status !== "clear")
403
+ throw new writeHold_js_1.WriteHeldError(held);
404
+ return handle.send(client, (gate) => (0, contractWrite_js_1.submitReviewedContractWrite)({
405
+ request: call,
406
+ expectedAccount: account,
407
+ review: () => Promise.resolve(),
408
+ switchChain: async (chainId) => {
409
+ if (adapter.chainId() !== chainId)
410
+ await adapter.switchChain(chainId);
411
+ },
412
+ currentAccount: () => adapter.account(),
413
+ reverify: async () => {
414
+ await hooks.recheck?.();
415
+ // A lapsed payment would only revert in simulation.
416
+ if ((0, relayr_js_1.quoteExpired)(details.deadline))
417
+ throw new QuoteExpiredError();
418
+ await (0, relayr_js_1.requireRelayrPaymentRuntime)(client);
419
+ },
420
+ simulate: async () => {
421
+ const [, found] = await Promise.all([
422
+ (0, relayr_js_1.simulateRelayrPayment)(client, {
423
+ from: account,
424
+ payment: details,
425
+ }),
426
+ // A Safe never proposes again a payment it already queued exactly.
427
+ safe && (0, safeService_js_1.hasSafeService)(details.chainId)
428
+ ? (0, safeService_js_1.findPendingSafeAppProposal)(client, details.chainId, account, {
429
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
430
+ data: details.calldata,
431
+ value: details.amount,
432
+ }, deps.hold.safeService, true)
433
+ : null,
434
+ ]);
435
+ queued = found;
436
+ return details;
437
+ },
438
+ beforeWrite: async () => {
439
+ const { intent } = hooks;
440
+ // Only the check and the reservation are under the lock: never a
441
+ // chain switch, simulation or wallet that might not answer.
442
+ await (intent
443
+ ? (0, writeRecovery_js_1.browserLocks)().request(`nana-sdk:relayr-payment:${account.toLowerCase()}:${intent.key}`, { mode: "exclusive" }, async () => {
444
+ requireIntentClear(deps, account, intent);
445
+ await gate.beforeSend();
446
+ })
447
+ : gate.beforeSend());
448
+ reserved = handle.peek().reservation;
449
+ try {
450
+ await hooks.onSending?.();
451
+ }
452
+ catch (error) {
453
+ gate.onRejected();
454
+ throw error;
455
+ }
456
+ saved = true;
457
+ },
458
+ beforeSend: () => {
459
+ try {
460
+ if (details.target.toLowerCase() !== relayr_js_1.RELAYR_PAYMENT_ADDRESS ||
461
+ details.calldata.slice(0, 10).toLowerCase() !==
462
+ relayr_js_1.RELAYR_PAYMENT_SELECTOR) {
463
+ throw new Error("The Relayr payment is not to its pinned contract.");
464
+ }
465
+ if ((0, relayr_js_1.quoteExpired)(details.deadline))
466
+ throw new QuoteExpiredError();
467
+ if (adapter.isSafe() !== safe)
468
+ throw new Error(safe
469
+ ? "Wallet connection changed. Review the payment again."
470
+ : ORDINARY_WALLET);
471
+ if (adapter.chainId() !== details.chainId) {
472
+ throw new Error("Your wallet changed networks. Review the payment again.");
473
+ }
474
+ // Last, after every callback above could have run.
475
+ if (adapter.account()?.toLowerCase() !== account.toLowerCase()) {
476
+ throw new Error(ACCOUNT_CHANGED);
477
+ }
478
+ }
479
+ catch (error) {
480
+ throw new relayr_js_1.RelayrPaymentNotSentError(error);
481
+ }
482
+ },
483
+ onBeforeWriteAborted: () => gate.onRejected(),
484
+ onWriteRejected: () => gate.onRejected(),
485
+ onWriteSubmitted: async (submitted) => {
486
+ gate.afterSubmit(submitted, queued?.tx);
487
+ await hooks.onSent?.(submitted);
488
+ },
489
+ // The pinned contract and gas, never the quote's word.
490
+ write: async ({ chainId, calldata, amount }) => {
491
+ // An adopted proposal is already with the Safe: never "not sent".
492
+ invoked = true;
493
+ if (queued)
494
+ return queued.proposalHash;
495
+ try {
496
+ return await adapter.sendTransaction({
497
+ chainId,
498
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
499
+ data: calldata,
500
+ value: amount,
501
+ gas: safe ? 0n : relayr_js_1.RELAYR_PAYMENT_GAS,
502
+ });
503
+ }
504
+ catch (error) {
505
+ // Only the wallet's own 4001 says it declined.
506
+ throw (0, relayr_js_1.relayrWalletPaymentError)(error);
507
+ }
508
+ },
509
+ }));
510
+ };
511
+ let hash;
512
+ try {
513
+ if (hooks.intent)
514
+ requireIntentClear(deps, account, hooks.intent);
515
+ hash = await attempt();
516
+ }
517
+ catch (error) {
518
+ // Saved as sending, refused by a final gate, never given to the wallet.
519
+ if (saved && !invoked && !(error instanceof relayr_js_1.RelayrPaymentNotSentError)) {
520
+ throw new relayr_js_1.RelayrPaymentNotSentError(error);
521
+ }
522
+ throw error;
523
+ }
524
+ // A proposal: its hold follows it to the Safe's execution.
525
+ if (safe)
526
+ return hash;
527
+ // From here the payment was sent: it ends proven, reverted or
528
+ // contradicted as the chain shows it, or unreadable with its hash, never
529
+ // as a bare read failure.
530
+ try {
531
+ // The watcher's receipt only says when to ask the hold: the hold checks
532
+ // the receipt itself and settles, so a reverted payment can be reviewed
533
+ // and sent again without waiting on a view. Its settlement is the only
534
+ // word on a revert; a success is proven below either way.
535
+ const seen = await (0, receipt_js_1.waitForTrackedReceipt)(client, hash);
536
+ const state = await handle.state(client).catch(() => undefined);
537
+ const settled = state?.status === "clear" &&
538
+ reserved !== undefined &&
539
+ state.reservation === reserved &&
540
+ state.settled &&
541
+ "hash" in state.settled
542
+ ? state.settled
543
+ : undefined;
544
+ // A wallet that sped the payment up mined it under another hash.
545
+ const mined = settled?.hash ?? seen.transactionHash;
546
+ if (mined.toLowerCase() !== hash.toLowerCase()) {
547
+ try {
548
+ await hooks.onSent?.(mined);
549
+ }
550
+ catch (error) {
551
+ throw new contractWrite_js_1.SubmittedContractWriteError(mined, error);
552
+ }
553
+ }
554
+ if (settled?.result === "failed")
555
+ throw new lineError_js_1.ReviewedCallRevertedError(0, mined, await (0, receipt_js_1.heldReceipt)(settled, client, seen));
556
+ if (!settled && seen.status === "reverted")
557
+ throw new relayr_js_1.RelayrProofUnavailableError(`Could not read Relayr payment ${mined} on chain ${details.chainId}. Do not pay again; check it later.`);
558
+ // A proof the node can't read yet is read again, as long as `follow` would
559
+ // follow a step, a read that stalls included; a contradicting proof is
560
+ // never retried. Past that, it is unreadable, its hash kept in the line.
561
+ const deadline = Date.now() + heldWrite_js_1.FOLLOW_MS;
562
+ let unread;
563
+ for (;;) {
564
+ const left = deadline - Date.now();
565
+ let timer;
566
+ try {
567
+ const proven = await Promise.race([
568
+ (0, relayr_js_1.verifyRelayrPayment)(client, {
569
+ hash: mined,
570
+ from: account,
571
+ payment: details,
572
+ }).then(() => true),
573
+ new Promise((resolve) => {
574
+ timer = setTimeout(() => resolve(false), Math.max(left, 0));
575
+ }),
576
+ ]);
577
+ if (proven)
578
+ return mined;
579
+ throw Object.assign(new relayr_js_1.RelayrProofUnavailableError(`Could not read Relayr payment ${mined} on chain ${details.chainId}. Do not pay again; check it later.`), { cause: unread });
580
+ }
581
+ catch (error) {
582
+ if (!(error instanceof relayr_js_1.RelayrProofUnavailableError) ||
583
+ deadline - Date.now() <= 0)
584
+ throw error;
585
+ unread = error;
586
+ await (0, pause_js_1.pause)(Math.min(heldWrite_js_1.RECEIPT_RETRY_MS, deadline - Date.now()), undefined, () => null);
587
+ }
588
+ finally {
589
+ clearTimeout(timer);
590
+ }
591
+ }
592
+ }
593
+ catch (error) {
594
+ if (error instanceof lineError_js_1.ReviewedCallRevertedError ||
595
+ error instanceof relayr_js_1.RelayrProofError ||
596
+ error instanceof relayr_js_1.RelayrProofUnavailableError ||
597
+ error instanceof contractWrite_js_1.SubmittedContractWriteError)
598
+ throw error;
599
+ throw Object.assign(new relayr_js_1.RelayrProofUnavailableError(`Could not read Relayr payment ${hash} on chain ${details.chainId}. Do not pay again; check it later.`), { cause: error });
600
+ }
601
+ }
602
+ /**
603
+ * Signs `calls` as ERC-2771 forward requests after one review of the
604
+ * requests, decoded, and returns the Relayr bundle entries that run them.
605
+ * Each destination must trust the chain's canonical forwarder. Nothing is
606
+ * posted or paid.
607
+ */
608
+ async function signReviewedForwardRequests(calls, action, deps) {
609
+ const { account } = action;
610
+ await requireOrdinaryWallet(deps.adapter, account);
611
+ const requests = await forwardRequests(calls, account, deps.clientFor);
612
+ const prepared = requests.map(({ chainId, request }) => (0, sign_js_1.prepareSignature)({ kind: "forward-request", chainId, request }, account));
613
+ const model = (0, model_js_1.buildReviewModel)({
614
+ calls: [],
615
+ signatures: prepared.map(({ review }) => review),
616
+ title: action.title ?? "Review relayed transactions",
617
+ ...(action.context ? { context: action.context } : {}),
618
+ });
619
+ await (0, confirm_js_1.promptReview)(model, Promise.resolve({ status: "passed" }), Promise.resolve(model));
620
+ const signatures = await (0, sign_js_1.signPrepared)(prepared, account, deps.adapter);
621
+ return requests.map(({ chainId, request }, index) => entryOf(chainId, request, signatures[index]));
622
+ }
623
+ /**
624
+ * Pays a Relayr quote after one review of the payment: the option on
625
+ * `chainId`, authenticated against the quote, sent to Relayr's pinned
626
+ * contract and proven from the chain. For a payment resumed apart from its
627
+ * signatures. A Safe app pays by proposal: `safeTxHash` comes back, held
628
+ * until the Safe runs it. `onSending` runs after the hold reserves, right
629
+ * before the wallet opens (a throw sends nothing); `onSent` gets every hash
630
+ * the payment is known by. With `plan` and `relayrRound`, a quote of exactly
631
+ * that round's calls spends the round's reviewed fee bound once: at most
632
+ * the bound pays with no prompt, and a higher fee, a spent round or another
633
+ * chain is asked.
634
+ */
635
+ async function payRelayrReviewed(quote, chainId, action, deps) {
636
+ const { account } = action;
637
+ await (0, wallet_js_1.walletReady)(deps.adapter);
638
+ const safe = deps.adapter.isSafe();
639
+ await requireOrdinaryWallet(deps.adapter, account, safe);
640
+ const details = paymentOn(quote, chainId);
641
+ const intent = {
642
+ key: `relayr:${details.bundleUuid}`,
643
+ funding: (0, relayr_js_1.relayrPaymentChains)(quote.expectedTransactions.map((binding) => binding.chain)),
644
+ paidOnce: true,
645
+ };
646
+ requireIntentClear(deps, account, intent);
647
+ if (action.plan && action.relayrRound !== undefined) {
648
+ const cap = (0, plan_js_1.spendPlannedRelayrRound)(action.plan, account, action.relayrRound, quotedCalls(quote), details.chainId);
649
+ if (cap === undefined || details.amount > cap)
650
+ await reviewPayment(details, account, {
651
+ title: cap ? "The network fee went up" : "Review network fee",
652
+ ...(action.context ? { context: action.context } : {}),
653
+ }, safe);
654
+ }
655
+ else if (action.plan)
656
+ (0, plan_js_1.spendPlan)(action.plan, account, [
657
+ {
658
+ chainId: details.chainId,
659
+ from: account,
660
+ to: relayr_js_1.RELAYR_PAYMENT_ADDRESS,
661
+ data: details.calldata,
662
+ value: details.amount,
663
+ },
664
+ ]);
665
+ else
666
+ await reviewPayment(details, account, action, safe);
667
+ const hash = await sendPayment(details, account, deps, {
668
+ intent,
669
+ // Relayr's own word too, whatever this browser kept of earlier payments.
670
+ recheck: () => (0, relayr_js_1.requireRelayrBundleUnpaid)(details.bundleUuid),
671
+ ...(action.onSending ? { onSending: action.onSending } : {}),
672
+ ...(action.onSent ? { onSent: action.onSent } : {}),
673
+ safe,
674
+ });
675
+ return safe ? { safeTxHash: hash } : { hash };
676
+ }
677
+ /**
678
+ * Relayr's bundle once every one of its `expectedCount` transactions reports
679
+ * success. Only `failed`, in any case, is final; every other state, and a
680
+ * read that fails, is polled again every 2.5 seconds, for up to 5 minutes.
681
+ * Relayr's word is not proof: verify the destinations from the chain.
682
+ */
683
+ async function pollRelayrBundle(uuid, expectedCount, options = {}) {
684
+ if (!Number.isSafeInteger(expectedCount) || expectedCount < 1) {
685
+ throw new Error("Relayr polling requires the exact destination count.");
686
+ }
687
+ const { signal } = options;
688
+ const until = Date.now() + POLL_TIMEOUT_MS;
689
+ for (;;) {
690
+ signal?.throwIfAborted();
691
+ const bundle = await (0, relayr_js_1.readRelayrBundle)(uuid, {
692
+ ...(options.fetch ? { fetch: options.fetch } : {}),
693
+ }).catch(() => null);
694
+ const records = Array.isArray(bundle?.transactions)
695
+ ? bundle.transactions
696
+ : [];
697
+ const failed = records.filter((record) => (0, relayr_js_1.relayrStateIsFailed)(record?.status?.state)).length;
698
+ if (failed) {
699
+ throw new Error(`Relayr could not run this on ${failed} chain${failed === 1 ? "" : "s"}.`);
700
+ }
701
+ if (bundle &&
702
+ records.length === expectedCount &&
703
+ records.every((record) => (0, relayr_js_1.relayrStateIsSuccess)(record?.status?.state))) {
704
+ return bundle;
705
+ }
706
+ if (Date.now() >= until) {
707
+ throw new Error(`Relayr is still processing paid bundle ${uuid}. Do not submit this action again; check it later.`);
708
+ }
709
+ await new Promise((resolve, reject) => {
710
+ const timer = setTimeout(resolve, POLL_INTERVAL_MS);
711
+ signal?.addEventListener("abort", () => {
712
+ clearTimeout(timer);
713
+ reject(signal.reason);
714
+ }, { once: true });
715
+ });
716
+ }
717
+ }
718
+ /** A Safe execution as the review shows it: the Safe's `execTransaction`, with the call or MultiSend inside. */
719
+ function safeExecutionCall(entry) {
720
+ const decoded = (0, viem_1.decodeFunctionData)({ abi: safeService_js_1.SAFE_EXEC_ABI, data: entry.data });
721
+ if (decoded.functionName !== "execTransaction") {
722
+ throw new Error("The saved call is not a Safe execution.");
723
+ }
724
+ const [to, value, data, operation] = decoded.args;
725
+ const inner = (0, safe_js_1.multiSendCallsOf)({ to, data, operation }) ?? [
726
+ { to, value, data },
727
+ ];
728
+ return {
729
+ chainId: entry.chain,
730
+ to: entry.target,
731
+ data: entry.data,
732
+ value: BigInt(entry.value),
733
+ abi: safeService_js_1.SAFE_EXEC_ABI,
734
+ functionName: "execTransaction",
735
+ args: decoded.args,
736
+ contractName: "Safe",
737
+ calls: inner.map((call) => (0, decodeCall_js_1.decodeReviewCall)({ chainId: entry.chain, from: entry.target, ...call })),
738
+ };
739
+ }
740
+ /**
741
+ * The wallet side of {@link createSafeRelayrController}: `review` shows the
742
+ * frozen Safe executions in core's review, and `sendPayment` reviews and
743
+ * sends the selected payment as {@link payRelayrReviewed} does, with the
744
+ * controller's checks and journal callbacks around the wallet. A quote paid
745
+ * before is paid again only when {@link requireRelayrRetry} clears every
746
+ * earlier payment.
747
+ */
748
+ function safeRelayrWalletDeps(deps) {
749
+ return {
750
+ review: async (executions, { resumed }) => {
751
+ const model = (0, model_js_1.buildReviewModel)({
752
+ calls: executions.map(({ entry }) => safeExecutionCall(entry)),
753
+ title: `Review ${executions.length} Safe execution${executions.length === 1 ? "" : "s"}`,
754
+ confirmLabel: resumed
755
+ ? "Use saved quote"
756
+ : "Review & get payment options",
757
+ });
758
+ await (0, confirm_js_1.promptReview)(model, Promise.resolve({ status: "passed" }), Promise.resolve(model));
759
+ },
760
+ sendPayment: async ({ session, payment, beforeSend, onSending, onSent, }) => {
761
+ const { account } = session;
762
+ await requireOrdinaryWallet(deps.adapter, account);
763
+ if (session.payments.length >= relayr_js_1.MAX_RELAYR_SENT_PAYMENTS) {
764
+ throw new Error("This Relayr quote was paid too many times to pay again. Keep it pending; do not pay again.");
765
+ }
766
+ if (!session.quote)
767
+ throw new Error("This Safe action has no quote to pay.");
768
+ const details = (0, relayr_js_1.relayrPaymentDetails)(payment, {
769
+ bundleUuid: session.quote.bundle_uuid,
770
+ destinationChainIds: session.executions.map(({ entry }) => entry.chain),
771
+ });
772
+ await reviewPayment(details, account, {});
773
+ const payments = [...session.payments];
774
+ const hash = await sendPayment(details, account, deps, {
775
+ recheck: async () => {
776
+ await beforeSend();
777
+ if (session.payments.length) {
778
+ await (0, relayr_js_1.requireRelayrRetry)(deps.clientFor, {
779
+ payments: session.payments,
780
+ from: account,
781
+ bundleUuid: details.bundleUuid,
782
+ });
783
+ }
784
+ },
785
+ onSending,
786
+ onSent: async (sent) => {
787
+ payments.push((0, relayr_js_1.sentRelayrPayment)(details, sent));
788
+ await onSent([...payments]);
789
+ },
790
+ });
791
+ return { hash, payments };
792
+ },
793
+ };
794
+ }
795
+ //# sourceMappingURL=relayrSend.js.map