tapimo 0.7.1 → 0.8.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 (786) hide show
  1. package/README.md +10 -7
  2. package/dist/ApiKey.d.ts +3 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +10 -0
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +29 -8
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +24 -5
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +20680 -15487
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +250 -129
  13. package/dist/App.js.map +1 -1
  14. package/dist/Assets.d.ts +10 -0
  15. package/dist/Assets.d.ts.map +1 -1
  16. package/dist/Assets.js +17 -4
  17. package/dist/Assets.js.map +1 -1
  18. package/dist/Scope.d.ts +19 -8
  19. package/dist/Scope.d.ts.map +1 -1
  20. package/dist/Scope.js +25 -9
  21. package/dist/Scope.js.map +1 -1
  22. package/dist/Webhooks.d.ts +1 -1
  23. package/dist/admin/App.d.ts +667 -76
  24. package/dist/admin/App.d.ts.map +1 -1
  25. package/dist/admin/App.js +12 -2
  26. package/dist/admin/App.js.map +1 -1
  27. package/dist/admin/apps/api-keys.d.ts +107 -11
  28. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  29. package/dist/admin/apps/api-keys.js +145 -32
  30. package/dist/admin/apps/api-keys.js.map +1 -1
  31. package/dist/admin/apps/earn-vaults.d.ts +1069 -0
  32. package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
  33. package/dist/admin/apps/earn-vaults.js +409 -0
  34. package/dist/admin/apps/earn-vaults.js.map +1 -0
  35. package/dist/admin/apps/organizations.d.ts +2 -0
  36. package/dist/admin/apps/organizations.d.ts.map +1 -1
  37. package/dist/admin/apps/verified-tokens.d.ts +74 -74
  38. package/dist/admin/ui.generated.d.ts +1 -1
  39. package/dist/admin/ui.generated.d.ts.map +1 -1
  40. package/dist/admin/ui.generated.js +99 -43
  41. package/dist/admin/ui.generated.js.map +1 -1
  42. package/dist/analytics/Analytics.d.ts +4 -0
  43. package/dist/analytics/Analytics.d.ts.map +1 -1
  44. package/dist/analytics/Analytics.js +21 -2
  45. package/dist/analytics/Analytics.js.map +1 -1
  46. package/dist/analytics/tables/requestEvents.d.ts +22 -1
  47. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  48. package/dist/analytics/tables/requestEvents.js +59 -39
  49. package/dist/analytics/tables/requestEvents.js.map +1 -1
  50. package/dist/apps/Zones.d.ts +8335 -0
  51. package/dist/apps/Zones.d.ts.map +1 -0
  52. package/dist/apps/Zones.js +38 -0
  53. package/dist/apps/Zones.js.map +1 -0
  54. package/dist/apps/data/App.d.ts +5666 -3934
  55. package/dist/apps/data/App.d.ts.map +1 -1
  56. package/dist/apps/data/App.js +90 -22
  57. package/dist/apps/data/App.js.map +1 -1
  58. package/dist/apps/data/FxOracle.d.ts +1 -1
  59. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  60. package/dist/apps/data/index.d.ts +0 -1
  61. package/dist/apps/data/index.d.ts.map +1 -1
  62. package/dist/apps/data/index.js +0 -1
  63. package/dist/apps/data/index.js.map +1 -1
  64. package/dist/apps/data/routes/activities.d.ts +56 -56
  65. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  66. package/dist/apps/data/routes/activities.js +130 -65
  67. package/dist/apps/data/routes/activities.js.map +1 -1
  68. package/dist/apps/data/routes/addresses.d.ts +65 -65
  69. package/dist/apps/data/routes/balances.d.ts +14 -14
  70. package/dist/apps/data/routes/balances.js +5 -5
  71. package/dist/apps/data/routes/balances.js.map +1 -1
  72. package/dist/apps/data/routes/blocks.d.ts +39 -39
  73. package/dist/apps/data/routes/coingecko.d.ts +54 -54
  74. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  75. package/dist/apps/data/routes/coingecko.js +62 -35
  76. package/dist/apps/data/routes/coingecko.js.map +1 -1
  77. package/dist/apps/data/routes/earn.d.ts +2574 -0
  78. package/dist/apps/data/routes/earn.d.ts.map +1 -0
  79. package/dist/apps/data/routes/earn.js +1574 -0
  80. package/dist/apps/data/routes/earn.js.map +1 -0
  81. package/dist/apps/data/routes/exchanges.d.ts +1626 -719
  82. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  83. package/dist/apps/data/routes/exchanges.js +656 -193
  84. package/dist/apps/data/routes/exchanges.js.map +1 -1
  85. package/dist/apps/data/routes/fee-amm.d.ts +108 -108
  86. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  87. package/dist/apps/data/routes/fee-amm.js +59 -8
  88. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  89. package/dist/apps/data/routes/indexer.d.ts +35 -35
  90. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  91. package/dist/apps/data/routes/indexer.js +23 -3
  92. package/dist/apps/data/routes/indexer.js.map +1 -1
  93. package/dist/apps/data/routes/receipts.d.ts +33 -33
  94. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  95. package/dist/apps/data/routes/receipts.js +11 -11
  96. package/dist/apps/data/routes/receipts.js.map +1 -1
  97. package/dist/apps/data/routes/rpc.d.ts +6 -6
  98. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  99. package/dist/apps/data/routes/rpc.js +214 -22
  100. package/dist/apps/data/routes/rpc.js.map +1 -1
  101. package/dist/apps/data/routes/tokenlist.d.ts +1 -1
  102. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  103. package/dist/apps/data/routes/tokenlist.js +39 -8
  104. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  105. package/dist/apps/data/routes/tokens.d.ts +115 -87
  106. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  107. package/dist/apps/data/routes/tokens.js +194 -91
  108. package/dist/apps/data/routes/tokens.js.map +1 -1
  109. package/dist/apps/data/routes/transactions.d.ts +54 -54
  110. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  111. package/dist/apps/data/routes/transactions.js +78 -39
  112. package/dist/apps/data/routes/transactions.js.map +1 -1
  113. package/dist/apps/data/routes/transfers.d.ts +76 -27
  114. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  115. package/dist/apps/data/routes/transfers.js +165 -67
  116. package/dist/apps/data/routes/transfers.js.map +1 -1
  117. package/dist/apps/data/routes/valuation.d.ts +42 -42
  118. package/dist/apps/data/routes/valuation.js +2 -2
  119. package/dist/apps/data/routes/valuation.js.map +1 -1
  120. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  121. package/dist/apps/data/routes/webhooks.d.ts +370 -368
  122. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  123. package/dist/apps/data/routes/webhooks.js +161 -59
  124. package/dist/apps/data/routes/webhooks.js.map +1 -1
  125. package/dist/apps/data/routes/zones.d.ts +281 -0
  126. package/dist/apps/data/routes/zones.d.ts.map +1 -0
  127. package/dist/apps/data/routes/zones.js +252 -0
  128. package/dist/apps/data/routes/zones.js.map +1 -0
  129. package/dist/apps/docs/reference.js +6 -5
  130. package/dist/apps/docs/reference.js.map +1 -1
  131. package/dist/apps/funding/Access.d.ts +16 -0
  132. package/dist/apps/funding/Access.d.ts.map +1 -0
  133. package/dist/apps/funding/Access.js +22 -0
  134. package/dist/apps/funding/Access.js.map +1 -0
  135. package/dist/apps/funding/App.d.ts +3183 -0
  136. package/dist/apps/funding/App.d.ts.map +1 -0
  137. package/dist/apps/funding/App.js +46 -0
  138. package/dist/apps/funding/App.js.map +1 -0
  139. package/dist/apps/funding/Inventory.d.ts +5 -0
  140. package/dist/apps/funding/Inventory.d.ts.map +1 -0
  141. package/dist/apps/funding/Inventory.js +25 -0
  142. package/dist/apps/funding/Inventory.js.map +1 -0
  143. package/dist/apps/funding/ProviderAttempts.d.ts +5 -0
  144. package/dist/apps/funding/ProviderAttempts.d.ts.map +1 -0
  145. package/dist/apps/funding/ProviderAttempts.js +24 -0
  146. package/dist/apps/funding/ProviderAttempts.js.map +1 -0
  147. package/dist/apps/funding/index.d.ts +2 -0
  148. package/dist/apps/funding/index.d.ts.map +1 -0
  149. package/dist/apps/funding/index.js +2 -0
  150. package/dist/apps/funding/index.js.map +1 -0
  151. package/dist/apps/funding/routes/chains.d.ts +169 -0
  152. package/dist/apps/funding/routes/chains.d.ts.map +1 -0
  153. package/dist/apps/funding/routes/chains.js +80 -0
  154. package/dist/apps/funding/routes/chains.js.map +1 -0
  155. package/dist/apps/funding/routes/deposit-addresses.d.ts +2388 -0
  156. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -0
  157. package/dist/apps/funding/routes/deposit-addresses.js +860 -0
  158. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -0
  159. package/dist/apps/funding/routes/providers.d.ts +91 -0
  160. package/dist/apps/funding/routes/providers.d.ts.map +1 -0
  161. package/dist/apps/funding/routes/providers.js +56 -0
  162. package/dist/apps/funding/routes/providers.js.map +1 -0
  163. package/dist/apps/{data/routes/funding.d.ts → funding/routes/quotes.d.ts} +26 -396
  164. package/dist/apps/funding/routes/quotes.d.ts.map +1 -0
  165. package/dist/apps/funding/routes/quotes.js +188 -0
  166. package/dist/apps/funding/routes/quotes.js.map +1 -0
  167. package/dist/apps/funding/routes/transfers.d.ts +1999 -0
  168. package/dist/apps/funding/routes/transfers.d.ts.map +1 -0
  169. package/dist/apps/funding/routes/transfers.js +614 -0
  170. package/dist/apps/funding/routes/transfers.js.map +1 -0
  171. package/dist/apps/index.d.ts +3 -1
  172. package/dist/apps/index.d.ts.map +1 -1
  173. package/dist/apps/index.js +3 -1
  174. package/dist/apps/index.js.map +1 -1
  175. package/dist/apps/management/App.d.ts +839 -574
  176. package/dist/apps/management/App.d.ts.map +1 -1
  177. package/dist/apps/management/Billing.d.ts +8 -0
  178. package/dist/apps/management/Billing.d.ts.map +1 -1
  179. package/dist/apps/management/Billing.js +12 -0
  180. package/dist/apps/management/Billing.js.map +1 -1
  181. package/dist/apps/management/Error.d.ts +12 -0
  182. package/dist/apps/management/Error.d.ts.map +1 -0
  183. package/dist/apps/management/Error.js +10 -0
  184. package/dist/apps/management/Error.js.map +1 -0
  185. package/dist/apps/management/routes/api-keys.d.ts +296 -19
  186. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  187. package/dist/apps/management/routes/api-keys.js +77 -9
  188. package/dist/apps/management/routes/api-keys.js.map +1 -1
  189. package/dist/apps/management/routes/billing.d.ts +119 -119
  190. package/dist/apps/management/routes/faucet.d.ts +35 -35
  191. package/dist/apps/management/routes/invitations.d.ts +17 -17
  192. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  193. package/dist/apps/management/routes/invitations.js +4 -10
  194. package/dist/apps/management/routes/invitations.js.map +1 -1
  195. package/dist/apps/management/routes/invite-links.d.ts +38 -38
  196. package/dist/apps/management/routes/me.d.ts +6 -6
  197. package/dist/apps/management/routes/members.d.ts +69 -69
  198. package/dist/apps/management/routes/orgs.d.ts +16 -16
  199. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  200. package/dist/apps/management/routes/orgs.js +2 -8
  201. package/dist/apps/management/routes/orgs.js.map +1 -1
  202. package/dist/apps/management/routes/projects.d.ts +19 -19
  203. package/dist/apps/management/routes/scopes.d.ts +1 -1
  204. package/dist/apps/management/routes/scopes.js +2 -2
  205. package/dist/apps/management/routes/scopes.js.map +1 -1
  206. package/dist/apps/management/routes/usage.d.ts +72 -72
  207. package/dist/apps/management/routes/verified-token-requests.d.ts +18 -18
  208. package/dist/apps/management/routes/webhooks.d.ts +122 -122
  209. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  210. package/dist/apps/management/routes/webhooks.js +15 -3
  211. package/dist/apps/management/routes/webhooks.js.map +1 -1
  212. package/dist/apps/mcp.d.ts +2 -3
  213. package/dist/apps/mcp.d.ts.map +1 -1
  214. package/dist/apps/mcp.js +16 -14
  215. package/dist/apps/mcp.js.map +1 -1
  216. package/dist/apps/metadata.d.ts +4 -0
  217. package/dist/apps/metadata.d.ts.map +1 -1
  218. package/dist/apps/metadata.js +10 -0
  219. package/dist/apps/metadata.js.map +1 -1
  220. package/dist/apps/mpp/App.d.ts +57 -58
  221. package/dist/apps/mpp/App.d.ts.map +1 -1
  222. package/dist/apps/mpp/App.js +192 -27
  223. package/dist/apps/mpp/App.js.map +1 -1
  224. package/dist/apps/mpp/Mpp.d.ts +0 -20
  225. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  226. package/dist/apps/mpp/Mpp.js +0 -24
  227. package/dist/apps/mpp/Mpp.js.map +1 -1
  228. package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
  229. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
  230. package/dist/apps/mpp/internal/Adapter.js +66 -0
  231. package/dist/apps/mpp/internal/Adapter.js.map +1 -0
  232. package/dist/apps/mpp/internal/Error.d.ts +4 -0
  233. package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
  234. package/dist/apps/mpp/internal/Error.js +41 -0
  235. package/dist/apps/mpp/internal/Error.js.map +1 -0
  236. package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
  237. package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
  238. package/dist/apps/mpp/internal/Idempotency.js +28 -0
  239. package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
  240. package/dist/apps/mpp/internal/Policy.d.ts +46 -0
  241. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
  242. package/dist/apps/mpp/internal/Policy.js +57 -0
  243. package/dist/apps/mpp/internal/Policy.js.map +1 -0
  244. package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
  245. package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
  246. package/dist/apps/mpp/internal/ScreenManager.js +18 -0
  247. package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
  248. package/dist/apps/mpp/internal/Screening.d.ts +35 -0
  249. package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
  250. package/dist/apps/mpp/internal/Screening.js +20 -0
  251. package/dist/apps/mpp/internal/Screening.js.map +1 -0
  252. package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
  253. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
  254. package/dist/apps/mpp/internal/Sponsorship.js +103 -0
  255. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
  256. package/dist/apps/mpp/internal/Utils.d.ts +7 -0
  257. package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
  258. package/dist/apps/mpp/internal/Utils.js +24 -0
  259. package/dist/apps/mpp/internal/Utils.js.map +1 -0
  260. package/dist/apps/relay/App.js +183 -23
  261. package/dist/apps/relay/App.js.map +1 -1
  262. package/dist/apps/relay/Sponsorships.d.ts +4 -0
  263. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  264. package/dist/apps/relay/Sponsorships.js +15 -6
  265. package/dist/apps/relay/Sponsorships.js.map +1 -1
  266. package/dist/cloudflare.d.ts +50 -0
  267. package/dist/cloudflare.d.ts.map +1 -1
  268. package/dist/cloudflare.js +178 -0
  269. package/dist/cloudflare.js.map +1 -1
  270. package/dist/db/Db.d.ts +22 -0
  271. package/dist/db/Db.d.ts.map +1 -1
  272. package/dist/db/Db.js +379 -0
  273. package/dist/db/Db.js.map +1 -1
  274. package/dist/db/Schema.d.ts +933 -1
  275. package/dist/db/Schema.d.ts.map +1 -1
  276. package/dist/db/Schema.js +289 -1
  277. package/dist/db/Schema.js.map +1 -1
  278. package/dist/db/tables/earnVaults.d.ts +68 -0
  279. package/dist/db/tables/earnVaults.d.ts.map +1 -0
  280. package/dist/db/tables/earnVaults.js +72 -0
  281. package/dist/db/tables/earnVaults.js.map +1 -0
  282. package/dist/db/tables/fundingCatalog.d.ts +56 -0
  283. package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
  284. package/dist/db/tables/fundingCatalog.js +85 -0
  285. package/dist/db/tables/fundingCatalog.js.map +1 -0
  286. package/dist/db/tables/fundingDepositAddresses.d.ts +172 -0
  287. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
  288. package/dist/db/tables/fundingDepositAddresses.js +218 -0
  289. package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
  290. package/dist/db/tables/fundingDepositRequestObservations.d.ts +45 -0
  291. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +1 -0
  292. package/dist/db/tables/fundingDepositRequestObservations.js +46 -0
  293. package/dist/db/tables/fundingDepositRequestObservations.js.map +1 -0
  294. package/dist/db/tables/fundingDeposits.d.ts +171 -0
  295. package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
  296. package/dist/db/tables/fundingDeposits.js +182 -0
  297. package/dist/db/tables/fundingDeposits.js.map +1 -0
  298. package/dist/db/tables/fundingIdempotency.d.ts +91 -0
  299. package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
  300. package/dist/db/tables/fundingIdempotency.js +103 -0
  301. package/dist/db/tables/fundingIdempotency.js.map +1 -0
  302. package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
  303. package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
  304. package/dist/db/tables/fundingTransferEvents.js +18 -0
  305. package/dist/db/tables/fundingTransferEvents.js.map +1 -0
  306. package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
  307. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
  308. package/dist/db/tables/fundingTransferTransactions.js +27 -0
  309. package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
  310. package/dist/db/tables/fundingTransfers.d.ts +82 -0
  311. package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
  312. package/dist/db/tables/fundingTransfers.js +89 -0
  313. package/dist/db/tables/fundingTransfers.js.map +1 -0
  314. package/dist/db/tables/organizations.d.ts +8 -0
  315. package/dist/db/tables/organizations.d.ts.map +1 -1
  316. package/dist/db/tables/organizations.js +16 -0
  317. package/dist/db/tables/organizations.js.map +1 -1
  318. package/dist/db/tables/projects.d.ts +8 -0
  319. package/dist/db/tables/projects.d.ts.map +1 -1
  320. package/dist/db/tables/projects.js +16 -0
  321. package/dist/db/tables/projects.js.map +1 -1
  322. package/dist/db/tables/requestUsage.d.ts +13 -0
  323. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  324. package/dist/db/tables/requestUsage.js +16 -0
  325. package/dist/db/tables/requestUsage.js.map +1 -1
  326. package/dist/db/tables/sponsoredTransactions.d.ts +2 -2
  327. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  328. package/dist/db/tables/sponsoredTransactions.js +1 -1
  329. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  330. package/dist/db/tables/users.d.ts +8 -0
  331. package/dist/db/tables/users.d.ts.map +1 -1
  332. package/dist/db/tables/users.js +16 -0
  333. package/dist/db/tables/users.js.map +1 -1
  334. package/dist/db/tables/verifiedTokens.d.ts +14 -7
  335. package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
  336. package/dist/db/tables/verifiedTokens.js +9 -7
  337. package/dist/db/tables/verifiedTokens.js.map +1 -1
  338. package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
  339. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  340. package/dist/db/tables/webhookSubscriptions.js +24 -3
  341. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  342. package/dist/handlers/relay.js +108 -108
  343. package/dist/handlers/relay.js.map +1 -1
  344. package/dist/internal/Auth.d.ts +37 -11
  345. package/dist/internal/Auth.d.ts.map +1 -1
  346. package/dist/internal/Auth.js +75 -16
  347. package/dist/internal/Auth.js.map +1 -1
  348. package/dist/internal/Cache.d.ts.map +1 -1
  349. package/dist/internal/Cache.js +17 -11
  350. package/dist/internal/Cache.js.map +1 -1
  351. package/dist/internal/Cursor.js +1 -1
  352. package/dist/internal/Cursor.js.map +1 -1
  353. package/dist/internal/EarnRates.d.ts +89 -0
  354. package/dist/internal/EarnRates.d.ts.map +1 -0
  355. package/dist/internal/EarnRates.js +266 -0
  356. package/dist/internal/EarnRates.js.map +1 -0
  357. package/dist/internal/EarnVaults.d.ts +171 -0
  358. package/dist/internal/EarnVaults.d.ts.map +1 -0
  359. package/dist/internal/EarnVaults.js +547 -0
  360. package/dist/internal/EarnVaults.js.map +1 -0
  361. package/dist/internal/EdgeCache.d.ts +10 -3
  362. package/dist/internal/EdgeCache.d.ts.map +1 -1
  363. package/dist/internal/EdgeCache.js +43 -11
  364. package/dist/internal/EdgeCache.js.map +1 -1
  365. package/dist/internal/Id.d.ts +11 -0
  366. package/dist/internal/Id.d.ts.map +1 -1
  367. package/dist/internal/Id.js +13 -0
  368. package/dist/internal/Id.js.map +1 -1
  369. package/dist/internal/Idempotency.d.ts +83 -0
  370. package/dist/internal/Idempotency.d.ts.map +1 -0
  371. package/dist/internal/Idempotency.js +113 -0
  372. package/dist/internal/Idempotency.js.map +1 -0
  373. package/dist/internal/IpAllowlist.d.ts +15 -0
  374. package/dist/internal/IpAllowlist.d.ts.map +1 -0
  375. package/dist/internal/IpAllowlist.js +27 -0
  376. package/dist/internal/IpAllowlist.js.map +1 -0
  377. package/dist/internal/Log.d.ts +64 -9
  378. package/dist/internal/Log.d.ts.map +1 -1
  379. package/dist/internal/Log.js +29 -7
  380. package/dist/internal/Log.js.map +1 -1
  381. package/dist/internal/MetricSink.d.ts.map +1 -1
  382. package/dist/internal/MetricSink.js +47 -1
  383. package/dist/internal/MetricSink.js.map +1 -1
  384. package/dist/internal/OpenApi.d.ts +2 -2
  385. package/dist/internal/OpenApi.d.ts.map +1 -1
  386. package/dist/internal/OpenApi.js +4 -1
  387. package/dist/internal/OpenApi.js.map +1 -1
  388. package/dist/internal/Provider.d.ts +14 -0
  389. package/dist/internal/Provider.d.ts.map +1 -0
  390. package/dist/internal/Provider.js +5 -0
  391. package/dist/internal/Provider.js.map +1 -0
  392. package/dist/internal/Schema.d.ts +6 -1
  393. package/dist/internal/Schema.d.ts.map +1 -1
  394. package/dist/internal/Schema.js +20 -11
  395. package/dist/internal/Schema.js.map +1 -1
  396. package/dist/internal/Store.d.ts +6 -0
  397. package/dist/internal/Store.d.ts.map +1 -1
  398. package/dist/internal/Store.js +35 -0
  399. package/dist/internal/Store.js.map +1 -1
  400. package/dist/internal/Tidx.d.ts +49 -24
  401. package/dist/internal/Tidx.d.ts.map +1 -1
  402. package/dist/internal/Tidx.js +90 -12
  403. package/dist/internal/Tidx.js.map +1 -1
  404. package/dist/internal/Viem.d.ts +90 -65
  405. package/dist/internal/Viem.d.ts.map +1 -1
  406. package/dist/internal/Viem.js +90 -12
  407. package/dist/internal/Viem.js.map +1 -1
  408. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  409. package/dist/internal/WebhookDestination.js +34 -28
  410. package/dist/internal/WebhookDestination.js.map +1 -1
  411. package/dist/internal/Webhooks.d.ts +9 -0
  412. package/dist/internal/Webhooks.d.ts.map +1 -1
  413. package/dist/internal/Webhooks.js +15 -10
  414. package/dist/internal/Webhooks.js.map +1 -1
  415. package/dist/internal/exchange/Provider.d.ts +219 -0
  416. package/dist/internal/exchange/Provider.d.ts.map +1 -0
  417. package/dist/internal/exchange/Provider.js +117 -0
  418. package/dist/internal/exchange/Provider.js.map +1 -0
  419. package/dist/internal/exchange/index.d.ts +2 -0
  420. package/dist/internal/exchange/index.d.ts.map +1 -0
  421. package/dist/internal/exchange/index.js +2 -0
  422. package/dist/internal/exchange/index.js.map +1 -0
  423. package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
  424. package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
  425. package/dist/internal/exchange/providers/uniswap.js +553 -0
  426. package/dist/internal/exchange/providers/uniswap.js.map +1 -0
  427. package/dist/internal/funding/Action.d.ts +55 -0
  428. package/dist/internal/funding/Action.d.ts.map +1 -0
  429. package/dist/internal/funding/Action.js +74 -0
  430. package/dist/internal/funding/Action.js.map +1 -0
  431. package/dist/internal/funding/Catalog.d.ts +107 -0
  432. package/dist/internal/funding/Catalog.d.ts.map +1 -0
  433. package/dist/internal/funding/Catalog.js +270 -0
  434. package/dist/internal/funding/Catalog.js.map +1 -0
  435. package/dist/internal/funding/Chain.d.ts +76 -0
  436. package/dist/internal/funding/Chain.d.ts.map +1 -0
  437. package/dist/internal/funding/Chain.js +38 -0
  438. package/dist/internal/funding/Chain.js.map +1 -0
  439. package/dist/internal/funding/Deposit.d.ts +408 -0
  440. package/dist/internal/funding/Deposit.d.ts.map +1 -0
  441. package/dist/internal/funding/Deposit.js +318 -0
  442. package/dist/internal/funding/Deposit.js.map +1 -0
  443. package/dist/internal/funding/DepositAddress.d.ts +345 -0
  444. package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
  445. package/dist/internal/funding/DepositAddress.js +189 -0
  446. package/dist/internal/funding/DepositAddress.js.map +1 -0
  447. package/dist/internal/funding/Evidence.d.ts +48 -0
  448. package/dist/internal/funding/Evidence.d.ts.map +1 -0
  449. package/dist/internal/funding/Evidence.js +315 -0
  450. package/dist/internal/funding/Evidence.js.map +1 -0
  451. package/dist/internal/funding/Provider.d.ts +1288 -0
  452. package/dist/internal/funding/Provider.d.ts.map +1 -0
  453. package/dist/internal/funding/Provider.js +1086 -0
  454. package/dist/internal/funding/Provider.js.map +1 -0
  455. package/dist/internal/funding/Reconciliation.d.ts +127 -0
  456. package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
  457. package/dist/internal/funding/Reconciliation.js +885 -0
  458. package/dist/internal/funding/Reconciliation.js.map +1 -0
  459. package/dist/internal/funding/Route.d.ts +21 -0
  460. package/dist/internal/funding/Route.d.ts.map +1 -0
  461. package/dist/internal/funding/Route.js +5 -0
  462. package/dist/internal/funding/Route.js.map +1 -0
  463. package/dist/internal/funding/SourceObservation.d.ts +108 -0
  464. package/dist/internal/funding/SourceObservation.d.ts.map +1 -0
  465. package/dist/internal/funding/SourceObservation.js +143 -0
  466. package/dist/internal/funding/SourceObservation.js.map +1 -0
  467. package/dist/internal/funding/Subsidy.d.ts +113 -0
  468. package/dist/internal/funding/Subsidy.d.ts.map +1 -0
  469. package/dist/internal/funding/Subsidy.js +138 -0
  470. package/dist/internal/funding/Subsidy.js.map +1 -0
  471. package/dist/internal/funding/Token.d.ts +41 -0
  472. package/dist/internal/funding/Token.d.ts.map +1 -0
  473. package/dist/internal/funding/Token.js +22 -0
  474. package/dist/internal/funding/Token.js.map +1 -0
  475. package/dist/internal/funding/Transfer.d.ts +643 -0
  476. package/dist/internal/funding/Transfer.d.ts.map +1 -0
  477. package/dist/internal/funding/Transfer.js +332 -0
  478. package/dist/internal/funding/Transfer.js.map +1 -0
  479. package/dist/internal/funding/index.d.ts +14 -0
  480. package/dist/internal/funding/index.d.ts.map +1 -0
  481. package/dist/internal/funding/index.js +14 -0
  482. package/dist/internal/funding/index.js.map +1 -0
  483. package/dist/internal/funding/providers/across.d.ts +21 -0
  484. package/dist/internal/funding/providers/across.d.ts.map +1 -0
  485. package/dist/internal/funding/providers/across.js +117 -0
  486. package/dist/internal/funding/providers/across.js.map +1 -0
  487. package/dist/internal/funding/providers/relay.d.ts +88 -0
  488. package/dist/internal/funding/providers/relay.d.ts.map +1 -0
  489. package/dist/internal/funding/providers/relay.js +871 -0
  490. package/dist/internal/funding/providers/relay.js.map +1 -0
  491. package/dist/internal/funding/providers/rhino.d.ts +15 -0
  492. package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
  493. package/dist/internal/funding/providers/rhino.js +116 -0
  494. package/dist/internal/funding/providers/rhino.js.map +1 -0
  495. package/dist/internal/funding/providers/squid.d.ts +19 -0
  496. package/dist/internal/funding/providers/squid.d.ts.map +1 -0
  497. package/dist/internal/funding/providers/squid.js +120 -0
  498. package/dist/internal/funding/providers/squid.js.map +1 -0
  499. package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
  500. package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
  501. package/dist/internal/funding/providers/symbiosis.js +176 -0
  502. package/dist/internal/funding/providers/symbiosis.js.map +1 -0
  503. package/dist/internal/index.d.ts +5 -1
  504. package/dist/internal/index.d.ts.map +1 -1
  505. package/dist/internal/index.js +5 -1
  506. package/dist/internal/index.js.map +1 -1
  507. package/dist/internal/webhookDestinations/url.js +61 -57
  508. package/dist/internal/webhookDestinations/url.js.map +1 -1
  509. package/dist/providers/index.d.ts +43 -0
  510. package/dist/providers/index.d.ts.map +1 -0
  511. package/dist/providers/index.js +19 -0
  512. package/dist/providers/index.js.map +1 -0
  513. package/package.json +10 -5
  514. package/src/ApiKey.test.ts +35 -0
  515. package/src/ApiKey.ts +27 -0
  516. package/src/ApiKeys.test.ts +40 -7
  517. package/src/ApiKeys.ts +46 -10
  518. package/src/App.test.ts +108 -15
  519. package/src/App.ts +296 -138
  520. package/src/Assets.ts +29 -4
  521. package/src/Client.test-d.ts +809 -37
  522. package/src/Scope.test.ts +19 -0
  523. package/src/Scope.ts +28 -11
  524. package/src/Webhooks.test.ts +25 -0
  525. package/src/Webhooks.ts +1 -1
  526. package/src/admin/App.test.ts +9 -2
  527. package/src/admin/App.ts +32 -9
  528. package/src/admin/apps/api-keys.test.ts +190 -22
  529. package/src/admin/apps/api-keys.ts +170 -28
  530. package/src/admin/apps/earn-vaults.test.ts +338 -0
  531. package/src/admin/apps/earn-vaults.ts +572 -0
  532. package/src/admin/apps/scopes.test.ts +16 -1
  533. package/src/admin/ui/plugin.ts +2 -2
  534. package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
  535. package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
  536. package/src/admin/ui/src/components/Page.tsx +1 -1
  537. package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
  538. package/src/admin/ui/src/lib/api-keys.ts +37 -7
  539. package/src/admin/ui/src/lib/client.ts +1 -1
  540. package/src/admin/ui/src/lib/config.ts +1 -1
  541. package/src/admin/ui/src/lib/early-access.ts +8 -9
  542. package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
  543. package/src/admin/ui/src/lib/format.ts +13 -0
  544. package/src/admin/ui/src/lib/organizations.test.ts +14 -4
  545. package/src/admin/ui/src/lib/organizations.ts +7 -1
  546. package/src/admin/ui/src/lib/response.ts +22 -0
  547. package/src/admin/ui/src/lib/scopes.test.ts +19 -11
  548. package/src/admin/ui/src/lib/scopes.ts +28 -7
  549. package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
  550. package/src/admin/ui/src/routeTree.gen.ts +70 -7
  551. package/src/admin/ui/src/router.tsx +2 -2
  552. package/src/admin/ui/src/routes/__root.tsx +9 -8
  553. package/src/admin/ui/src/routes/api-keys.tsx +475 -64
  554. package/src/admin/ui/src/routes/early-access.tsx +5 -12
  555. package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
  556. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
  557. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
  558. package/src/admin/ui/src/routes/organizations.tsx +4 -7
  559. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
  560. package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
  561. package/src/admin/ui/vite.config.ts +4 -1
  562. package/src/admin/ui.generated.ts +113 -43
  563. package/src/analytics/Analytics.test.ts +69 -10
  564. package/src/analytics/Analytics.ts +24 -1
  565. package/src/analytics/tables/requestEvents.ts +79 -37
  566. package/src/apps/Zones.test.ts +33 -0
  567. package/src/apps/Zones.ts +40 -0
  568. package/src/apps/composition.test.ts +184 -3
  569. package/src/apps/data/App.test.ts +28 -23
  570. package/src/apps/data/App.ts +95 -36
  571. package/src/apps/data/FxOracle.ts +1 -1
  572. package/src/apps/data/index.ts +0 -1
  573. package/src/apps/data/routes/activities.test.ts +82 -6
  574. package/src/apps/data/routes/activities.ts +131 -71
  575. package/src/apps/data/routes/balances.test.ts +50 -37
  576. package/src/apps/data/routes/balances.ts +5 -5
  577. package/src/apps/data/routes/blocks.test.ts +2 -0
  578. package/src/apps/data/routes/coingecko.test.ts +22 -0
  579. package/src/apps/data/routes/coingecko.ts +84 -48
  580. package/src/apps/data/routes/earn.test.ts +1391 -0
  581. package/src/apps/data/routes/earn.ts +2188 -0
  582. package/src/apps/data/routes/exchanges.test.ts +82 -33
  583. package/src/apps/data/routes/exchanges.ts +842 -227
  584. package/src/apps/data/routes/fee-amm.test.ts +4 -6
  585. package/src/apps/data/routes/fee-amm.ts +69 -12
  586. package/src/apps/data/routes/indexer.test.ts +43 -34
  587. package/src/apps/data/routes/indexer.ts +21 -3
  588. package/src/apps/data/routes/receipts.test.ts +5 -3
  589. package/src/apps/data/routes/receipts.ts +13 -11
  590. package/src/apps/data/routes/rpc.test.ts +446 -28
  591. package/src/apps/data/routes/rpc.ts +245 -25
  592. package/src/apps/data/routes/tokenlist.ts +72 -19
  593. package/src/apps/data/routes/tokens.test.ts +6 -8
  594. package/src/apps/data/routes/tokens.ts +258 -86
  595. package/src/apps/data/routes/transactions.test.ts +2 -0
  596. package/src/apps/data/routes/transactions.ts +77 -42
  597. package/src/apps/data/routes/transfers.test.ts +166 -4
  598. package/src/apps/data/routes/transfers.ts +216 -78
  599. package/src/apps/data/routes/valuation.test.ts +62 -9
  600. package/src/apps/data/routes/valuation.ts +2 -2
  601. package/src/apps/data/routes/webhooks.test.ts +386 -43
  602. package/src/apps/data/routes/webhooks.ts +172 -71
  603. package/src/apps/data/routes/zones.test.ts +473 -0
  604. package/src/apps/data/routes/zones.ts +338 -0
  605. package/src/apps/docs/reference.ts +8 -6
  606. package/src/apps/funding/Access.ts +26 -0
  607. package/src/apps/funding/App.test.ts +78 -0
  608. package/src/apps/funding/App.ts +63 -0
  609. package/src/apps/funding/Inventory.ts +30 -0
  610. package/src/apps/funding/ProviderAttempts.ts +26 -0
  611. package/src/apps/funding/index.ts +1 -0
  612. package/src/apps/funding/routes/chains.test.ts +78 -0
  613. package/src/apps/funding/routes/chains.ts +101 -0
  614. package/src/apps/funding/routes/deposit-addresses.test.ts +1628 -0
  615. package/src/apps/funding/routes/deposit-addresses.ts +1015 -0
  616. package/src/apps/funding/routes/providers.test.ts +165 -0
  617. package/src/apps/funding/routes/providers.ts +73 -0
  618. package/src/apps/funding/routes/quotes.test.ts +511 -0
  619. package/src/apps/funding/routes/quotes.ts +205 -0
  620. package/src/apps/funding/routes/transfers.test.ts +1255 -0
  621. package/src/apps/funding/routes/transfers.ts +704 -0
  622. package/src/apps/index.ts +3 -1
  623. package/src/apps/management/Billing.test.ts +29 -0
  624. package/src/apps/management/Billing.ts +23 -0
  625. package/src/apps/management/Error.ts +12 -0
  626. package/src/apps/management/routes/api-keys.test.ts +103 -3
  627. package/src/apps/management/routes/api-keys.ts +98 -10
  628. package/src/apps/management/routes/invitations.ts +4 -11
  629. package/src/apps/management/routes/orgs.ts +2 -9
  630. package/src/apps/management/routes/scopes.test.ts +7 -2
  631. package/src/apps/management/routes/scopes.ts +2 -2
  632. package/src/apps/management/routes/webhooks.test.ts +6 -1
  633. package/src/apps/management/routes/webhooks.ts +15 -3
  634. package/src/apps/mcp.test.ts +17 -2
  635. package/src/apps/mcp.ts +18 -13
  636. package/src/apps/metadata.ts +12 -0
  637. package/src/apps/mpp/App.ts +276 -29
  638. package/src/apps/mpp/Mpp.test.ts +631 -26
  639. package/src/apps/mpp/Mpp.ts +0 -42
  640. package/src/apps/mpp/internal/Adapter.ts +108 -3
  641. package/src/apps/mpp/internal/Error.test.ts +33 -0
  642. package/src/apps/mpp/internal/Error.ts +44 -6
  643. package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
  644. package/src/apps/mpp/internal/Idempotency.ts +59 -5
  645. package/src/apps/mpp/internal/Policy.test.ts +128 -0
  646. package/src/apps/mpp/internal/Policy.ts +98 -0
  647. package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
  648. package/src/apps/mpp/internal/ScreenManager.ts +41 -0
  649. package/src/apps/mpp/internal/Screening.ts +40 -3
  650. package/src/apps/mpp/internal/Sponsorship.ts +144 -0
  651. package/src/apps/mpp/internal/Utils.ts +30 -0
  652. package/src/apps/relay/App.test.ts +493 -62
  653. package/src/apps/relay/App.ts +233 -23
  654. package/src/apps/relay/Sponsorships.test.ts +49 -0
  655. package/src/apps/relay/Sponsorships.ts +18 -6
  656. package/src/cloudflare.ts +279 -0
  657. package/src/db/Db.ts +501 -0
  658. package/src/db/Schema.ts +349 -2
  659. package/src/db/tables/earnVaults.test.ts +185 -0
  660. package/src/db/tables/earnVaults.ts +151 -0
  661. package/src/db/tables/fundingCatalog.test.ts +108 -0
  662. package/src/db/tables/fundingCatalog.ts +157 -0
  663. package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
  664. package/src/db/tables/fundingDepositAddresses.ts +404 -0
  665. package/src/db/tables/fundingDepositRequestObservations.test.ts +106 -0
  666. package/src/db/tables/fundingDepositRequestObservations.ts +99 -0
  667. package/src/db/tables/fundingDeposits.test.ts +399 -0
  668. package/src/db/tables/fundingDeposits.ts +373 -0
  669. package/src/db/tables/fundingIdempotency.test.ts +182 -0
  670. package/src/db/tables/fundingIdempotency.ts +180 -0
  671. package/src/db/tables/fundingTransferEvents.ts +28 -0
  672. package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
  673. package/src/db/tables/fundingTransferTransactions.ts +37 -0
  674. package/src/db/tables/fundingTransfers.test.ts +89 -0
  675. package/src/db/tables/fundingTransfers.ts +153 -0
  676. package/src/db/tables/organizations.ts +16 -0
  677. package/src/db/tables/projects.ts +16 -0
  678. package/src/db/tables/requestUsage.ts +23 -0
  679. package/src/db/tables/sponsoredTransactions.test.ts +11 -0
  680. package/src/db/tables/sponsoredTransactions.ts +3 -3
  681. package/src/db/tables/users.ts +16 -0
  682. package/src/db/tables/verifiedTokens.ts +19 -14
  683. package/src/db/tables/webhookSubscriptions.ts +58 -3
  684. package/src/handlers/relay.test.ts +2 -0
  685. package/src/handlers/relay.ts +95 -99
  686. package/src/internal/Auth.test.ts +225 -5
  687. package/src/internal/Auth.ts +109 -20
  688. package/src/internal/Cache.test.ts +37 -3
  689. package/src/internal/Cache.ts +14 -10
  690. package/src/internal/Cursor.test.ts +2 -2
  691. package/src/internal/Cursor.ts +1 -1
  692. package/src/internal/EarnRates.test.ts +125 -0
  693. package/src/internal/EarnRates.ts +409 -0
  694. package/src/internal/EarnVaults.test.ts +195 -0
  695. package/src/internal/EarnVaults.ts +876 -0
  696. package/src/internal/EdgeCache.test.ts +26 -7
  697. package/src/internal/EdgeCache.ts +48 -9
  698. package/src/internal/Id.ts +14 -0
  699. package/src/internal/Idempotency.test.ts +109 -0
  700. package/src/internal/Idempotency.ts +237 -0
  701. package/src/internal/IpAllowlist.test.ts +52 -0
  702. package/src/internal/IpAllowlist.ts +39 -0
  703. package/src/internal/Log.test-d.ts +41 -8
  704. package/src/internal/Log.test.ts +196 -9
  705. package/src/internal/Log.ts +124 -17
  706. package/src/internal/MetricSink.test.ts +244 -4
  707. package/src/internal/MetricSink.ts +51 -1
  708. package/src/internal/OpenApi.ts +4 -1
  709. package/src/internal/Provider.test.ts +17 -0
  710. package/src/internal/Provider.ts +17 -0
  711. package/src/internal/Schema.ts +27 -17
  712. package/src/internal/Store.test.ts +25 -0
  713. package/src/internal/Store.ts +46 -0
  714. package/src/internal/Tidx.local.test.ts +78 -3
  715. package/src/internal/Tidx.test.ts +240 -18
  716. package/src/internal/Tidx.ts +129 -33
  717. package/src/internal/VerifiedTokens.test.ts +15 -0
  718. package/src/internal/Viem.test.ts +198 -17
  719. package/src/internal/Viem.ts +127 -28
  720. package/src/internal/WebhookDestination.ts +25 -23
  721. package/src/internal/Webhooks.test.ts +59 -0
  722. package/src/internal/Webhooks.ts +34 -10
  723. package/src/internal/exchange/Provider.test.ts +216 -0
  724. package/src/internal/exchange/Provider.ts +326 -0
  725. package/src/internal/exchange/index.test.ts +6 -0
  726. package/src/internal/exchange/index.ts +1 -0
  727. package/src/internal/exchange/providers/uniswap.test.ts +122 -0
  728. package/src/internal/exchange/providers/uniswap.ts +682 -0
  729. package/src/internal/funding/Action.test.ts +138 -0
  730. package/src/internal/funding/Action.ts +117 -0
  731. package/src/internal/funding/Catalog.test.ts +311 -0
  732. package/src/internal/funding/Catalog.ts +347 -0
  733. package/src/internal/funding/Chain.test.ts +79 -0
  734. package/src/internal/funding/Chain.ts +120 -0
  735. package/src/internal/funding/Deposit.test.ts +26 -0
  736. package/src/internal/funding/Deposit.ts +522 -0
  737. package/src/internal/funding/DepositAddress.test.ts +18 -0
  738. package/src/internal/funding/DepositAddress.ts +312 -0
  739. package/src/internal/funding/Evidence.test.ts +297 -0
  740. package/src/internal/funding/Evidence.ts +425 -0
  741. package/src/internal/funding/Provider.test.ts +1328 -0
  742. package/src/internal/funding/Provider.ts +1911 -0
  743. package/src/internal/funding/Reconciliation.local.test.ts +511 -0
  744. package/src/internal/funding/Reconciliation.test.ts +3037 -0
  745. package/src/internal/funding/Reconciliation.ts +1202 -0
  746. package/src/internal/funding/Route.test.ts +66 -0
  747. package/src/internal/funding/Route.ts +29 -0
  748. package/src/internal/funding/SourceObservation.test.ts +301 -0
  749. package/src/internal/funding/SourceObservation.ts +267 -0
  750. package/src/internal/funding/Subsidy.local.test.ts +152 -0
  751. package/src/internal/funding/Subsidy.test.ts +75 -0
  752. package/src/internal/funding/Subsidy.ts +260 -0
  753. package/src/internal/funding/Token.test.ts +47 -0
  754. package/src/internal/funding/Token.ts +59 -0
  755. package/src/internal/funding/Transfer.test.ts +369 -0
  756. package/src/internal/funding/Transfer.ts +522 -0
  757. package/src/internal/funding/index.test.ts +21 -0
  758. package/src/internal/funding/index.ts +13 -0
  759. package/src/internal/funding/providers/across.ts +149 -0
  760. package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
  761. package/src/internal/funding/providers/relay.test.ts +564 -0
  762. package/src/internal/funding/providers/relay.ts +1060 -0
  763. package/src/internal/funding/providers/rhino.ts +139 -0
  764. package/src/internal/funding/providers/squid.ts +151 -0
  765. package/src/internal/funding/providers/symbiosis.ts +221 -0
  766. package/src/internal/index.test.ts +5 -1
  767. package/src/internal/index.ts +5 -1
  768. package/src/internal/webhookDestinations/url.ts +49 -45
  769. package/src/providers/index.test.ts +14 -0
  770. package/src/providers/index.ts +54 -0
  771. package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
  772. package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
  773. package/dist/apps/data/FundingQuoteProviders.js +0 -775
  774. package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
  775. package/dist/apps/data/routes/funding.d.ts.map +0 -1
  776. package/dist/apps/data/routes/funding.js +0 -410
  777. package/dist/apps/data/routes/funding.js.map +0 -1
  778. package/dist/internal/FundingQuotes.d.ts +0 -864
  779. package/dist/internal/FundingQuotes.d.ts.map +0 -1
  780. package/dist/internal/FundingQuotes.js +0 -672
  781. package/dist/internal/FundingQuotes.js.map +0 -1
  782. package/src/apps/data/FundingQuoteProviders.ts +0 -1043
  783. package/src/apps/data/routes/funding.test.ts +0 -503
  784. package/src/apps/data/routes/funding.ts +0 -604
  785. package/src/internal/FundingQuotes.test.ts +0 -456
  786. package/src/internal/FundingQuotes.ts +0 -944
@@ -0,0 +1,1202 @@
1
+ import { Hex } from 'ox'
2
+
3
+ import * as Db from '../../db/Db.js'
4
+ import * as FundingDepositAddresses from '../../db/tables/fundingDepositAddresses.js'
5
+ import * as FundingDepositRequestObservations from '../../db/tables/fundingDepositRequestObservations.js'
6
+ import * as FundingDeposits from '../../db/tables/fundingDeposits.js'
7
+ import type * as Metrics from '../../Metrics.js'
8
+ import * as Value from '../Value.js'
9
+ import * as Deposit from './Deposit.js'
10
+ import * as Provider from './Provider.js'
11
+ import * as Subsidy from './Subsidy.js'
12
+
13
+ const defaultBatchSize = 25
14
+ const defaultLeaseMs = 2 * 60_000
15
+ const defaultPollIntervalMs = 60_000
16
+ const followUpDelaySeconds = { delivery: 1, provider: 5, settlement: 2 } as const satisfies Record<
17
+ Provider.Webhook.receive.FollowUp['kind'],
18
+ number
19
+ >
20
+ const maximumPages = 100
21
+ const maximumFollowUpAttempts = 6
22
+
23
+ /** Verified token transfer returned by an authoritative chain reader. */
24
+ export type TransferEvidence = {
25
+ /** Token quantity in base units. */
26
+ amount: string
27
+ /** Verified sender account, when the chain exposes it. */
28
+ sender?: string | undefined
29
+ /** Verified transaction reference. */
30
+ transactionHash: string
31
+ /** Transfer position within the transaction. */
32
+ transferIndex: number
33
+ }
34
+
35
+ /** Authoritative chain-evidence reader used during deposit reconciliation. */
36
+ export type VerifyTransfers = (
37
+ parameters: VerifyTransfers.Parameters,
38
+ ) => Promise<readonly TransferEvidence[]>
39
+
40
+ /** Parameters passed to an authoritative chain-evidence reader. */
41
+ export declare namespace VerifyTransfers {
42
+ type Parameters = {
43
+ /** Account that must receive the token transfer. */
44
+ recipient: string
45
+ /** Chain containing the transaction. */
46
+ chain: Provider.ChainRef
47
+ /** Token that must be transferred. */
48
+ token: Provider.TokenRef
49
+ /** Provider-discovered transaction reference to verify. */
50
+ transactionHash: string
51
+ }
52
+ }
53
+
54
+ /** Creates a reusable-address reconciliation tracker. */
55
+ export function createTracker(options: createTracker.Options): createTracker.Tracker {
56
+ const now = options.now ?? (() => new Date())
57
+ const batchSize = options.batchSize ?? defaultBatchSize
58
+ const leaseMs = options.leaseMs ?? defaultLeaseMs
59
+ const pollIntervalMs = options.pollIntervalMs ?? defaultPollIntervalMs
60
+
61
+ const record = (outcome: string, providerId: string, trigger: Deposit.DetectionTrigger) => {
62
+ options.metrics?.count('funding_deposit_reconciliation_count', 1, {
63
+ outcome,
64
+ provider: providerId,
65
+ trigger,
66
+ })
67
+ }
68
+
69
+ return {
70
+ async reconcile(message) {
71
+ const database = Db.get(options.db)
72
+ const startedAt = now()
73
+ // Legacy poll messages carry a lease version; legacy webhook messages do not.
74
+ const trigger = (() => {
75
+ if (message.trigger) return message.trigger
76
+ if (message.pollLeaseVersion !== undefined) return 'poll'
77
+ return 'webhook'
78
+ })()
79
+ const claimed = await claim(database, message, {
80
+ leaseUntil: new Date(startedAt.getTime() + leaseMs).toISOString(),
81
+ now: startedAt.toISOString(),
82
+ })
83
+ if (!claimed) return { type: 'busy' }
84
+
85
+ const provider = options.providers.find((candidate) => candidate.id === claimed.providerId)
86
+ if (!provider || !Provider.canListDepositAddressRequests(provider)) {
87
+ await fail(database, claimed, startedAt, pollIntervalMs)
88
+ record('provider_unavailable', claimed.providerId, trigger)
89
+ return { type: 'provider_unavailable' }
90
+ }
91
+
92
+ const heartbeat = maintainLease(database, claimed, { leaseMs, now })
93
+ try {
94
+ await heartbeat.ready()
95
+ const requests = await listRequests(provider, {
96
+ address: claimed,
97
+ requestId: message.requestId,
98
+ signal: options.signal,
99
+ })
100
+ if (trigger === 'poll')
101
+ await FundingDepositRequestObservations.observePoll(database, {
102
+ depositAddressId: claimed.id,
103
+ observedAt: now().toISOString(),
104
+ providerRequestIds: requests.requests.map((request) => request.id),
105
+ })
106
+ const webhookUpdateObserved = (() => {
107
+ const timing = message.webhookTiming
108
+ if (!timing) return true
109
+ if (!message.requestId) return false
110
+ // Relay can send a webhook before its requests API indexes the same update.
111
+ return requests.requests.some(
112
+ (request) =>
113
+ request.id === message.requestId && request.updatedAt >= timing.providerUpdatedAt,
114
+ )
115
+ })()
116
+ heartbeat.assert()
117
+ let created = 0
118
+ let updated = 0
119
+ const pendingRequestIds = new Set([
120
+ ...requests.pendingRequestIds,
121
+ ...(message.requestId ? [message.requestId] : []),
122
+ ])
123
+ let followUpKind: Provider.Webhook.receive.FollowUp['kind'] | undefined
124
+ for (const request of requests.requests) {
125
+ const result = await reconcileRequest(database, {
126
+ address: claimed,
127
+ metrics: options.metrics,
128
+ provider,
129
+ request,
130
+ signal: options.signal,
131
+ subsidies: options.subsidies,
132
+ trigger,
133
+ verifyTransfers: options.verifyTransfers,
134
+ })
135
+ heartbeat.assert()
136
+ created += result.created
137
+ updated += result.updated
138
+ if (result.terminal) pendingRequestIds.delete(request.id)
139
+ else {
140
+ pendingRequestIds.add(request.id)
141
+ followUpKind = result.followUp ?? followUpKind ?? 'provider'
142
+ }
143
+ }
144
+ const awaitsProvider = await FundingDeposits.hasUnattributed(database, claimed.id)
145
+ if (message.requestId && message.webhookTiming && !webhookUpdateObserved)
146
+ pendingRequestIds.add(message.requestId)
147
+ if (created > 0)
148
+ options.metrics?.count('funding_deposit_detection_count', created, {
149
+ provider: claimed.providerId,
150
+ trigger,
151
+ })
152
+
153
+ const leaseFailure = await heartbeat.stop()
154
+ if (leaseFailure !== undefined) throw leaseFailure
155
+ const completedAt = now()
156
+ const stored = await FundingDepositAddresses.completePoll(database, {
157
+ id: claimed.id,
158
+ lastPolledAt: completedAt.toISOString(),
159
+ nextPollAt: new Date(completedAt.getTime() + pollIntervalMs).toISOString(),
160
+ pollLeaseVersion: claimed.pollLeaseVersion,
161
+ providerRequestIds: claimed.providerRequestIds,
162
+ providerState: reconciliationState(claimed.providerState, {
163
+ pendingRequestIds: [...pendingRequestIds],
164
+ requests,
165
+ ...(message.webhookTiming && message.requestId && webhookUpdateObserved
166
+ ? {
167
+ webhookTiming: {
168
+ ...message.webhookTiming,
169
+ reconciliationCompletedAt: completedAt.toISOString(),
170
+ requestId: message.requestId,
171
+ },
172
+ }
173
+ : {}),
174
+ }),
175
+ })
176
+ if (!stored) return { type: 'stale' }
177
+ if (pendingRequestIds.size > 0 || awaitsProvider) {
178
+ const followUp = nextFollowUp(message, followUpKind ?? 'provider')
179
+ if (followUp)
180
+ await options
181
+ .dispatch(
182
+ {
183
+ addressId: claimed.id,
184
+ followUp: followUp.state,
185
+ ...(message.requestId ? { requestId: message.requestId } : {}),
186
+ trigger,
187
+ type: 'funding:deposit-address:reconcile',
188
+ ...(message.webhookTiming && !webhookUpdateObserved
189
+ ? { webhookTiming: message.webhookTiming }
190
+ : {}),
191
+ },
192
+ { delaySeconds: followUp.delaySeconds },
193
+ )
194
+ .catch((cause) => {
195
+ record('follow_up_enqueue_failed', claimed.providerId, trigger)
196
+ throw cause
197
+ })
198
+ record(
199
+ followUp ? 'follow_up_enqueued' : 'follow_up_exhausted',
200
+ claimed.providerId,
201
+ trigger,
202
+ )
203
+ }
204
+ if (message.webhookTiming && webhookUpdateObserved)
205
+ recordWebhookLatency(options.metrics, {
206
+ completedAt,
207
+ providerId: claimed.providerId,
208
+ timing: message.webhookTiming,
209
+ })
210
+ record('completed', claimed.providerId, trigger)
211
+ options.metrics?.histogram(
212
+ 'funding_deposit_reconciliation_duration_ms',
213
+ completedAt.getTime() - startedAt.getTime(),
214
+ { provider: claimed.providerId, trigger },
215
+ )
216
+ return { created, type: 'completed', updated }
217
+ } catch (cause) {
218
+ const leaseFailure = await heartbeat.stop()
219
+ await fail(database, claimed, now(), pollIntervalMs)
220
+ record('failed', claimed.providerId, trigger)
221
+ throw leaseFailure ?? cause
222
+ } finally {
223
+ options.metrics?.flush()
224
+ }
225
+ },
226
+
227
+ async tick() {
228
+ const database = Db.get(options.db)
229
+ const startedAt = now()
230
+ const leaseUntil = new Date(startedAt.getTime() + leaseMs).toISOString()
231
+ let claimed = 0
232
+ let failed = 0
233
+ for (const provider of options.providers) {
234
+ if (!Provider.canListDepositAddressRequests(provider)) continue
235
+ const records = await FundingDepositAddresses.claimDue(database, {
236
+ leaseUntil,
237
+ limit: Math.max(0, batchSize - claimed),
238
+ now: startedAt.toISOString(),
239
+ providerId: provider.id,
240
+ })
241
+ for (const address of records) {
242
+ claimed += 1
243
+ options.metrics?.histogram(
244
+ 'funding_deposit_poll_lag_ms',
245
+ Math.max(0, startedAt.getTime() - new Date(address.nextPollAt).getTime()),
246
+ { provider: provider.id },
247
+ )
248
+ try {
249
+ await options.dispatch({
250
+ addressId: address.id,
251
+ pollLeaseVersion: address.pollLeaseVersion,
252
+ trigger: 'poll',
253
+ type: 'funding:deposit-address:reconcile',
254
+ })
255
+ record('enqueued', provider.id, 'poll')
256
+ } catch {
257
+ failed += 1
258
+ await fail(database, address, startedAt, pollIntervalMs)
259
+ record('enqueue_failed', provider.id, 'poll')
260
+ }
261
+ }
262
+ if (claimed >= batchSize) break
263
+ }
264
+ options.metrics?.flush()
265
+ return { claimed, failed }
266
+ },
267
+ }
268
+ }
269
+
270
+ export declare namespace createTracker {
271
+ /** Dependencies and bounds for deposit reconciliation. */
272
+ type Options = {
273
+ /** Maximum addresses claimed by one scheduled tick. */
274
+ batchSize?: number | undefined
275
+ /** Authoritative database or per-invocation database factory. */
276
+ db: Db.Source
277
+ /** Durable reconciliation queue transport. */
278
+ dispatch: (
279
+ message: Provider.Webhook.receive.Dispatchable,
280
+ options?: createTracker.DispatchOptions,
281
+ ) => Promise<void>
282
+ /** Duration of one reconciliation lease. */
283
+ leaseMs?: number | undefined
284
+ /** Optional bounded operational metrics sink. */
285
+ metrics?: Metrics.Metrics | undefined
286
+ /** Clock used for scheduling and tests. */
287
+ now?: (() => Date) | undefined
288
+ /** Delay before a successfully reconciled address is polled again. */
289
+ pollIntervalMs?: number | undefined
290
+ /** Configured funding provider integrations. */
291
+ providers: readonly Provider.Provider[]
292
+ /** Optional cancellation signal for provider reads. */
293
+ signal?: AbortSignal | undefined
294
+ /** Optional pathUSD-funded subsidy settler. */
295
+ subsidies?: Subsidy.Settler | undefined
296
+ /** Authoritative source and Tempo transfer verifier. */
297
+ verifyTransfers: VerifyTransfers
298
+ }
299
+
300
+ /** Delivery options for one reconciliation queue message. */
301
+ type DispatchOptions = {
302
+ /** Delay before the queue makes the message available. */
303
+ delaySeconds: number
304
+ }
305
+
306
+ /** Result of reconciling one queue message. */
307
+ type ReconcileResult =
308
+ | { type: 'busy' | 'provider_unavailable' | 'stale' }
309
+ | { created: number; type: 'completed'; updated: number }
310
+
311
+ /** Scheduled and queue-driven reusable-address tracker. */
312
+ type Tracker = {
313
+ /** Reconciles one address from provider discovery and verified chain evidence. */
314
+ reconcile(message: Provider.Webhook.receive.Queued): Promise<ReconcileResult>
315
+ /** Claims and enqueues one bounded batch of due reusable addresses. */
316
+ tick(): Promise<{ claimed: number; failed: number }>
317
+ }
318
+ }
319
+
320
+ type ClaimOptions = {
321
+ leaseUntil: string
322
+ now: string
323
+ }
324
+
325
+ async function claim(db: Db.Db, message: Provider.Webhook.receive.Queued, options: ClaimOptions) {
326
+ if (message.pollLeaseVersion === undefined)
327
+ return FundingDepositAddresses.claim(db, {
328
+ id: message.addressId,
329
+ leaseUntil: options.leaseUntil,
330
+ now: options.now,
331
+ })
332
+ const current = await FundingDepositAddresses.get(db, message.addressId)
333
+ if (
334
+ !current?.pollLeaseUntil ||
335
+ current.pollLeaseUntil <= options.now ||
336
+ current.pollLeaseVersion !== message.pollLeaseVersion
337
+ )
338
+ return undefined
339
+ return current
340
+ }
341
+
342
+ async function fail(
343
+ db: Db.Db,
344
+ address: FundingDepositAddresses.Record,
345
+ now: Date,
346
+ pollIntervalMs: number,
347
+ ) {
348
+ const delay = Math.min(pollIntervalMs * 2 ** address.pollFailureCount, 15 * 60_000)
349
+ return FundingDepositAddresses.failPoll(db, {
350
+ id: address.id,
351
+ nextPollAt: new Date(now.getTime() + delay).toISOString(),
352
+ pollLeaseVersion: address.pollLeaseVersion,
353
+ })
354
+ }
355
+
356
+ type MaintainLeaseOptions = {
357
+ leaseMs: number
358
+ now: () => Date
359
+ }
360
+
361
+ function maintainLease(
362
+ db: Db.Db,
363
+ address: FundingDepositAddresses.Record,
364
+ options: MaintainLeaseOptions,
365
+ ) {
366
+ let failure: unknown
367
+ let stopped = false
368
+ const extend = async () => {
369
+ if (stopped || failure !== undefined) return
370
+ const renewed = await FundingDepositAddresses.renewPoll(db, {
371
+ id: address.id,
372
+ leaseUntil: new Date(options.now().getTime() + options.leaseMs).toISOString(),
373
+ pollLeaseVersion: address.pollLeaseVersion,
374
+ })
375
+ if (!renewed) failure = new StaleLeaseError()
376
+ }
377
+ const captureFailure = (cause: unknown) => {
378
+ failure = cause
379
+ }
380
+ let renewal = extend().catch(captureFailure)
381
+ const timer = setInterval(
382
+ () => {
383
+ renewal = renewal.then(extend).catch(captureFailure)
384
+ },
385
+ Math.max(1, Math.floor(options.leaseMs / 2)),
386
+ )
387
+
388
+ return {
389
+ assert() {
390
+ if (failure !== undefined) throw failure
391
+ },
392
+ async ready() {
393
+ await renewal
394
+ if (failure !== undefined) throw failure
395
+ },
396
+ async stop() {
397
+ if (!stopped) {
398
+ stopped = true
399
+ clearInterval(timer)
400
+ }
401
+ await renewal
402
+ return failure
403
+ },
404
+ }
405
+ }
406
+
407
+ type Requests = {
408
+ highWaterRequestIds: readonly string[]
409
+ highWaterUpdatedAt?: string | undefined
410
+ pendingRequestIds: readonly string[]
411
+ requests: readonly Provider.listDepositAddressRequests.ReturnType['requests'][number][]
412
+ }
413
+
414
+ type ListRequestsOptions = {
415
+ address: FundingDepositAddresses.Record
416
+ requestId?: string | undefined
417
+ signal?: AbortSignal | undefined
418
+ }
419
+
420
+ async function listRequests(
421
+ provider: Provider.Provider & {
422
+ listDepositAddressRequests: NonNullable<Provider.Provider['listDepositAddressRequests']>
423
+ },
424
+ options: ListRequestsOptions,
425
+ ): Promise<Requests> {
426
+ const highWater = readHighWater(options.address.providerState)
427
+ const highWaterRequestIds = new Set(highWater.requestIds)
428
+ const pendingRequestIds = new Set(highWater.pendingRequestIds)
429
+ const requests: Provider.listDepositAddressRequests.ReturnType['requests'][number][] = []
430
+ let continuation: string | undefined
431
+ for (let page = 0; page < maximumPages; page++) {
432
+ const result = await provider.listDepositAddressRequests(
433
+ { address: options.address.address, ...(continuation ? { continuation } : {}) },
434
+ options.signal ?? new AbortController().signal,
435
+ )
436
+ requests.push(
437
+ ...result.requests.filter(
438
+ (request) =>
439
+ !highWater.updatedAt ||
440
+ request.updatedAt > highWater.updatedAt ||
441
+ (request.updatedAt === highWater.updatedAt &&
442
+ (!highWaterRequestIds.has(request.id) || pendingRequestIds.has(request.id))),
443
+ ),
444
+ )
445
+ const reached = result.requests.some(
446
+ (request) => highWater.updatedAt && request.updatedAt < highWater.updatedAt,
447
+ )
448
+ continuation = result.continuation
449
+ if (!continuation || reached) break
450
+ if (page === maximumPages - 1) throw new PaginationLimitError()
451
+ }
452
+
453
+ const observed = new Set(requests.map((request) => request.id))
454
+ for (const requestId of unique([
455
+ ...highWater.pendingRequestIds,
456
+ ...(options.requestId ? [options.requestId] : []),
457
+ ])) {
458
+ if (observed.has(requestId)) continue
459
+ const result = await provider.listDepositAddressRequests(
460
+ { address: options.address.address, requestId },
461
+ options.signal ?? new AbortController().signal,
462
+ )
463
+ requests.push(...result.requests)
464
+ }
465
+
466
+ const addressRequests = requests.filter(
467
+ (request) => !highWater.pendingRequestIds.includes(request.id),
468
+ )
469
+ const newest = addressRequests.reduce<string | undefined>(
470
+ (value, request) => (!value || request.updatedAt > value ? request.updatedAt : value),
471
+ highWater.updatedAt,
472
+ )
473
+ return {
474
+ highWaterRequestIds: newest
475
+ ? unique([
476
+ ...(newest === highWater.updatedAt ? highWater.requestIds : []),
477
+ ...addressRequests
478
+ .filter((request) => request.updatedAt === newest)
479
+ .map((request) => request.id),
480
+ ])
481
+ : [],
482
+ highWaterUpdatedAt: newest,
483
+ pendingRequestIds: highWater.pendingRequestIds,
484
+ requests,
485
+ }
486
+ }
487
+
488
+ type HighWater = {
489
+ pendingRequestIds: readonly string[]
490
+ requestIds: readonly string[]
491
+ updatedAt?: string | undefined
492
+ }
493
+
494
+ function readHighWater(state: FundingDepositAddresses.Record['providerState']): HighWater {
495
+ if (!state || typeof state !== 'object') return { pendingRequestIds: [], requestIds: [] }
496
+ const reconciliation = state['reconciliation']
497
+ if (!reconciliation || typeof reconciliation !== 'object')
498
+ return { pendingRequestIds: [], requestIds: [] }
499
+ const pendingRequestIds =
500
+ 'pendingRequestIds' in reconciliation && Array.isArray(reconciliation.pendingRequestIds)
501
+ ? reconciliation.pendingRequestIds.filter(
502
+ (value: unknown): value is string => typeof value === 'string',
503
+ )
504
+ : []
505
+ const requestIds =
506
+ 'requestIds' in reconciliation && Array.isArray(reconciliation.requestIds)
507
+ ? reconciliation.requestIds.filter(
508
+ (value: unknown): value is string => typeof value === 'string',
509
+ )
510
+ : []
511
+ return {
512
+ pendingRequestIds,
513
+ requestIds,
514
+ ...('updatedAt' in reconciliation && typeof reconciliation.updatedAt === 'string'
515
+ ? { updatedAt: reconciliation.updatedAt }
516
+ : {}),
517
+ }
518
+ }
519
+
520
+ type ReconciledWebhookTiming = Provider.Webhook.receive.WebhookTiming & {
521
+ /** When Tempo completed the webhook-triggered reconciliation. */
522
+ reconciliationCompletedAt: string
523
+ /** Provider request matched to the observed update. */
524
+ requestId: string
525
+ }
526
+
527
+ type ReconciliationStateOptions = {
528
+ /** Provider requests that still require reconciliation. */
529
+ pendingRequestIds: readonly string[]
530
+ /** Provider requests and high-water state observed in this pass. */
531
+ requests: Requests
532
+ /** Completed webhook timing retained for diagnostics. */
533
+ webhookTiming?: ReconciledWebhookTiming | undefined
534
+ }
535
+
536
+ function reconciliationState(
537
+ state: FundingDepositAddresses.Record['providerState'],
538
+ options: ReconciliationStateOptions,
539
+ ) {
540
+ const current = state && typeof state === 'object' ? state : {}
541
+ const reconciliation = (() => {
542
+ const value = current['reconciliation']
543
+ if (value && typeof value === 'object') return value
544
+ return {}
545
+ })()
546
+ return {
547
+ ...current,
548
+ reconciliation: {
549
+ ...reconciliation,
550
+ pendingRequestIds: options.pendingRequestIds,
551
+ requestIds: options.requests.highWaterRequestIds,
552
+ ...(options.requests.highWaterUpdatedAt
553
+ ? { updatedAt: options.requests.highWaterUpdatedAt }
554
+ : {}),
555
+ ...(options.webhookTiming ? { webhookTiming: options.webhookTiming } : {}),
556
+ },
557
+ }
558
+ }
559
+
560
+ type ObservedSourceTransaction = {
561
+ deposits: FundingDeposits.Record[]
562
+ transactionHash: string
563
+ transfers: readonly TransferEvidence[]
564
+ }
565
+
566
+ type VerifiedDeposit = {
567
+ deposit: FundingDeposits.Record
568
+ required: bigint
569
+ source: TransferEvidence
570
+ sourceAmount: bigint
571
+ }
572
+
573
+ async function observeProviderDelivery(
574
+ options: reconcileRequest.Options,
575
+ verified: readonly VerifiedDeposit[],
576
+ ) {
577
+ const [entry] = verified
578
+ if (
579
+ !entry ||
580
+ verified.length !== 1 ||
581
+ options.address.deliveryStrategy !== 'provider' ||
582
+ options.address.providerOutputToken.tokenKey !==
583
+ options.address.snapshot.destinationToken.tokenKey ||
584
+ (options.request.status === 'success' &&
585
+ options.request.destinationTransactionHashes.length > 0) ||
586
+ !options.provider ||
587
+ !Provider.canObserveDepositAddressRequest(options.provider)
588
+ )
589
+ return undefined
590
+
591
+ const result = await options.provider
592
+ .observeDepositAddressRequest(
593
+ {
594
+ address: options.address.address,
595
+ destinationChain: options.address.snapshot.destinationChain,
596
+ destinationToken: options.address.providerOutputToken,
597
+ providerState: entry.deposit.providerState ?? undefined,
598
+ recipient: options.address.recipient,
599
+ refundAddress: options.address.refundAddress,
600
+ request: options.request,
601
+ source: entry.source,
602
+ sourceChain: options.address.snapshot.sourceChain,
603
+ sourceToken: options.address.snapshot.sourceToken,
604
+ },
605
+ options.signal ?? new AbortController().signal,
606
+ )
607
+ .catch((cause) => {
608
+ if (options.signal?.aborted) throw cause
609
+ return undefined
610
+ })
611
+ options.metrics?.count('funding_deposit_delivery_observation_count', 1, {
612
+ outcome: result?.type ?? 'failed',
613
+ provider: options.address.providerId,
614
+ })
615
+ return result
616
+ }
617
+
618
+ /** Reconciles one provider request against verified chain evidence. */
619
+ export async function reconcileRequest(
620
+ db: Db.Db,
621
+ options: reconcileRequest.Options,
622
+ ): Promise<reconcileRequest.ReturnType> {
623
+ const trigger = options.trigger ?? 'poll'
624
+ const observation = await FundingDepositRequestObservations.get(db, {
625
+ depositAddressId: options.address.id,
626
+ providerRequestId: options.request.id,
627
+ })
628
+ if (observation)
629
+ await FundingDeposits.recordRequestObservation(db, {
630
+ depositAddressId: observation.depositAddressId,
631
+ ...(observation.pollObservedAt ? { pollObservedAt: observation.pollObservedAt } : {}),
632
+ providerRequestId: observation.providerRequestId,
633
+ ...(observation.webhookReceivedAt
634
+ ? { webhookReceivedAt: observation.webhookReceivedAt }
635
+ : {}),
636
+ })
637
+ let created = 0
638
+ let followUp: reconcileRequest.ReturnType['followUp']
639
+ const observed: ObservedSourceTransaction[] = []
640
+ // Persist provider observations first so transient chain failures do not hide acknowledged deposits.
641
+ for (const transactionHash of unique(options.request.sourceTransactionHashes)) {
642
+ const deposits = await FundingDeposits.withSourceTransaction(db, {
643
+ depositAddressId: options.address.id,
644
+ fn: async (tx): Promise<FundingDeposits.Record[]> => {
645
+ let records = await FundingDeposits.listByProviderObservation(tx, {
646
+ depositAddressId: options.address.id,
647
+ providerRequestId: options.request.id,
648
+ sourceTransactionHash: transactionHash,
649
+ })
650
+ if (records.length === 0)
651
+ records = await FundingDeposits.listBySourceTransaction(tx, {
652
+ depositAddressId: options.address.id,
653
+ sourceTransactionHash: transactionHash,
654
+ })
655
+ if (records.length > 0) return records
656
+ created += 1
657
+ return [
658
+ await Deposit.create(tx, {
659
+ detectionTrigger: trigger,
660
+ now: new Date(options.request.createdAt),
661
+ ...(observation?.pollObservedAt ? { pollObservedAt: observation.pollObservedAt } : {}),
662
+ providerRequestId: options.request.id,
663
+ snapshot: {
664
+ depositAddressId: options.address.id,
665
+ destinationChain: options.address.snapshot.destinationChain,
666
+ destinationToken: options.address.snapshot.destinationToken,
667
+ provider: options.address.snapshot.provider,
668
+ recipient: options.address.recipient,
669
+ refundAddress: options.address.refundAddress,
670
+ sourceChain: options.address.snapshot.sourceChain,
671
+ sourceToken: options.address.snapshot.sourceToken,
672
+ sourceTransactionHashes: [transactionHash],
673
+ },
674
+ sourceTransactionHash: transactionHash,
675
+ ...(observation?.webhookReceivedAt
676
+ ? { webhookReceivedAt: observation.webhookReceivedAt }
677
+ : {}),
678
+ }),
679
+ ]
680
+ },
681
+ sourceTransactionHash: transactionHash,
682
+ })
683
+ observed.push({ deposits, transactionHash, transfers: [] })
684
+ }
685
+
686
+ const sources = await Promise.all(
687
+ observed.map(
688
+ async (source): Promise<ObservedSourceTransaction> => ({
689
+ ...source,
690
+ transfers: await options.verifyTransfers({
691
+ chain: options.address.snapshot.sourceChain,
692
+ recipient: options.address.address,
693
+ token: options.address.snapshot.sourceToken,
694
+ transactionHash: source.transactionHash,
695
+ }),
696
+ }),
697
+ ),
698
+ )
699
+
700
+ const sourceEvidenceComplete =
701
+ sources.length > 0 && sources.every((source) => source.transfers.length > 0)
702
+ let terminal = sourceEvidenceComplete
703
+ const updatedIds = new Set<string>()
704
+ const verified: VerifiedDeposit[] = []
705
+ for (const source of sources) {
706
+ const transfers = [...source.transfers].sort(
707
+ (left, right) => left.transferIndex - right.transferIndex,
708
+ )
709
+ for (const [providerTransferIndex, transfer] of transfers.entries()) {
710
+ const required = destinationBaseUnits(
711
+ BigInt(transfer.amount),
712
+ options.address.snapshot.sourceToken.decimals,
713
+ options.address.snapshot.destinationToken.decimals,
714
+ )
715
+ const sourceAmount = Value.tokenAmount({
716
+ baseUnits: transfer.amount,
717
+ currency: options.address.snapshot.sourceToken.currency,
718
+ decimals: options.address.snapshot.sourceToken.decimals,
719
+ })
720
+ const destinationAmountRequired = Value.tokenAmount({
721
+ baseUnits: required,
722
+ currency: options.address.snapshot.destinationToken.currency,
723
+ decimals: options.address.snapshot.destinationToken.decimals,
724
+ })
725
+ // Bind the placeholder to transfers in deterministic log order when one transaction contains several deposits.
726
+ let deposit = source.deposits.find((record) =>
727
+ record.providerRequestId === null
728
+ ? record.sourceTransferIndex === transfer.transferIndex
729
+ : record.providerTransferIndex === providerTransferIndex,
730
+ )
731
+ if (!deposit) {
732
+ deposit = await Deposit.create(db, {
733
+ detectionTrigger: trigger,
734
+ now: new Date(options.request.createdAt),
735
+ ...(observation?.pollObservedAt ? { pollObservedAt: observation.pollObservedAt } : {}),
736
+ providerRequestId: options.request.id,
737
+ providerTransferIndex,
738
+ snapshot: {
739
+ depositAddressId: options.address.id,
740
+ ...(options.address.snapshot.subsidize ? { destinationAmountRequired } : {}),
741
+ destinationChain: options.address.snapshot.destinationChain,
742
+ destinationToken: options.address.snapshot.destinationToken,
743
+ provider: options.address.snapshot.provider,
744
+ recipient: options.address.recipient,
745
+ refundAddress: options.address.refundAddress,
746
+ ...(transfer.sender ? { sender: transfer.sender } : {}),
747
+ sourceAmount,
748
+ sourceChain: options.address.snapshot.sourceChain,
749
+ sourceToken: options.address.snapshot.sourceToken,
750
+ sourceTransactionHashes: [transfer.transactionHash],
751
+ },
752
+ sourceTransactionHash: transfer.transactionHash,
753
+ sourceTransferIndex: transfer.transferIndex,
754
+ ...(observation?.webhookReceivedAt
755
+ ? { webhookReceivedAt: observation.webhookReceivedAt }
756
+ : {}),
757
+ })
758
+ source.deposits.push(deposit)
759
+ created += 1
760
+ }
761
+ if (!Deposit.isTerminal(deposit.status)) {
762
+ const result = await Deposit.transition(db, {
763
+ expectedVersion: deposit.version,
764
+ id: deposit.id,
765
+ providerRequestId: options.request.id,
766
+ providerRequestIds: unique([...deposit.providerRequestIds, options.request.id]),
767
+ providerTransferIndex,
768
+ snapshot: {
769
+ ...deposit.snapshot,
770
+ ...(options.address.snapshot.subsidize ? { destinationAmountRequired } : {}),
771
+ ...(transfer.sender ? { sender: transfer.sender } : {}),
772
+ sourceAmount,
773
+ },
774
+ sourceTransferIndex: transfer.transferIndex,
775
+ status: deposit.status === 'detected' ? 'bridging' : deposit.status,
776
+ })
777
+ if (result.type === 'applied') {
778
+ deposit = result.record
779
+ updatedIds.add(deposit.id)
780
+ }
781
+ }
782
+ verified.push({ deposit, required, source: transfer, sourceAmount: BigInt(transfer.amount) })
783
+ }
784
+ }
785
+ if (verified.length === 0) return { created, terminal: false, updated: updatedIds.size }
786
+ if (!sourceEvidenceComplete) return { created, terminal: false, updated: updatedIds.size }
787
+
788
+ const deliveryObservation = await observeProviderDelivery(options, verified)
789
+ if (deliveryObservation?.type === 'pending') followUp = 'delivery'
790
+ const destinationTransactionHashes = unique([
791
+ ...options.request.destinationTransactionHashes,
792
+ ...(deliveryObservation?.type === 'verified'
793
+ ? deliveryObservation.destinationTransactionHashes
794
+ : []),
795
+ ])
796
+ const destinationEvidence = await Promise.all(
797
+ destinationTransactionHashes.map((transactionHash) =>
798
+ options.verifyTransfers({
799
+ chain: options.address.snapshot.destinationChain,
800
+ recipient: options.address.recipient,
801
+ token: options.address.providerOutputToken,
802
+ transactionHash,
803
+ }),
804
+ ),
805
+ )
806
+ const destinationTransfers = destinationEvidence.flat()
807
+ const providerEvidenceComplete =
808
+ (options.request.status === 'success' || deliveryObservation?.type === 'verified') &&
809
+ destinationEvidence.length > 0 &&
810
+ destinationEvidence.every((transfers) => transfers.length > 0)
811
+ const providerOutput = destinationTransfers.reduce(
812
+ (total, transfer) => total + BigInt(transfer.amount),
813
+ 0n,
814
+ )
815
+ const totalRequired = verified.reduce((total, entry) => total + entry.required, 0n)
816
+ let allocated = 0n
817
+ let cumulativeRequired = 0n
818
+
819
+ for (const entry of verified) {
820
+ const { required, sourceAmount } = entry
821
+ cumulativeRequired += required
822
+ const nextAllocated =
823
+ totalRequired === 0n ? 0n : (providerOutput * cumulativeRequired) / totalRequired
824
+ const delivered = nextAllocated - allocated
825
+ allocated = nextAllocated
826
+ const { deposit } = entry
827
+ if (Deposit.isTerminal(deposit.status)) continue
828
+
829
+ const settlement = await reconcileSubsidy({
830
+ address: options.address,
831
+ delivered,
832
+ deposit,
833
+ providerEvidenceComplete,
834
+ required,
835
+ sourceAmount,
836
+ subsidies: options.subsidies,
837
+ verifyTransfers: options.verifyTransfers,
838
+ })
839
+ if (settlement.outcome)
840
+ options.metrics?.count('funding_deposit_subsidy_count', 1, {
841
+ outcome: settlement.outcome,
842
+ provider: options.address.providerId,
843
+ })
844
+ if (settlement.status === 'bridging' || settlement.status === 'settling') terminal = false
845
+ if (settlement.status === 'settling') followUp = 'settlement'
846
+ const destinationAmount = Value.tokenAmount({
847
+ baseUnits: delivered + settlement.delivered,
848
+ currency: options.address.snapshot.destinationToken.currency,
849
+ decimals: options.address.snapshot.destinationToken.decimals,
850
+ })
851
+ const result = await Deposit.transition(db, {
852
+ expectedVersion: deposit.version,
853
+ id: deposit.id,
854
+ ...(delivered > 0n
855
+ ? {
856
+ providerOutputAmount: Value.tokenAmount({
857
+ baseUnits: delivered,
858
+ currency: options.address.providerOutputToken.currency,
859
+ decimals: options.address.providerOutputToken.decimals,
860
+ }),
861
+ }
862
+ : {}),
863
+ providerRequestIds: unique([...deposit.providerRequestIds, options.request.id]),
864
+ ...(deliveryObservation?.providerState
865
+ ? {
866
+ providerState: {
867
+ ...deposit.providerState,
868
+ ...deliveryObservation.providerState,
869
+ },
870
+ }
871
+ : {}),
872
+ providerTransactionHashes: unique([
873
+ ...deposit.providerTransactionHashes,
874
+ ...options.request.destinationTransactionHashes,
875
+ ...(deliveryObservation?.providerTransactionHashes ?? []),
876
+ ]),
877
+ ...(settlement.settlementTransaction
878
+ ? { settlementTransaction: settlement.settlementTransaction }
879
+ : {}),
880
+ ...(settlement.settlementTransactionHash
881
+ ? { settlementTransactionHash: settlement.settlementTransactionHash }
882
+ : {}),
883
+ snapshot: {
884
+ ...deposit.snapshot,
885
+ ...(delivered + settlement.delivered > 0n ? { destinationAmount } : {}),
886
+ ...(settlement.status === 'completed' && !options.address.snapshot.subsidize
887
+ ? { destinationAmountRequired: destinationAmount }
888
+ : {}),
889
+ destinationTransactionHashes: unique([
890
+ ...(deposit.snapshot.destinationTransactionHashes ?? []),
891
+ ...destinationTransfers.map((evidence) => evidence.transactionHash),
892
+ ...settlement.destinationTransactionHashes,
893
+ ]),
894
+ },
895
+ status: settlement.status,
896
+ ...(settlement.statusReason ? { statusReason: settlement.statusReason } : {}),
897
+ ...(settlement.subsidyAmount ? { subsidyAmount: settlement.subsidyAmount } : {}),
898
+ ...(settlement.tempoGasPaid ? { tempoGasPaid: settlement.tempoGasPaid } : {}),
899
+ })
900
+ if (result.type === 'applied') {
901
+ updatedIds.add(deposit.id)
902
+ if (settlement.broadcast && options.subsidies) {
903
+ await options.subsidies.broadcast(settlement.broadcast).catch((cause) => {
904
+ options.metrics?.count('funding_deposit_subsidy_count', 1, {
905
+ outcome: 'broadcast_failed',
906
+ provider: options.address.providerId,
907
+ })
908
+ throw cause
909
+ })
910
+ options.metrics?.count('funding_deposit_subsidy_count', 1, {
911
+ outcome: 'broadcast',
912
+ provider: options.address.providerId,
913
+ })
914
+ }
915
+ }
916
+ }
917
+ return { created, ...(followUp ? { followUp } : {}), terminal, updated: updatedIds.size }
918
+ }
919
+
920
+ export declare namespace reconcileRequest {
921
+ /** Provider request, address, and settlement dependencies. */
922
+ type Options = {
923
+ /** Reusable deposit address attributed by the provider. */
924
+ address: FundingDepositAddresses.Record
925
+ /** Optional bounded operational metrics sink. */
926
+ metrics?: Metrics.Metrics | undefined
927
+ /** Provider integration that discovered the request. */
928
+ provider?: Provider.Provider | undefined
929
+ /** Provider request containing discovered chain transactions. */
930
+ request: Provider.listDepositAddressRequests.ReturnType['requests'][number]
931
+ /** Abort signal forwarded to provider delivery observation. */
932
+ signal?: AbortSignal | undefined
933
+ /** Optional pathUSD-funded subsidy settler. */
934
+ subsidies?: Subsidy.Settler | undefined
935
+ /** Mechanism that requested reconciliation. */
936
+ trigger?: Deposit.DetectionTrigger | undefined
937
+ /** Authoritative source and destination transfer verifier. */
938
+ verifyTransfers: VerifyTransfers
939
+ }
940
+
941
+ /** Material changes produced by one provider request. */
942
+ type ReturnType = {
943
+ /** Number of newly detected source transfers. */
944
+ created: number
945
+ /** Work that needs a bounded delayed follow-up. */
946
+ followUp?: 'delivery' | 'settlement' | undefined
947
+ /** Whether every deposit from this request reached a terminal state. */
948
+ terminal: boolean
949
+ /** Number of existing or new deposits materially changed. */
950
+ updated: number
951
+ }
952
+ }
953
+
954
+ type ReconcileSubsidyOptions = {
955
+ address: FundingDepositAddresses.Record
956
+ delivered: bigint
957
+ deposit: FundingDeposits.Record
958
+ providerEvidenceComplete: boolean
959
+ required: bigint
960
+ sourceAmount: bigint
961
+ subsidies?: Subsidy.Settler | undefined
962
+ verifyTransfers: VerifyTransfers
963
+ }
964
+
965
+ type ReconcileSubsidyResult = {
966
+ broadcast?: Subsidy.Settler.broadcast.Parameters | undefined
967
+ delivered: bigint
968
+ destinationTransactionHashes: readonly string[]
969
+ outcome?: string | undefined
970
+ settlementTransaction?: string | undefined
971
+ settlementTransactionHash?: string | undefined
972
+ status: Deposit.Status
973
+ statusReason?: Deposit.StatusReason | undefined
974
+ subsidyAmount?: Deposit.Snapshot['destinationAmountRequired'] | undefined
975
+ tempoGasPaid?: string | undefined
976
+ }
977
+
978
+ async function reconcileSubsidy(options: ReconcileSubsidyOptions): Promise<ReconcileSubsidyResult> {
979
+ const empty = { delivered: 0n, destinationTransactionHashes: [] } as const
980
+ if (options.required === 0n)
981
+ return {
982
+ ...empty,
983
+ status: 'action-required',
984
+ statusReason: {
985
+ code: 'source_amount_not_supported',
986
+ message: 'The source amount is smaller than one destination-token base unit.',
987
+ },
988
+ }
989
+ const deficit = options.required > options.delivered ? options.required - options.delivered : 0n
990
+ const subsidyAmount =
991
+ options.deposit.subsidyAmount ??
992
+ Value.tokenAmount({
993
+ baseUnits: deficit,
994
+ currency: options.address.snapshot.destinationToken.currency,
995
+ decimals: options.address.snapshot.destinationToken.decimals,
996
+ })
997
+ if (options.deposit.settlementTransaction && options.deposit.settlementTransactionHash) {
998
+ if (!options.subsidies)
999
+ return {
1000
+ ...empty,
1001
+ outcome: 'unavailable',
1002
+ status: 'action-required',
1003
+ statusReason: {
1004
+ code: 'subsidy_failed',
1005
+ message: 'Tempo subsidy settlement is unavailable.',
1006
+ },
1007
+ subsidyAmount,
1008
+ }
1009
+ const hash = options.deposit.settlementTransactionHash as Hex.Hex
1010
+ const status = await options.subsidies.status({ hash })
1011
+ if (status.type === 'reverted')
1012
+ return {
1013
+ ...empty,
1014
+ outcome: 'reverted',
1015
+ status: 'action-required',
1016
+ statusReason: {
1017
+ code: 'subsidy_failed',
1018
+ message: 'Tempo could not deliver the required subsidy.',
1019
+ },
1020
+ subsidyAmount,
1021
+ tempoGasPaid: status.tempoGasPaid,
1022
+ }
1023
+ if (status.type === 'pending')
1024
+ return {
1025
+ ...empty,
1026
+ broadcast: {
1027
+ hash,
1028
+ transaction: options.deposit.settlementTransaction as Hex.Hex,
1029
+ },
1030
+ outcome: 'pending',
1031
+ status: 'settling',
1032
+ subsidyAmount,
1033
+ }
1034
+
1035
+ const transfers = await options.verifyTransfers({
1036
+ chain: options.address.snapshot.destinationChain,
1037
+ recipient: options.address.recipient,
1038
+ token: options.address.snapshot.destinationToken,
1039
+ transactionHash: hash,
1040
+ })
1041
+ const delivered = transfers.reduce((total, transfer) => total + BigInt(transfer.amount), 0n)
1042
+ return {
1043
+ delivered,
1044
+ destinationTransactionHashes: transfers.map((transfer) => transfer.transactionHash),
1045
+ outcome: options.delivered + delivered >= options.required ? 'completed' : 'underfilled',
1046
+ status: options.delivered + delivered >= options.required ? 'completed' : 'settling',
1047
+ subsidyAmount,
1048
+ tempoGasPaid: status.tempoGasPaid,
1049
+ }
1050
+ }
1051
+
1052
+ if (options.delivered >= options.required) return { ...empty, status: 'completed' }
1053
+ if (!options.address.snapshot.subsidize) {
1054
+ if (!options.providerEvidenceComplete) return { ...empty, status: 'bridging' }
1055
+ if (options.delivered > 0n) return { ...empty, status: 'completed' }
1056
+ return {
1057
+ ...empty,
1058
+ status: 'action-required',
1059
+ statusReason: {
1060
+ code: 'delivery_failed',
1061
+ message: 'The provider completed without delivering destination funds.',
1062
+ },
1063
+ }
1064
+ }
1065
+ if (!options.providerEvidenceComplete) return { ...empty, status: 'bridging' }
1066
+ if (!options.subsidies)
1067
+ return {
1068
+ ...empty,
1069
+ outcome: 'unavailable',
1070
+ status: 'action-required',
1071
+ statusReason: {
1072
+ code: 'subsidy_failed',
1073
+ message: 'Tempo subsidy settlement is unavailable.',
1074
+ },
1075
+ }
1076
+ if (
1077
+ !Subsidy.supports(options.subsidies.policy, {
1078
+ amount: options.sourceAmount.toString(),
1079
+ destinationToken: options.address.snapshot.destinationToken,
1080
+ sourceToken: options.address.snapshot.sourceToken,
1081
+ })
1082
+ )
1083
+ return {
1084
+ ...empty,
1085
+ outcome: 'unsupported',
1086
+ status: 'action-required',
1087
+ statusReason: {
1088
+ code: 'source_amount_not_supported',
1089
+ message: 'The source amount is outside the subsidized deposit limit.',
1090
+ },
1091
+ }
1092
+
1093
+ const prepared = await options.subsidies
1094
+ .prepare({
1095
+ amount: deficit,
1096
+ depositId: options.deposit.id,
1097
+ recipient: options.address.recipient as Hex.Hex,
1098
+ token: options.address.snapshot.destinationToken.address as Hex.Hex,
1099
+ })
1100
+ .catch((cause) => {
1101
+ if (cause instanceof Subsidy.BalanceUnavailableError) return undefined
1102
+ if (cause instanceof Subsidy.LiquidityUnavailableError) return null
1103
+ throw cause
1104
+ })
1105
+ if (prepared === null)
1106
+ return {
1107
+ ...empty,
1108
+ outcome: 'liquidity_unavailable',
1109
+ status: 'settling',
1110
+ subsidyAmount,
1111
+ }
1112
+ if (!prepared)
1113
+ return {
1114
+ ...empty,
1115
+ outcome: 'balance_unavailable',
1116
+ status: 'action-required',
1117
+ statusReason: {
1118
+ code: 'subsidy_balance_unavailable',
1119
+ message: 'Tempo lacks enough pathUSD for the required subsidy.',
1120
+ },
1121
+ subsidyAmount,
1122
+ }
1123
+ return {
1124
+ ...empty,
1125
+ broadcast: prepared,
1126
+ outcome: 'prepared',
1127
+ settlementTransaction: prepared.transaction,
1128
+ settlementTransactionHash: prepared.hash,
1129
+ status: 'settling',
1130
+ subsidyAmount,
1131
+ }
1132
+ }
1133
+
1134
+ function destinationBaseUnits(amount: bigint, sourceDecimals: number, destinationDecimals: number) {
1135
+ if (destinationDecimals >= sourceDecimals)
1136
+ return amount * 10n ** BigInt(destinationDecimals - sourceDecimals)
1137
+ const divisor = 10n ** BigInt(sourceDecimals - destinationDecimals)
1138
+ // Destination tokens cannot represent finer source precision, so retain only
1139
+ // the amount expressible in destination base units.
1140
+ return amount / divisor
1141
+ }
1142
+
1143
+ function unique(values: readonly string[]) {
1144
+ return [...new Set(values)]
1145
+ }
1146
+
1147
+ function nextFollowUp(
1148
+ message: Provider.Webhook.receive.Queued,
1149
+ kind: Provider.Webhook.receive.FollowUp['kind'],
1150
+ ) {
1151
+ const attempt = message.followUp?.kind === kind ? message.followUp.attempt + 1 : 0
1152
+ if (attempt >= maximumFollowUpAttempts) return undefined
1153
+ return { delaySeconds: followUpDelaySeconds[kind], state: { attempt, kind } }
1154
+ }
1155
+
1156
+ type RecordWebhookLatencyOptions = {
1157
+ /** When Tempo completed the webhook-triggered reconciliation. */
1158
+ completedAt: Date
1159
+ /** Funding provider that sent the webhook. */
1160
+ providerId: string
1161
+ /** Authenticated timestamps carried from webhook receipt. */
1162
+ timing: Provider.Webhook.receive.WebhookTiming
1163
+ }
1164
+
1165
+ function recordWebhookLatency(
1166
+ metrics: Metrics.Metrics | undefined,
1167
+ options: RecordWebhookLatencyOptions,
1168
+ ) {
1169
+ if (!metrics) return
1170
+ const completedAt = options.completedAt.getTime()
1171
+ const enqueuedAt = Date.parse(options.timing.enqueuedAt)
1172
+ const providerUpdatedAt = Date.parse(options.timing.providerUpdatedAt)
1173
+ const receivedAt = Date.parse(options.timing.receivedAt)
1174
+ const sentAt = Date.parse(options.timing.sentAt)
1175
+ const segments = [
1176
+ { from: providerUpdatedAt, segment: 'provider_to_sent', to: sentAt },
1177
+ { from: sentAt, segment: 'sent_to_received', to: receivedAt },
1178
+ { from: receivedAt, segment: 'received_to_enqueued', to: enqueuedAt },
1179
+ { from: enqueuedAt, segment: 'enqueued_to_reconciled', to: completedAt },
1180
+ { from: providerUpdatedAt, segment: 'provider_to_reconciled', to: completedAt },
1181
+ ] as const
1182
+ for (const segment of segments)
1183
+ metrics.histogram(
1184
+ 'funding_deposit_webhook_latency_ms',
1185
+ Math.max(0, segment.to - segment.from),
1186
+ {
1187
+ provider: options.providerId,
1188
+ segment: segment.segment,
1189
+ status: options.timing.providerStatus,
1190
+ },
1191
+ )
1192
+ }
1193
+
1194
+ /** Provider pagination exceeded the bounded reconciliation limit. */
1195
+ export class PaginationLimitError extends Error {
1196
+ override name = 'Funding.Reconciliation.PaginationLimitError'
1197
+ }
1198
+
1199
+ /** The reconciliation lease was claimed by another worker. */
1200
+ export class StaleLeaseError extends Error {
1201
+ override name = 'Funding.Reconciliation.StaleLeaseError'
1202
+ }