tapimo 0.12.0 → 0.14.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 (398) hide show
  1. package/dist/App.d.ts +11333 -9563
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +39 -3
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +2 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +17 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/Webhooks.js +2 -2
  10. package/dist/Webhooks.js.map +1 -1
  11. package/dist/admin/App.d.ts +1064 -924
  12. package/dist/admin/App.d.ts.map +1 -1
  13. package/dist/admin/apps/api-keys.d.ts +80 -0
  14. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  15. package/dist/admin/apps/api-keys.js +54 -0
  16. package/dist/admin/apps/api-keys.js.map +1 -1
  17. package/dist/admin/apps/earn-vaults.d.ts +63 -15
  18. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  19. package/dist/admin/apps/earn-vaults.js +2 -1
  20. package/dist/admin/apps/earn-vaults.js.map +1 -1
  21. package/dist/admin/apps/organizations.d.ts +92 -3
  22. package/dist/admin/apps/organizations.d.ts.map +1 -1
  23. package/dist/admin/apps/organizations.js +69 -7
  24. package/dist/admin/apps/organizations.js.map +1 -1
  25. package/dist/admin/apps/verified-tokens.d.ts +7 -7
  26. package/dist/admin/ui.generated.d.ts +1 -1
  27. package/dist/admin/ui.generated.d.ts.map +1 -1
  28. package/dist/admin/ui.generated.js +151 -151
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/apps/Zones.d.ts +28 -28
  31. package/dist/apps/Zones.js +7 -7
  32. package/dist/apps/data/App.d.ts +2909 -2523
  33. package/dist/apps/data/App.d.ts.map +1 -1
  34. package/dist/apps/data/App.js +26 -21
  35. package/dist/apps/data/App.js.map +1 -1
  36. package/dist/apps/data/ZoneSelection.d.ts +8 -8
  37. package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
  38. package/dist/apps/data/ZoneSelection.js +1 -1
  39. package/dist/apps/data/ZoneSelection.js.map +1 -1
  40. package/dist/apps/data/routes/activities.d.ts +588 -584
  41. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  42. package/dist/apps/data/routes/activities.js +1561 -1239
  43. package/dist/apps/data/routes/activities.js.map +1 -1
  44. package/dist/apps/data/routes/addresses.d.ts +22 -22
  45. package/dist/apps/data/routes/balances.d.ts +26 -26
  46. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  47. package/dist/apps/data/routes/balances.js +43 -16
  48. package/dist/apps/data/routes/balances.js.map +1 -1
  49. package/dist/apps/data/routes/blocks.d.ts +44 -44
  50. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  51. package/dist/apps/data/routes/blocks.js +21 -11
  52. package/dist/apps/data/routes/blocks.js.map +1 -1
  53. package/dist/apps/data/routes/coingecko.d.ts +3 -3
  54. package/dist/apps/data/routes/earn.d.ts +201 -25
  55. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  56. package/dist/apps/data/routes/earn.js +434 -75
  57. package/dist/apps/data/routes/earn.js.map +1 -1
  58. package/dist/apps/data/routes/exchanges.d.ts +160 -145
  59. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  60. package/dist/apps/data/routes/exchanges.js +180 -114
  61. package/dist/apps/data/routes/exchanges.js.map +1 -1
  62. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  63. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  64. package/dist/apps/data/routes/fee-amm.js +18 -19
  65. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  66. package/dist/apps/data/routes/receipts.d.ts +155 -55
  67. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  68. package/dist/apps/data/routes/receipts.js +28 -10
  69. package/dist/apps/data/routes/receipts.js.map +1 -1
  70. package/dist/apps/data/routes/tokenlist.d.ts +13 -13
  71. package/dist/apps/data/routes/tokens.d.ts +5 -5
  72. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  73. package/dist/apps/data/routes/tokens.js +51 -20
  74. package/dist/apps/data/routes/tokens.js.map +1 -1
  75. package/dist/apps/data/routes/transactions.d.ts +7 -2
  76. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  77. package/dist/apps/data/routes/transactions.js +37 -17
  78. package/dist/apps/data/routes/transactions.js.map +1 -1
  79. package/dist/apps/data/routes/transfers.d.ts +13 -13
  80. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  81. package/dist/apps/data/routes/transfers.js +18 -12
  82. package/dist/apps/data/routes/transfers.js.map +1 -1
  83. package/dist/apps/data/routes/valuation.d.ts +31 -31
  84. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  85. package/dist/apps/data/routes/valuation.js +12 -7
  86. package/dist/apps/data/routes/valuation.js.map +1 -1
  87. package/dist/apps/data/routes/verified-tokens.d.ts +8 -8
  88. package/dist/apps/data/routes/webhooks.d.ts +816 -113
  89. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  90. package/dist/apps/data/routes/webhooks.js +47 -5
  91. package/dist/apps/data/routes/webhooks.js.map +1 -1
  92. package/dist/apps/data/routes/zones.d.ts +14 -14
  93. package/dist/apps/data/routes/zones.js +1 -1
  94. package/dist/apps/funding/App.d.ts +466 -44
  95. package/dist/apps/funding/App.d.ts.map +1 -1
  96. package/dist/apps/funding/App.js +1 -1
  97. package/dist/apps/funding/App.js.map +1 -1
  98. package/dist/apps/funding/routes/deposit-addresses.d.ts +17 -17
  99. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  100. package/dist/apps/funding/routes/deposit-addresses.js +17 -12
  101. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  102. package/dist/apps/funding/routes/transfers.d.ts +650 -57
  103. package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
  104. package/dist/apps/funding/routes/transfers.js +238 -24
  105. package/dist/apps/funding/routes/transfers.js.map +1 -1
  106. package/dist/apps/management/App.d.ts +5120 -4152
  107. package/dist/apps/management/App.d.ts.map +1 -1
  108. package/dist/apps/management/Billing.d.ts +1 -1
  109. package/dist/apps/management/Billing.d.ts.map +1 -1
  110. package/dist/apps/management/Billing.js +17 -1
  111. package/dist/apps/management/Billing.js.map +1 -1
  112. package/dist/apps/management/routes/api-keys.d.ts +632 -81
  113. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  114. package/dist/apps/management/routes/api-keys.js +236 -4
  115. package/dist/apps/management/routes/api-keys.js.map +1 -1
  116. package/dist/apps/management/routes/billing.d.ts +76 -76
  117. package/dist/apps/management/routes/faucet.d.ts +6 -6
  118. package/dist/apps/management/routes/invitations.d.ts +24 -24
  119. package/dist/apps/management/routes/invite-links.d.ts +4 -4
  120. package/dist/apps/management/routes/members.d.ts +16 -16
  121. package/dist/apps/management/routes/orgs.d.ts +20 -20
  122. package/dist/apps/management/routes/projects.d.ts +4 -4
  123. package/dist/apps/management/routes/usage.d.ts +8 -8
  124. package/dist/apps/management/routes/verified-token-requests.d.ts +17 -17
  125. package/dist/apps/management/routes/webhooks.d.ts +675 -25
  126. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  127. package/dist/apps/management/routes/webhooks.js +21 -21
  128. package/dist/apps/management/routes/webhooks.js.map +1 -1
  129. package/dist/apps/relay/App.d.ts.map +1 -1
  130. package/dist/apps/relay/App.js +115 -23
  131. package/dist/apps/relay/App.js.map +1 -1
  132. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  133. package/dist/apps/relay/Sponsorships.js +27 -1
  134. package/dist/apps/relay/Sponsorships.js.map +1 -1
  135. package/dist/db/Db.d.ts.map +1 -1
  136. package/dist/db/Db.js +34 -1
  137. package/dist/db/Db.js.map +1 -1
  138. package/dist/db/Schema.d.ts +11 -5
  139. package/dist/db/Schema.d.ts.map +1 -1
  140. package/dist/db/Schema.js +21 -3
  141. package/dist/db/Schema.js.map +1 -1
  142. package/dist/db/tables/fundingCatalog.d.ts +4 -2
  143. package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
  144. package/dist/db/tables/fundingCatalog.js +5 -1
  145. package/dist/db/tables/fundingCatalog.js.map +1 -1
  146. package/dist/db/tables/fundingTransferTransactions.d.ts +38 -0
  147. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -1
  148. package/dist/db/tables/fundingTransferTransactions.js +44 -3
  149. package/dist/db/tables/fundingTransferTransactions.js.map +1 -1
  150. package/dist/db/tables/fundingTransfers.d.ts +17 -0
  151. package/dist/db/tables/fundingTransfers.d.ts.map +1 -1
  152. package/dist/db/tables/fundingTransfers.js +21 -0
  153. package/dist/db/tables/fundingTransfers.js.map +1 -1
  154. package/dist/db/tables/organizations.d.ts +24 -0
  155. package/dist/db/tables/organizations.d.ts.map +1 -1
  156. package/dist/db/tables/organizations.js +27 -0
  157. package/dist/db/tables/organizations.js.map +1 -1
  158. package/dist/db/tables/projects.d.ts +25 -1
  159. package/dist/db/tables/projects.d.ts.map +1 -1
  160. package/dist/db/tables/projects.js +26 -0
  161. package/dist/db/tables/projects.js.map +1 -1
  162. package/dist/db/tables/sponsoredTransactions.d.ts +44 -0
  163. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  164. package/dist/db/tables/sponsoredTransactions.js +146 -13
  165. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  166. package/dist/db/tables/webhookSubscriptions.d.ts +10 -6
  167. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  168. package/dist/db/tables/webhookSubscriptions.js +9 -6
  169. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  170. package/dist/handlers/internal/utils.d.ts.map +1 -1
  171. package/dist/handlers/internal/utils.js +9 -0
  172. package/dist/handlers/internal/utils.js.map +1 -1
  173. package/dist/internal/Auth.d.ts +3 -1
  174. package/dist/internal/Auth.d.ts.map +1 -1
  175. package/dist/internal/Auth.js +6 -3
  176. package/dist/internal/Auth.js.map +1 -1
  177. package/dist/internal/EarnVaults.d.ts +3 -3
  178. package/dist/internal/EarnVaults.js +5 -5
  179. package/dist/internal/EarnVaults.js.map +1 -1
  180. package/dist/internal/Fetch.d.ts +23 -0
  181. package/dist/internal/Fetch.d.ts.map +1 -0
  182. package/dist/internal/Fetch.js +26 -0
  183. package/dist/internal/Fetch.js.map +1 -0
  184. package/dist/internal/Log.d.ts +4 -2
  185. package/dist/internal/Log.d.ts.map +1 -1
  186. package/dist/internal/Log.js +16 -3
  187. package/dist/internal/Log.js.map +1 -1
  188. package/dist/internal/OpenApi.d.ts +5 -3
  189. package/dist/internal/OpenApi.d.ts.map +1 -1
  190. package/dist/internal/OpenApi.js +13 -3
  191. package/dist/internal/OpenApi.js.map +1 -1
  192. package/dist/internal/Response.d.ts +1 -1
  193. package/dist/internal/Response.d.ts.map +1 -1
  194. package/dist/internal/Schema.d.ts +6 -3
  195. package/dist/internal/Schema.d.ts.map +1 -1
  196. package/dist/internal/Schema.js +8 -2
  197. package/dist/internal/Schema.js.map +1 -1
  198. package/dist/internal/Store.d.ts +16 -3
  199. package/dist/internal/Store.d.ts.map +1 -1
  200. package/dist/internal/Store.js +82 -16
  201. package/dist/internal/Store.js.map +1 -1
  202. package/dist/internal/Tidx.d.ts.map +1 -1
  203. package/dist/internal/Tidx.js +7 -2
  204. package/dist/internal/Tidx.js.map +1 -1
  205. package/dist/internal/Timeout.d.ts +36 -0
  206. package/dist/internal/Timeout.d.ts.map +1 -0
  207. package/dist/internal/Timeout.js +37 -0
  208. package/dist/internal/Timeout.js.map +1 -0
  209. package/dist/internal/Timing.d.ts +9 -0
  210. package/dist/internal/Timing.d.ts.map +1 -1
  211. package/dist/internal/Timing.js +7 -0
  212. package/dist/internal/Timing.js.map +1 -1
  213. package/dist/internal/Viem.d.ts +16 -1
  214. package/dist/internal/Viem.d.ts.map +1 -1
  215. package/dist/internal/Viem.js +12 -2
  216. package/dist/internal/Viem.js.map +1 -1
  217. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  218. package/dist/internal/WebhookDestination.js +3 -0
  219. package/dist/internal/WebhookDestination.js.map +1 -1
  220. package/dist/internal/funding/Action.d.ts +9 -0
  221. package/dist/internal/funding/Action.d.ts.map +1 -1
  222. package/dist/internal/funding/Action.js +16 -8
  223. package/dist/internal/funding/Action.js.map +1 -1
  224. package/dist/internal/funding/Catalog.d.ts +9 -2
  225. package/dist/internal/funding/Catalog.d.ts.map +1 -1
  226. package/dist/internal/funding/Catalog.js +19 -8
  227. package/dist/internal/funding/Catalog.js.map +1 -1
  228. package/dist/internal/funding/DepositWebhook.d.ts.map +1 -1
  229. package/dist/internal/funding/DepositWebhook.js +2 -1
  230. package/dist/internal/funding/DepositWebhook.js.map +1 -1
  231. package/dist/internal/funding/Evidence.d.ts.map +1 -1
  232. package/dist/internal/funding/Evidence.js +2 -10
  233. package/dist/internal/funding/Evidence.js.map +1 -1
  234. package/dist/internal/funding/Provider.d.ts +108 -13
  235. package/dist/internal/funding/Provider.d.ts.map +1 -1
  236. package/dist/internal/funding/Provider.js +34 -8
  237. package/dist/internal/funding/Provider.js.map +1 -1
  238. package/dist/internal/funding/SourceObservation.d.ts.map +1 -1
  239. package/dist/internal/funding/SourceObservation.js +5 -7
  240. package/dist/internal/funding/SourceObservation.js.map +1 -1
  241. package/dist/internal/funding/Transfer.d.ts +114 -18
  242. package/dist/internal/funding/Transfer.d.ts.map +1 -1
  243. package/dist/internal/funding/Transfer.js +185 -55
  244. package/dist/internal/funding/Transfer.js.map +1 -1
  245. package/dist/internal/funding/TransferReconciliation.d.ts +52 -0
  246. package/dist/internal/funding/TransferReconciliation.d.ts.map +1 -0
  247. package/dist/internal/funding/TransferReconciliation.js +192 -0
  248. package/dist/internal/funding/TransferReconciliation.js.map +1 -0
  249. package/dist/internal/funding/TransferWebhook.d.ts +21 -0
  250. package/dist/internal/funding/TransferWebhook.d.ts.map +1 -0
  251. package/dist/internal/funding/TransferWebhook.js +43 -0
  252. package/dist/internal/funding/TransferWebhook.js.map +1 -0
  253. package/dist/internal/funding/index.d.ts +1 -0
  254. package/dist/internal/funding/index.d.ts.map +1 -1
  255. package/dist/internal/funding/index.js +1 -0
  256. package/dist/internal/funding/index.js.map +1 -1
  257. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  258. package/dist/internal/funding/providers/relay.js +3 -12
  259. package/dist/internal/funding/providers/relay.js.map +1 -1
  260. package/dist/internal/funding/providers/stargate.d.ts +127 -9
  261. package/dist/internal/funding/providers/stargate.d.ts.map +1 -1
  262. package/dist/internal/funding/providers/stargate.js +548 -112
  263. package/dist/internal/funding/providers/stargate.js.map +1 -1
  264. package/dist/internal/index.d.ts +1 -0
  265. package/dist/internal/index.d.ts.map +1 -1
  266. package/dist/internal/index.js +1 -0
  267. package/dist/internal/index.js.map +1 -1
  268. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  269. package/dist/internal/webhookDestinations/slack.js +16 -0
  270. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  271. package/package.json +2 -2
  272. package/src/App.test.ts +100 -0
  273. package/src/App.ts +43 -3
  274. package/src/Client.test-d.ts +129 -2
  275. package/src/Scope.test.ts +20 -0
  276. package/src/Scope.ts +16 -0
  277. package/src/Webhooks.ts +2 -2
  278. package/src/admin/apps/api-keys.test.ts +75 -0
  279. package/src/admin/apps/api-keys.ts +64 -0
  280. package/src/admin/apps/earn-vaults.test.ts +1 -1
  281. package/src/admin/apps/earn-vaults.ts +2 -1
  282. package/src/admin/apps/organizations.test.ts +53 -1
  283. package/src/admin/apps/organizations.ts +90 -5
  284. package/src/admin/ui/src/lib/api-keys.ts +19 -0
  285. package/src/admin/ui/src/lib/organizations.test.ts +112 -1
  286. package/src/admin/ui/src/lib/organizations.ts +55 -0
  287. package/src/admin/ui/src/routes/api-keys.tsx +89 -2
  288. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +116 -0
  289. package/src/admin/ui.generated.ts +189 -151
  290. package/src/apps/Zones.test.ts +7 -7
  291. package/src/apps/Zones.ts +7 -7
  292. package/src/apps/composition.test.ts +2 -1
  293. package/src/apps/data/App.test.ts +41 -0
  294. package/src/apps/data/App.ts +30 -21
  295. package/src/apps/data/ZoneSelection.test.ts +2 -2
  296. package/src/apps/data/ZoneSelection.ts +8 -8
  297. package/src/apps/data/routes/activities.test.ts +1526 -12
  298. package/src/apps/data/routes/activities.ts +1774 -1356
  299. package/src/apps/data/routes/balances.ts +133 -97
  300. package/src/apps/data/routes/blocks.test.ts +533 -0
  301. package/src/apps/data/routes/blocks.ts +35 -16
  302. package/src/apps/data/routes/earn.test.ts +373 -16
  303. package/src/apps/data/routes/earn.ts +548 -79
  304. package/src/apps/data/routes/earn.zone-access.test.ts +6 -6
  305. package/src/apps/data/routes/exchanges.test.ts +740 -15
  306. package/src/apps/data/routes/exchanges.ts +954 -753
  307. package/src/apps/data/routes/fee-amm.ts +17 -18
  308. package/src/apps/data/routes/receipts.ts +47 -16
  309. package/src/apps/data/routes/tokens.test.ts +578 -0
  310. package/src/apps/data/routes/tokens.ts +283 -225
  311. package/src/apps/data/routes/transactions.ts +68 -29
  312. package/src/apps/data/routes/transfers.test.ts +421 -0
  313. package/src/apps/data/routes/transfers.ts +45 -27
  314. package/src/apps/data/routes/valuation.ts +94 -78
  315. package/src/apps/data/routes/webhooks.test.ts +21 -5
  316. package/src/apps/data/routes/webhooks.ts +63 -8
  317. package/src/apps/data/routes/zones.test.ts +2 -2
  318. package/src/apps/data/routes/zones.ts +1 -1
  319. package/src/apps/funding/App.ts +12 -2
  320. package/src/apps/funding/routes/deposit-addresses.test.ts +29 -7
  321. package/src/apps/funding/routes/deposit-addresses.ts +19 -14
  322. package/src/apps/funding/routes/quotes.test.ts +5 -9
  323. package/src/apps/funding/routes/transfers.test.ts +901 -23
  324. package/src/apps/funding/routes/transfers.ts +347 -64
  325. package/src/apps/management/Billing.ts +18 -5
  326. package/src/apps/management/routes/api-keys.test.ts +220 -0
  327. package/src/apps/management/routes/api-keys.ts +280 -3
  328. package/src/apps/management/routes/webhooks.test.ts +3 -3
  329. package/src/apps/management/routes/webhooks.ts +24 -25
  330. package/src/apps/relay/App.test.ts +212 -1
  331. package/src/apps/relay/App.ts +158 -29
  332. package/src/apps/relay/Sponsorships.ts +24 -1
  333. package/src/db/Db.ts +48 -1
  334. package/src/db/Schema.ts +22 -4
  335. package/src/db/tables/earnVaults.test.ts +9 -9
  336. package/src/db/tables/fundingCatalog.test.ts +16 -2
  337. package/src/db/tables/fundingCatalog.ts +9 -3
  338. package/src/db/tables/fundingTransferTransactions.test.ts +43 -0
  339. package/src/db/tables/fundingTransferTransactions.ts +79 -3
  340. package/src/db/tables/fundingTransfers.test.ts +26 -0
  341. package/src/db/tables/fundingTransfers.ts +36 -0
  342. package/src/db/tables/organizations.test.ts +41 -0
  343. package/src/db/tables/organizations.ts +49 -0
  344. package/src/db/tables/projects.test.ts +55 -0
  345. package/src/db/tables/projects.ts +46 -1
  346. package/src/db/tables/sponsoredTransactions.test.ts +338 -0
  347. package/src/db/tables/sponsoredTransactions.ts +197 -13
  348. package/src/db/tables/webhookSubscriptions.ts +18 -11
  349. package/src/handlers/internal/utils.test.ts +53 -0
  350. package/src/handlers/internal/utils.ts +15 -0
  351. package/src/internal/Auth.ts +12 -4
  352. package/src/internal/EarnVaults.capabilities.test.ts +2 -2
  353. package/src/internal/EarnVaults.test.ts +1 -1
  354. package/src/internal/EarnVaults.ts +5 -5
  355. package/src/internal/Fetch.test.ts +46 -0
  356. package/src/internal/Fetch.ts +56 -0
  357. package/src/internal/Log.test-d.ts +2 -0
  358. package/src/internal/Log.test.ts +21 -0
  359. package/src/internal/Log.ts +22 -5
  360. package/src/internal/OpenApi.ts +14 -4
  361. package/src/internal/Response.ts +1 -1
  362. package/src/internal/Schema.test.ts +2 -0
  363. package/src/internal/Schema.ts +12 -2
  364. package/src/internal/Store.test.ts +178 -0
  365. package/src/internal/Store.ts +104 -18
  366. package/src/internal/Tidx.test.ts +2 -1
  367. package/src/internal/Tidx.ts +7 -2
  368. package/src/internal/Timeout.test.ts +35 -0
  369. package/src/internal/Timeout.ts +73 -0
  370. package/src/internal/Timing.ts +16 -0
  371. package/src/internal/Viem.ts +39 -3
  372. package/src/internal/WebhookDestination.ts +3 -0
  373. package/src/internal/Webhooks.test.ts +45 -0
  374. package/src/internal/funding/Action.test.ts +41 -1
  375. package/src/internal/funding/Action.ts +69 -41
  376. package/src/internal/funding/Catalog.test.ts +34 -0
  377. package/src/internal/funding/Catalog.ts +28 -11
  378. package/src/internal/funding/DepositWebhook.ts +2 -1
  379. package/src/internal/funding/Evidence.ts +2 -13
  380. package/src/internal/funding/Provider.test.ts +73 -0
  381. package/src/internal/funding/Provider.ts +125 -28
  382. package/src/internal/funding/SourceObservation.ts +5 -9
  383. package/src/internal/funding/Transfer.test.ts +155 -0
  384. package/src/internal/funding/Transfer.ts +387 -147
  385. package/src/internal/funding/TransferReconciliation.test.ts +147 -0
  386. package/src/internal/funding/TransferReconciliation.ts +264 -0
  387. package/src/internal/funding/TransferWebhook.test.ts +128 -0
  388. package/src/internal/funding/TransferWebhook.ts +67 -0
  389. package/src/internal/funding/index.test.ts +1 -0
  390. package/src/internal/funding/index.ts +1 -0
  391. package/src/internal/funding/providers/index.test.ts +4 -167
  392. package/src/internal/funding/providers/relay.test.ts +2 -2
  393. package/src/internal/funding/providers/relay.ts +3 -15
  394. package/src/internal/funding/providers/stargate.test.ts +328 -0
  395. package/src/internal/funding/providers/stargate.ts +807 -135
  396. package/src/internal/index.test.ts +1 -0
  397. package/src/internal/index.ts +1 -0
  398. package/src/internal/webhookDestinations/slack.ts +15 -0
@@ -0,0 +1,147 @@
1
+ import { tempoMainnet } from 'viem/tempo/chains'
2
+
3
+ import * as Anvil from '../../../test/Anvil.js'
4
+ import * as TestApp from '../../../test/App.js'
5
+ import * as TestFunding from '../../../test/Funding.js'
6
+ import * as Catalog from './Catalog.js'
7
+ import * as Transfer from './Transfer.js'
8
+ import * as TransferReconciliation from './TransferReconciliation.js'
9
+
10
+ const db = TestApp.database()
11
+ const destinationTransactionHash =
12
+ '0x3dfaba0a78b8f4bc09e55e05211c8120729e7b6879efe32613883befbca666da'
13
+ const guid = '0x5549d117c8b23f0ecdf05c2604ed989cf0034f378707bd81319e93834f2f85f2'
14
+ const recipient = '0x7212623e4cff9ad010d28aa065fad2bf58578783'
15
+ const sender = '0x52b650a62e384f68880d0a1dc2b84dfed47d5660'
16
+ const sourceTransactionHash = '0xfd71359adf5095f2ab512a19e0a2df6c8cc0db14ac8a52286d61287daabdccd4'
17
+ const routeConfiguration = TestFunding.snapshot.routesByProvider
18
+ .get('stargate')!
19
+ .find((candidate) => candidate.route.source.chain.id === 'eip155:8453')!.configuration!
20
+
21
+ describe.skipIf(!Anvil.available)('createTracker', () => {
22
+ let destination: Anvil.start.ReturnType
23
+
24
+ beforeAll(async () => {
25
+ destination = await Anvil.start({
26
+ chain: tempoMainnet,
27
+ forkUrl: tempoMainnet.rpcUrls.default.http[0]!,
28
+ })
29
+ await Catalog.publish(db, {
30
+ ...TestFunding.data,
31
+ chains: TestFunding.data.chains.map((chain) =>
32
+ chain.id === 'eip155:4217' ? { ...chain, rpcUrls: [destination.rpcUrl] } : chain,
33
+ ),
34
+ })
35
+ })
36
+
37
+ afterAll(async () => {
38
+ await destination?.stop()
39
+ })
40
+
41
+ test('completes a registered transfer from Tempo evidence', async () => {
42
+ const amount = {
43
+ baseUnits: '200000',
44
+ currency: 'USD',
45
+ decimals: 6,
46
+ formatted: '0.2',
47
+ } as const
48
+ const transfer = await Transfer.create(db, {
49
+ apiKeyId: 'key_test',
50
+ environment: 'production',
51
+ orgId: 'org_test',
52
+ providerState: {
53
+ destinationBlockNumber: (
54
+ await destination.client.getTransactionReceipt({ hash: destinationTransactionHash })
55
+ ).blockNumber.toString(),
56
+ routeConfiguration,
57
+ },
58
+ snapshot: TestFunding.transferSnapshot({
59
+ destinationAmount: amount,
60
+ destinationAmountMin: amount,
61
+ provider: { id: 'stargate', name: 'Stargate' },
62
+ recipient,
63
+ sender,
64
+ sourceAmount: amount,
65
+ }),
66
+ })
67
+ await Transfer.registerSourceTransaction(db, {
68
+ chainId: 'eip155:8453',
69
+ id: transfer.id,
70
+ providerState: { stargate: { guid, sourceEid: 30_184 } },
71
+ transactionHash: sourceTransactionHash,
72
+ })
73
+ await Catalog.publish(db, {
74
+ ...TestFunding.data,
75
+ chains: TestFunding.data.chains.map((chain) =>
76
+ chain.id === 'eip155:4217' ? { ...chain, rpcUrls: [destination.rpcUrl] } : chain,
77
+ ),
78
+ routes: TestFunding.data.routes.filter((route) => route.providerId !== 'stargate'),
79
+ })
80
+
81
+ const tracker = TransferReconciliation.createTracker({ db })
82
+ await expect(
83
+ tracker.reconcile({ transferId: transfer.id, type: 'funding:transfer:reconcile' }),
84
+ ).resolves.toEqual({ type: 'completed' })
85
+
86
+ const completed = await Transfer.transition(db, {
87
+ expectedVersion: 2,
88
+ id: transfer.id,
89
+ status: 'completed',
90
+ })
91
+ expect(completed.type).toBe('stale')
92
+ if (completed.type !== 'stale') return
93
+ expect({
94
+ destinationTransactionHashes: completed.current.snapshot.destinationTransactionHashes,
95
+ status: completed.current.status,
96
+ version: completed.current.version,
97
+ }).toEqual({
98
+ destinationTransactionHashes: [destinationTransactionHash],
99
+ status: 'completed',
100
+ version: 3,
101
+ })
102
+ })
103
+ })
104
+
105
+ describe('tick', () => {
106
+ test('advances through bounded recovery pages', async () => {
107
+ const database = TestApp.database()
108
+ await TestFunding.publish(database)
109
+ for (let index = 0; index < 26; index++) {
110
+ const transfer = await Transfer.create(database, {
111
+ apiKeyId: 'key_test',
112
+ environment: 'production',
113
+ id: Transfer.generateId(new Date(Date.UTC(2026, 0, 1, 0, 0, index))),
114
+ orgId: 'org_test',
115
+ providerState: {},
116
+ snapshot: TestFunding.transferSnapshot({
117
+ provider: { id: 'stargate', name: 'Stargate' },
118
+ }),
119
+ })
120
+ await Transfer.transition(database, {
121
+ expectedVersion: 1,
122
+ id: transfer.id,
123
+ status: 'processing',
124
+ })
125
+ }
126
+
127
+ type Dispatch = { delaySeconds: number; message: TransferReconciliation.Message }
128
+ const dispatches: Dispatch[] = []
129
+ let available = false
130
+ const tracker = TransferReconciliation.createTracker({
131
+ db: database,
132
+ dispatch: async (message, options) => {
133
+ dispatches.push({ delaySeconds: options.delaySeconds, message })
134
+ if (!available) throw new Error('queue unavailable')
135
+ },
136
+ })
137
+ await expect(tracker.tick()).rejects.toThrow('queue unavailable')
138
+ available = true
139
+ await expect(tracker.tick()).resolves.toEqual({ checked: 25 })
140
+ await expect(tracker.tick()).resolves.toEqual({ checked: 1 })
141
+
142
+ expect(dispatches).toHaveLength(27)
143
+ expect(dispatches[0]).toEqual(dispatches[1])
144
+ expect(new Set(dispatches.map(({ delaySeconds }) => delaySeconds))).toEqual(new Set([0]))
145
+ expect(new Set(dispatches.map(({ message }) => message.transferId)).size).toBe(26)
146
+ })
147
+ })
@@ -0,0 +1,264 @@
1
+ import { Hash } from 'ox'
2
+ import * as z from 'zod/mini'
3
+
4
+ import * as Db from '../../db/Db.js'
5
+ import * as FundingTransferTransactions from '../../db/tables/fundingTransferTransactions.js'
6
+ import * as FundingTransfers from '../../db/tables/fundingTransfers.js'
7
+ import type * as Metrics from '../../Metrics.js'
8
+ import * as Schema from '../Schema.js'
9
+ import type * as Webhooks from '../Webhooks.js'
10
+ import * as Catalog from './Catalog.js'
11
+ import type * as Provider from './Provider.js'
12
+ import * as Stargate from './providers/stargate.js'
13
+ import * as Transfer from './Transfer.js'
14
+
15
+ const followUpDelaySeconds = 15
16
+ const maximumFollowUpAttempts = 120
17
+ const sweepLimit = 25
18
+
19
+ const providerState = z.object({
20
+ destinationBlockNumber: z.string().check(z.regex(/^\d+$/)),
21
+ routeConfiguration: Stargate.schema.Configuration,
22
+ stargate: z.object({
23
+ guid: Schema.Hash,
24
+ sourceBlock: z.optional(
25
+ z.object({
26
+ hash: Schema.Hash,
27
+ number: z.string().check(z.regex(/^\d+$/)),
28
+ }),
29
+ ),
30
+ sourceEid: z.number().check(z.int(), z.positive()),
31
+ }),
32
+ })
33
+
34
+ /** Queue message that advances one registered funding transfer. */
35
+ export type Message = {
36
+ /** Zero-based destination reconciliation attempt. */
37
+ attempt?: number | undefined
38
+ /** Funding transfer id (`ftr_…`). */
39
+ transferId: string
40
+ /** Funding transfer reconciliation discriminator. */
41
+ type: 'funding:transfer:reconcile'
42
+ }
43
+
44
+ /** Creates a tracker that verifies and completes registered funding transfers. */
45
+ export function createTracker(options: createTracker.Options): createTracker.Tracker {
46
+ const fetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init))
47
+ let sweepCursor: string | undefined
48
+ const record = (outcome: string, count = 1) => {
49
+ options.metrics?.count('funding_transfer_reconciliation_count', count, {
50
+ outcome,
51
+ provider: 'stargate',
52
+ })
53
+ }
54
+
55
+ return {
56
+ async reconcile(message) {
57
+ const db = Db.get(options.db)
58
+ const transfer = await FundingTransfers.get(db, message.transferId)
59
+ if (!transfer || transfer.status === 'completed') {
60
+ record(transfer ? 'already_completed' : 'not_found')
61
+ return { type: 'ignored' }
62
+ }
63
+ if (transfer.status !== 'processing' || transfer.providerId !== 'stargate') {
64
+ record('invalid_state')
65
+ return { type: 'ignored' }
66
+ }
67
+
68
+ const state = providerState.safeParse(transfer.providerState)
69
+ const transactions = await FundingTransferTransactions.listByTransfer(db, transfer.id)
70
+ const source = transactions.find((transaction) => transaction.role === 'source')
71
+ const catalog = await Catalog.read(db)
72
+ const destinationChain = catalog.chainsByKey.get(transfer.snapshot.destinationChain.id)
73
+ const sourceChain = catalog.chainsByKey.get(transfer.snapshot.sourceChain.id)
74
+ const destinationAmount = transfer.snapshot.destinationAmount
75
+ if (
76
+ !state.success ||
77
+ !source ||
78
+ !Hash.validate(source.transactionRef) ||
79
+ !destinationChain ||
80
+ !destinationAmount ||
81
+ !sourceChain ||
82
+ !transfer.snapshot.sender
83
+ )
84
+ throw new EvidenceError('Registered Stargate transfer evidence is incomplete.')
85
+
86
+ const delivery = await Stargate.verifyDestinationDelivery({
87
+ configuration: state.data.routeConfiguration,
88
+ destinationAmount: destinationAmount.baseUnits,
89
+ destinationBlockNumber: state.data.destinationBlockNumber,
90
+ destinationChain,
91
+ destinationTokenAddress: transfer.snapshot.destinationToken.address,
92
+ fetch,
93
+ guid: state.data.stargate.guid,
94
+ recipient: transfer.snapshot.recipient,
95
+ sourceChainId: transfer.snapshot.sourceChain.id,
96
+ sourceTokenAddress: transfer.snapshot.sourceToken.address,
97
+ })
98
+ if (delivery.type === 'invalid')
99
+ throw new EvidenceError('Tempo delivery conflicts with registered transfer terms.')
100
+ if (delivery.type === 'pending') {
101
+ const verified = await Stargate.verifySourceTransaction({
102
+ configuration: state.data.routeConfiguration,
103
+ destinationTokenAddress: transfer.snapshot.destinationToken.address,
104
+ fetch,
105
+ recipient: transfer.snapshot.recipient,
106
+ sender: transfer.snapshot.sender,
107
+ sourceAmount: transfer.snapshot.sourceAmount.baseUnits,
108
+ sourceBlock: state.data.stargate.sourceBlock
109
+ ? {
110
+ hash: state.data.stargate.sourceBlock.hash,
111
+ number: BigInt(state.data.stargate.sourceBlock.number),
112
+ }
113
+ : undefined,
114
+ sourceChain,
115
+ sourceTokenAddress: transfer.snapshot.sourceToken.address,
116
+ transactionHash: source.transactionRef,
117
+ validAfter: transfer.snapshot.quote.sampledAt,
118
+ })
119
+ if (verified.type === 'reorged') {
120
+ const reopened = await Transfer.reopenSourceTransaction(db, {
121
+ chainId: transfer.snapshot.sourceChain.id,
122
+ id: transfer.id,
123
+ providerState: {
124
+ destinationBlockNumber: state.data.destinationBlockNumber,
125
+ routeConfiguration: state.data.routeConfiguration,
126
+ },
127
+ transactionHash: source.transactionRef,
128
+ })
129
+ if (reopened.type !== 'reopened') {
130
+ record('invalid_state')
131
+ return { type: 'ignored' }
132
+ }
133
+ if (options.dispatchTransferUpdates && reopened.references.length > 0)
134
+ await options.dispatchTransferUpdates(reopened.references)
135
+ record('reopened')
136
+ return { type: 'reopened' }
137
+ }
138
+ if (verified.type === 'pending') return followUp(message, options, record)
139
+ if (
140
+ verified.type === 'invalid' ||
141
+ verified.guid.toLowerCase() !== state.data.stargate.guid.toLowerCase() ||
142
+ verified.sourceEid !== state.data.stargate.sourceEid
143
+ )
144
+ throw new EvidenceError('Source transaction conflicts with registered Stargate evidence.')
145
+ return followUp(message, options, record)
146
+ }
147
+
148
+ const completed = await Transfer.complete(db, {
149
+ chainId: transfer.snapshot.destinationChain.id,
150
+ destinationAmount,
151
+ id: transfer.id,
152
+ transactionHash: delivery.transactionHash,
153
+ })
154
+ if (completed.type === 'invalid')
155
+ throw new EvidenceError('Funding transfer cannot accept destination evidence.')
156
+ if (completed.type === 'not_found') {
157
+ record('not_found')
158
+ return { type: 'ignored' }
159
+ }
160
+ if (
161
+ completed.type === 'completed' &&
162
+ options.dispatchTransferUpdates &&
163
+ completed.references.length > 0
164
+ )
165
+ await options.dispatchTransferUpdates(completed.references)
166
+ record(completed.type)
167
+ return { type: 'completed' }
168
+ },
169
+ async tick() {
170
+ if (!options.dispatch) throw new DispatchError()
171
+ const db = Db.get(options.db)
172
+ let records = await FundingTransfers.listProcessing(db, {
173
+ cursor: sweepCursor,
174
+ limit: sweepLimit,
175
+ providerId: 'stargate',
176
+ })
177
+ if (records.length === 0 && sweepCursor !== undefined) {
178
+ sweepCursor = undefined
179
+ records = await FundingTransfers.listProcessing(db, {
180
+ limit: sweepLimit,
181
+ providerId: 'stargate',
182
+ })
183
+ }
184
+ let checked = 0
185
+ for (const transfer of records) {
186
+ await options.dispatch(
187
+ {
188
+ transferId: transfer.id,
189
+ type: 'funding:transfer:reconcile',
190
+ },
191
+ { delaySeconds: 0 },
192
+ )
193
+ sweepCursor = transfer.id
194
+ checked++
195
+ }
196
+ record('swept', checked)
197
+ return { checked }
198
+ },
199
+ }
200
+ }
201
+
202
+ export declare namespace createTracker {
203
+ /** Tracker dependencies and queue dispatch. */
204
+ type Options = {
205
+ /** Authoritative database or per-invocation database factory. */
206
+ db: Db.Source
207
+ /** Enqueues one delayed reconciliation follow-up. */
208
+ dispatch?: ((message: Message, options: { delaySeconds: number }) => Promise<void>) | undefined
209
+ /** Enqueues webhook updates staged with transfer mutations. */
210
+ dispatchTransferUpdates?:
211
+ | ((references: readonly Webhooks.QueueReference[]) => Promise<number>)
212
+ | undefined
213
+ /** Fetch implementation override for chain RPC requests. */
214
+ fetch?: Provider.Fetch | undefined
215
+ /** Optional bounded operational metrics. */
216
+ metrics?: Metrics.Metrics | undefined
217
+ }
218
+
219
+ /** Reconciles one registered funding transfer. */
220
+ type Tracker = {
221
+ /** Verifies or defers one destination delivery. */
222
+ reconcile(message: Message): Promise<Result>
223
+ /** Enqueues processing transfers whose initial dispatch may have failed. */
224
+ tick(): Promise<{ checked: number }>
225
+ }
226
+
227
+ /** One reconciliation disposition. */
228
+ type Result =
229
+ | { type: 'completed' }
230
+ | { type: 'ignored' }
231
+ | { type: 'pending' }
232
+ | { type: 'reopened' }
233
+ }
234
+
235
+ async function followUp(
236
+ message: Message,
237
+ options: createTracker.Options,
238
+ record: (outcome: string) => void,
239
+ ): Promise<createTracker.Result> {
240
+ const attempt = (message.attempt ?? 0) + 1
241
+ if (attempt > maximumFollowUpAttempts) {
242
+ record('exhausted')
243
+ throw new ExhaustedError()
244
+ }
245
+ if (!options.dispatch) throw new DispatchError()
246
+ await options.dispatch(
247
+ { attempt, transferId: message.transferId, type: 'funding:transfer:reconcile' },
248
+ { delaySeconds: followUpDelaySeconds },
249
+ )
250
+ record('pending')
251
+ return { type: 'pending' }
252
+ }
253
+
254
+ class DispatchError extends Error {
255
+ override name = 'Funding.TransferReconciliation.DispatchError'
256
+ }
257
+
258
+ class EvidenceError extends Error {
259
+ override name = 'Funding.TransferReconciliation.EvidenceError'
260
+ }
261
+
262
+ class ExhaustedError extends Error {
263
+ override name = 'Funding.TransferReconciliation.ExhaustedError'
264
+ }
@@ -0,0 +1,128 @@
1
+ import * as TestApp from '../../../test/App.js'
2
+ import * as TestFunding from '../../../test/Funding.js'
3
+ import * as FundingTransferEvents from '../../db/tables/fundingTransferEvents.js'
4
+ import * as Webhooks from '../Webhooks.js'
5
+ import * as Transfer from './Transfer.js'
6
+ import * as TransferWebhook from './TransferWebhook.js'
7
+
8
+ const db = TestApp.database()
9
+
10
+ describe('stage', () => {
11
+ test('stages owner-scoped public versions with stable event ids', async () => {
12
+ const id = Transfer.generateId()
13
+ const orgId = 'org_funding_transfer_webhook'
14
+ const projectId = 'prj_funding_transfer_webhook'
15
+ const org = await subscription({ filters: { id }, orgId })
16
+ const project = await subscription({ filters: { id, status: 'completed' }, orgId, projectId })
17
+ await subscription({ filters: { id }, orgId, projectId: 'prj_funding_transfer_sibling' })
18
+ await subscription({ environment: 'sandbox', filters: { id }, orgId })
19
+ await subscription({ filters: { id: Transfer.generateId() }, orgId })
20
+ await subscription({ filters: { id }, now: new Date('2099-01-01T00:00:00.000Z'), orgId })
21
+
22
+ const created = await db.transaction((tx) =>
23
+ Transfer.createIn(tx, {
24
+ apiKeyId: 'key_funding_transfer_webhook',
25
+ environment: 'production',
26
+ id,
27
+ orgId,
28
+ projectId,
29
+ providerState: { privateRequestId: 'provider-private' },
30
+ snapshot: TestFunding.transferSnapshot(),
31
+ }),
32
+ )
33
+ const processing = await Transfer.transition(db, {
34
+ expectedVersion: created.record.version,
35
+ id,
36
+ status: 'processing',
37
+ })
38
+ if (processing.type !== 'applied') throw new Error('Expected processing transition.')
39
+ const completed = await Transfer.transition(db, {
40
+ expectedVersion: processing.record.version,
41
+ id,
42
+ status: 'completed',
43
+ })
44
+ if (completed.type !== 'applied') throw new Error('Expected completion transition.')
45
+
46
+ expect({
47
+ completed: completed.references.length,
48
+ created: created.references.length,
49
+ processing: processing.references.length,
50
+ }).toEqual({ completed: 2, created: 1, processing: 1 })
51
+
52
+ const rows = await db.kysely
53
+ .selectFrom('webhook_queue_events')
54
+ .select(['envelope', 'subscriptionId'])
55
+ .where('subscriptionId', 'in', [org.id, project.id])
56
+ .orderBy('subscriptionId')
57
+ .execute()
58
+ expect(
59
+ rows.map(({ envelope, subscriptionId }) => ({
60
+ data: envelope.data,
61
+ eventId: envelope.id,
62
+ subscriptionId,
63
+ type: envelope.type,
64
+ })),
65
+ ).toEqual(
66
+ expect.arrayContaining([
67
+ expect.objectContaining({
68
+ data: expect.objectContaining({ id, status: 'awaiting-source', version: 1 }),
69
+ subscriptionId: org.id,
70
+ type: 'funding:transfer.updated',
71
+ }),
72
+ expect.objectContaining({
73
+ data: expect.objectContaining({ id, status: 'processing', version: 2 }),
74
+ subscriptionId: org.id,
75
+ type: 'funding:transfer.updated',
76
+ }),
77
+ expect.objectContaining({
78
+ data: expect.objectContaining({ id, status: 'completed', version: 3 }),
79
+ subscriptionId: org.id,
80
+ type: 'funding:transfer.updated',
81
+ }),
82
+ expect.objectContaining({
83
+ data: expect.objectContaining({ id, status: 'completed', version: 3 }),
84
+ subscriptionId: project.id,
85
+ type: 'funding:transfer.updated',
86
+ }),
87
+ ]),
88
+ )
89
+ expect(rows).toHaveLength(4)
90
+ expect(rows[0]?.envelope.data).not.toHaveProperty('action')
91
+ expect(rows[0]?.envelope.data).not.toHaveProperty('providerState')
92
+
93
+ const events = await FundingTransferEvents.listByTransfer(db, id)
94
+ const repeated = await TransferWebhook.stage(db, {
95
+ changes: [{ event: events.at(-1)!, record: completed.record }],
96
+ })
97
+ expect(repeated.created).toBe(0)
98
+ expect(new Set(repeated.references.map((reference) => reference.eventId))).toEqual(
99
+ new Set([rows.find(({ subscriptionId }) => subscriptionId === project.id)?.envelope.id]),
100
+ )
101
+ })
102
+ })
103
+
104
+ function subscription(options: subscription.Options) {
105
+ return Webhooks.createSubscription(
106
+ db,
107
+ {
108
+ chainId: 4217,
109
+ destination: { type: 'url', url: 'https://example.com/webhooks/tempo' },
110
+ environment: options.environment ?? 'production',
111
+ eventType: 'funding:transfer.updated',
112
+ filters: options.filters,
113
+ owner: { orgId: options.orgId, type: 'api_key' },
114
+ ...(options.projectId === undefined ? {} : { projectId: options.projectId }),
115
+ },
116
+ options.now === undefined ? {} : { now: () => options.now! },
117
+ )
118
+ }
119
+
120
+ declare namespace subscription {
121
+ type Options = {
122
+ environment?: 'production' | 'sandbox' | undefined
123
+ filters: Record<string, unknown>
124
+ now?: Date | undefined
125
+ orgId: string
126
+ projectId?: string | undefined
127
+ }
128
+ }
@@ -0,0 +1,67 @@
1
+ import type * as Db from '../../db/Db.js'
2
+ import type * as FundingTransferEvents from '../../db/tables/fundingTransferEvents.js'
3
+ import type * as FundingTransfers from '../../db/tables/fundingTransfers.js'
4
+ import * as WebhookSubscriptions from '../../db/tables/webhookSubscriptions.js'
5
+ import * as Webhooks from '../Webhooks.js'
6
+
7
+ /** Stages durable webhook obligations for committed funding transfer versions. */
8
+ export async function stage(
9
+ db: Db.Db,
10
+ options: stage.Options,
11
+ ): Promise<Webhooks.ensureQueueEvents.Result> {
12
+ const dispatchables: Webhooks.ensureQueueEvents.Dispatchable[] = []
13
+ const now = new Date().toISOString()
14
+ for (const { event, record } of options.changes) {
15
+ const match = /^eip155:(\d+)$/.exec(event.snapshot.destinationChain.id)
16
+ if (!match?.[1]) continue
17
+ const chainId = Number(match[1])
18
+ if (!Number.isSafeInteger(chainId) || chainId <= 0) continue
19
+ const subscriptions = await WebhookSubscriptions.listActiveForFundingEvent(db, {
20
+ chainId,
21
+ environment: record.environment,
22
+ eventCreatedAt: event.createdAt,
23
+ eventType: 'funding:transfer.updated',
24
+ now,
25
+ orgId: record.orgId,
26
+ ...(record.projectId === null ? {} : { projectId: record.projectId }),
27
+ })
28
+ for (const subscription of subscriptions) {
29
+ if (
30
+ typeof subscription.filters['id'] === 'string' &&
31
+ subscription.filters['id'] !== event.transferId
32
+ )
33
+ continue
34
+ if (
35
+ typeof subscription.filters['status'] === 'string' &&
36
+ subscription.filters['status'] !== event.status
37
+ )
38
+ continue
39
+ dispatchables.push({
40
+ envelope: Webhooks.buildKeyedEnvelope({
41
+ createdAt: new Date(event.createdAt),
42
+ data: event.snapshot,
43
+ key: `${event.transferId}:${event.version}`,
44
+ subscription,
45
+ }),
46
+ subscription,
47
+ })
48
+ }
49
+ }
50
+ return Webhooks.ensureQueueEvents(db, dispatchables)
51
+ }
52
+
53
+ export declare namespace stage {
54
+ /** One committed transfer record and its immutable public event. */
55
+ type Change = {
56
+ /** Immutable public transfer version. */
57
+ event: FundingTransferEvents.Record
58
+ /** Transfer ownership and environment record. */
59
+ record: FundingTransfers.Record
60
+ }
61
+
62
+ /** Committed transfer changes eligible for customer webhook delivery. */
63
+ type Options = {
64
+ /** Transfer changes committed with their delivery obligations. */
65
+ changes: readonly Change[]
66
+ }
67
+ }
@@ -17,6 +17,7 @@ test('exports funding modules', () => {
17
17
  "Subsidy",
18
18
  "Token",
19
19
  "Transfer",
20
+ "TransferReconciliation",
20
21
  ]
21
22
  `)
22
23
  })
@@ -12,3 +12,4 @@ export * as SourceObservation from './SourceObservation.js'
12
12
  export * as Subsidy from './Subsidy.js'
13
13
  export * as Token from './Token.js'
14
14
  export * as Transfer from './Transfer.js'
15
+ export * as TransferReconciliation from './TransferReconciliation.js'