@waiaas/daemon 2.11.0-rc.8 → 2.11.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 (414) hide show
  1. package/README.md +5 -5
  2. package/dist/api/middleware/address-validation.d.ts +6 -33
  3. package/dist/api/middleware/address-validation.d.ts.map +1 -1
  4. package/dist/api/middleware/address-validation.js +5 -129
  5. package/dist/api/middleware/address-validation.js.map +1 -1
  6. package/dist/api/middleware/host-guard.d.ts +1 -1
  7. package/dist/api/middleware/host-guard.js +2 -2
  8. package/dist/api/middleware/host-guard.js.map +1 -1
  9. package/dist/api/middleware/index.d.ts +1 -0
  10. package/dist/api/middleware/index.d.ts.map +1 -1
  11. package/dist/api/middleware/index.js +1 -0
  12. package/dist/api/middleware/index.js.map +1 -1
  13. package/dist/api/middleware/master-auth.d.ts +2 -5
  14. package/dist/api/middleware/master-auth.d.ts.map +1 -1
  15. package/dist/api/middleware/master-auth.js.map +1 -1
  16. package/dist/api/middleware/rate-limiter.d.ts +51 -0
  17. package/dist/api/middleware/rate-limiter.d.ts.map +1 -0
  18. package/dist/api/middleware/rate-limiter.js +146 -0
  19. package/dist/api/middleware/rate-limiter.js.map +1 -0
  20. package/dist/api/middleware/siwe-verify.d.ts +6 -26
  21. package/dist/api/middleware/siwe-verify.d.ts.map +1 -1
  22. package/dist/api/middleware/siwe-verify.js +5 -50
  23. package/dist/api/middleware/siwe-verify.js.map +1 -1
  24. package/dist/api/routes/actions.d.ts +1 -0
  25. package/dist/api/routes/actions.d.ts.map +1 -1
  26. package/dist/api/routes/actions.js +52 -4
  27. package/dist/api/routes/actions.js.map +1 -1
  28. package/dist/api/routes/admin-actions.d.ts +1 -0
  29. package/dist/api/routes/admin-actions.d.ts.map +1 -1
  30. package/dist/api/routes/admin-actions.js +3 -3
  31. package/dist/api/routes/admin-actions.js.map +1 -1
  32. package/dist/api/routes/admin-auth.d.ts.map +1 -1
  33. package/dist/api/routes/admin-auth.js +12 -7
  34. package/dist/api/routes/admin-auth.js.map +1 -1
  35. package/dist/api/routes/admin-credentials.js +2 -2
  36. package/dist/api/routes/admin-credentials.js.map +1 -1
  37. package/dist/api/routes/admin-monitoring.d.ts +10 -0
  38. package/dist/api/routes/admin-monitoring.d.ts.map +1 -1
  39. package/dist/api/routes/admin-monitoring.js +59 -14
  40. package/dist/api/routes/admin-monitoring.js.map +1 -1
  41. package/dist/api/routes/admin-notifications.d.ts.map +1 -1
  42. package/dist/api/routes/admin-notifications.js +2 -15
  43. package/dist/api/routes/admin-notifications.js.map +1 -1
  44. package/dist/api/routes/admin-settings.d.ts.map +1 -1
  45. package/dist/api/routes/admin-settings.js +90 -1
  46. package/dist/api/routes/admin-settings.js.map +1 -1
  47. package/dist/api/routes/admin-wallets.d.ts +16 -1
  48. package/dist/api/routes/admin-wallets.d.ts.map +1 -1
  49. package/dist/api/routes/admin-wallets.js +64 -75
  50. package/dist/api/routes/admin-wallets.js.map +1 -1
  51. package/dist/api/routes/admin.d.ts +1 -0
  52. package/dist/api/routes/admin.d.ts.map +1 -1
  53. package/dist/api/routes/admin.js.map +1 -1
  54. package/dist/api/routes/credentials.js +2 -2
  55. package/dist/api/routes/credentials.js.map +1 -1
  56. package/dist/api/routes/defi-positions.js.map +1 -1
  57. package/dist/api/routes/nfts.js.map +1 -1
  58. package/dist/api/routes/openapi-schemas.d.ts +412 -12
  59. package/dist/api/routes/openapi-schemas.d.ts.map +1 -1
  60. package/dist/api/routes/openapi-schemas.js +38 -5
  61. package/dist/api/routes/openapi-schemas.js.map +1 -1
  62. package/dist/api/routes/policies.d.ts +2 -0
  63. package/dist/api/routes/policies.d.ts.map +1 -1
  64. package/dist/api/routes/policies.js +55 -6
  65. package/dist/api/routes/policies.js.map +1 -1
  66. package/dist/api/routes/rpc-proxy.js.map +1 -1
  67. package/dist/api/routes/sessions.d.ts.map +1 -1
  68. package/dist/api/routes/sessions.js +47 -28
  69. package/dist/api/routes/sessions.js.map +1 -1
  70. package/dist/api/routes/staking.d.ts.map +1 -1
  71. package/dist/api/routes/staking.js +4 -76
  72. package/dist/api/routes/staking.js.map +1 -1
  73. package/dist/api/routes/tokens.d.ts.map +1 -1
  74. package/dist/api/routes/tokens.js.map +1 -1
  75. package/dist/api/routes/transactions.d.ts +1 -0
  76. package/dist/api/routes/transactions.d.ts.map +1 -1
  77. package/dist/api/routes/transactions.js +8 -2
  78. package/dist/api/routes/transactions.js.map +1 -1
  79. package/dist/api/routes/userop.d.ts.map +1 -1
  80. package/dist/api/routes/userop.js +0 -2
  81. package/dist/api/routes/userop.js.map +1 -1
  82. package/dist/api/routes/wallet-apps.d.ts.map +1 -1
  83. package/dist/api/routes/wallet-apps.js +20 -13
  84. package/dist/api/routes/wallet-apps.js.map +1 -1
  85. package/dist/api/routes/wallet.js.map +1 -1
  86. package/dist/api/routes/wallets.d.ts.map +1 -1
  87. package/dist/api/routes/wallets.js +3 -0
  88. package/dist/api/routes/wallets.js.map +1 -1
  89. package/dist/api/routes/wc.d.ts.map +1 -1
  90. package/dist/api/routes/wc.js +13 -8
  91. package/dist/api/routes/wc.js.map +1 -1
  92. package/dist/api/routes/x402.d.ts.map +1 -1
  93. package/dist/api/routes/x402.js +1 -2
  94. package/dist/api/routes/x402.js.map +1 -1
  95. package/dist/api/server.d.ts +8 -4
  96. package/dist/api/server.d.ts.map +1 -1
  97. package/dist/api/server.js +46 -5
  98. package/dist/api/server.js.map +1 -1
  99. package/dist/constants.d.ts +1 -1
  100. package/dist/constants.d.ts.map +1 -1
  101. package/dist/constants.js +1 -1
  102. package/dist/constants.js.map +1 -1
  103. package/dist/infrastructure/action/action-provider-registry.d.ts.map +1 -1
  104. package/dist/infrastructure/action/action-provider-registry.js +2 -3
  105. package/dist/infrastructure/action/action-provider-registry.js.map +1 -1
  106. package/dist/infrastructure/action/builtin-metadata.d.ts +22 -0
  107. package/dist/infrastructure/action/builtin-metadata.d.ts.map +1 -0
  108. package/dist/infrastructure/action/builtin-metadata.js +29 -0
  109. package/dist/infrastructure/action/builtin-metadata.js.map +1 -0
  110. package/dist/infrastructure/adapter-pool.d.ts +2 -1
  111. package/dist/infrastructure/adapter-pool.d.ts.map +1 -1
  112. package/dist/infrastructure/adapter-pool.js.map +1 -1
  113. package/dist/infrastructure/auth/address-validation.d.ts +38 -0
  114. package/dist/infrastructure/auth/address-validation.d.ts.map +1 -0
  115. package/dist/infrastructure/auth/address-validation.js +134 -0
  116. package/dist/infrastructure/auth/address-validation.js.map +1 -0
  117. package/dist/infrastructure/auth/siwe-verify.d.ts +34 -0
  118. package/dist/infrastructure/auth/siwe-verify.d.ts.map +1 -0
  119. package/dist/infrastructure/auth/siwe-verify.js +58 -0
  120. package/dist/infrastructure/auth/siwe-verify.js.map +1 -0
  121. package/dist/infrastructure/auth/types.d.ts +12 -0
  122. package/dist/infrastructure/auth/types.d.ts.map +1 -0
  123. package/dist/infrastructure/auth/types.js +8 -0
  124. package/dist/infrastructure/auth/types.js.map +1 -0
  125. package/dist/infrastructure/config/loader.d.ts +1 -10
  126. package/dist/infrastructure/config/loader.d.ts.map +1 -1
  127. package/dist/infrastructure/config/loader.js +0 -2
  128. package/dist/infrastructure/config/loader.js.map +1 -1
  129. package/dist/infrastructure/database/migrate.d.ts +6 -18
  130. package/dist/infrastructure/database/migrate.d.ts.map +1 -1
  131. package/dist/infrastructure/database/migrate.js +25 -2856
  132. package/dist/infrastructure/database/migrate.js.map +1 -1
  133. package/dist/infrastructure/database/migrations/v11-v20.d.ts +17 -0
  134. package/dist/infrastructure/database/migrations/v11-v20.d.ts.map +1 -0
  135. package/dist/infrastructure/database/migrations/v11-v20.js +295 -0
  136. package/dist/infrastructure/database/migrations/v11-v20.js.map +1 -0
  137. package/dist/infrastructure/database/migrations/v2-v10.d.ts +16 -0
  138. package/dist/infrastructure/database/migrations/v2-v10.d.ts.map +1 -0
  139. package/dist/infrastructure/database/migrations/v2-v10.js +539 -0
  140. package/dist/infrastructure/database/migrations/v2-v10.js.map +1 -0
  141. package/dist/infrastructure/database/migrations/v21-v30.d.ts +17 -0
  142. package/dist/infrastructure/database/migrations/v21-v30.d.ts.map +1 -0
  143. package/dist/infrastructure/database/migrations/v21-v30.js +507 -0
  144. package/dist/infrastructure/database/migrations/v21-v30.js.map +1 -0
  145. package/dist/infrastructure/database/migrations/v31-v40.d.ts +17 -0
  146. package/dist/infrastructure/database/migrations/v31-v40.d.ts.map +1 -0
  147. package/dist/infrastructure/database/migrations/v31-v40.js +203 -0
  148. package/dist/infrastructure/database/migrations/v31-v40.js.map +1 -0
  149. package/dist/infrastructure/database/migrations/v41-v50.d.ts +17 -0
  150. package/dist/infrastructure/database/migrations/v41-v50.d.ts.map +1 -0
  151. package/dist/infrastructure/database/migrations/v41-v50.js +188 -0
  152. package/dist/infrastructure/database/migrations/v41-v50.js.map +1 -0
  153. package/dist/infrastructure/database/migrations/v51-v59.d.ts +17 -0
  154. package/dist/infrastructure/database/migrations/v51-v59.d.ts.map +1 -0
  155. package/dist/infrastructure/database/migrations/v51-v59.js +420 -0
  156. package/dist/infrastructure/database/migrations/v51-v59.js.map +1 -0
  157. package/dist/infrastructure/database/schema-ddl.d.ts +24 -0
  158. package/dist/infrastructure/database/schema-ddl.d.ts.map +1 -0
  159. package/dist/infrastructure/database/schema-ddl.js +596 -0
  160. package/dist/infrastructure/database/schema-ddl.js.map +1 -0
  161. package/dist/infrastructure/database/schema.d.ts +38 -0
  162. package/dist/infrastructure/database/schema.d.ts.map +1 -1
  163. package/dist/infrastructure/database/schema.js +2 -0
  164. package/dist/infrastructure/database/schema.js.map +1 -1
  165. package/dist/infrastructure/jwt/jwt-secret-manager.d.ts.map +1 -1
  166. package/dist/infrastructure/jwt/jwt-secret-manager.js +16 -3
  167. package/dist/infrastructure/jwt/jwt-secret-manager.js.map +1 -1
  168. package/dist/infrastructure/nft/alchemy-nft-indexer.d.ts.map +1 -1
  169. package/dist/infrastructure/nft/alchemy-nft-indexer.js +0 -1
  170. package/dist/infrastructure/nft/alchemy-nft-indexer.js.map +1 -1
  171. package/dist/infrastructure/nft/helius-nft-indexer.d.ts.map +1 -1
  172. package/dist/infrastructure/nft/helius-nft-indexer.js +1 -2
  173. package/dist/infrastructure/nft/helius-nft-indexer.js.map +1 -1
  174. package/dist/infrastructure/nft/nft-indexer-client.d.ts.map +1 -1
  175. package/dist/infrastructure/nft/nft-indexer-client.js +0 -2
  176. package/dist/infrastructure/nft/nft-indexer-client.js.map +1 -1
  177. package/dist/infrastructure/security/ssrf-guard.d.ts +33 -0
  178. package/dist/infrastructure/security/ssrf-guard.d.ts.map +1 -0
  179. package/dist/infrastructure/security/ssrf-guard.js +244 -0
  180. package/dist/infrastructure/security/ssrf-guard.js.map +1 -0
  181. package/dist/infrastructure/settings/hot-reload.d.ts +1 -1
  182. package/dist/infrastructure/settings/hot-reload.d.ts.map +1 -1
  183. package/dist/infrastructure/settings/hot-reload.js +0 -2
  184. package/dist/infrastructure/settings/hot-reload.js.map +1 -1
  185. package/dist/infrastructure/settings/index.d.ts +2 -2
  186. package/dist/infrastructure/settings/index.d.ts.map +1 -1
  187. package/dist/infrastructure/settings/index.js +1 -1
  188. package/dist/infrastructure/settings/index.js.map +1 -1
  189. package/dist/infrastructure/settings/setting-keys.d.ts +14 -0
  190. package/dist/infrastructure/settings/setting-keys.d.ts.map +1 -1
  191. package/dist/infrastructure/settings/setting-keys.js +296 -214
  192. package/dist/infrastructure/settings/setting-keys.js.map +1 -1
  193. package/dist/infrastructure/settings/settings-service.d.ts +6 -1
  194. package/dist/infrastructure/settings/settings-service.d.ts.map +1 -1
  195. package/dist/infrastructure/settings/settings-service.js +15 -5
  196. package/dist/infrastructure/settings/settings-service.js.map +1 -1
  197. package/dist/infrastructure/telegram/telegram-bot-service.d.ts.map +1 -1
  198. package/dist/infrastructure/telegram/telegram-bot-service.js +3 -2
  199. package/dist/infrastructure/telegram/telegram-bot-service.js.map +1 -1
  200. package/dist/infrastructure/token-registry/builtin-tokens.d.ts.map +1 -1
  201. package/dist/infrastructure/token-registry/builtin-tokens.js +4 -7
  202. package/dist/infrastructure/token-registry/builtin-tokens.js.map +1 -1
  203. package/dist/lifecycle/daemon-pipeline.d.ts +49 -0
  204. package/dist/lifecycle/daemon-pipeline.d.ts.map +1 -0
  205. package/dist/lifecycle/daemon-pipeline.js +281 -0
  206. package/dist/lifecycle/daemon-pipeline.js.map +1 -0
  207. package/dist/lifecycle/daemon-shutdown.d.ts +14 -0
  208. package/dist/lifecycle/daemon-shutdown.d.ts.map +1 -0
  209. package/dist/lifecycle/daemon-shutdown.js +176 -0
  210. package/dist/lifecycle/daemon-shutdown.js.map +1 -0
  211. package/dist/lifecycle/daemon-startup.d.ts +15 -0
  212. package/dist/lifecycle/daemon-startup.d.ts.map +1 -0
  213. package/dist/lifecycle/daemon-startup.js +1527 -0
  214. package/dist/lifecycle/daemon-startup.js.map +1 -0
  215. package/dist/lifecycle/daemon.d.ts +171 -114
  216. package/dist/lifecycle/daemon.d.ts.map +1 -1
  217. package/dist/lifecycle/daemon.js +22 -1904
  218. package/dist/lifecycle/daemon.js.map +1 -1
  219. package/dist/notifications/channels/discord.d.ts.map +1 -1
  220. package/dist/notifications/channels/discord.js +1 -0
  221. package/dist/notifications/channels/discord.js.map +1 -1
  222. package/dist/notifications/channels/slack.d.ts.map +1 -1
  223. package/dist/notifications/channels/slack.js +1 -0
  224. package/dist/notifications/channels/slack.js.map +1 -1
  225. package/dist/notifications/index.d.ts +0 -1
  226. package/dist/notifications/index.d.ts.map +1 -1
  227. package/dist/notifications/index.js +0 -1
  228. package/dist/notifications/index.js.map +1 -1
  229. package/dist/notifications/notification-service.d.ts.map +1 -1
  230. package/dist/notifications/notification-service.js +8 -6
  231. package/dist/notifications/notification-service.js.map +1 -1
  232. package/dist/pipeline/database-policy-engine.d.ts +18 -438
  233. package/dist/pipeline/database-policy-engine.d.ts.map +1 -1
  234. package/dist/pipeline/database-policy-engine.js +154 -1321
  235. package/dist/pipeline/database-policy-engine.js.map +1 -1
  236. package/dist/pipeline/dry-run.d.ts +5 -2
  237. package/dist/pipeline/dry-run.d.ts.map +1 -1
  238. package/dist/pipeline/dry-run.js +102 -8
  239. package/dist/pipeline/dry-run.js.map +1 -1
  240. package/dist/pipeline/evaluators/allowed-tokens.d.ts +28 -0
  241. package/dist/pipeline/evaluators/allowed-tokens.d.ts.map +1 -0
  242. package/dist/pipeline/evaluators/allowed-tokens.js +129 -0
  243. package/dist/pipeline/evaluators/allowed-tokens.js.map +1 -0
  244. package/dist/pipeline/evaluators/approved-spenders.d.ts +26 -0
  245. package/dist/pipeline/evaluators/approved-spenders.d.ts.map +1 -0
  246. package/dist/pipeline/evaluators/approved-spenders.js +115 -0
  247. package/dist/pipeline/evaluators/approved-spenders.js.map +1 -0
  248. package/dist/pipeline/evaluators/contract-whitelist.d.ts +28 -0
  249. package/dist/pipeline/evaluators/contract-whitelist.d.ts.map +1 -0
  250. package/dist/pipeline/evaluators/contract-whitelist.js +168 -0
  251. package/dist/pipeline/evaluators/contract-whitelist.js.map +1 -0
  252. package/dist/pipeline/evaluators/helpers.d.ts +9 -0
  253. package/dist/pipeline/evaluators/helpers.d.ts.map +1 -0
  254. package/dist/pipeline/evaluators/helpers.js +13 -0
  255. package/dist/pipeline/evaluators/helpers.js.map +1 -0
  256. package/dist/pipeline/evaluators/lending-asset-whitelist.d.ts +18 -0
  257. package/dist/pipeline/evaluators/lending-asset-whitelist.d.ts.map +1 -0
  258. package/dist/pipeline/evaluators/lending-asset-whitelist.js +44 -0
  259. package/dist/pipeline/evaluators/lending-asset-whitelist.js.map +1 -0
  260. package/dist/pipeline/evaluators/lending-ltv-limit.d.ts +24 -0
  261. package/dist/pipeline/evaluators/lending-ltv-limit.d.ts.map +1 -0
  262. package/dist/pipeline/evaluators/lending-ltv-limit.js +130 -0
  263. package/dist/pipeline/evaluators/lending-ltv-limit.js.map +1 -0
  264. package/dist/pipeline/evaluators/spending-limit.d.ts +46 -0
  265. package/dist/pipeline/evaluators/spending-limit.d.ts.map +1 -0
  266. package/dist/pipeline/evaluators/spending-limit.js +241 -0
  267. package/dist/pipeline/evaluators/spending-limit.js.map +1 -0
  268. package/dist/pipeline/evaluators/types.d.ts +71 -0
  269. package/dist/pipeline/evaluators/types.d.ts.map +1 -0
  270. package/dist/pipeline/evaluators/types.js +7 -0
  271. package/dist/pipeline/evaluators/types.js.map +1 -0
  272. package/dist/pipeline/external-action-pipeline.js.map +1 -1
  273. package/dist/pipeline/gas-condition-tracker.d.ts +1 -1
  274. package/dist/pipeline/gas-condition-tracker.js +1 -1
  275. package/dist/pipeline/pipeline-helpers.d.ts +146 -0
  276. package/dist/pipeline/pipeline-helpers.d.ts.map +1 -0
  277. package/dist/pipeline/pipeline-helpers.js +260 -0
  278. package/dist/pipeline/pipeline-helpers.js.map +1 -0
  279. package/dist/pipeline/pipeline.d.ts +1 -0
  280. package/dist/pipeline/pipeline.d.ts.map +1 -1
  281. package/dist/pipeline/pipeline.js +3 -2
  282. package/dist/pipeline/pipeline.js.map +1 -1
  283. package/dist/pipeline/resolve-effective-amount-usd.d.ts.map +1 -1
  284. package/dist/pipeline/resolve-effective-amount-usd.js +4 -10
  285. package/dist/pipeline/resolve-effective-amount-usd.js.map +1 -1
  286. package/dist/pipeline/sign-message.js +1 -1
  287. package/dist/pipeline/sign-message.js.map +1 -1
  288. package/dist/pipeline/sleep.d.ts +1 -5
  289. package/dist/pipeline/sleep.d.ts.map +1 -1
  290. package/dist/pipeline/sleep.js +2 -7
  291. package/dist/pipeline/sleep.js.map +1 -1
  292. package/dist/pipeline/stage1-validate.d.ts +8 -0
  293. package/dist/pipeline/stage1-validate.d.ts.map +1 -0
  294. package/dist/pipeline/stage1-validate.js +69 -0
  295. package/dist/pipeline/stage1-validate.js.map +1 -0
  296. package/dist/pipeline/stage2-auth.d.ts +12 -0
  297. package/dist/pipeline/stage2-auth.d.ts.map +1 -0
  298. package/dist/pipeline/stage2-auth.js +18 -0
  299. package/dist/pipeline/stage2-auth.js.map +1 -0
  300. package/dist/pipeline/stage3-policy.d.ts +26 -0
  301. package/dist/pipeline/stage3-policy.d.ts.map +1 -0
  302. package/dist/pipeline/stage3-policy.js +384 -0
  303. package/dist/pipeline/stage3-policy.js.map +1 -0
  304. package/dist/pipeline/stage4-wait.d.ts +8 -0
  305. package/dist/pipeline/stage4-wait.d.ts.map +1 -0
  306. package/dist/pipeline/stage4-wait.js +87 -0
  307. package/dist/pipeline/stage4-wait.js.map +1 -0
  308. package/dist/pipeline/stage5-execute.d.ts +120 -0
  309. package/dist/pipeline/stage5-execute.d.ts.map +1 -0
  310. package/dist/pipeline/stage5-execute.js +1070 -0
  311. package/dist/pipeline/stage5-execute.js.map +1 -0
  312. package/dist/pipeline/stage6-confirm.d.ts +11 -0
  313. package/dist/pipeline/stage6-confirm.d.ts.map +1 -0
  314. package/dist/pipeline/stage6-confirm.js +110 -0
  315. package/dist/pipeline/stage6-confirm.js.map +1 -0
  316. package/dist/pipeline/stages.d.ts +11 -245
  317. package/dist/pipeline/stages.d.ts.map +1 -1
  318. package/dist/pipeline/stages.js +11 -1896
  319. package/dist/pipeline/stages.js.map +1 -1
  320. package/dist/rpc-proxy/sync-pipeline.js +2 -2
  321. package/dist/rpc-proxy/sync-pipeline.js.map +1 -1
  322. package/dist/services/autostop/autostop-service.d.ts +4 -1
  323. package/dist/services/autostop/autostop-service.d.ts.map +1 -1
  324. package/dist/services/autostop/autostop-service.js +27 -7
  325. package/dist/services/autostop/autostop-service.js.map +1 -1
  326. package/dist/services/defi/position-tracker.d.ts +5 -0
  327. package/dist/services/defi/position-tracker.d.ts.map +1 -1
  328. package/dist/services/defi/position-tracker.js +41 -6
  329. package/dist/services/defi/position-tracker.js.map +1 -1
  330. package/dist/services/defi/position-write-queue.d.ts.map +1 -1
  331. package/dist/services/defi/position-write-queue.js +3 -2
  332. package/dist/services/defi/position-write-queue.js.map +1 -1
  333. package/dist/services/incoming/__tests__/integration-wiring.test.js +58 -0
  334. package/dist/services/incoming/__tests__/integration-wiring.test.js.map +1 -1
  335. package/dist/services/incoming/incoming-tx-monitor-service.d.ts.map +1 -1
  336. package/dist/services/incoming/incoming-tx-monitor-service.js +11 -14
  337. package/dist/services/incoming/incoming-tx-monitor-service.js.map +1 -1
  338. package/dist/services/incoming/incoming-tx-workers.d.ts +2 -2
  339. package/dist/services/incoming/incoming-tx-workers.d.ts.map +1 -1
  340. package/dist/services/incoming/incoming-tx-workers.js +1 -1
  341. package/dist/services/incoming/incoming-tx-workers.js.map +1 -1
  342. package/dist/services/incoming/safety-rules.d.ts.map +1 -1
  343. package/dist/services/incoming/safety-rules.js +3 -2
  344. package/dist/services/incoming/safety-rules.js.map +1 -1
  345. package/dist/services/incoming/subscription-multiplexer.d.ts +2 -6
  346. package/dist/services/incoming/subscription-multiplexer.d.ts.map +1 -1
  347. package/dist/services/incoming/subscription-multiplexer.js +1 -3
  348. package/dist/services/incoming/subscription-multiplexer.js.map +1 -1
  349. package/dist/services/monitoring/balance-monitor-service.d.ts.map +1 -1
  350. package/dist/services/monitoring/balance-monitor-service.js +2 -2
  351. package/dist/services/monitoring/balance-monitor-service.js.map +1 -1
  352. package/dist/services/signing-sdk/approval-channel-router.d.ts +7 -7
  353. package/dist/services/signing-sdk/approval-channel-router.d.ts.map +1 -1
  354. package/dist/services/signing-sdk/approval-channel-router.js +13 -13
  355. package/dist/services/signing-sdk/approval-channel-router.js.map +1 -1
  356. package/dist/services/signing-sdk/channels/index.d.ts +2 -2
  357. package/dist/services/signing-sdk/channels/index.d.ts.map +1 -1
  358. package/dist/services/signing-sdk/channels/index.js +1 -1
  359. package/dist/services/signing-sdk/channels/index.js.map +1 -1
  360. package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts +59 -0
  361. package/dist/services/signing-sdk/channels/push-relay-signing-channel.d.ts.map +1 -0
  362. package/dist/services/signing-sdk/channels/push-relay-signing-channel.js +190 -0
  363. package/dist/services/signing-sdk/channels/push-relay-signing-channel.js.map +1 -0
  364. package/dist/services/signing-sdk/channels/telegram-signing-channel.d.ts +1 -1
  365. package/dist/services/signing-sdk/channels/telegram-signing-channel.js +1 -1
  366. package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts +6 -7
  367. package/dist/services/signing-sdk/channels/wallet-notification-channel.d.ts.map +1 -1
  368. package/dist/services/signing-sdk/channels/wallet-notification-channel.js +38 -55
  369. package/dist/services/signing-sdk/channels/wallet-notification-channel.js.map +1 -1
  370. package/dist/services/signing-sdk/index.d.ts +3 -3
  371. package/dist/services/signing-sdk/index.d.ts.map +1 -1
  372. package/dist/services/signing-sdk/index.js +2 -2
  373. package/dist/services/signing-sdk/index.js.map +1 -1
  374. package/dist/services/signing-sdk/preset-auto-setup.js +2 -2
  375. package/dist/services/signing-sdk/preset-auto-setup.js.map +1 -1
  376. package/dist/services/signing-sdk/sign-request-builder.d.ts +2 -2
  377. package/dist/services/signing-sdk/sign-request-builder.d.ts.map +1 -1
  378. package/dist/services/signing-sdk/sign-request-builder.js +17 -25
  379. package/dist/services/signing-sdk/sign-request-builder.js.map +1 -1
  380. package/dist/services/signing-sdk/wallet-app-service.d.ts +4 -0
  381. package/dist/services/signing-sdk/wallet-app-service.d.ts.map +1 -1
  382. package/dist/services/signing-sdk/wallet-app-service.js +12 -5
  383. package/dist/services/signing-sdk/wallet-app-service.js.map +1 -1
  384. package/dist/services/staking/aggregate-staking-balance.d.ts +24 -0
  385. package/dist/services/staking/aggregate-staking-balance.d.ts.map +1 -0
  386. package/dist/services/staking/aggregate-staking-balance.js +82 -0
  387. package/dist/services/staking/aggregate-staking-balance.js.map +1 -0
  388. package/dist/services/wc-session-service.d.ts.map +1 -1
  389. package/dist/services/wc-session-service.js +2 -1
  390. package/dist/services/wc-session-service.js.map +1 -1
  391. package/dist/services/wc-signing-bridge.js +2 -2
  392. package/dist/services/wc-signing-bridge.js.map +1 -1
  393. package/dist/services/x402/payment-signer.d.ts.map +1 -1
  394. package/dist/services/x402/payment-signer.js +2 -5
  395. package/dist/services/x402/payment-signer.js.map +1 -1
  396. package/dist/services/x402/ssrf-guard.d.ts +4 -23
  397. package/dist/services/x402/ssrf-guard.d.ts.map +1 -1
  398. package/dist/services/x402/ssrf-guard.js +3 -232
  399. package/dist/services/x402/ssrf-guard.js.map +1 -1
  400. package/dist/signing/capabilities/eip712-signer.d.ts.map +1 -1
  401. package/dist/signing/capabilities/eip712-signer.js +2 -0
  402. package/dist/signing/capabilities/eip712-signer.js.map +1 -1
  403. package/package.json +5 -5
  404. package/public/admin/assets/index-CpFF2lCo.js +3 -0
  405. package/public/admin/index.html +1 -1
  406. package/dist/notifications/channels/ntfy.d.ts +0 -13
  407. package/dist/notifications/channels/ntfy.d.ts.map +0 -1
  408. package/dist/notifications/channels/ntfy.js +0 -74
  409. package/dist/notifications/channels/ntfy.js.map +0 -1
  410. package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts +0 -66
  411. package/dist/services/signing-sdk/channels/ntfy-signing-channel.d.ts.map +0 -1
  412. package/dist/services/signing-sdk/channels/ntfy-signing-channel.js +0 -270
  413. package/dist/services/signing-sdk/channels/ntfy-signing-channel.js.map +0 -1
  414. package/public/admin/assets/index-CQ3i4P2U.js +0 -3
@@ -0,0 +1,1070 @@
1
+ /**
2
+ * Stage 5: On-chain execution (build -> simulate -> sign -> submit).
3
+ *
4
+ * Contains:
5
+ * - buildByType: route to correct adapter method based on request.type
6
+ * - ERC721/ERC1155 UserOp ABI constants
7
+ * - buildUserOpCalls: convert request to viem calls[] for UserOperation
8
+ * - stage5ExecuteSmartAccount: smart account UserOperation pipeline
9
+ * - stage5Execute: main EOA execution with CONC-01 retry logic
10
+ *
11
+ * @see docs/32-pipeline-design.md
12
+ */
13
+ import { eq } from 'drizzle-orm';
14
+ import { WAIaaSError, ChainError, } from '@waiaas/core';
15
+ import { wallets, transactions } from '../infrastructure/database/schema.js';
16
+ import { insertAuditLog } from '../infrastructure/database/audit-helper.js';
17
+ import { GAS_SAFETY_NUMERATOR, GAS_SAFETY_DENOMINATOR } from '../constants.js';
18
+ import { sleep } from './sleep.js';
19
+ // v30.6: ERC-4337 smart account imports
20
+ import { privateKeyToAccount } from 'viem/accounts';
21
+ import { createPublicClient, http, encodeFunctionData, toHex } from 'viem';
22
+ import { SmartAccountService, SOLADY_FACTORY_ADDRESS } from '../infrastructure/smart-account/smart-account-service.js';
23
+ import { createSmartAccountBundlerClient } from '../infrastructure/smart-account/smart-account-clients.js';
24
+ import { decryptProviderApiKey } from '../infrastructure/smart-account/aa-provider-crypto.js';
25
+ import { getRequestAmount, getRequestTo, getRequestMemo, resolveNotificationTo, formatNotificationAmount, resolveDisplayAmount, } from './pipeline-helpers.js';
26
+ // ---------------------------------------------------------------------------
27
+ // Helper: buildByType -- route to correct adapter method based on request.type
28
+ // ---------------------------------------------------------------------------
29
+ /**
30
+ * Build unsigned transaction by dispatching to the correct IChainAdapter method
31
+ * based on request.type (TRANSFER/TOKEN_TRANSFER/CONTRACT_CALL/APPROVE/BATCH).
32
+ */
33
+ export async function buildByType(adapter, request, walletPublicKey) {
34
+ const type = ('type' in request && request.type) || 'TRANSFER';
35
+ switch (type) {
36
+ case 'TRANSFER': {
37
+ return adapter.buildTransaction({
38
+ from: walletPublicKey,
39
+ to: getRequestTo(request),
40
+ amount: BigInt(getRequestAmount(request)),
41
+ memo: getRequestMemo(request),
42
+ });
43
+ }
44
+ case 'TOKEN_TRANSFER': {
45
+ const req = request;
46
+ return adapter.buildTokenTransfer({
47
+ from: walletPublicKey,
48
+ to: req.to,
49
+ amount: BigInt(req.amount),
50
+ token: req.token,
51
+ memo: req.memo,
52
+ });
53
+ }
54
+ case 'CONTRACT_CALL': {
55
+ const req = request;
56
+ return adapter.buildContractCall({
57
+ from: walletPublicKey,
58
+ to: req.to,
59
+ calldata: req.calldata,
60
+ abi: req.abi,
61
+ value: req.value ? BigInt(req.value) : undefined,
62
+ programId: req.programId,
63
+ instructionData: req.instructionData
64
+ ? Buffer.from(req.instructionData, 'base64')
65
+ : undefined,
66
+ accounts: req.accounts,
67
+ // Pass through preInstructions for Solana (e.g., ATA creation for Jito staking)
68
+ preInstructions: req.preInstructions?.map((pre) => ({
69
+ programId: pre.programId,
70
+ data: Buffer.from(pre.data, 'base64'),
71
+ accounts: pre.accounts,
72
+ })),
73
+ });
74
+ }
75
+ case 'APPROVE': {
76
+ const req = request;
77
+ // v31.0: NFT approval routing
78
+ if (req.nft) {
79
+ const approvalType = req.amount === '0' ? 'single' : 'all';
80
+ return adapter.approveNft({
81
+ from: walletPublicKey,
82
+ spender: req.spender,
83
+ token: {
84
+ address: req.token.address,
85
+ tokenId: req.nft.tokenId,
86
+ standard: req.nft.standard,
87
+ },
88
+ approvalType,
89
+ });
90
+ }
91
+ return adapter.buildApprove({
92
+ from: walletPublicKey,
93
+ spender: req.spender,
94
+ token: req.token,
95
+ amount: BigInt(req.amount),
96
+ });
97
+ }
98
+ case 'NFT_TRANSFER': {
99
+ const req = request;
100
+ return adapter.buildNftTransferTx({
101
+ from: walletPublicKey,
102
+ to: req.to,
103
+ token: {
104
+ address: req.token.address,
105
+ tokenId: req.token.tokenId,
106
+ standard: req.token.standard,
107
+ },
108
+ amount: BigInt(req.amount ?? '1'),
109
+ });
110
+ }
111
+ case 'CONTRACT_DEPLOY': {
112
+ const req = request;
113
+ // Contract deployment: to=undefined, data=bytecode(+constructorArgs)
114
+ const deployData = req.constructorArgs
115
+ ? req.bytecode + req.constructorArgs.replace(/^0x/, '')
116
+ : req.bytecode;
117
+ return adapter.buildContractCall({
118
+ from: walletPublicKey,
119
+ to: '', // adapter handles to='' as to=undefined for deploy
120
+ calldata: deployData,
121
+ value: req.value ? BigInt(req.value) : undefined,
122
+ });
123
+ }
124
+ case 'BATCH': {
125
+ const req = request;
126
+ return adapter.buildBatch({
127
+ from: walletPublicKey,
128
+ instructions: req.instructions.map((instr) => {
129
+ // Classify by field presence (same logic as classifyInstruction in Phase 80)
130
+ if ('spender' in instr) {
131
+ const a = instr;
132
+ return {
133
+ from: walletPublicKey,
134
+ spender: a.spender,
135
+ token: a.token,
136
+ amount: BigInt(a.amount),
137
+ };
138
+ }
139
+ if ('token' in instr) {
140
+ const t = instr;
141
+ return {
142
+ from: walletPublicKey,
143
+ to: t.to,
144
+ amount: BigInt(t.amount),
145
+ token: t.token,
146
+ memo: t.memo,
147
+ };
148
+ }
149
+ if ('programId' in instr || 'calldata' in instr) {
150
+ const c = instr;
151
+ return {
152
+ from: walletPublicKey,
153
+ to: c.to,
154
+ calldata: c.calldata,
155
+ programId: c.programId,
156
+ instructionData: c.instructionData
157
+ ? Buffer.from(c.instructionData, 'base64')
158
+ : undefined,
159
+ accounts: c.accounts,
160
+ value: c.value ? BigInt(c.value) : undefined,
161
+ };
162
+ }
163
+ // Default: TRANSFER instruction
164
+ const tr = instr;
165
+ return {
166
+ from: walletPublicKey,
167
+ to: tr.to,
168
+ amount: BigInt(tr.amount),
169
+ memo: tr.memo,
170
+ };
171
+ }),
172
+ });
173
+ }
174
+ default:
175
+ throw new WAIaaSError('CHAIN_ERROR', {
176
+ message: `Unknown transaction type: ${type}`,
177
+ });
178
+ }
179
+ }
180
+ // ---------------------------------------------------------------------------
181
+ // Stage 5: Smart account ERC-4337 UserOperation helpers
182
+ // ---------------------------------------------------------------------------
183
+ /**
184
+ * Minimal ERC-20 ABI for transfer/approve encoding in UserOperation calls.
185
+ * Inline to avoid cross-package import from @waiaas/adapters-evm.
186
+ */
187
+ const ERC20_USEROP_ABI = [
188
+ { type: 'function', name: 'transfer', inputs: [{ name: 'to', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
189
+ { type: 'function', name: 'approve', inputs: [{ name: 'spender', type: 'address' }, { name: 'amount', type: 'uint256' }], outputs: [{ type: 'bool' }] },
190
+ ];
191
+ /** ERC-721 ABI for NFT UserOp calls (safeTransferFrom, approve, setApprovalForAll). */
192
+ export const ERC721_USEROP_ABI = [
193
+ { type: 'function', name: 'safeTransferFrom', inputs: [
194
+ { name: 'from', type: 'address' }, { name: 'to', type: 'address' }, { name: 'tokenId', type: 'uint256' },
195
+ ], outputs: [] },
196
+ { type: 'function', name: 'approve', inputs: [
197
+ { name: 'to', type: 'address' }, { name: 'tokenId', type: 'uint256' },
198
+ ], outputs: [] },
199
+ { type: 'function', name: 'setApprovalForAll', inputs: [
200
+ { name: 'operator', type: 'address' }, { name: 'approved', type: 'bool' },
201
+ ], outputs: [] },
202
+ ];
203
+ /** ERC-1155 ABI for NFT UserOp calls (safeTransferFrom, setApprovalForAll). */
204
+ export const ERC1155_USEROP_ABI = [
205
+ { type: 'function', name: 'safeTransferFrom', inputs: [
206
+ { name: 'from', type: 'address' }, { name: 'to', type: 'address' },
207
+ { name: 'id', type: 'uint256' }, { name: 'amount', type: 'uint256' }, { name: 'data', type: 'bytes' },
208
+ ], outputs: [] },
209
+ { type: 'function', name: 'setApprovalForAll', inputs: [
210
+ { name: 'operator', type: 'address' }, { name: 'approved', type: 'bool' },
211
+ ], outputs: [] },
212
+ ];
213
+ /**
214
+ * Convert a TransactionRequest to viem's calls[] format for UserOperation submission.
215
+ * Each call is { to, value, data } for the smart account to execute.
216
+ *
217
+ * @param walletAddress - Smart account address (required for NFT_TRANSFER safeTransferFrom 'from' param)
218
+ */
219
+ export function buildUserOpCalls(request, walletAddress) {
220
+ const type = ('type' in request && request.type) || 'TRANSFER';
221
+ switch (type) {
222
+ case 'TRANSFER': {
223
+ return [{
224
+ to: getRequestTo(request),
225
+ value: BigInt(getRequestAmount(request)),
226
+ data: '0x',
227
+ }];
228
+ }
229
+ case 'TOKEN_TRANSFER': {
230
+ const req = request;
231
+ return [{
232
+ to: req.token.address,
233
+ value: 0n,
234
+ data: encodeFunctionData({
235
+ abi: ERC20_USEROP_ABI,
236
+ functionName: 'transfer',
237
+ args: [req.to, BigInt(req.amount)],
238
+ }),
239
+ }];
240
+ }
241
+ case 'CONTRACT_CALL': {
242
+ const req = request;
243
+ return [{
244
+ to: req.to,
245
+ value: BigInt(req.value ?? '0'),
246
+ data: (req.calldata || '0x'),
247
+ }];
248
+ }
249
+ case 'APPROVE': {
250
+ const req = request;
251
+ // v31.0: NFT approval routing for Smart Account
252
+ if (req.nft) {
253
+ const approvalType = req.amount === '0' ? 'single' : 'all';
254
+ if (req.nft.standard === 'METAPLEX') {
255
+ throw new WAIaaSError('CHAIN_ERROR', {
256
+ message: 'Smart Account (ERC-4337) does not support Solana METAPLEX NFT approvals',
257
+ });
258
+ }
259
+ if (approvalType === 'single' && req.nft.standard === 'ERC-721') {
260
+ return [{
261
+ to: req.token.address,
262
+ value: 0n,
263
+ data: encodeFunctionData({
264
+ abi: ERC721_USEROP_ABI,
265
+ functionName: 'approve',
266
+ args: [req.spender, BigInt(req.nft.tokenId)],
267
+ }),
268
+ }];
269
+ }
270
+ // setApprovalForAll (ERC-721 all / ERC-1155 all)
271
+ const nftAbi = req.nft.standard === 'ERC-721' ? ERC721_USEROP_ABI : ERC1155_USEROP_ABI;
272
+ return [{
273
+ to: req.token.address,
274
+ value: 0n,
275
+ data: encodeFunctionData({
276
+ abi: nftAbi,
277
+ functionName: 'setApprovalForAll',
278
+ args: [req.spender, true],
279
+ }),
280
+ }];
281
+ }
282
+ return [{
283
+ to: req.token.address,
284
+ value: 0n,
285
+ data: encodeFunctionData({
286
+ abi: ERC20_USEROP_ABI,
287
+ functionName: 'approve',
288
+ args: [req.spender, BigInt(req.amount)],
289
+ }),
290
+ }];
291
+ }
292
+ case 'BATCH': {
293
+ const req = request;
294
+ return req.instructions.map((instr) => {
295
+ if ('spender' in instr) {
296
+ // APPROVE instruction
297
+ const a = instr;
298
+ return {
299
+ to: a.token.address,
300
+ value: 0n,
301
+ data: encodeFunctionData({
302
+ abi: ERC20_USEROP_ABI,
303
+ functionName: 'approve',
304
+ args: [a.spender, BigInt(a.amount)],
305
+ }),
306
+ };
307
+ }
308
+ if ('token' in instr) {
309
+ // TOKEN_TRANSFER instruction
310
+ const t = instr;
311
+ return {
312
+ to: t.token.address,
313
+ value: 0n,
314
+ data: encodeFunctionData({
315
+ abi: ERC20_USEROP_ABI,
316
+ functionName: 'transfer',
317
+ args: [t.to, BigInt(t.amount)],
318
+ }),
319
+ };
320
+ }
321
+ if ('calldata' in instr) {
322
+ // CONTRACT_CALL instruction (also used by ActionProvider resolve() output)
323
+ const c = instr;
324
+ return {
325
+ to: c.to,
326
+ value: BigInt(c.value ?? '0'),
327
+ data: (c.calldata || '0x'),
328
+ };
329
+ }
330
+ // TRANSFER instruction (native transfer)
331
+ const t = instr;
332
+ return {
333
+ to: t.to,
334
+ value: BigInt(t.amount),
335
+ data: '0x',
336
+ };
337
+ });
338
+ }
339
+ case 'NFT_TRANSFER': {
340
+ const req = request;
341
+ if (req.token.standard === 'METAPLEX') {
342
+ throw new WAIaaSError('CHAIN_ERROR', {
343
+ message: 'Smart Account (ERC-4337) does not support Solana METAPLEX NFT transfers',
344
+ });
345
+ }
346
+ const from = (walletAddress ?? '0x0000000000000000000000000000000000000000');
347
+ if (req.token.standard === 'ERC-721') {
348
+ return [{
349
+ to: req.token.address,
350
+ value: 0n,
351
+ data: encodeFunctionData({
352
+ abi: ERC721_USEROP_ABI,
353
+ functionName: 'safeTransferFrom',
354
+ args: [from, req.to, BigInt(req.token.tokenId)],
355
+ }),
356
+ }];
357
+ }
358
+ // ERC-1155
359
+ return [{
360
+ to: req.token.address,
361
+ value: 0n,
362
+ data: encodeFunctionData({
363
+ abi: ERC1155_USEROP_ABI,
364
+ functionName: 'safeTransferFrom',
365
+ args: [from, req.to, BigInt(req.token.tokenId), BigInt(req.amount ?? '1'), '0x'],
366
+ }),
367
+ }];
368
+ }
369
+ case 'CONTRACT_DEPLOY': {
370
+ const req = request;
371
+ const deployData = req.constructorArgs
372
+ ? req.bytecode + req.constructorArgs.replace(/^0x/, '')
373
+ : req.bytecode;
374
+ // Smart account contract deployment via CREATE2-like pattern
375
+ // to is empty (factory handles deployment), data is full bytecode+args
376
+ return [{
377
+ to: '0x', // will be interpreted as factory/self call
378
+ value: BigInt(req.value ?? '0'),
379
+ data: deployData,
380
+ }];
381
+ }
382
+ default:
383
+ throw new WAIaaSError('CHAIN_ERROR', {
384
+ message: `Unknown transaction type for UserOp: ${type}`,
385
+ });
386
+ }
387
+ }
388
+ /**
389
+ * Stage 5 smart account path: execute via UserOperation through BundlerClient.
390
+ *
391
+ * Flow:
392
+ * 1. Decrypt signer key -> create LocalAccount via viem's privateKeyToAccount
393
+ * 2. Create SmartAccount instance via SmartAccountService
394
+ * 3. Create BundlerClient via createSmartAccountBundlerClient
395
+ * 4. Build calls[] from request via buildUserOpCalls
396
+ * 5. prepareUserOperation -> apply 120% gas safety margin
397
+ * 6. sendUserOperation -> waitForUserOperationReceipt
398
+ * 7. Update DB: SUBMITTED -> CONFIRMED, update deployed status if needed
399
+ *
400
+ * Error mapping:
401
+ * - Paymaster rejection (message contains 'paymaster'/'PM_') -> PAYMASTER_REJECTED
402
+ * - UserOperationReverted -> TRANSACTION_REVERTED
403
+ * - Receipt timeout -> TRANSACTION_TIMEOUT
404
+ * - Other -> CHAIN_ERROR
405
+ */
406
+ async function stage5ExecuteSmartAccount(ctx) {
407
+ // Check for deprecated Solady factory before proceeding
408
+ if (ctx.wallet.factoryAddress?.toLowerCase() === SOLADY_FACTORY_ADDRESS.toLowerCase()) {
409
+ throw new WAIaaSError('DEPRECATED_SMART_ACCOUNT');
410
+ }
411
+ const reqAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
412
+ const displayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
413
+ // Build calls[] from request (pass wallet address for NFT safeTransferFrom 'from' param)
414
+ const calls = buildUserOpCalls(ctx.request, ctx.wallet.publicKey);
415
+ // CRITICAL: key MUST be released in finally block
416
+ let privateKey = null;
417
+ try {
418
+ // Step 1: Decrypt signer key
419
+ privateKey = await ctx.keyStore.decryptPrivateKey(ctx.walletId, ctx.masterPassword);
420
+ const hexKey = toHex(privateKey);
421
+ const localAccount = privateKeyToAccount(hexKey);
422
+ // Step 2: Create SmartAccount via SmartAccountService
423
+ const smartAccountService = new SmartAccountService();
424
+ // #251: Resolve viem Chain from EVM_CHAIN_MAP using network ID
425
+ const { EVM_CHAIN_MAP } = await import('@waiaas/adapter-evm');
426
+ const chainEntry = EVM_CHAIN_MAP[ctx.resolvedNetwork];
427
+ const publicClient = createPublicClient({
428
+ chain: chainEntry?.viemChain,
429
+ transport: http(ctx.resolvedRpcUrl),
430
+ });
431
+ const smartAccountInfo = await smartAccountService.createSmartAccount({
432
+ owner: localAccount,
433
+ client: publicClient,
434
+ });
435
+ // Step 3: Create BundlerClient from wallet's provider data (v30.9)
436
+ const decryptedApiKey = ctx.wallet.aaProviderApiKeyEncrypted
437
+ ? decryptProviderApiKey(ctx.wallet.aaProviderApiKeyEncrypted, ctx.masterPassword)
438
+ : null;
439
+ const walletProvider = {
440
+ aaProvider: ctx.wallet.aaProvider ?? null,
441
+ aaProviderApiKey: decryptedApiKey,
442
+ aaBundlerUrl: ctx.wallet.aaBundlerUrl ?? null,
443
+ aaPaymasterUrl: ctx.wallet.aaPaymasterUrl ?? null,
444
+ aaPaymasterPolicyId: ctx.wallet.aaPaymasterPolicyId ?? null,
445
+ };
446
+ const bundlerClient = createSmartAccountBundlerClient({
447
+ client: publicClient,
448
+ account: smartAccountInfo.account,
449
+ networkId: ctx.resolvedNetwork,
450
+ walletProvider,
451
+ settingsService: ctx.settingsService,
452
+ });
453
+ // Step 4: Prepare UserOperation to get gas estimates
454
+ const prepared = await bundlerClient.prepareUserOperation({ calls });
455
+ // Step 5: Apply 120% gas safety margin per CLAUDE.md rule
456
+ const safeCallGasLimit = (BigInt(prepared.callGasLimit) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
457
+ const safeVerificationGasLimit = (BigInt(prepared.verificationGasLimit) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
458
+ const safePreVerificationGas = (BigInt(prepared.preVerificationGas) * GAS_SAFETY_NUMERATOR) / GAS_SAFETY_DENOMINATOR;
459
+ // Step 6: Submit UserOperation with overridden gas limits
460
+ ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
461
+ const userOpHash = await bundlerClient.sendUserOperation({
462
+ calls,
463
+ userOperation: {
464
+ callGasLimit: safeCallGasLimit,
465
+ verificationGasLimit: safeVerificationGasLimit,
466
+ preVerificationGas: safePreVerificationGas,
467
+ },
468
+ });
469
+ ctx.metricsCounter?.increment('tx.submitted', { network: ctx.resolvedNetwork });
470
+ // Update DB: SUBMITTED with userOpHash
471
+ await ctx.db
472
+ .update(transactions)
473
+ .set({ status: 'SUBMITTED', txHash: userOpHash })
474
+ .where(eq(transactions.id, ctx.txId));
475
+ // Audit log: TX_SUBMITTED
476
+ if (ctx.sqlite) {
477
+ insertAuditLog(ctx.sqlite, {
478
+ eventType: 'TX_SUBMITTED',
479
+ actor: ctx.sessionId ?? 'system',
480
+ walletId: ctx.walletId,
481
+ txId: ctx.txId,
482
+ details: {
483
+ txHash: userOpHash,
484
+ chain: ctx.wallet.chain,
485
+ network: ctx.resolvedNetwork,
486
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
487
+ accountType: 'smart',
488
+ },
489
+ severity: 'info',
490
+ });
491
+ }
492
+ // Notify TX_SUBMITTED
493
+ void ctx.notificationService?.notify('TX_SUBMITTED', ctx.walletId, {
494
+ txId: ctx.txId,
495
+ txHash: userOpHash,
496
+ amount: reqAmount,
497
+ to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
498
+ display_amount: displayAmount,
499
+ network: ctx.resolvedNetwork,
500
+ }, { txId: ctx.txId });
501
+ // Emit wallet:activity
502
+ ctx.eventBus?.emit('wallet:activity', {
503
+ walletId: ctx.walletId,
504
+ activity: 'TX_SUBMITTED',
505
+ details: { txId: ctx.txId, txHash: userOpHash },
506
+ timestamp: Math.floor(Date.now() / 1000),
507
+ });
508
+ // Step 7: Wait for UserOperation receipt (120s timeout)
509
+ const receipt = await bundlerClient.waitForUserOperationReceipt({
510
+ hash: userOpHash,
511
+ timeout: 120_000,
512
+ });
513
+ const txHash = receipt?.receipt?.transactionHash ?? userOpHash;
514
+ // Update DB: CONFIRMED with actual txHash
515
+ await ctx.db
516
+ .update(transactions)
517
+ .set({ status: 'CONFIRMED', txHash })
518
+ .where(eq(transactions.id, ctx.txId));
519
+ // Update deployed status if this was first UserOp (lazy deployment)
520
+ const walletRow = ctx.db.select().from(wallets).where(eq(wallets.id, ctx.walletId)).get();
521
+ if (walletRow && !walletRow.deployed) {
522
+ ctx.db.update(wallets).set({ deployed: true }).where(eq(wallets.id, ctx.walletId)).run();
523
+ }
524
+ ctx.metricsCounter?.increment('tx.confirmed', { network: ctx.resolvedNetwork });
525
+ // Store submitResult for Stage 6
526
+ ctx.submitResult = { txHash, status: 'confirmed' };
527
+ // Audit log: TX_CONFIRMED
528
+ if (ctx.sqlite) {
529
+ insertAuditLog(ctx.sqlite, {
530
+ eventType: 'TX_CONFIRMED',
531
+ actor: ctx.sessionId ?? 'system',
532
+ walletId: ctx.walletId,
533
+ txId: ctx.txId,
534
+ details: {
535
+ txHash,
536
+ chain: ctx.wallet.chain,
537
+ network: ctx.resolvedNetwork,
538
+ accountType: 'smart',
539
+ },
540
+ severity: 'info',
541
+ });
542
+ }
543
+ // Notify TX_CONFIRMED
544
+ void ctx.notificationService?.notify('TX_CONFIRMED', ctx.walletId, {
545
+ txId: ctx.txId,
546
+ txHash,
547
+ amount: reqAmount,
548
+ to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
549
+ display_amount: displayAmount,
550
+ network: ctx.resolvedNetwork,
551
+ }, { txId: ctx.txId });
552
+ // Emit transaction:completed event
553
+ ctx.eventBus?.emit('transaction:completed', {
554
+ walletId: ctx.walletId,
555
+ txId: ctx.txId,
556
+ txHash,
557
+ network: ctx.resolvedNetwork,
558
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
559
+ timestamp: Math.floor(Date.now() / 1000),
560
+ });
561
+ }
562
+ catch (err) {
563
+ const errMsg = err instanceof Error ? err.message : String(err);
564
+ const errName = err instanceof Error ? err.name : '';
565
+ // Already a WAIaaSError? (e.g., CHAIN_ERROR from bundler URL not configured)
566
+ if (err instanceof WAIaaSError) {
567
+ // Update DB to FAILED
568
+ await ctx.db
569
+ .update(transactions)
570
+ .set({ status: 'FAILED', error: errMsg })
571
+ .where(eq(transactions.id, ctx.txId));
572
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
573
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
574
+ txId: ctx.txId,
575
+ error: errMsg,
576
+ amount: reqAmount,
577
+ display_amount: displayAmount,
578
+ network: ctx.resolvedNetwork,
579
+ }, { txId: ctx.txId });
580
+ ctx.eventBus?.emit('transaction:failed', {
581
+ walletId: ctx.walletId,
582
+ txId: ctx.txId,
583
+ error: errMsg,
584
+ network: ctx.resolvedNetwork,
585
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
586
+ timestamp: Math.floor(Date.now() / 1000),
587
+ });
588
+ throw err;
589
+ }
590
+ // Paymaster rejection detection
591
+ if (errMsg.toLowerCase().includes('paymaster') ||
592
+ errMsg.includes('PM_') ||
593
+ errName.includes('Paymaster')) {
594
+ await ctx.db
595
+ .update(transactions)
596
+ .set({ status: 'FAILED', error: `Paymaster rejected: ${errMsg}` })
597
+ .where(eq(transactions.id, ctx.txId));
598
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
599
+ if (ctx.sqlite) {
600
+ insertAuditLog(ctx.sqlite, {
601
+ eventType: 'TX_FAILED',
602
+ actor: ctx.sessionId ?? 'system',
603
+ walletId: ctx.walletId,
604
+ txId: ctx.txId,
605
+ details: { error: errMsg, stage: 5, reason: 'paymaster_rejected' },
606
+ severity: 'warning',
607
+ });
608
+ }
609
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
610
+ txId: ctx.txId,
611
+ error: `Paymaster rejected: ${errMsg}`,
612
+ amount: reqAmount,
613
+ display_amount: displayAmount,
614
+ network: ctx.resolvedNetwork,
615
+ }, { txId: ctx.txId });
616
+ ctx.eventBus?.emit('transaction:failed', {
617
+ walletId: ctx.walletId,
618
+ txId: ctx.txId,
619
+ error: `Paymaster rejected: ${errMsg}`,
620
+ network: ctx.resolvedNetwork,
621
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
622
+ timestamp: Math.floor(Date.now() / 1000),
623
+ });
624
+ throw new WAIaaSError('PAYMASTER_REJECTED', {
625
+ message: `Paymaster rejected the UserOperation: ${errMsg}`,
626
+ });
627
+ }
628
+ // UserOperationReverted
629
+ if (errName === 'UserOperationReverted' || errMsg.includes('UserOperation reverted')) {
630
+ await ctx.db
631
+ .update(transactions)
632
+ .set({ status: 'FAILED', error: errMsg })
633
+ .where(eq(transactions.id, ctx.txId));
634
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
635
+ if (ctx.sqlite) {
636
+ insertAuditLog(ctx.sqlite, {
637
+ eventType: 'TX_FAILED',
638
+ actor: ctx.sessionId ?? 'system',
639
+ walletId: ctx.walletId,
640
+ txId: ctx.txId,
641
+ details: { error: errMsg, stage: 5, reason: 'user_op_reverted' },
642
+ severity: 'warning',
643
+ });
644
+ }
645
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
646
+ txId: ctx.txId,
647
+ error: errMsg,
648
+ amount: reqAmount,
649
+ display_amount: displayAmount,
650
+ network: ctx.resolvedNetwork,
651
+ }, { txId: ctx.txId });
652
+ ctx.eventBus?.emit('transaction:failed', {
653
+ walletId: ctx.walletId,
654
+ txId: ctx.txId,
655
+ error: errMsg,
656
+ network: ctx.resolvedNetwork,
657
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
658
+ timestamp: Math.floor(Date.now() / 1000),
659
+ });
660
+ throw new WAIaaSError('TRANSACTION_REVERTED', {
661
+ message: errMsg,
662
+ });
663
+ }
664
+ // Receipt timeout
665
+ if (errName === 'WaitForUserOperationReceiptTimeoutError' || errMsg.includes('timed out')) {
666
+ await ctx.db
667
+ .update(transactions)
668
+ .set({ status: 'FAILED', error: `UserOp receipt timeout: ${errMsg}` })
669
+ .where(eq(transactions.id, ctx.txId));
670
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
671
+ if (ctx.sqlite) {
672
+ insertAuditLog(ctx.sqlite, {
673
+ eventType: 'TX_FAILED',
674
+ actor: ctx.sessionId ?? 'system',
675
+ walletId: ctx.walletId,
676
+ txId: ctx.txId,
677
+ details: { error: errMsg, stage: 5, reason: 'user_op_timeout' },
678
+ severity: 'warning',
679
+ });
680
+ }
681
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
682
+ txId: ctx.txId,
683
+ error: `Receipt timeout: ${errMsg}`,
684
+ amount: reqAmount,
685
+ display_amount: displayAmount,
686
+ network: ctx.resolvedNetwork,
687
+ }, { txId: ctx.txId });
688
+ ctx.eventBus?.emit('transaction:failed', {
689
+ walletId: ctx.walletId,
690
+ txId: ctx.txId,
691
+ error: `Receipt timeout: ${errMsg}`,
692
+ network: ctx.resolvedNetwork,
693
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
694
+ timestamp: Math.floor(Date.now() / 1000),
695
+ });
696
+ throw new WAIaaSError('TRANSACTION_TIMEOUT', {
697
+ message: `UserOperation receipt timed out: ${errMsg}`,
698
+ });
699
+ }
700
+ // Generic fallback
701
+ await ctx.db
702
+ .update(transactions)
703
+ .set({ status: 'FAILED', error: errMsg })
704
+ .where(eq(transactions.id, ctx.txId));
705
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
706
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
707
+ txId: ctx.txId,
708
+ error: errMsg,
709
+ amount: reqAmount,
710
+ display_amount: displayAmount,
711
+ network: ctx.resolvedNetwork,
712
+ }, { txId: ctx.txId });
713
+ ctx.eventBus?.emit('transaction:failed', {
714
+ walletId: ctx.walletId,
715
+ txId: ctx.txId,
716
+ error: errMsg,
717
+ network: ctx.resolvedNetwork,
718
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
719
+ timestamp: Math.floor(Date.now() / 1000),
720
+ });
721
+ throw new WAIaaSError('CHAIN_ERROR', { message: errMsg });
722
+ }
723
+ finally {
724
+ if (privateKey) {
725
+ ctx.keyStore.releaseKey(privateKey);
726
+ }
727
+ }
728
+ }
729
+ // ---------------------------------------------------------------------------
730
+ // Stage 5: On-chain execution (CONC-01 retry loop)
731
+ // ---------------------------------------------------------------------------
732
+ /**
733
+ * Stage 5: Build -> Simulate -> Sign -> Submit with CONC-01 retry logic.
734
+ *
735
+ * For smart accounts (accountType === 'smart'), delegates to stage5ExecuteSmartAccount
736
+ * which uses the UserOperation pipeline (BundlerClient + PaymasterClient).
737
+ *
738
+ * For EOA accounts, uses the existing buildByType -> simulate -> sign -> submit path.
739
+ *
740
+ * ChainError category-based retry:
741
+ * - PERMANENT: immediate FAILED, no retry
742
+ * - TRANSIENT: exponential backoff (1s, 2s, 4s), max 3 retries (retryCount >= 3 guard)
743
+ * - STALE: rebuild from Stage 5a, max 1 (retryCount >= 1 guard)
744
+ *
745
+ * retryCount is shared between TRANSIENT and STALE to limit total retry count.
746
+ * Total attempts: initial 1 + up to 3 retries = 4 max.
747
+ */
748
+ export async function stage5Execute(ctx) {
749
+ // Smart account UserOperation path
750
+ if (ctx.wallet.accountType === 'smart') {
751
+ await stage5ExecuteSmartAccount(ctx);
752
+ return;
753
+ }
754
+ // v31.4: ApiDirectResult path -- skip on-chain execution entirely (HDESIGN-01)
755
+ if (ctx.actionResult) {
756
+ const result = ctx.actionResult;
757
+ // Update transaction status to CONFIRMED with API direct result metadata
758
+ await ctx.db
759
+ .update(transactions)
760
+ .set({
761
+ status: 'CONFIRMED',
762
+ metadata: JSON.stringify({
763
+ apiDirect: true,
764
+ provider: result.provider,
765
+ action: result.action,
766
+ externalId: result.externalId,
767
+ resultStatus: result.status,
768
+ data: result.data,
769
+ ...(result.metadata ?? {}),
770
+ }),
771
+ })
772
+ .where(eq(transactions.id, ctx.txId));
773
+ // Audit log: TX_CONFIRMED (API direct)
774
+ if (ctx.sqlite) {
775
+ insertAuditLog(ctx.sqlite, {
776
+ eventType: 'TX_CONFIRMED',
777
+ actor: ctx.sessionId ?? 'system',
778
+ walletId: ctx.walletId,
779
+ txId: ctx.txId,
780
+ details: {
781
+ provider: result.provider,
782
+ action: result.action,
783
+ externalId: result.externalId,
784
+ apiDirect: true,
785
+ chain: ctx.wallet.chain,
786
+ network: ctx.resolvedNetwork,
787
+ },
788
+ severity: 'info',
789
+ });
790
+ }
791
+ // Fire-and-forget: notify TX_CONFIRMED
792
+ const apiDirectAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
793
+ const apiDirectDisplayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
794
+ void ctx.notificationService?.notify('TX_CONFIRMED', ctx.walletId, {
795
+ txId: ctx.txId,
796
+ provider: result.provider,
797
+ action: result.action,
798
+ externalId: result.externalId,
799
+ network: ctx.resolvedNetwork,
800
+ amount: apiDirectAmount,
801
+ to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
802
+ display_amount: apiDirectDisplayAmount,
803
+ }, { txId: ctx.txId });
804
+ // Emit transaction:completed event (txHash = externalId for API direct)
805
+ ctx.eventBus?.emit('transaction:completed', {
806
+ walletId: ctx.walletId,
807
+ txId: ctx.txId,
808
+ txHash: result.externalId,
809
+ network: ctx.resolvedNetwork,
810
+ type: 'CONTRACT_CALL',
811
+ timestamp: Math.floor(Date.now() / 1000),
812
+ });
813
+ // Increment metrics
814
+ ctx.metricsCounter?.increment('tx.completed', { network: ctx.resolvedNetwork });
815
+ return; // Skip on-chain execution
816
+ }
817
+ // --- EOA execution path (unchanged) ---
818
+ const reqAmount = formatNotificationAmount(ctx.request, ctx.wallet.chain);
819
+ // [Phase 139] Resolve display amount once for all Stage 5 notifications
820
+ const displayAmount = await resolveDisplayAmount(ctx.amountUsd ?? null, ctx.settingsService, ctx.forexRateService);
821
+ let retryCount = 0;
822
+ // Outer buildLoop: STALE errors return here to rebuild from Stage 5a
823
+ buildLoop: while (true) {
824
+ try {
825
+ // Stage 5a: Build unsigned transaction (type-routed)
826
+ ctx.unsignedTx = await buildByType(ctx.adapter, ctx.request, ctx.wallet.publicKey);
827
+ // Stage 5b: Simulate (with RPC metrics)
828
+ const simStart = Date.now();
829
+ ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
830
+ const simResult = await ctx.adapter.simulateTransaction(ctx.unsignedTx);
831
+ ctx.metricsCounter?.recordLatency('rpc.latency', Date.now() - simStart, { network: ctx.resolvedNetwork });
832
+ if (!simResult.success) {
833
+ ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
834
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
835
+ await ctx.db
836
+ .update(transactions)
837
+ .set({ status: 'FAILED', error: simResult.error ?? 'Simulation failed' })
838
+ .where(eq(transactions.id, ctx.txId));
839
+ // Audit log: TX_FAILED (simulation failure)
840
+ if (ctx.sqlite) {
841
+ insertAuditLog(ctx.sqlite, {
842
+ eventType: 'TX_FAILED',
843
+ actor: ctx.sessionId ?? 'system',
844
+ walletId: ctx.walletId,
845
+ txId: ctx.txId,
846
+ details: { error: simResult.error ?? 'Simulation failed', stage: 5, chain: ctx.wallet.chain, network: ctx.resolvedNetwork },
847
+ severity: 'warning',
848
+ });
849
+ }
850
+ // Fire-and-forget: notify TX_FAILED on simulation failure
851
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
852
+ txId: ctx.txId,
853
+ error: simResult.error ?? 'Simulation failed',
854
+ amount: reqAmount,
855
+ display_amount: displayAmount,
856
+ network: ctx.resolvedNetwork,
857
+ }, { txId: ctx.txId });
858
+ // v1.6: emit transaction:failed event (simulation failure)
859
+ ctx.eventBus?.emit('transaction:failed', {
860
+ walletId: ctx.walletId,
861
+ txId: ctx.txId,
862
+ error: simResult.error ?? 'Simulation failed',
863
+ network: ctx.resolvedNetwork,
864
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
865
+ timestamp: Math.floor(Date.now() / 1000),
866
+ });
867
+ throw new WAIaaSError('SIMULATION_FAILED', {
868
+ message: simResult.error ?? 'Transaction simulation failed',
869
+ });
870
+ }
871
+ // Stage 5c: Decrypt private key, sign
872
+ // CRITICAL: key MUST be released in finally block
873
+ let privateKey = null;
874
+ try {
875
+ privateKey = await ctx.keyStore.decryptPrivateKey(ctx.walletId, ctx.masterPassword);
876
+ ctx.signedTx = await ctx.adapter.signTransaction(ctx.unsignedTx, privateKey);
877
+ }
878
+ finally {
879
+ if (privateKey) {
880
+ ctx.keyStore.releaseKey(privateKey);
881
+ }
882
+ }
883
+ // Stage 5d: Submit (with RPC metrics)
884
+ const submitStart = Date.now();
885
+ ctx.metricsCounter?.increment('rpc.calls', { network: ctx.resolvedNetwork });
886
+ ctx.submitResult = await ctx.adapter.submitTransaction(ctx.signedTx);
887
+ ctx.metricsCounter?.recordLatency('rpc.latency', Date.now() - submitStart, { network: ctx.resolvedNetwork });
888
+ // Success: increment tx.submitted counter
889
+ ctx.metricsCounter?.increment('tx.submitted', { network: ctx.resolvedNetwork });
890
+ // Success: Update DB SUBMITTED + txHash
891
+ await ctx.db
892
+ .update(transactions)
893
+ .set({ status: 'SUBMITTED', txHash: ctx.submitResult.txHash })
894
+ .where(eq(transactions.id, ctx.txId));
895
+ // Audit log: TX_SUBMITTED
896
+ if (ctx.sqlite) {
897
+ const txType = ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER';
898
+ const auditDetails = {
899
+ txHash: ctx.submitResult.txHash,
900
+ chain: ctx.wallet.chain,
901
+ network: ctx.resolvedNetwork,
902
+ type: txType,
903
+ };
904
+ // v31.14 DEPL-06: log keccak256(bytecode) for CONTRACT_DEPLOY audit trail
905
+ if (txType === 'CONTRACT_DEPLOY' && 'bytecode' in ctx.request) {
906
+ const { keccak256, toBytes } = await import('viem');
907
+ auditDetails.bytecodeHash = keccak256(toBytes(ctx.request.bytecode));
908
+ }
909
+ insertAuditLog(ctx.sqlite, {
910
+ eventType: 'TX_SUBMITTED',
911
+ actor: ctx.sessionId ?? 'system',
912
+ walletId: ctx.walletId,
913
+ txId: ctx.txId,
914
+ details: auditDetails,
915
+ severity: 'info',
916
+ });
917
+ }
918
+ // Fire-and-forget: notify TX_SUBMITTED
919
+ void ctx.notificationService?.notify('TX_SUBMITTED', ctx.walletId, {
920
+ txId: ctx.txId,
921
+ txHash: ctx.submitResult.txHash,
922
+ amount: reqAmount,
923
+ to: resolveNotificationTo(ctx.request, ctx.resolvedNetwork, ctx.contractNameRegistry),
924
+ display_amount: displayAmount,
925
+ network: ctx.resolvedNetwork,
926
+ }, { txId: ctx.txId });
927
+ // v1.6: emit wallet:activity TX_SUBMITTED event
928
+ ctx.eventBus?.emit('wallet:activity', {
929
+ walletId: ctx.walletId,
930
+ activity: 'TX_SUBMITTED',
931
+ details: { txId: ctx.txId, txHash: ctx.submitResult.txHash },
932
+ timestamp: Math.floor(Date.now() / 1000),
933
+ });
934
+ return; // Success -- exit the loop
935
+ }
936
+ catch (err) {
937
+ // Non-ChainError: rethrow as-is (WAIaaSError, validation errors, etc.)
938
+ if (!(err instanceof ChainError)) {
939
+ throw err;
940
+ }
941
+ // ChainError: category-based retry logic
942
+ switch (err.category) {
943
+ case 'PERMANENT': {
944
+ // Immediate failure, no retry
945
+ ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
946
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
947
+ await ctx.db
948
+ .update(transactions)
949
+ .set({ status: 'FAILED', error: err.message })
950
+ .where(eq(transactions.id, ctx.txId));
951
+ // Audit log: TX_FAILED (permanent chain error)
952
+ if (ctx.sqlite) {
953
+ insertAuditLog(ctx.sqlite, {
954
+ eventType: 'TX_FAILED',
955
+ actor: ctx.sessionId ?? 'system',
956
+ walletId: ctx.walletId,
957
+ txId: ctx.txId,
958
+ details: { error: err.message, stage: 5, chain: ctx.wallet.chain, network: ctx.resolvedNetwork },
959
+ severity: 'warning',
960
+ });
961
+ }
962
+ // Fire-and-forget: notify TX_FAILED
963
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
964
+ txId: ctx.txId,
965
+ error: err.message,
966
+ amount: reqAmount,
967
+ display_amount: displayAmount,
968
+ network: ctx.resolvedNetwork,
969
+ }, { txId: ctx.txId });
970
+ // v1.6: emit transaction:failed event (permanent chain error)
971
+ ctx.eventBus?.emit('transaction:failed', {
972
+ walletId: ctx.walletId,
973
+ txId: ctx.txId,
974
+ error: err.message,
975
+ network: ctx.resolvedNetwork,
976
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
977
+ timestamp: Math.floor(Date.now() / 1000),
978
+ });
979
+ throw new WAIaaSError('CHAIN_ERROR', {
980
+ message: err.message,
981
+ cause: err,
982
+ });
983
+ }
984
+ case 'TRANSIENT': {
985
+ ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
986
+ if (retryCount >= 3) {
987
+ // Max retries exhausted
988
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
989
+ await ctx.db
990
+ .update(transactions)
991
+ .set({ status: 'FAILED', error: `${err.code} (max retries exceeded)` })
992
+ .where(eq(transactions.id, ctx.txId));
993
+ // Fire-and-forget: notify TX_FAILED
994
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
995
+ txId: ctx.txId,
996
+ error: `${err.code} (max retries exceeded)`,
997
+ amount: reqAmount,
998
+ display_amount: displayAmount,
999
+ network: ctx.resolvedNetwork,
1000
+ }, { txId: ctx.txId });
1001
+ // v1.6: emit transaction:failed event (transient max retries)
1002
+ ctx.eventBus?.emit('transaction:failed', {
1003
+ walletId: ctx.walletId,
1004
+ txId: ctx.txId,
1005
+ error: `${err.code} (max retries exceeded)`,
1006
+ network: ctx.resolvedNetwork,
1007
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
1008
+ timestamp: Math.floor(Date.now() / 1000),
1009
+ });
1010
+ throw new WAIaaSError('CHAIN_ERROR', {
1011
+ message: `${err.message} (max retries exceeded)`,
1012
+ cause: err,
1013
+ });
1014
+ }
1015
+ // Exponential backoff: 1s, 2s, 4s
1016
+ await sleep(1000 * Math.pow(2, retryCount));
1017
+ retryCount++;
1018
+ continue buildLoop; // Retry from Stage 5a (rebuild)
1019
+ }
1020
+ case 'STALE': {
1021
+ ctx.metricsCounter?.increment('rpc.errors', { network: ctx.resolvedNetwork });
1022
+ if (retryCount >= 1) {
1023
+ // Stale retry exhausted (shared retryCount)
1024
+ ctx.metricsCounter?.increment('tx.failed', { network: ctx.resolvedNetwork });
1025
+ await ctx.db
1026
+ .update(transactions)
1027
+ .set({ status: 'FAILED', error: `${err.code} (stale retry exhausted)` })
1028
+ .where(eq(transactions.id, ctx.txId));
1029
+ // Fire-and-forget: notify TX_FAILED
1030
+ void ctx.notificationService?.notify('TX_FAILED', ctx.walletId, {
1031
+ txId: ctx.txId,
1032
+ error: `${err.code} (stale retry exhausted)`,
1033
+ amount: reqAmount,
1034
+ display_amount: displayAmount,
1035
+ network: ctx.resolvedNetwork,
1036
+ }, { txId: ctx.txId });
1037
+ // v1.6: emit transaction:failed event (stale retry exhausted)
1038
+ ctx.eventBus?.emit('transaction:failed', {
1039
+ walletId: ctx.walletId,
1040
+ txId: ctx.txId,
1041
+ error: `${err.code} (stale retry exhausted)`,
1042
+ network: ctx.resolvedNetwork,
1043
+ type: ('type' in ctx.request && ctx.request.type) ? ctx.request.type : 'TRANSFER',
1044
+ timestamp: Math.floor(Date.now() / 1000),
1045
+ });
1046
+ throw new WAIaaSError('CHAIN_ERROR', {
1047
+ message: `${err.message} (stale retry exhausted)`,
1048
+ cause: err,
1049
+ });
1050
+ }
1051
+ // Rebuild from Stage 5a with new blockhash/nonce
1052
+ retryCount++;
1053
+ continue buildLoop;
1054
+ }
1055
+ default: {
1056
+ // Unknown category: treat as permanent
1057
+ await ctx.db
1058
+ .update(transactions)
1059
+ .set({ status: 'FAILED', error: err.message })
1060
+ .where(eq(transactions.id, ctx.txId));
1061
+ throw new WAIaaSError('CHAIN_ERROR', {
1062
+ message: err.message,
1063
+ cause: err,
1064
+ });
1065
+ }
1066
+ }
1067
+ }
1068
+ }
1069
+ }
1070
+ //# sourceMappingURL=stage5-execute.js.map