@bananapus/nana-sdk-core 3.5.2 → 4.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 (292) hide show
  1. package/bin/wallet-check.mjs +489 -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 +52 -0
  11. package/dist/cjs/review/confirm.d.ts.map +1 -0
  12. package/dist/cjs/review/confirm.js +88 -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 +8 -7
  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.map +1 -1
  27. package/dist/cjs/review/heldWrite.js +5 -4
  28. package/dist/cjs/review/heldWrite.js.map +1 -1
  29. package/dist/cjs/review/index.d.ts +11 -0
  30. package/dist/cjs/review/index.d.ts.map +1 -1
  31. package/dist/cjs/review/index.js +24 -0
  32. package/dist/cjs/review/index.js.map +1 -1
  33. package/dist/cjs/review/intents.d.ts +10 -0
  34. package/dist/cjs/review/intents.d.ts.map +1 -1
  35. package/dist/cjs/review/intents.js +13 -0
  36. package/dist/cjs/review/intents.js.map +1 -1
  37. package/dist/cjs/review/lineError.d.ts +34 -0
  38. package/dist/cjs/review/lineError.d.ts.map +1 -0
  39. package/dist/cjs/review/lineError.js +42 -0
  40. package/dist/cjs/review/lineError.js.map +1 -0
  41. package/dist/cjs/review/messages.d.ts +15 -3
  42. package/dist/cjs/review/messages.d.ts.map +1 -1
  43. package/dist/cjs/review/messages.js +16 -4
  44. package/dist/cjs/review/messages.js.map +1 -1
  45. package/dist/cjs/review/model.d.ts +149 -0
  46. package/dist/cjs/review/model.d.ts.map +1 -0
  47. package/dist/cjs/review/model.js +750 -0
  48. package/dist/cjs/review/model.js.map +1 -0
  49. package/dist/cjs/review/plan.d.ts +63 -0
  50. package/dist/cjs/review/plan.d.ts.map +1 -0
  51. package/dist/cjs/review/plan.js +149 -0
  52. package/dist/cjs/review/plan.js.map +1 -0
  53. package/dist/cjs/review/react/index.d.ts +1 -0
  54. package/dist/cjs/review/react/index.d.ts.map +1 -1
  55. package/dist/cjs/review/react/index.js +1 -0
  56. package/dist/cjs/review/react/index.js.map +1 -1
  57. package/dist/cjs/review/react/useReviewedRun.d.ts +96 -0
  58. package/dist/cjs/review/react/useReviewedRun.d.ts.map +1 -0
  59. package/dist/cjs/review/react/useReviewedRun.js +261 -0
  60. package/dist/cjs/review/react/useReviewedRun.js.map +1 -0
  61. package/dist/cjs/review/receipt.d.ts +4 -1
  62. package/dist/cjs/review/receipt.d.ts.map +1 -1
  63. package/dist/cjs/review/receipt.js +7 -3
  64. package/dist/cjs/review/receipt.js.map +1 -1
  65. package/dist/cjs/review/relayr.d.ts +13 -4
  66. package/dist/cjs/review/relayr.d.ts.map +1 -1
  67. package/dist/cjs/review/relayr.js +51 -8
  68. package/dist/cjs/review/relayr.js.map +1 -1
  69. package/dist/cjs/review/relayrSend.d.ts +135 -0
  70. package/dist/cjs/review/relayrSend.d.ts.map +1 -0
  71. package/dist/cjs/review/relayrSend.js +943 -0
  72. package/dist/cjs/review/relayrSend.js.map +1 -0
  73. package/dist/cjs/review/reviewQueue.d.ts +10 -9
  74. package/dist/cjs/review/reviewQueue.d.ts.map +1 -1
  75. package/dist/cjs/review/reviewQueue.js +19 -29
  76. package/dist/cjs/review/reviewQueue.js.map +1 -1
  77. package/dist/cjs/review/reviewRequests.d.ts +86 -0
  78. package/dist/cjs/review/reviewRequests.d.ts.map +1 -0
  79. package/dist/cjs/review/reviewRequests.js +266 -0
  80. package/dist/cjs/review/reviewRequests.js.map +1 -0
  81. package/dist/cjs/review/safeRelayr.d.ts +3 -1
  82. package/dist/cjs/review/safeRelayr.d.ts.map +1 -1
  83. package/dist/cjs/review/safeRelayr.js +5 -1
  84. package/dist/cjs/review/safeRelayr.js.map +1 -1
  85. package/dist/cjs/review/safeSend.d.ts +69 -0
  86. package/dist/cjs/review/safeSend.d.ts.map +1 -0
  87. package/dist/cjs/review/safeSend.js +308 -0
  88. package/dist/cjs/review/safeSend.js.map +1 -0
  89. package/dist/cjs/review/send.d.ts +241 -0
  90. package/dist/cjs/review/send.d.ts.map +1 -0
  91. package/dist/cjs/review/send.js +1017 -0
  92. package/dist/cjs/review/send.js.map +1 -0
  93. package/dist/cjs/review/sequence.d.ts +77 -0
  94. package/dist/cjs/review/sequence.d.ts.map +1 -0
  95. package/dist/cjs/review/sequence.js +232 -0
  96. package/dist/cjs/review/sequence.js.map +1 -0
  97. package/dist/cjs/review/sign.d.ts +109 -0
  98. package/dist/cjs/review/sign.d.ts.map +1 -0
  99. package/dist/cjs/review/sign.js +374 -0
  100. package/dist/cjs/review/sign.js.map +1 -0
  101. package/dist/cjs/review/simulation.d.ts +41 -2
  102. package/dist/cjs/review/simulation.d.ts.map +1 -1
  103. package/dist/cjs/review/simulation.js +99 -29
  104. package/dist/cjs/review/simulation.js.map +1 -1
  105. package/dist/cjs/review/transaction-message.d.ts +13 -0
  106. package/dist/cjs/review/transaction-message.d.ts.map +1 -1
  107. package/dist/cjs/review/transaction-message.js +25 -0
  108. package/dist/cjs/review/transaction-message.js.map +1 -1
  109. package/dist/cjs/review/transactionReview.d.ts +27 -19
  110. package/dist/cjs/review/transactionReview.d.ts.map +1 -1
  111. package/dist/cjs/review/transactionReview.js +22 -63
  112. package/dist/cjs/review/transactionReview.js.map +1 -1
  113. package/dist/cjs/review/wallet.d.ts +82 -0
  114. package/dist/cjs/review/wallet.d.ts.map +1 -0
  115. package/dist/cjs/review/wallet.js +157 -0
  116. package/dist/cjs/review/wallet.js.map +1 -0
  117. package/dist/cjs/review/writeHold.d.ts +100 -12
  118. package/dist/cjs/review/writeHold.d.ts.map +1 -1
  119. package/dist/cjs/review/writeHold.js +61 -13
  120. package/dist/cjs/review/writeHold.js.map +1 -1
  121. package/dist/cjs/review/writeRecovery.d.ts +6 -1
  122. package/dist/cjs/review/writeRecovery.d.ts.map +1 -1
  123. package/dist/cjs/review/writeRecovery.js +108 -40
  124. package/dist/cjs/review/writeRecovery.js.map +1 -1
  125. package/dist/cjs/safeService.d.ts +27 -4
  126. package/dist/cjs/safeService.d.ts.map +1 -1
  127. package/dist/cjs/safeService.js +120 -3
  128. package/dist/cjs/safeService.js.map +1 -1
  129. package/dist/cjs/testing.d.ts +24 -0
  130. package/dist/cjs/testing.d.ts.map +1 -1
  131. package/dist/cjs/testing.js +26 -1
  132. package/dist/cjs/testing.js.map +1 -1
  133. package/dist/cjs/v6/defifa.d.ts.map +1 -1
  134. package/dist/cjs/v6/defifa.js +24 -23
  135. package/dist/cjs/v6/defifa.js.map +1 -1
  136. package/dist/cjs/v6/executionErrors.d.ts.map +1 -1
  137. package/dist/cjs/v6/executionErrors.js +3 -2
  138. package/dist/cjs/v6/executionErrors.js.map +1 -1
  139. package/dist/cjs/v6/pay.d.ts +25 -8
  140. package/dist/cjs/v6/pay.d.ts.map +1 -1
  141. package/dist/cjs/v6/pay.js +117 -23
  142. package/dist/cjs/v6/pay.js.map +1 -1
  143. package/dist/cjs/v6/suckers.d.ts +30 -0
  144. package/dist/cjs/v6/suckers.d.ts.map +1 -1
  145. package/dist/cjs/v6/suckers.js +69 -5
  146. package/dist/cjs/v6/suckers.js.map +1 -1
  147. package/dist/esm/actions/suckerPairs.d.ts +5 -3
  148. package/dist/esm/actions/suckerPairs.d.ts.map +1 -1
  149. package/dist/esm/actions/suckerPairs.js +7 -27
  150. package/dist/esm/actions/suckerPairs.js.map +1 -1
  151. package/dist/esm/pause.d.ts +2 -0
  152. package/dist/esm/pause.d.ts.map +1 -1
  153. package/dist/esm/pause.js +16 -0
  154. package/dist/esm/pause.js.map +1 -1
  155. package/dist/esm/review/confirm.d.ts +52 -0
  156. package/dist/esm/review/confirm.d.ts.map +1 -0
  157. package/dist/esm/review/confirm.js +83 -0
  158. package/dist/esm/review/confirm.js.map +1 -0
  159. package/dist/esm/review/contractWrite.d.ts +5 -3
  160. package/dist/esm/review/contractWrite.d.ts.map +1 -1
  161. package/dist/esm/review/contractWrite.js +8 -7
  162. package/dist/esm/review/contractWrite.js.map +1 -1
  163. package/dist/esm/review/decode.d.ts +19 -1
  164. package/dist/esm/review/decode.d.ts.map +1 -1
  165. package/dist/esm/review/decode.js +29 -14
  166. package/dist/esm/review/decode.js.map +1 -1
  167. package/dist/esm/review/decodeCall.d.ts +21 -0
  168. package/dist/esm/review/decodeCall.d.ts.map +1 -0
  169. package/dist/esm/review/decodeCall.js +180 -0
  170. package/dist/esm/review/decodeCall.js.map +1 -0
  171. package/dist/esm/review/heldWrite.d.ts.map +1 -1
  172. package/dist/esm/review/heldWrite.js +5 -4
  173. package/dist/esm/review/heldWrite.js.map +1 -1
  174. package/dist/esm/review/index.d.ts +11 -0
  175. package/dist/esm/review/index.d.ts.map +1 -1
  176. package/dist/esm/review/index.js +11 -0
  177. package/dist/esm/review/index.js.map +1 -1
  178. package/dist/esm/review/intents.d.ts +10 -0
  179. package/dist/esm/review/intents.d.ts.map +1 -1
  180. package/dist/esm/review/intents.js +12 -0
  181. package/dist/esm/review/intents.js.map +1 -1
  182. package/dist/esm/review/lineError.d.ts +34 -0
  183. package/dist/esm/review/lineError.d.ts.map +1 -0
  184. package/dist/esm/review/lineError.js +36 -0
  185. package/dist/esm/review/lineError.js.map +1 -0
  186. package/dist/esm/review/messages.d.ts +15 -3
  187. package/dist/esm/review/messages.d.ts.map +1 -1
  188. package/dist/esm/review/messages.js +15 -3
  189. package/dist/esm/review/messages.js.map +1 -1
  190. package/dist/esm/review/model.d.ts +149 -0
  191. package/dist/esm/review/model.d.ts.map +1 -0
  192. package/dist/esm/review/model.js +746 -0
  193. package/dist/esm/review/model.js.map +1 -0
  194. package/dist/esm/review/plan.d.ts +63 -0
  195. package/dist/esm/review/plan.d.ts.map +1 -0
  196. package/dist/esm/review/plan.js +141 -0
  197. package/dist/esm/review/plan.js.map +1 -0
  198. package/dist/esm/review/react/index.d.ts +1 -0
  199. package/dist/esm/review/react/index.d.ts.map +1 -1
  200. package/dist/esm/review/react/index.js +1 -0
  201. package/dist/esm/review/react/index.js.map +1 -1
  202. package/dist/esm/review/react/useReviewedRun.d.ts +96 -0
  203. package/dist/esm/review/react/useReviewedRun.d.ts.map +1 -0
  204. package/dist/esm/review/react/useReviewedRun.js +257 -0
  205. package/dist/esm/review/react/useReviewedRun.js.map +1 -0
  206. package/dist/esm/review/receipt.d.ts +4 -1
  207. package/dist/esm/review/receipt.d.ts.map +1 -1
  208. package/dist/esm/review/receipt.js +6 -2
  209. package/dist/esm/review/receipt.js.map +1 -1
  210. package/dist/esm/review/relayr.d.ts +13 -4
  211. package/dist/esm/review/relayr.d.ts.map +1 -1
  212. package/dist/esm/review/relayr.js +50 -8
  213. package/dist/esm/review/relayr.js.map +1 -1
  214. package/dist/esm/review/relayrSend.d.ts +135 -0
  215. package/dist/esm/review/relayrSend.d.ts.map +1 -0
  216. package/dist/esm/review/relayrSend.js +934 -0
  217. package/dist/esm/review/relayrSend.js.map +1 -0
  218. package/dist/esm/review/reviewQueue.d.ts +10 -9
  219. package/dist/esm/review/reviewQueue.d.ts.map +1 -1
  220. package/dist/esm/review/reviewQueue.js +17 -26
  221. package/dist/esm/review/reviewQueue.js.map +1 -1
  222. package/dist/esm/review/reviewRequests.d.ts +86 -0
  223. package/dist/esm/review/reviewRequests.d.ts.map +1 -0
  224. package/dist/esm/review/reviewRequests.js +263 -0
  225. package/dist/esm/review/reviewRequests.js.map +1 -0
  226. package/dist/esm/review/safeRelayr.d.ts +3 -1
  227. package/dist/esm/review/safeRelayr.d.ts.map +1 -1
  228. package/dist/esm/review/safeRelayr.js +5 -1
  229. package/dist/esm/review/safeRelayr.js.map +1 -1
  230. package/dist/esm/review/safeSend.d.ts +69 -0
  231. package/dist/esm/review/safeSend.d.ts.map +1 -0
  232. package/dist/esm/review/safeSend.js +303 -0
  233. package/dist/esm/review/safeSend.js.map +1 -0
  234. package/dist/esm/review/send.d.ts +241 -0
  235. package/dist/esm/review/send.d.ts.map +1 -0
  236. package/dist/esm/review/send.js +1011 -0
  237. package/dist/esm/review/send.js.map +1 -0
  238. package/dist/esm/review/sequence.d.ts +77 -0
  239. package/dist/esm/review/sequence.d.ts.map +1 -0
  240. package/dist/esm/review/sequence.js +223 -0
  241. package/dist/esm/review/sequence.js.map +1 -0
  242. package/dist/esm/review/sign.d.ts +109 -0
  243. package/dist/esm/review/sign.d.ts.map +1 -0
  244. package/dist/esm/review/sign.js +368 -0
  245. package/dist/esm/review/sign.js.map +1 -0
  246. package/dist/esm/review/simulation.d.ts +41 -2
  247. package/dist/esm/review/simulation.d.ts.map +1 -1
  248. package/dist/esm/review/simulation.js +95 -29
  249. package/dist/esm/review/simulation.js.map +1 -1
  250. package/dist/esm/review/transaction-message.d.ts +13 -0
  251. package/dist/esm/review/transaction-message.d.ts.map +1 -1
  252. package/dist/esm/review/transaction-message.js +23 -0
  253. package/dist/esm/review/transaction-message.js.map +1 -1
  254. package/dist/esm/review/transactionReview.d.ts +27 -19
  255. package/dist/esm/review/transactionReview.d.ts.map +1 -1
  256. package/dist/esm/review/transactionReview.js +19 -56
  257. package/dist/esm/review/transactionReview.js.map +1 -1
  258. package/dist/esm/review/wallet.d.ts +82 -0
  259. package/dist/esm/review/wallet.d.ts.map +1 -0
  260. package/dist/esm/review/wallet.js +150 -0
  261. package/dist/esm/review/wallet.js.map +1 -0
  262. package/dist/esm/review/writeHold.d.ts +100 -12
  263. package/dist/esm/review/writeHold.d.ts.map +1 -1
  264. package/dist/esm/review/writeHold.js +59 -13
  265. package/dist/esm/review/writeHold.js.map +1 -1
  266. package/dist/esm/review/writeRecovery.d.ts +6 -1
  267. package/dist/esm/review/writeRecovery.d.ts.map +1 -1
  268. package/dist/esm/review/writeRecovery.js +111 -43
  269. package/dist/esm/review/writeRecovery.js.map +1 -1
  270. package/dist/esm/safeService.d.ts +27 -4
  271. package/dist/esm/safeService.d.ts.map +1 -1
  272. package/dist/esm/safeService.js +119 -4
  273. package/dist/esm/safeService.js.map +1 -1
  274. package/dist/esm/testing.d.ts +24 -0
  275. package/dist/esm/testing.d.ts.map +1 -1
  276. package/dist/esm/testing.js +23 -1
  277. package/dist/esm/testing.js.map +1 -1
  278. package/dist/esm/v6/defifa.d.ts.map +1 -1
  279. package/dist/esm/v6/defifa.js +24 -23
  280. package/dist/esm/v6/defifa.js.map +1 -1
  281. package/dist/esm/v6/executionErrors.d.ts.map +1 -1
  282. package/dist/esm/v6/executionErrors.js +3 -2
  283. package/dist/esm/v6/executionErrors.js.map +1 -1
  284. package/dist/esm/v6/pay.d.ts +25 -8
  285. package/dist/esm/v6/pay.d.ts.map +1 -1
  286. package/dist/esm/v6/pay.js +115 -22
  287. package/dist/esm/v6/pay.js.map +1 -1
  288. package/dist/esm/v6/suckers.d.ts +30 -0
  289. package/dist/esm/v6/suckers.d.ts.map +1 -1
  290. package/dist/esm/v6/suckers.js +67 -5
  291. package/dist/esm/v6/suckers.js.map +1 -1
  292. package/package.json +11 -2
@@ -0,0 +1,746 @@
1
+ import { erc20Abi, keccak256, toHex, } from "viem";
2
+ import { NATIVE_TOKEN } from "../constants.js";
3
+ import { USDC_ADDRESSES } from "../pureConstants.js";
4
+ import { describeJBHookMetadata, describePermissionsData, describeSafeInitializer, describeSafeInnerCall, describeSplitGroups, describeSuckerClaim, describeUniversalRouterExecute, describeV4UnlockData, functionFromCall, knownAddressName, namedValue, nativeValue, readableValue, reviewDescription, unixTime, } from "./decode.js";
5
+ import { transactionReviewJson, } from "./transactionReview.js";
6
+ const SAFE_GAS_NONZERO = "If this call fails, the Safe still executes and uses this nonce.";
7
+ const DELEGATECALL = "DELEGATECALL: runs foreign code with the Safe's own storage and funds";
8
+ const ABI_UNAVAILABLE = "This call’s ABI is not available in this flow. Check the complete calldata in Raw before continuing.";
9
+ const UNKNOWN_CONTRACT = "This destination is not a contract the app recognizes. Check the address before continuing.";
10
+ const UNLIMITED_APPROVAL = "Unlimited approval: the spender can move all of this token you hold, now and later.";
11
+ const OWNER_ACTION = "This changes who or what controls this contract or project.";
12
+ const PERMISSION_GRANT = "This lets another address act for you.";
13
+ const DECIMALS_UNKNOWN = "The token's decimals could not be read, so its amount shows in base units.";
14
+ const UNREADABLE = "Part of this request can't be read here. Check it in your wallet before continuing.";
15
+ const POSSIBLE_TOKEN_ID = "ERC-721 NFTs use this same function, so this number may be an NFT's token ID rather than an amount.";
16
+ /** Address arguments that give the address a part, by argument name. */
17
+ const ROLE_OF = {
18
+ spender: "spender",
19
+ recipient: "recipient",
20
+ beneficiary: "beneficiary",
21
+ owner: "owner",
22
+ newOwner: "owner",
23
+ operator: "operator",
24
+ };
25
+ /**
26
+ * ERC-20, ERC-2612 and Permit2 approvals and transfers by signature.
27
+ * ERC-721 shares `approve(address,uint256)` and
28
+ * `transferFrom(address,address,uint256)`; where the ABI names the last
29
+ * argument `tokenId`, it is a token ID, not an amount.
30
+ */
31
+ const TOKEN_CALLS = {
32
+ "approve(address,uint256)": {
33
+ spender: 0,
34
+ amount: 1,
35
+ sharedWithErc721: true,
36
+ },
37
+ "increaseAllowance(address,uint256)": { spender: 0, amount: 1 },
38
+ "transfer(address,uint256)": { recipient: 0, amount: 1 },
39
+ "transferFrom(address,address,uint256)": {
40
+ recipient: 1,
41
+ amount: 2,
42
+ sharedWithErc721: true,
43
+ },
44
+ "permit(address,address,uint256,uint256,uint8,bytes32,bytes32)": {
45
+ spender: 1,
46
+ amount: 2,
47
+ },
48
+ "approve(address,address,uint160,uint48)": {
49
+ token: 0,
50
+ spender: 1,
51
+ amount: 2,
52
+ },
53
+ };
54
+ /** The token call `fn` is, with no amount for an ERC-721 token ID; null for any other function. */
55
+ function tokenCallOf(fn) {
56
+ const shape = TOKEN_CALLS[`${fn.name}(${fn.inputs.map((input) => input.type).join(",")})`];
57
+ if (!shape)
58
+ return null;
59
+ return shape.amount !== undefined &&
60
+ fn.inputs[shape.amount].name === "tokenId"
61
+ ? { ...shape, amount: undefined, tokenId: shape.amount }
62
+ : shape;
63
+ }
64
+ /**
65
+ * Calls that change a contract's owner, a Safe's owners or threshold, what
66
+ * else can act as the Safe, or a project's controller or terminals.
67
+ */
68
+ const OWNER_ACTIONS = new Set([
69
+ "transferOwnership",
70
+ "renounceOwnership",
71
+ "addOwnerWithThreshold",
72
+ "removeOwner",
73
+ "swapOwner",
74
+ "changeThreshold",
75
+ "enableModule",
76
+ "setGuard",
77
+ "setFallbackHandler",
78
+ "transferOwnershipToProject",
79
+ "setControllerOf",
80
+ "setTerminalsOf",
81
+ ]);
82
+ /** MultiSend's `transactions` argument is where its decoded calls show. */
83
+ function nestsCallsInArgument(fn) {
84
+ return (fn?.name === "multiSend" &&
85
+ fn.inputs.some((input) => input.name === "transactions"));
86
+ }
87
+ function isOne(value) {
88
+ return value === 1 || value === 1n;
89
+ }
90
+ /** A decoder's view of one argument, or null for {@link readableValue}'s text alone. */
91
+ function specialArgument(call, fn, inputName, value) {
92
+ const steps = (found) => found ? { steps: found } : null;
93
+ switch (fn.name) {
94
+ case "modifyLiquidities": {
95
+ if (inputName !== "unlockData")
96
+ return null;
97
+ const v4Plan = describeV4UnlockData(value);
98
+ return v4Plan ? { v4Plan } : null;
99
+ }
100
+ case "pay":
101
+ case "addToBalanceOf":
102
+ return inputName === "metadata"
103
+ ? steps(describeJBHookMetadata("pay", value))
104
+ : null;
105
+ case "cashOutTokensOf":
106
+ return inputName === "metadata"
107
+ ? steps(describeJBHookMetadata("cashOut", value))
108
+ : null;
109
+ case "claim":
110
+ return steps(describeSuckerClaim(call.chainId, value));
111
+ case "execTransaction":
112
+ if (inputName === "data") {
113
+ return steps(describeSafeInnerCall(call.chainId, call.args?.[0], value));
114
+ }
115
+ if (inputName !== "operation")
116
+ return null;
117
+ return {
118
+ text: isOne(value)
119
+ ? `1 — ${DELEGATECALL}`
120
+ : value === 0 || value === 0n
121
+ ? "0 — CALL"
122
+ : String(value),
123
+ };
124
+ case "createProxyWithNonce":
125
+ return inputName === "initializer"
126
+ ? steps(describeSafeInitializer(call.chainId, value))
127
+ : null;
128
+ case "setPermissionsFor":
129
+ return inputName === "permissionsData"
130
+ ? steps(describePermissionsData(call.chainId, value))
131
+ : null;
132
+ case "setSplitGroupsOf":
133
+ return inputName === "splitGroups"
134
+ ? steps(describeSplitGroups(call.chainId, value))
135
+ : null;
136
+ }
137
+ return inputName === "transactions" &&
138
+ nestsCallsInArgument(fn) &&
139
+ call.calls?.length
140
+ ? { nested: call.calls.map(reviewCall) }
141
+ : null;
142
+ }
143
+ function reviewValue(parameter, value, chainId) {
144
+ return {
145
+ name: parameter.name ?? "",
146
+ type: parameter.type,
147
+ text: readableValue(parameter.type, value, chainId),
148
+ children: reviewChildren(parameter, value, chainId),
149
+ };
150
+ }
151
+ function reviewChildren(parameter, value, chainId) {
152
+ const array = /^(.*)\[\d*\]$/u.exec(parameter.type);
153
+ if (array && Array.isArray(value)) {
154
+ return value.map((item, index) => reviewValue({ ...parameter, name: `[${index}]`, type: array[1] }, item, chainId));
155
+ }
156
+ if ("components" in parameter && Array.isArray(parameter.components)) {
157
+ return parameter.components.map((component, index) => reviewValue(component, namedValue(value, component.name ?? "", index), chainId));
158
+ }
159
+ return null;
160
+ }
161
+ /** Every address argument, a tuple's components and an array's elements included, under its own name. */
162
+ function addressArguments(parameter, value) {
163
+ const array = /^(.*)\[\d*\]$/u.exec(parameter.type);
164
+ if (array && Array.isArray(value)) {
165
+ const item = { ...parameter, type: array[1] };
166
+ return value.flatMap((element) => addressArguments(item, element));
167
+ }
168
+ if ("components" in parameter && Array.isArray(parameter.components)) {
169
+ return parameter.components.flatMap((component, index) => addressArguments(component, namedValue(value, component.name ?? "", index)));
170
+ }
171
+ return parameter.type === "address" ? [[parameter.name ?? "", value]] : [];
172
+ }
173
+ function reviewRoles(call, fn) {
174
+ const roles = [];
175
+ const seen = new Set();
176
+ const add = (role, address) => {
177
+ if (!role || typeof address !== "string")
178
+ return;
179
+ const key = `${role}:${address.toLowerCase()}`;
180
+ if (seen.has(key))
181
+ return;
182
+ seen.add(key);
183
+ roles.push({
184
+ role,
185
+ address: address,
186
+ name: knownAddressName(call.chainId, address),
187
+ });
188
+ };
189
+ const tokenCall = tokenCallOf(fn);
190
+ if (tokenCall?.spender !== undefined) {
191
+ add("spender", call.args?.[tokenCall.spender]);
192
+ }
193
+ if (tokenCall?.recipient !== undefined) {
194
+ add("recipient", call.args?.[tokenCall.recipient]);
195
+ }
196
+ fn.inputs.forEach((input, index) => {
197
+ for (const [name, address] of addressArguments(input, call.args?.[index])) {
198
+ add(ROLE_OF[name], address);
199
+ }
200
+ });
201
+ return roles;
202
+ }
203
+ /** Native ETH and USDC need no read. */
204
+ function knownToken(chainId, token) {
205
+ if (token === "native")
206
+ return { decimals: 18, symbol: "ETH" };
207
+ const usdc = USDC_ADDRESSES[chainId];
208
+ return usdc?.toLowerCase() === token.toLowerCase()
209
+ ? { decimals: 6, symbol: "USDC" }
210
+ : { decimals: null, symbol: null };
211
+ }
212
+ function tokenAmount(chainId, address, amount) {
213
+ if (typeof address !== "string" || typeof amount !== "bigint")
214
+ return null;
215
+ const token = address.toLowerCase() === NATIVE_TOKEN.toLowerCase()
216
+ ? "native"
217
+ : address;
218
+ return { token, amount, ...knownToken(chainId, token) };
219
+ }
220
+ /**
221
+ * What a terminal payment sends, or what an ERC-20 or Permit2 approval or
222
+ * transfer moves. A native payment sends the call's value, whatever its
223
+ * `amount` argument says.
224
+ */
225
+ function tokenAmountOf(call, fn) {
226
+ const args = call.args ?? [];
227
+ if (fn.name === "pay" || fn.name === "addToBalanceOf") {
228
+ const token = fn.inputs.findIndex((input) => input.name === "token");
229
+ const amount = fn.inputs.findIndex((input) => input.name === "amount");
230
+ if (token < 0 || amount < 0)
231
+ return null;
232
+ const native = typeof args[token] === "string" &&
233
+ args[token].toLowerCase() === NATIVE_TOKEN.toLowerCase();
234
+ return tokenAmount(call.chainId, args[token], native ? (call.value ?? 0n) : args[amount]);
235
+ }
236
+ const tokenCall = tokenCallOf(fn);
237
+ if (tokenCall?.amount === undefined)
238
+ return null;
239
+ return tokenAmount(call.chainId, tokenCall.token === undefined ? call.to : args[tokenCall.token], args[tokenCall.amount]);
240
+ }
241
+ /** An approval of the type's largest amount, which never runs down. */
242
+ function isUnlimitedApproval(call, fn) {
243
+ const tokenCall = tokenCallOf(fn);
244
+ if (tokenCall?.spender === undefined || tokenCall.amount === undefined) {
245
+ return false;
246
+ }
247
+ const bits = BigInt(fn.inputs[tokenCall.amount].type.slice(4) || 256);
248
+ return call.args?.[tokenCall.amount] === (1n << bits) - 1n;
249
+ }
250
+ /** An address the app does not name, other than zero, which grants nothing. */
251
+ function isUnnamed(chainId, address) {
252
+ return (typeof address === "string" &&
253
+ !/^0x0{40}$/iu.test(address) &&
254
+ knownAddressName(chainId, address) === null);
255
+ }
256
+ /**
257
+ * An operator grant, or an approval, permit or approval for all that lets an
258
+ * address the app does not name move the signer's tokens. A zero ERC-20
259
+ * approval revokes and grants nothing, but only once the token is known to
260
+ * be ERC-20: to ERC-721, zero is a token ID. {@link enrichReviewModel}
261
+ * clears the grant when it confirms the token.
262
+ */
263
+ function grantsPermission(call, fn) {
264
+ if (fn.name === "setPermissionsFor")
265
+ return true;
266
+ if (fn.name === "setApprovalForAll") {
267
+ return call.args?.[1] === true && isUnnamed(call.chainId, call.args[0]);
268
+ }
269
+ const tokenCall = tokenCallOf(fn);
270
+ if (tokenCall?.spender === undefined)
271
+ return false;
272
+ return (isUnnamed(call.chainId, call.args?.[tokenCall.spender]) &&
273
+ (tokenCall.amount === undefined ||
274
+ call.args?.[tokenCall.amount] !== 0n ||
275
+ mayBeTokenId(call, fn)));
276
+ }
277
+ /** An ERC-20 reading of a call ERC-721 shares, to a contract the SDK does not know. */
278
+ function mayBeTokenId(call, fn) {
279
+ const tokenCall = tokenCallOf(fn);
280
+ return (tokenCall?.sharedWithErc721 === true &&
281
+ tokenCall.amount !== undefined &&
282
+ knownAddressName(call.chainId, call.to) === null);
283
+ }
284
+ /** The NFT a call names where its ABI calls the argument a token ID. */
285
+ function nftOf(call, fn) {
286
+ const tokenCall = tokenCallOf(fn);
287
+ const tokenId = tokenCall?.tokenId === undefined ? null : call.args?.[tokenCall.tokenId];
288
+ return typeof tokenId === "bigint" ? { token: call.to, tokenId } : null;
289
+ }
290
+ function reviewArguments(call, fn) {
291
+ const values = call.args ?? [];
292
+ const plain = fn.inputs.map((input, index) => ({
293
+ ...reviewValue(input, values[index], call.chainId),
294
+ steps: null,
295
+ v4Plan: null,
296
+ nested: null,
297
+ }));
298
+ const plan = fn.name === "execute"
299
+ ? describeUniversalRouterExecute(call.chainId, values)
300
+ : null;
301
+ if (plan) {
302
+ plain[0].steps = plan;
303
+ const deadline = values[2];
304
+ if (plain[2] &&
305
+ (typeof deadline === "bigint" || typeof deadline === "number")) {
306
+ plain[2].text = unixTime(deadline);
307
+ }
308
+ return plain;
309
+ }
310
+ return plain.map((argument, index) => ({
311
+ ...argument,
312
+ ...specialArgument(call, fn, argument.name, values[index]),
313
+ }));
314
+ }
315
+ function reviewCall(call) {
316
+ const fn = functionFromCall(call);
317
+ const args = fn ? reviewArguments(call, fn) : null;
318
+ const batched = call.calls?.length && !nestsCallsInArgument(fn) ? call.calls : null;
319
+ const warnings = [];
320
+ if (call.safeTxGas !== undefined && call.safeTxGas !== 0n) {
321
+ warnings.push({ code: "safe-gas-nonzero", text: SAFE_GAS_NONZERO });
322
+ }
323
+ if (!fn) {
324
+ warnings.push({ code: "abi-unavailable", text: ABI_UNAVAILABLE });
325
+ }
326
+ else if (fn.name === "execTransaction") {
327
+ const operation = fn.inputs.findIndex((input) => input.name === "operation");
328
+ if (isOne(call.args?.[operation])) {
329
+ warnings.push({ code: "delegatecall", text: DELEGATECALL });
330
+ }
331
+ }
332
+ const contractName = call.contractName ?? knownAddressName(call.chainId, call.to);
333
+ if (contractName === null && call.data.length >= 10) {
334
+ warnings.push({ code: "unknown-contract", text: UNKNOWN_CONTRACT });
335
+ }
336
+ if (fn && isUnlimitedApproval(call, fn)) {
337
+ warnings.push({ code: "unlimited-approval", text: UNLIMITED_APPROVAL });
338
+ }
339
+ if (fn && OWNER_ACTIONS.has(fn.name)) {
340
+ warnings.push({ code: "owner-action", text: OWNER_ACTION });
341
+ }
342
+ if (fn && grantsPermission(call, fn)) {
343
+ warnings.push({ code: "permission-grant", text: PERMISSION_GRANT });
344
+ }
345
+ if (fn && mayBeTokenId(call, fn)) {
346
+ warnings.push({ code: "possible-token-id", text: POSSIBLE_TOKEN_ID });
347
+ }
348
+ const amount = fn ? tokenAmountOf(call, fn) : null;
349
+ const tokenAmounts = amount ? [amount] : [];
350
+ return {
351
+ chainId: call.chainId,
352
+ from: call.from ?? null,
353
+ to: call.to,
354
+ contractName,
355
+ value: call.value ?? 0n,
356
+ valueText: nativeValue(call.value),
357
+ gas: call.gas ?? null,
358
+ safeTxGas: call.safeTxGas ?? null,
359
+ label: call.label ?? null,
360
+ functionName: fn?.name ?? null,
361
+ data: call.data,
362
+ selector: call.data.slice(0, 10),
363
+ byteLength: Math.max(0, (call.data.length - 2) / 2),
364
+ args,
365
+ calls: batched ? batched.map(reviewCall) : null,
366
+ roles: fn ? reviewRoles(call, fn) : [],
367
+ tokenAmounts,
368
+ nft: fn ? nftOf(call, fn) : null,
369
+ warnings: withDecimalsWarning(warnings, tokenAmounts),
370
+ };
371
+ }
372
+ /**
373
+ * JSON-ready data with object keys sorted at every depth, so equal data
374
+ * encodes alike, and a bigint tagged as `{ $bigint }` so it never encodes like
375
+ * a string. A key that starts with `$` gains another, so no input can forge
376
+ * the tag. Anything JSON would not keep exactly (a boxed primitive, a class
377
+ * instance, a non-finite number) throws rather than bind as something else.
378
+ */
379
+ function canonical(value) {
380
+ if (typeof value === "bigint")
381
+ return { $bigint: value.toString() };
382
+ if (typeof value === "number" && !Number.isFinite(value)) {
383
+ throw new Error(`The review cannot bind the number ${value}.`);
384
+ }
385
+ if (Array.isArray(value))
386
+ return value.map(canonical);
387
+ if (value && typeof value === "object") {
388
+ const prototype = Object.getPrototypeOf(value);
389
+ if (prototype !== Object.prototype && prototype !== null) {
390
+ throw new Error("The review can only bind plain data.");
391
+ }
392
+ return Object.fromEntries(Object.keys(value)
393
+ .sort()
394
+ .map((key) => [
395
+ key.startsWith("$") ? `$${key}` : key,
396
+ canonical(value[key]),
397
+ ]));
398
+ }
399
+ return value;
400
+ }
401
+ /** What a call sends, and the decoded calls the review shows inside it. */
402
+ function bindingCall(call) {
403
+ return {
404
+ chainId: call.chainId,
405
+ from: call.from ?? null,
406
+ to: call.to,
407
+ value: call.value ?? 0n,
408
+ gas: call.gas ?? null,
409
+ safeTxGas: call.safeTxGas ?? null,
410
+ data: call.data,
411
+ calls: call.calls?.length ? call.calls.map(bindingCall) : null,
412
+ // Bound only when set, so a model without it keeps its id.
413
+ ...(call.adoptIgnoringArgs
414
+ ? { adoptIgnoringArgs: [...call.adoptIgnoringArgs] }
415
+ : {}),
416
+ };
417
+ }
418
+ /**
419
+ * The plain-data review of a request: what every client's review dialog
420
+ * shows, decoded once. `context` is display only and never feeds `calls`.
421
+ * It never throws: a request it can't read or bind exactly gets a model with
422
+ * an `unreadable` warning, showing what it can read, and an id that matches
423
+ * no other model. Core's own prompts refuse such a model: it confirms nothing.
424
+ */
425
+ export function buildReviewModel(request) {
426
+ try {
427
+ return readModel(request);
428
+ }
429
+ catch {
430
+ try {
431
+ return unreadableModel(request);
432
+ }
433
+ catch {
434
+ // Even its parts can't be read: the warning alone.
435
+ return unreadableModel(null);
436
+ }
437
+ }
438
+ }
439
+ function readModel(request) {
440
+ // Copies, so the request changing after review never changes what the model shows.
441
+ const signatures = (request.signatures ?? []).map(reviewSignature);
442
+ const signsMessage = request.authorization?.kind ===
443
+ "message";
444
+ const kind = request.kind === "authorization"
445
+ ? signsMessage
446
+ ? "message"
447
+ : "authorization"
448
+ : !request.calls.length && signatures.length
449
+ ? signatures.every((signature) => signature.kind === "message")
450
+ ? "message"
451
+ : "authorization"
452
+ : "transaction";
453
+ const context = (request.context ?? []).map((row) => ({
454
+ ...row,
455
+ ...(row.lines ? { lines: [...row.lines] } : {}),
456
+ }));
457
+ const authorization = structuredClone(request.authorization ?? null);
458
+ const messages = signatures.filter((signature) => signature.message !== null);
459
+ const message = messages.length === 1 ? messages[0].message : null;
460
+ const binding = {
461
+ kind,
462
+ calls: request.calls.map(bindingCall),
463
+ authorization,
464
+ message,
465
+ context,
466
+ ...(signatures.length
467
+ ? {
468
+ signatures: signatures.map((signature, index) => ({
469
+ kind: signature.kind,
470
+ chainId: signature.chainId,
471
+ typedData: signature.typedData,
472
+ message: signature.message,
473
+ calls: (request.signatures[index].calls ?? []).map(bindingCall),
474
+ })),
475
+ }
476
+ : {}),
477
+ };
478
+ return {
479
+ id: keccak256(toHex(JSON.stringify(canonical(binding)))),
480
+ kind,
481
+ title: request.title ?? null,
482
+ description: reviewDescription(request),
483
+ confirmLabel: request.confirmLabel ?? null,
484
+ context,
485
+ calls: request.calls.map(reviewCall),
486
+ authorization,
487
+ message,
488
+ signatures,
489
+ rawJson: transactionReviewJson(request),
490
+ warnings: [],
491
+ };
492
+ }
493
+ /** `read()`, or `fallback` when it throws. */
494
+ function attempt(read, fallback) {
495
+ try {
496
+ return read();
497
+ }
498
+ catch {
499
+ return fallback;
500
+ }
501
+ }
502
+ const text = (value) => typeof value === "string" ? value : "";
503
+ /** The parts of a request {@link readModel} could not take whole, each read on its own. */
504
+ function unreadableModel(input) {
505
+ const request = (input && typeof input === "object" ? input : {});
506
+ const list = (value) => Array.isArray(value) ? value : [];
507
+ const warning = { code: "unreadable", text: UNREADABLE };
508
+ return {
509
+ id: keccak256(toHex(globalThis.crypto.randomUUID())),
510
+ kind: request.kind === "authorization" ? "authorization" : "transaction",
511
+ title: typeof request.title === "string" ? request.title : null,
512
+ description: attempt(() => reviewDescription(request), ""),
513
+ confirmLabel: typeof request.confirmLabel === "string" ? request.confirmLabel : null,
514
+ context: list(request.context).map((row) => {
515
+ const item = (row ?? {});
516
+ return {
517
+ label: text(item.label),
518
+ value: text(item.value),
519
+ ...(Array.isArray(item.lines) ? { lines: item.lines.map(text) } : {}),
520
+ ...(typeof item.note === "string" ? { note: item.note } : {}),
521
+ ...(item.strong === true ? { strong: true } : {}),
522
+ ...(item.mono === true ? { mono: true } : {}),
523
+ };
524
+ }),
525
+ calls: list(request.calls).map((call) => attempt(() => reviewCall(call), null) ?? rawCall(call)),
526
+ authorization: attempt(() => structuredClone(request.authorization ?? null), null),
527
+ message: null,
528
+ signatures: list(request.signatures).flatMap((signature) => attempt(() => [reviewSignature(signature)], [])),
529
+ rawJson: attempt(() => transactionReviewJson(request), ""),
530
+ warnings: [warning],
531
+ };
532
+ }
533
+ /** A call {@link reviewCall} could not read: its destination, value and bytes, as far as they read. */
534
+ function rawCall(input) {
535
+ const call = (input ?? {});
536
+ const data = typeof call.data === "string" && /^0x[\da-f]*$/iu.test(call.data)
537
+ ? call.data
538
+ : "0x";
539
+ const value = typeof call.value === "bigint" ? call.value : 0n;
540
+ return {
541
+ chainId: typeof call.chainId === "number" ? call.chainId : 0,
542
+ from: null,
543
+ to: text(call.to),
544
+ contractName: null,
545
+ value,
546
+ valueText: nativeValue(value),
547
+ gas: null,
548
+ safeTxGas: null,
549
+ label: typeof call.label === "string" ? call.label : null,
550
+ functionName: null,
551
+ data,
552
+ selector: data.slice(0, 10),
553
+ byteLength: (data.length - 2) / 2,
554
+ args: null,
555
+ calls: null,
556
+ roles: [],
557
+ tokenAmounts: [],
558
+ nft: null,
559
+ warnings: [{ code: "unreadable", text: UNREADABLE }],
560
+ };
561
+ }
562
+ function reviewSignature(signature) {
563
+ return {
564
+ kind: signature.kind,
565
+ chainId: signature.chainId,
566
+ typedData: structuredClone(signature.typedData ?? null),
567
+ message: signature.message ?? null,
568
+ calls: (signature.calls ?? []).map(reviewCall),
569
+ steps: structuredClone([...(signature.steps ?? [])]),
570
+ };
571
+ }
572
+ /** `warnings` with one `decimals-unknown` last when any amount's decimals are unknown. */
573
+ function withDecimalsWarning(warnings, tokenAmounts) {
574
+ const kept = warnings.filter((warning) => warning.code !== "decimals-unknown");
575
+ return tokenAmounts.some((amount) => amount.decimals === null)
576
+ ? [...kept, { code: "decimals-unknown", text: DECIMALS_UNKNOWN }]
577
+ : kept;
578
+ }
579
+ const ERC165_ABI = [
580
+ {
581
+ type: "function",
582
+ name: "supportsInterface",
583
+ stateMutability: "view",
584
+ inputs: [{ name: "interfaceId", type: "bytes4" }],
585
+ outputs: [{ type: "bool" }],
586
+ },
587
+ ];
588
+ const ERC721_INTERFACE_ID = "0x80ac58cd";
589
+ /**
590
+ * A token's decimals and symbol, and when `probe` is set whether it is
591
+ * ERC-721. Each is null when its read fails or returns something else.
592
+ */
593
+ async function readToken(client, token, probe) {
594
+ if (!client)
595
+ return { decimals: null, symbol: null, erc721: null };
596
+ const read = async (request) => {
597
+ try {
598
+ return await request();
599
+ }
600
+ catch {
601
+ return null;
602
+ }
603
+ };
604
+ const [decimals, symbol, erc721] = await Promise.all([
605
+ read(() => client.readContract({
606
+ address: token,
607
+ abi: erc20Abi,
608
+ functionName: "decimals",
609
+ })),
610
+ read(() => client.readContract({
611
+ address: token,
612
+ abi: erc20Abi,
613
+ functionName: "symbol",
614
+ })),
615
+ probe
616
+ ? read(() => client.readContract({
617
+ address: token,
618
+ abi: ERC165_ABI,
619
+ functionName: "supportsInterface",
620
+ args: [ERC721_INTERFACE_ID],
621
+ }))
622
+ : null,
623
+ ]);
624
+ return {
625
+ erc721: typeof erc721 === "boolean" ? erc721 : null,
626
+ decimals: typeof decimals === "number" &&
627
+ Number.isInteger(decimals) &&
628
+ decimals >= 0 &&
629
+ decimals <= 255
630
+ ? decimals
631
+ : null,
632
+ symbol: typeof symbol === "string" && symbol.trim() && symbol.length <= 32
633
+ ? symbol.trim()
634
+ : null,
635
+ };
636
+ }
637
+ /** Every call the model shows, the ones inside other calls and arguments included. */
638
+ function eachCall(calls, visit) {
639
+ for (const call of calls) {
640
+ visit(call);
641
+ eachCall(call.calls ?? [], visit);
642
+ for (const argument of call.args ?? []) {
643
+ eachCall(argument.nested ?? [], visit);
644
+ }
645
+ }
646
+ }
647
+ /**
648
+ * The model with each token's decimals and symbol read from the token, once
649
+ * per token per chain. A failed read leaves them null, never zero, and keeps
650
+ * the `decimals-unknown` warning. A call ERC-721 shares, to an unknown
651
+ * contract, also asks the contract whether it is ERC-721: a yes shows the
652
+ * number as the NFT's token ID; a no, or decimals it answers, clears
653
+ * `possible-token-id`; no answer keeps it. The id is unchanged: the reads
654
+ * only explain the calls already bound.
655
+ */
656
+ export async function enrichReviewModel(model, clientFor) {
657
+ const wanted = new Map();
658
+ const key = (chainId, token) => `${chainId}:${token.toLowerCase()}`;
659
+ const probes = (call) => call.warnings.some((warning) => warning.code === "possible-token-id");
660
+ const signed = model.signatures.flatMap((signature) => signature.calls);
661
+ eachCall([...model.calls, ...signed], (call) => {
662
+ for (const { token, decimals, symbol } of call.tokenAmounts) {
663
+ if (token === "native" || (decimals !== null && symbol !== null)) {
664
+ continue;
665
+ }
666
+ const id = key(call.chainId, token);
667
+ const probe = probes(call) && token.toLowerCase() === call.to.toLowerCase();
668
+ const seen = wanted.get(id);
669
+ wanted.set(id, {
670
+ chainId: call.chainId,
671
+ token,
672
+ probe: probe || (seen?.probe ?? false),
673
+ });
674
+ }
675
+ });
676
+ const read = new Map(await Promise.all([...wanted].map(async ([id, { chainId, token, probe }]) => {
677
+ let client;
678
+ try {
679
+ client = clientFor(chainId);
680
+ }
681
+ catch {
682
+ client = undefined;
683
+ }
684
+ return [id, await readToken(client, token, probe)];
685
+ })));
686
+ const enrich = (call) => {
687
+ const nested = {
688
+ args: call.args?.map((argument) => argument.nested
689
+ ? { ...argument, nested: argument.nested.map(enrich) }
690
+ : argument) ?? null,
691
+ calls: call.calls?.map(enrich) ?? null,
692
+ };
693
+ const target = probes(call) ? read.get(key(call.chainId, call.to)) : null;
694
+ if (target?.erc721 === true) {
695
+ const [{ amount: tokenId }] = call.tokenAmounts;
696
+ const cleared = new Set([
697
+ "possible-token-id",
698
+ "unlimited-approval",
699
+ "decimals-unknown",
700
+ ]);
701
+ return {
702
+ ...call,
703
+ ...nested,
704
+ tokenAmounts: [],
705
+ nft: { token: call.to, tokenId },
706
+ warnings: call.warnings.filter((warning) => !cleared.has(warning.code)),
707
+ };
708
+ }
709
+ // Decimals it answers, and no ERC-721 yes, confirm ERC-20: a zero
710
+ // approval then revokes rather than grants.
711
+ const revokes = target?.decimals !== null &&
712
+ target?.decimals !== undefined &&
713
+ call.tokenAmounts[0]?.amount === 0n;
714
+ const warnings = target && (target.erc721 === false || target.decimals !== null)
715
+ ? call.warnings.filter((warning) => warning.code !== "possible-token-id" &&
716
+ !(revokes && warning.code === "permission-grant"))
717
+ : call.warnings;
718
+ const tokenAmounts = call.tokenAmounts.map((amount) => {
719
+ const found = amount.token === "native"
720
+ ? undefined
721
+ : read.get(key(call.chainId, amount.token));
722
+ return found
723
+ ? {
724
+ ...amount,
725
+ decimals: amount.decimals ?? found.decimals,
726
+ symbol: amount.symbol ?? found.symbol,
727
+ }
728
+ : amount;
729
+ });
730
+ return {
731
+ ...call,
732
+ ...nested,
733
+ tokenAmounts,
734
+ warnings: withDecimalsWarning(warnings, tokenAmounts),
735
+ };
736
+ };
737
+ return {
738
+ ...model,
739
+ calls: model.calls.map(enrich),
740
+ signatures: model.signatures.map((signature) => ({
741
+ ...signature,
742
+ calls: signature.calls.map(enrich),
743
+ })),
744
+ };
745
+ }
746
+ //# sourceMappingURL=model.js.map