tapimo 0.13.0 → 0.15.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 (1143) hide show
  1. package/README.md +7 -4
  2. package/dist/ApiKey.js +1 -1
  3. package/dist/ApiKey.js.map +1 -1
  4. package/dist/ApiKeys.d.ts +95 -14
  5. package/dist/ApiKeys.d.ts.map +1 -1
  6. package/dist/ApiKeys.js +360 -49
  7. package/dist/ApiKeys.js.map +1 -1
  8. package/dist/App.d.ts +21383 -18056
  9. package/dist/App.d.ts.map +1 -1
  10. package/dist/App.js +301 -22
  11. package/dist/App.js.map +1 -1
  12. package/dist/Assets.d.ts.map +1 -1
  13. package/dist/Assets.js +2 -1
  14. package/dist/Assets.js.map +1 -1
  15. package/dist/Handler.d.ts +0 -1
  16. package/dist/Handler.d.ts.map +1 -1
  17. package/dist/Handler.js +0 -1
  18. package/dist/Handler.js.map +1 -1
  19. package/dist/Scope.d.ts +13 -5
  20. package/dist/Scope.d.ts.map +1 -1
  21. package/dist/Scope.js +16 -5
  22. package/dist/Scope.js.map +1 -1
  23. package/dist/Webhooks.js +2 -2
  24. package/dist/Webhooks.js.map +1 -1
  25. package/dist/admin/App.d.ts +3936 -1337
  26. package/dist/admin/App.d.ts.map +1 -1
  27. package/dist/admin/App.js +26 -5
  28. package/dist/admin/App.js.map +1 -1
  29. package/dist/admin/apps/api-keys.d.ts +159 -7
  30. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  31. package/dist/admin/apps/api-keys.js +95 -43
  32. package/dist/admin/apps/api-keys.js.map +1 -1
  33. package/dist/admin/apps/earn-vaults.d.ts +1446 -0
  34. package/dist/admin/apps/earn-vaults.d.ts.map +1 -1
  35. package/dist/admin/apps/earn-vaults.js +465 -8
  36. package/dist/admin/apps/earn-vaults.js.map +1 -1
  37. package/dist/admin/apps/organizations.d.ts +344 -3
  38. package/dist/admin/apps/organizations.d.ts.map +1 -1
  39. package/dist/admin/apps/organizations.js +288 -10
  40. package/dist/admin/apps/organizations.js.map +1 -1
  41. package/dist/admin/apps/routes-support.d.ts +95 -0
  42. package/dist/admin/apps/routes-support.d.ts.map +1 -0
  43. package/dist/admin/apps/routes-support.js +151 -0
  44. package/dist/admin/apps/routes-support.js.map +1 -0
  45. package/dist/admin/apps/routes.d.ts +2764 -0
  46. package/dist/admin/apps/routes.d.ts.map +1 -0
  47. package/dist/admin/apps/routes.js +728 -0
  48. package/dist/admin/apps/routes.js.map +1 -0
  49. package/dist/admin/apps/subsidies.d.ts +501 -0
  50. package/dist/admin/apps/subsidies.d.ts.map +1 -0
  51. package/dist/admin/apps/subsidies.js +384 -0
  52. package/dist/admin/apps/subsidies.js.map +1 -0
  53. package/dist/admin/apps/verified-tokens.d.ts +16 -16
  54. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  55. package/dist/admin/apps/verified-tokens.js +3 -3
  56. package/dist/admin/apps/verified-tokens.js.map +1 -1
  57. package/dist/admin/ui.generated.d.ts +1 -1
  58. package/dist/admin/ui.generated.d.ts.map +1 -1
  59. package/dist/admin/ui.generated.js +129 -69
  60. package/dist/admin/ui.generated.js.map +1 -1
  61. package/dist/analytics/Analytics.d.ts +5 -2
  62. package/dist/analytics/Analytics.d.ts.map +1 -1
  63. package/dist/analytics/Analytics.js +31 -1
  64. package/dist/analytics/Analytics.js.map +1 -1
  65. package/dist/analytics/tables/requestEvents.d.ts +2 -1
  66. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  67. package/dist/analytics/tables/requestEvents.js +10 -1
  68. package/dist/analytics/tables/requestEvents.js.map +1 -1
  69. package/dist/analytics/tables/routesLifecycleIntervals.d.ts +72 -0
  70. package/dist/analytics/tables/routesLifecycleIntervals.d.ts.map +1 -0
  71. package/dist/analytics/tables/routesLifecycleIntervals.js +56 -0
  72. package/dist/analytics/tables/routesLifecycleIntervals.js.map +1 -0
  73. package/dist/apps/Zones.d.ts +21 -12526
  74. package/dist/apps/Zones.d.ts.map +1 -1
  75. package/dist/apps/Zones.js +40 -8
  76. package/dist/apps/Zones.js.map +1 -1
  77. package/dist/apps/data/App.d.ts +4310 -2548
  78. package/dist/apps/data/App.d.ts.map +1 -1
  79. package/dist/apps/data/App.js +86 -26
  80. package/dist/apps/data/App.js.map +1 -1
  81. package/dist/apps/data/routes/activities.d.ts +364 -34
  82. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  83. package/dist/apps/data/routes/activities.js +495 -190
  84. package/dist/apps/data/routes/activities.js.map +1 -1
  85. package/dist/apps/data/routes/addresses.d.ts +94 -22
  86. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  87. package/dist/apps/data/routes/blocks.d.ts +37 -37
  88. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  89. package/dist/apps/data/routes/coingecko.js +47 -21
  90. package/dist/apps/data/routes/coingecko.js.map +1 -1
  91. package/dist/apps/data/routes/earn.d.ts +1641 -352
  92. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  93. package/dist/apps/data/routes/earn.js +1561 -120
  94. package/dist/apps/data/routes/earn.js.map +1 -1
  95. package/dist/apps/data/routes/exchanges.d.ts +15 -0
  96. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  97. package/dist/apps/data/routes/exchanges.js +180 -114
  98. package/dist/apps/data/routes/exchanges.js.map +1 -1
  99. package/dist/apps/data/routes/fee-amm.d.ts +5 -0
  100. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  101. package/dist/apps/data/routes/fee-amm.js +49 -38
  102. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  103. package/dist/apps/data/routes/indexer.d.ts +125 -0
  104. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  105. package/dist/apps/data/routes/indexer.js +83 -27
  106. package/dist/apps/data/routes/indexer.js.map +1 -1
  107. package/dist/apps/data/routes/rpc.d.ts +507 -33
  108. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  109. package/dist/apps/data/routes/rpc.js +266 -156
  110. package/dist/apps/data/routes/rpc.js.map +1 -1
  111. package/dist/apps/data/routes/tokenlist.d.ts +47 -15
  112. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  113. package/dist/apps/data/routes/tokenlist.js +68 -11
  114. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  115. package/dist/apps/data/routes/tokens.d.ts +95 -93
  116. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  117. package/dist/apps/data/routes/tokens.js +26 -14
  118. package/dist/apps/data/routes/tokens.js.map +1 -1
  119. package/dist/apps/data/routes/transfers.d.ts +16 -0
  120. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  121. package/dist/apps/data/routes/transfers.js +9 -7
  122. package/dist/apps/data/routes/transfers.js.map +1 -1
  123. package/dist/apps/data/routes/verified-tokens.d.ts +4 -4
  124. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  125. package/dist/apps/data/routes/verified-tokens.js +64 -20
  126. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  127. package/dist/apps/data/routes/webhooks.d.ts +1210 -70
  128. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  129. package/dist/apps/data/routes/webhooks.js +301 -163
  130. package/dist/apps/data/routes/webhooks.js.map +1 -1
  131. package/dist/apps/data/routes/zones.d.ts.map +1 -1
  132. package/dist/apps/data/routes/zones.js +20 -12
  133. package/dist/apps/data/routes/zones.js.map +1 -1
  134. package/dist/apps/docs/reference.js +2 -2
  135. package/dist/apps/docs/reference.js.map +1 -1
  136. package/dist/apps/index.d.ts +1 -1
  137. package/dist/apps/index.d.ts.map +1 -1
  138. package/dist/apps/index.js +1 -1
  139. package/dist/apps/index.js.map +1 -1
  140. package/dist/apps/management/App.d.ts +4119 -3297
  141. package/dist/apps/management/App.d.ts.map +1 -1
  142. package/dist/apps/management/App.js +5 -14
  143. package/dist/apps/management/App.js.map +1 -1
  144. package/dist/apps/management/Billing.d.ts +49 -8
  145. package/dist/apps/management/Billing.d.ts.map +1 -1
  146. package/dist/apps/management/Billing.js +221 -26
  147. package/dist/apps/management/Billing.js.map +1 -1
  148. package/dist/apps/management/routes/api-keys.d.ts +174 -72
  149. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  150. package/dist/apps/management/routes/api-keys.js +43 -15
  151. package/dist/apps/management/routes/api-keys.js.map +1 -1
  152. package/dist/apps/management/routes/billing.d.ts +364 -78
  153. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  154. package/dist/apps/management/routes/billing.js +274 -49
  155. package/dist/apps/management/routes/billing.js.map +1 -1
  156. package/dist/apps/management/routes/faucet.d.ts +6 -6
  157. package/dist/apps/management/routes/faucet.js +1 -1
  158. package/dist/apps/management/routes/faucet.js.map +1 -1
  159. package/dist/apps/management/routes/invitations.d.ts +99 -24
  160. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  161. package/dist/apps/management/routes/invitations.js +117 -13
  162. package/dist/apps/management/routes/invitations.js.map +1 -1
  163. package/dist/apps/management/routes/invite-links.d.ts +42 -42
  164. package/dist/apps/management/routes/me.d.ts.map +1 -1
  165. package/dist/apps/management/routes/me.js +6 -2
  166. package/dist/apps/management/routes/me.js.map +1 -1
  167. package/dist/apps/management/routes/members.d.ts +16 -16
  168. package/dist/apps/management/routes/orgs.d.ts +36 -20
  169. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  170. package/dist/apps/management/routes/orgs.js +52 -12
  171. package/dist/apps/management/routes/orgs.js.map +1 -1
  172. package/dist/apps/management/routes/projects.d.ts +40 -40
  173. package/dist/apps/management/routes/projects.d.ts.map +1 -1
  174. package/dist/apps/management/routes/projects.js +6 -1
  175. package/dist/apps/management/routes/projects.js.map +1 -1
  176. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  177. package/dist/apps/management/routes/scopes.js +4 -1
  178. package/dist/apps/management/routes/scopes.js.map +1 -1
  179. package/dist/apps/management/routes/usage.d.ts +8 -8
  180. package/dist/apps/management/routes/usage.js +21 -4
  181. package/dist/apps/management/routes/usage.js.map +1 -1
  182. package/dist/apps/management/routes/verified-token-requests.d.ts +16 -16
  183. package/dist/apps/management/routes/webhooks.d.ts +931 -215
  184. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  185. package/dist/apps/management/routes/webhooks.js +71 -25
  186. package/dist/apps/management/routes/webhooks.js.map +1 -1
  187. package/dist/apps/mcp.d.ts +1 -1
  188. package/dist/apps/mcp.js +7 -7
  189. package/dist/apps/mcp.js.map +1 -1
  190. package/dist/apps/mpp/App.d.ts.map +1 -1
  191. package/dist/apps/mpp/App.js +35 -7
  192. package/dist/apps/mpp/App.js.map +1 -1
  193. package/dist/apps/mpp/internal/Adapter.d.ts +2 -0
  194. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -1
  195. package/dist/apps/mpp/internal/Adapter.js +30 -1
  196. package/dist/apps/mpp/internal/Adapter.js.map +1 -1
  197. package/dist/apps/mpp/internal/Policy.d.ts +22 -4
  198. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -1
  199. package/dist/apps/mpp/internal/Policy.js +24 -6
  200. package/dist/apps/mpp/internal/Policy.js.map +1 -1
  201. package/dist/apps/mpp/internal/Sponsorship.d.ts +3 -0
  202. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -1
  203. package/dist/apps/mpp/internal/Sponsorship.js +6 -3
  204. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -1
  205. package/dist/apps/relay/App.d.ts +2 -0
  206. package/dist/apps/relay/App.d.ts.map +1 -1
  207. package/dist/apps/relay/App.js +177 -26
  208. package/dist/apps/relay/App.js.map +1 -1
  209. package/dist/apps/relay/Sponsorships.d.ts +5 -3
  210. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  211. package/dist/apps/relay/Sponsorships.js +232 -25
  212. package/dist/apps/relay/Sponsorships.js.map +1 -1
  213. package/dist/apps/{funding → routes}/Access.d.ts +4 -4
  214. package/dist/apps/routes/Access.d.ts.map +1 -0
  215. package/dist/apps/{funding → routes}/Access.js +4 -4
  216. package/dist/apps/routes/Access.js.map +1 -0
  217. package/dist/apps/{funding → routes}/App.d.ts +841 -136
  218. package/dist/apps/{funding → routes}/App.d.ts.map +1 -1
  219. package/dist/apps/{funding → routes}/App.js +17 -17
  220. package/dist/apps/routes/App.js.map +1 -0
  221. package/dist/apps/routes/Inventory.d.ts.map +1 -0
  222. package/dist/apps/{funding → routes}/Inventory.js +2 -2
  223. package/dist/apps/routes/Inventory.js.map +1 -0
  224. package/dist/apps/routes/index.d.ts +2 -0
  225. package/dist/apps/routes/index.d.ts.map +1 -0
  226. package/dist/apps/routes/index.js +2 -0
  227. package/dist/apps/routes/index.js.map +1 -0
  228. package/dist/apps/{funding → routes}/routes/chains.d.ts +7 -7
  229. package/dist/apps/routes/routes/chains.d.ts.map +1 -0
  230. package/dist/apps/{funding → routes}/routes/chains.js +25 -25
  231. package/dist/apps/routes/routes/chains.js.map +1 -0
  232. package/dist/apps/{funding → routes}/routes/deposit-addresses.d.ts +123 -59
  233. package/dist/apps/routes/routes/deposit-addresses.d.ts.map +1 -0
  234. package/dist/apps/{funding → routes}/routes/deposit-addresses.js +498 -223
  235. package/dist/apps/routes/routes/deposit-addresses.js.map +1 -0
  236. package/dist/apps/{funding → routes}/routes/providers.d.ts +8 -8
  237. package/dist/apps/routes/routes/providers.d.ts.map +1 -0
  238. package/dist/apps/routes/routes/providers.js +57 -0
  239. package/dist/apps/routes/routes/providers.js.map +1 -0
  240. package/dist/apps/{funding → routes}/routes/quotes.d.ts +19 -16
  241. package/dist/apps/routes/routes/quotes.d.ts.map +1 -0
  242. package/dist/apps/{funding → routes}/routes/quotes.js +55 -38
  243. package/dist/apps/routes/routes/quotes.js.map +1 -0
  244. package/dist/apps/{funding → routes}/routes/transfers.d.ts +957 -71
  245. package/dist/apps/routes/routes/transfers.d.ts.map +1 -0
  246. package/dist/apps/routes/routes/transfers.js +1140 -0
  247. package/dist/apps/routes/routes/transfers.js.map +1 -0
  248. package/dist/cli/Cli.d.ts +30 -0
  249. package/dist/cli/Cli.d.ts.map +1 -1
  250. package/dist/cli/commands/admin.d.ts +36 -0
  251. package/dist/cli/commands/admin.d.ts.map +1 -1
  252. package/dist/cli/commands/admin.js +273 -0
  253. package/dist/cli/commands/admin.js.map +1 -1
  254. package/dist/cloudflare.d.ts +16 -14
  255. package/dist/cloudflare.d.ts.map +1 -1
  256. package/dist/cloudflare.js +26 -21
  257. package/dist/cloudflare.js.map +1 -1
  258. package/dist/db/Db.d.ts +63 -21
  259. package/dist/db/Db.d.ts.map +1 -1
  260. package/dist/db/Db.js +1052 -15
  261. package/dist/db/Db.js.map +1 -1
  262. package/dist/db/Schema.d.ts +785 -133
  263. package/dist/db/Schema.d.ts.map +1 -1
  264. package/dist/db/Schema.js +590 -162
  265. package/dist/db/Schema.js.map +1 -1
  266. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts +4 -0
  267. package/dist/db/tables/apiKeyAdmissionBootstraps.d.ts.map +1 -0
  268. package/dist/db/tables/apiKeyAdmissionBootstraps.js +2 -0
  269. package/dist/db/tables/apiKeyAdmissionBootstraps.js.map +1 -0
  270. package/dist/db/tables/apiKeyAdmissions.d.ts +73 -0
  271. package/dist/db/tables/apiKeyAdmissions.d.ts.map +1 -0
  272. package/dist/db/tables/apiKeyAdmissions.js +142 -0
  273. package/dist/db/tables/apiKeyAdmissions.js.map +1 -0
  274. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts +4 -0
  275. package/dist/db/tables/apiKeyOwnerAdmissions.d.ts.map +1 -0
  276. package/dist/db/tables/apiKeyOwnerAdmissions.js +2 -0
  277. package/dist/db/tables/apiKeyOwnerAdmissions.js.map +1 -0
  278. package/dist/db/tables/apiKeyOwnerTombstones.d.ts +20 -0
  279. package/dist/db/tables/apiKeyOwnerTombstones.d.ts.map +1 -0
  280. package/dist/db/tables/apiKeyOwnerTombstones.js +57 -0
  281. package/dist/db/tables/apiKeyOwnerTombstones.js.map +1 -0
  282. package/dist/db/tables/apiKeyRevocations.d.ts +21 -0
  283. package/dist/db/tables/apiKeyRevocations.d.ts.map +1 -0
  284. package/dist/db/tables/apiKeyRevocations.js +98 -0
  285. package/dist/db/tables/apiKeyRevocations.js.map +1 -0
  286. package/dist/db/tables/authAccounts.d.ts +47 -0
  287. package/dist/db/tables/authAccounts.d.ts.map +1 -0
  288. package/dist/db/tables/authAccounts.js +72 -0
  289. package/dist/db/tables/authAccounts.js.map +1 -0
  290. package/dist/db/tables/authSessions.d.ts +12 -0
  291. package/dist/db/tables/authSessions.d.ts.map +1 -0
  292. package/dist/db/tables/authSessions.js +2 -0
  293. package/dist/db/tables/authSessions.js.map +1 -0
  294. package/dist/db/tables/authVerifications.d.ts +12 -0
  295. package/dist/db/tables/authVerifications.d.ts.map +1 -0
  296. package/dist/db/tables/authVerifications.js +2 -0
  297. package/dist/db/tables/authVerifications.js.map +1 -0
  298. package/dist/db/tables/invitations.d.ts +17 -1
  299. package/dist/db/tables/invitations.d.ts.map +1 -1
  300. package/dist/db/tables/invitations.js +123 -43
  301. package/dist/db/tables/invitations.js.map +1 -1
  302. package/dist/db/tables/memberships.d.ts +8 -0
  303. package/dist/db/tables/memberships.d.ts.map +1 -1
  304. package/dist/db/tables/memberships.js +51 -2
  305. package/dist/db/tables/memberships.js.map +1 -1
  306. package/dist/db/tables/organizations.d.ts +51 -5
  307. package/dist/db/tables/organizations.d.ts.map +1 -1
  308. package/dist/db/tables/organizations.js +135 -47
  309. package/dist/db/tables/organizations.js.map +1 -1
  310. package/dist/db/tables/projects.d.ts +27 -1
  311. package/dist/db/tables/projects.d.ts.map +1 -1
  312. package/dist/db/tables/projects.js +38 -3
  313. package/dist/db/tables/projects.js.map +1 -1
  314. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  315. package/dist/db/tables/requestUsage.js.map +1 -1
  316. package/dist/db/tables/rewardAccounts.d.ts +86 -0
  317. package/dist/db/tables/rewardAccounts.d.ts.map +1 -0
  318. package/dist/db/tables/rewardAccounts.js +88 -0
  319. package/dist/db/tables/rewardAccounts.js.map +1 -0
  320. package/dist/db/tables/rewardCampaignDistributors.d.ts +36 -0
  321. package/dist/db/tables/rewardCampaignDistributors.d.ts.map +1 -0
  322. package/dist/db/tables/rewardCampaignDistributors.js +30 -0
  323. package/dist/db/tables/rewardCampaignDistributors.js.map +1 -0
  324. package/dist/db/tables/rewardCampaigns.d.ts +171 -0
  325. package/dist/db/tables/rewardCampaigns.d.ts.map +1 -0
  326. package/dist/db/tables/rewardCampaigns.js +392 -0
  327. package/dist/db/tables/rewardCampaigns.js.map +1 -0
  328. package/dist/db/tables/rewardCredits.d.ts +53 -0
  329. package/dist/db/tables/rewardCredits.d.ts.map +1 -0
  330. package/dist/db/tables/rewardCredits.js +63 -0
  331. package/dist/db/tables/rewardCredits.js.map +1 -0
  332. package/dist/db/tables/rewardEligibilityAssociations.d.ts +61 -0
  333. package/dist/db/tables/rewardEligibilityAssociations.d.ts.map +1 -0
  334. package/dist/db/tables/rewardEligibilityAssociations.js +103 -0
  335. package/dist/db/tables/rewardEligibilityAssociations.js.map +1 -0
  336. package/dist/db/tables/rewardRuns.d.ts +188 -0
  337. package/dist/db/tables/rewardRuns.d.ts.map +1 -0
  338. package/dist/db/tables/rewardRuns.js +278 -0
  339. package/dist/db/tables/rewardRuns.js.map +1 -0
  340. package/dist/db/tables/rewardTransactionAttempts.d.ts +100 -0
  341. package/dist/db/tables/rewardTransactionAttempts.d.ts.map +1 -0
  342. package/dist/db/tables/rewardTransactionAttempts.js +163 -0
  343. package/dist/db/tables/rewardTransactionAttempts.js.map +1 -0
  344. package/dist/db/tables/routesCatalog.d.ts +58 -0
  345. package/dist/db/tables/routesCatalog.d.ts.map +1 -0
  346. package/dist/db/tables/{fundingCatalog.js → routesCatalog.js} +19 -19
  347. package/dist/db/tables/routesCatalog.js.map +1 -0
  348. package/dist/db/tables/routesDepositAddresses.d.ts +476 -0
  349. package/dist/db/tables/routesDepositAddresses.d.ts.map +1 -0
  350. package/dist/db/tables/routesDepositAddresses.js +587 -0
  351. package/dist/db/tables/routesDepositAddresses.js.map +1 -0
  352. package/dist/db/tables/{fundingDepositRequestObservations.d.ts → routesDepositRequestObservations.d.ts} +6 -6
  353. package/dist/db/tables/routesDepositRequestObservations.d.ts.map +1 -0
  354. package/dist/db/tables/{fundingDepositRequestObservations.js → routesDepositRequestObservations.js} +6 -6
  355. package/dist/db/tables/routesDepositRequestObservations.js.map +1 -0
  356. package/dist/db/tables/{fundingDeposits.d.ts → routesDeposits.d.ts} +210 -22
  357. package/dist/db/tables/routesDeposits.d.ts.map +1 -0
  358. package/dist/db/tables/routesDeposits.js +576 -0
  359. package/dist/db/tables/routesDeposits.js.map +1 -0
  360. package/dist/db/tables/routesIdempotency.d.ts +166 -0
  361. package/dist/db/tables/routesIdempotency.d.ts.map +1 -0
  362. package/dist/db/tables/routesIdempotency.js +330 -0
  363. package/dist/db/tables/routesIdempotency.js.map +1 -0
  364. package/dist/db/tables/routesSubsidies.d.ts +27 -0
  365. package/dist/db/tables/routesSubsidies.d.ts.map +1 -0
  366. package/dist/db/tables/routesSubsidies.js +45 -0
  367. package/dist/db/tables/routesSubsidies.js.map +1 -0
  368. package/dist/db/tables/{fundingTransferEvents.d.ts → routesTransferEvents.d.ts} +3 -3
  369. package/dist/db/tables/routesTransferEvents.d.ts.map +1 -0
  370. package/dist/db/tables/{fundingTransferEvents.js → routesTransferEvents.js} +3 -3
  371. package/dist/db/tables/routesTransferEvents.js.map +1 -0
  372. package/dist/db/tables/routesTransferSubsidies.d.ts +19 -0
  373. package/dist/db/tables/routesTransferSubsidies.d.ts.map +1 -0
  374. package/dist/db/tables/routesTransferSubsidies.js +17 -0
  375. package/dist/db/tables/routesTransferSubsidies.js.map +1 -0
  376. package/dist/db/tables/routesTransferSubsidyNonces.d.ts +51 -0
  377. package/dist/db/tables/routesTransferSubsidyNonces.d.ts.map +1 -0
  378. package/dist/db/tables/routesTransferSubsidyNonces.js +82 -0
  379. package/dist/db/tables/routesTransferSubsidyNonces.js.map +1 -0
  380. package/dist/db/tables/routesTransferTransactions.d.ts +77 -0
  381. package/dist/db/tables/routesTransferTransactions.d.ts.map +1 -0
  382. package/dist/db/tables/routesTransferTransactions.js +86 -0
  383. package/dist/db/tables/routesTransferTransactions.js.map +1 -0
  384. package/dist/db/tables/routesTransfers.d.ts +319 -0
  385. package/dist/db/tables/routesTransfers.d.ts.map +1 -0
  386. package/dist/db/tables/routesTransfers.js +372 -0
  387. package/dist/db/tables/routesTransfers.js.map +1 -0
  388. package/dist/db/tables/sponsoredTransactions.d.ts +112 -13
  389. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  390. package/dist/db/tables/sponsoredTransactions.js +241 -38
  391. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  392. package/dist/db/tables/sponsorshipAttributions.d.ts +69 -0
  393. package/dist/db/tables/sponsorshipAttributions.d.ts.map +1 -0
  394. package/dist/db/tables/sponsorshipAttributions.js +77 -0
  395. package/dist/db/tables/sponsorshipAttributions.js.map +1 -0
  396. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts +22 -0
  397. package/dist/db/tables/sponsorshipReconciliationCursors.d.ts.map +1 -0
  398. package/dist/db/tables/sponsorshipReconciliationCursors.js +45 -0
  399. package/dist/db/tables/sponsorshipReconciliationCursors.js.map +1 -0
  400. package/dist/db/tables/stripeCustomers.d.ts +11 -0
  401. package/dist/db/tables/stripeCustomers.d.ts.map +1 -1
  402. package/dist/db/tables/stripeCustomers.js +13 -0
  403. package/dist/db/tables/stripeCustomers.js.map +1 -1
  404. package/dist/db/tables/users.d.ts +17 -1
  405. package/dist/db/tables/users.d.ts.map +1 -1
  406. package/dist/db/tables/users.js +47 -2
  407. package/dist/db/tables/users.js.map +1 -1
  408. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -1
  409. package/dist/db/tables/webhookQueueEvents.js +5 -1
  410. package/dist/db/tables/webhookQueueEvents.js.map +1 -1
  411. package/dist/db/tables/webhookSubscriptions.d.ts +22 -10
  412. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  413. package/dist/db/tables/webhookSubscriptions.js +50 -15
  414. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  415. package/dist/handlers/internal/executionError.d.ts +2 -2
  416. package/dist/handlers/internal/executionError.d.ts.map +1 -1
  417. package/dist/handlers/internal/executionError.js +1 -2
  418. package/dist/handlers/internal/executionError.js.map +1 -1
  419. package/dist/handlers/internal/multisig.d.ts +4 -232
  420. package/dist/handlers/internal/multisig.d.ts.map +1 -1
  421. package/dist/handlers/internal/multisig.js +11 -537
  422. package/dist/handlers/internal/multisig.js.map +1 -1
  423. package/dist/handlers/internal/sponsorship.d.ts +19 -8
  424. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  425. package/dist/handlers/internal/sponsorship.js +13 -9
  426. package/dist/handlers/internal/sponsorship.js.map +1 -1
  427. package/dist/handlers/relay.d.ts +9 -12
  428. package/dist/handlers/relay.d.ts.map +1 -1
  429. package/dist/handlers/relay.js +81 -85
  430. package/dist/handlers/relay.js.map +1 -1
  431. package/dist/index.d.ts +0 -17
  432. package/dist/index.d.ts.map +1 -1
  433. package/dist/index.js +0 -17
  434. package/dist/index.js.map +1 -1
  435. package/dist/internal/AssetResponse.d.ts +12 -0
  436. package/dist/internal/AssetResponse.d.ts.map +1 -0
  437. package/dist/internal/AssetResponse.js +21 -0
  438. package/dist/internal/AssetResponse.js.map +1 -0
  439. package/dist/internal/Auth.d.ts +48 -12
  440. package/dist/internal/Auth.d.ts.map +1 -1
  441. package/dist/internal/Auth.js +603 -175
  442. package/dist/internal/Auth.js.map +1 -1
  443. package/dist/internal/BetterAuth.d.ts +1488 -0
  444. package/dist/internal/BetterAuth.d.ts.map +1 -0
  445. package/dist/internal/BetterAuth.js +253 -0
  446. package/dist/internal/BetterAuth.js.map +1 -0
  447. package/dist/internal/Cache.d.ts +2 -0
  448. package/dist/internal/Cache.d.ts.map +1 -1
  449. package/dist/internal/Cache.js +2 -0
  450. package/dist/internal/Cache.js.map +1 -1
  451. package/dist/internal/EarnRates.d.ts +26 -3
  452. package/dist/internal/EarnRates.d.ts.map +1 -1
  453. package/dist/internal/EarnRates.js +84 -19
  454. package/dist/internal/EarnRates.js.map +1 -1
  455. package/dist/internal/EarnSharePrices.d.ts +120 -0
  456. package/dist/internal/EarnSharePrices.d.ts.map +1 -0
  457. package/dist/internal/EarnSharePrices.js +179 -0
  458. package/dist/internal/EarnSharePrices.js.map +1 -0
  459. package/dist/internal/EarnVaults.d.ts +4 -0
  460. package/dist/internal/EarnVaults.d.ts.map +1 -1
  461. package/dist/internal/EarnVaults.js +31 -14
  462. package/dist/internal/EarnVaults.js.map +1 -1
  463. package/dist/internal/Email.d.ts +37 -0
  464. package/dist/internal/Email.d.ts.map +1 -0
  465. package/dist/internal/Email.js +16 -0
  466. package/dist/internal/Email.js.map +1 -0
  467. package/dist/internal/Log.d.ts +32 -28
  468. package/dist/internal/Log.d.ts.map +1 -1
  469. package/dist/internal/Log.js +18 -11
  470. package/dist/internal/Log.js.map +1 -1
  471. package/dist/internal/MetricSink.d.ts +3 -0
  472. package/dist/internal/MetricSink.d.ts.map +1 -1
  473. package/dist/internal/MetricSink.js +67 -8
  474. package/dist/internal/MetricSink.js.map +1 -1
  475. package/dist/internal/Mpp.d.ts.map +1 -1
  476. package/dist/internal/Mpp.js +20 -25
  477. package/dist/internal/Mpp.js.map +1 -1
  478. package/dist/internal/OpenApi.d.ts +26 -3
  479. package/dist/internal/OpenApi.d.ts.map +1 -1
  480. package/dist/internal/OpenApi.js +25 -10
  481. package/dist/internal/OpenApi.js.map +1 -1
  482. package/dist/internal/Provider.d.ts +1 -1
  483. package/dist/internal/Provider.d.ts.map +1 -1
  484. package/dist/internal/RateLimit.d.ts.map +1 -1
  485. package/dist/internal/RateLimit.js +13 -1
  486. package/dist/internal/RateLimit.js.map +1 -1
  487. package/dist/internal/Store.d.ts +16 -0
  488. package/dist/internal/Store.d.ts.map +1 -1
  489. package/dist/internal/Store.js +59 -8
  490. package/dist/internal/Store.js.map +1 -1
  491. package/dist/internal/Tidx.d.ts +9 -2
  492. package/dist/internal/Tidx.d.ts.map +1 -1
  493. package/dist/internal/Tidx.js +78 -11
  494. package/dist/internal/Tidx.js.map +1 -1
  495. package/dist/internal/Timing.d.ts +26 -0
  496. package/dist/internal/Timing.d.ts.map +1 -1
  497. package/dist/internal/Timing.js +63 -5
  498. package/dist/internal/Timing.js.map +1 -1
  499. package/dist/internal/VercelOidc.d.ts +94 -0
  500. package/dist/internal/VercelOidc.d.ts.map +1 -0
  501. package/dist/internal/VercelOidc.js +128 -0
  502. package/dist/internal/VercelOidc.js.map +1 -0
  503. package/dist/internal/VerifiedTokens.d.ts +2 -8
  504. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  505. package/dist/internal/VerifiedTokens.js +24 -24
  506. package/dist/internal/VerifiedTokens.js.map +1 -1
  507. package/dist/internal/Viem.d.ts +46 -2068
  508. package/dist/internal/Viem.d.ts.map +1 -1
  509. package/dist/internal/Viem.js +171 -11
  510. package/dist/internal/Viem.js.map +1 -1
  511. package/dist/internal/Webhooks.d.ts +12 -4
  512. package/dist/internal/Webhooks.d.ts.map +1 -1
  513. package/dist/internal/Webhooks.js +9 -3
  514. package/dist/internal/Webhooks.js.map +1 -1
  515. package/dist/internal/ZoneRpc.d.ts +7 -0
  516. package/dist/internal/ZoneRpc.d.ts.map +1 -0
  517. package/dist/internal/ZoneRpc.js +49 -0
  518. package/dist/internal/ZoneRpc.js.map +1 -0
  519. package/dist/internal/index.d.ts +3 -1
  520. package/dist/internal/index.d.ts.map +1 -1
  521. package/dist/internal/index.js +3 -1
  522. package/dist/internal/index.js.map +1 -1
  523. package/dist/internal/rewards/Audit.d.ts +88 -0
  524. package/dist/internal/rewards/Audit.d.ts.map +1 -0
  525. package/dist/internal/rewards/Audit.js +134 -0
  526. package/dist/internal/rewards/Audit.js.map +1 -0
  527. package/dist/internal/rewards/Campaigns.d.ts +572 -0
  528. package/dist/internal/rewards/Campaigns.d.ts.map +1 -0
  529. package/dist/internal/rewards/Campaigns.js +531 -0
  530. package/dist/internal/rewards/Campaigns.js.map +1 -0
  531. package/dist/internal/rewards/Credits.d.ts +76 -0
  532. package/dist/internal/rewards/Credits.d.ts.map +1 -0
  533. package/dist/internal/rewards/Credits.js +95 -0
  534. package/dist/internal/rewards/Credits.js.map +1 -0
  535. package/dist/internal/rewards/Events.d.ts +100 -0
  536. package/dist/internal/rewards/Events.d.ts.map +1 -0
  537. package/dist/internal/rewards/Events.js +340 -0
  538. package/dist/internal/rewards/Events.js.map +1 -0
  539. package/dist/internal/rewards/Projection.d.ts +237 -0
  540. package/dist/internal/rewards/Projection.d.ts.map +1 -0
  541. package/dist/internal/rewards/Projection.js +616 -0
  542. package/dist/internal/rewards/Projection.js.map +1 -0
  543. package/dist/internal/rewards/Rates.d.ts +44 -0
  544. package/dist/internal/rewards/Rates.d.ts.map +1 -0
  545. package/dist/internal/rewards/Rates.js +60 -0
  546. package/dist/internal/rewards/Rates.js.map +1 -0
  547. package/dist/internal/rewards/Read.d.ts +158 -0
  548. package/dist/internal/rewards/Read.d.ts.map +1 -0
  549. package/dist/internal/rewards/Read.js +292 -0
  550. package/dist/internal/rewards/Read.js.map +1 -0
  551. package/dist/internal/rewards/Runner.d.ts +164 -0
  552. package/dist/internal/rewards/Runner.d.ts.map +1 -0
  553. package/dist/internal/rewards/Runner.js +1778 -0
  554. package/dist/internal/rewards/Runner.js.map +1 -0
  555. package/dist/internal/rewards/Signer.d.ts +224 -0
  556. package/dist/internal/rewards/Signer.d.ts.map +1 -0
  557. package/dist/internal/rewards/Signer.js +135 -0
  558. package/dist/internal/rewards/Signer.js.map +1 -0
  559. package/dist/internal/rewards/index.d.ts +15 -0
  560. package/dist/internal/rewards/index.d.ts.map +1 -0
  561. package/dist/internal/rewards/index.js +15 -0
  562. package/dist/internal/rewards/index.js.map +1 -0
  563. package/dist/internal/{funding → routes}/Action.d.ts +12 -1
  564. package/dist/internal/routes/Action.d.ts.map +1 -0
  565. package/dist/internal/{funding → routes}/Action.js +17 -9
  566. package/dist/internal/routes/Action.js.map +1 -0
  567. package/dist/internal/{funding → routes}/Catalog.d.ts +20 -20
  568. package/dist/internal/routes/Catalog.d.ts.map +1 -0
  569. package/dist/internal/{funding → routes}/Catalog.js +29 -29
  570. package/dist/internal/routes/Catalog.js.map +1 -0
  571. package/dist/internal/{funding → routes}/Chain.d.ts +10 -10
  572. package/dist/internal/routes/Chain.d.ts.map +1 -0
  573. package/dist/internal/{funding → routes}/Chain.js +3 -3
  574. package/dist/internal/routes/Chain.js.map +1 -0
  575. package/dist/internal/{funding → routes}/Deposit.d.ts +45 -23
  576. package/dist/internal/routes/Deposit.d.ts.map +1 -0
  577. package/dist/internal/{funding → routes}/Deposit.js +60 -27
  578. package/dist/internal/routes/Deposit.js.map +1 -0
  579. package/dist/internal/{funding → routes}/DepositAddress.d.ts +56 -27
  580. package/dist/internal/routes/DepositAddress.d.ts.map +1 -0
  581. package/dist/internal/{funding → routes}/DepositAddress.js +95 -33
  582. package/dist/internal/routes/DepositAddress.js.map +1 -0
  583. package/dist/internal/{funding → routes}/DepositWebhook.d.ts +4 -4
  584. package/dist/internal/routes/DepositWebhook.d.ts.map +1 -0
  585. package/dist/internal/{funding → routes}/DepositWebhook.js +4 -3
  586. package/dist/internal/routes/DepositWebhook.js.map +1 -0
  587. package/dist/internal/routes/Economics.d.ts +25 -0
  588. package/dist/internal/routes/Economics.d.ts.map +1 -0
  589. package/dist/internal/routes/Economics.js +28 -0
  590. package/dist/internal/routes/Economics.js.map +1 -0
  591. package/dist/internal/{funding → routes}/Evidence.d.ts +3 -3
  592. package/dist/internal/routes/Evidence.d.ts.map +1 -0
  593. package/dist/internal/{funding → routes}/Evidence.js +9 -17
  594. package/dist/internal/routes/Evidence.js.map +1 -0
  595. package/dist/internal/routes/Observability.d.ts +154 -0
  596. package/dist/internal/routes/Observability.d.ts.map +1 -0
  597. package/dist/internal/routes/Observability.js +389 -0
  598. package/dist/internal/routes/Observability.js.map +1 -0
  599. package/dist/internal/{funding → routes}/Provider.d.ts +350 -104
  600. package/dist/internal/routes/Provider.d.ts.map +1 -0
  601. package/dist/internal/{funding → routes}/Provider.js +233 -97
  602. package/dist/internal/routes/Provider.js.map +1 -0
  603. package/dist/internal/{funding → routes}/Reconciliation.d.ts +11 -6
  604. package/dist/internal/routes/Reconciliation.d.ts.map +1 -0
  605. package/dist/internal/{funding → routes}/Reconciliation.js +408 -158
  606. package/dist/internal/routes/Reconciliation.js.map +1 -0
  607. package/dist/internal/routes/Route.d.ts +21 -0
  608. package/dist/internal/routes/Route.d.ts.map +1 -0
  609. package/dist/internal/{funding → routes}/Route.js +1 -1
  610. package/dist/internal/routes/Route.js.map +1 -0
  611. package/dist/internal/{funding → routes}/SourceObservation.d.ts +6 -6
  612. package/dist/internal/routes/SourceObservation.d.ts.map +1 -0
  613. package/dist/internal/{funding → routes}/SourceObservation.js +13 -15
  614. package/dist/internal/routes/SourceObservation.js.map +1 -0
  615. package/dist/internal/{funding → routes}/Subsidy.d.ts +48 -3
  616. package/dist/internal/routes/Subsidy.d.ts.map +1 -0
  617. package/dist/internal/{funding → routes}/Subsidy.js +43 -3
  618. package/dist/internal/routes/Subsidy.js.map +1 -0
  619. package/dist/internal/{funding → routes}/Token.d.ts +4 -4
  620. package/dist/internal/routes/Token.d.ts.map +1 -0
  621. package/dist/internal/{funding → routes}/Token.js +3 -3
  622. package/dist/internal/routes/Token.js.map +1 -0
  623. package/dist/internal/{funding → routes}/Transfer.d.ts +324 -34
  624. package/dist/internal/routes/Transfer.d.ts.map +1 -0
  625. package/dist/internal/routes/Transfer.js +728 -0
  626. package/dist/internal/routes/Transfer.js.map +1 -0
  627. package/dist/internal/routes/TransferReconciliation.d.ts +55 -0
  628. package/dist/internal/routes/TransferReconciliation.d.ts.map +1 -0
  629. package/dist/internal/routes/TransferReconciliation.js +422 -0
  630. package/dist/internal/routes/TransferReconciliation.js.map +1 -0
  631. package/dist/internal/routes/TransferSubsidy.d.ts +201 -0
  632. package/dist/internal/routes/TransferSubsidy.d.ts.map +1 -0
  633. package/dist/internal/routes/TransferSubsidy.js +256 -0
  634. package/dist/internal/routes/TransferSubsidy.js.map +1 -0
  635. package/dist/internal/routes/TransferWebhook.d.ts +21 -0
  636. package/dist/internal/routes/TransferWebhook.d.ts.map +1 -0
  637. package/dist/internal/routes/TransferWebhook.js +43 -0
  638. package/dist/internal/routes/TransferWebhook.js.map +1 -0
  639. package/dist/internal/{funding → routes}/index.d.ts +3 -0
  640. package/dist/internal/routes/index.d.ts.map +1 -0
  641. package/dist/internal/{funding → routes}/index.js +3 -0
  642. package/dist/internal/routes/index.js.map +1 -0
  643. package/dist/internal/{funding → routes}/providers/across.d.ts +4 -4
  644. package/dist/internal/routes/providers/across.d.ts.map +1 -0
  645. package/dist/internal/{funding → routes}/providers/across.js +13 -13
  646. package/dist/internal/routes/providers/across.js.map +1 -0
  647. package/dist/internal/{funding → routes}/providers/relay.d.ts +21 -12
  648. package/dist/internal/routes/providers/relay.d.ts.map +1 -0
  649. package/dist/internal/{funding → routes}/providers/relay.js +197 -122
  650. package/dist/internal/routes/providers/relay.js.map +1 -0
  651. package/dist/internal/{funding → routes}/providers/rhino.d.ts +4 -4
  652. package/dist/internal/routes/providers/rhino.d.ts.map +1 -0
  653. package/dist/internal/{funding → routes}/providers/rhino.js +10 -10
  654. package/dist/internal/routes/providers/rhino.js.map +1 -0
  655. package/dist/internal/{funding → routes}/providers/squid.d.ts +4 -4
  656. package/dist/internal/routes/providers/squid.d.ts.map +1 -0
  657. package/dist/internal/{funding → routes}/providers/squid.js +14 -14
  658. package/dist/internal/routes/providers/squid.js.map +1 -0
  659. package/dist/internal/routes/providers/stargate.d.ts +165 -0
  660. package/dist/internal/routes/providers/stargate.d.ts.map +1 -0
  661. package/dist/internal/routes/providers/stargate.js +898 -0
  662. package/dist/internal/routes/providers/stargate.js.map +1 -0
  663. package/dist/internal/{funding → routes}/providers/symbiosis.d.ts +4 -4
  664. package/dist/internal/routes/providers/symbiosis.d.ts.map +1 -0
  665. package/dist/internal/{funding → routes}/providers/symbiosis.js +30 -20
  666. package/dist/internal/routes/providers/symbiosis.js.map +1 -0
  667. package/dist/internal/webhookDestinations/slack.d.ts.map +1 -1
  668. package/dist/internal/webhookDestinations/slack.js +22 -6
  669. package/dist/internal/webhookDestinations/slack.js.map +1 -1
  670. package/dist/providers/index.d.ts +12 -12
  671. package/dist/providers/index.d.ts.map +1 -1
  672. package/dist/providers/index.js +12 -12
  673. package/dist/providers/index.js.map +1 -1
  674. package/dist/server.d.ts +19 -0
  675. package/dist/server.d.ts.map +1 -0
  676. package/dist/server.js +19 -0
  677. package/dist/server.js.map +1 -0
  678. package/package.json +15 -4
  679. package/src/ApiKey.ts +1 -1
  680. package/src/ApiKeys.test.ts +1033 -3
  681. package/src/ApiKeys.ts +489 -48
  682. package/src/App.test-d.ts +1 -1
  683. package/src/App.test.ts +216 -25
  684. package/src/App.ts +335 -31
  685. package/src/Assets.test.ts +2 -2
  686. package/src/Assets.ts +3 -1
  687. package/src/Auth.test-d.ts +1 -1
  688. package/src/Client.test-d.ts +611 -101
  689. package/src/Handler.ts +0 -1
  690. package/src/OpenApi.contract.test.ts +195 -0
  691. package/src/Scope.ts +17 -5
  692. package/src/Webhooks.ts +2 -2
  693. package/src/admin/App.test.ts +30 -2
  694. package/src/admin/App.ts +42 -6
  695. package/src/admin/apps/api-keys.test.ts +267 -5
  696. package/src/admin/apps/api-keys.ts +100 -50
  697. package/src/admin/apps/earn-vaults.test.ts +158 -0
  698. package/src/admin/apps/earn-vaults.ts +681 -7
  699. package/src/admin/apps/organizations.test.ts +342 -1
  700. package/src/admin/apps/organizations.ts +368 -8
  701. package/src/admin/apps/routes-support.test.ts +200 -0
  702. package/src/admin/apps/routes-support.ts +201 -0
  703. package/src/admin/apps/routes.test.ts +450 -0
  704. package/src/admin/apps/routes.ts +896 -0
  705. package/src/admin/apps/scopes.test.ts +15 -5
  706. package/src/admin/apps/subsidies.test.ts +306 -0
  707. package/src/admin/apps/subsidies.ts +457 -0
  708. package/src/admin/apps/verified-tokens.test.ts +8 -3
  709. package/src/admin/apps/verified-tokens.ts +3 -3
  710. package/src/admin/ui/plugin.ts +1 -2
  711. package/src/admin/ui/src/components/RewardCampaignForm.tsx +1009 -0
  712. package/src/admin/ui/src/lib/config.ts +11 -2
  713. package/src/admin/ui/src/lib/earn-vaults.ts +2 -2
  714. package/src/admin/ui/src/lib/organizations.test.ts +147 -3
  715. package/src/admin/ui/src/lib/organizations.ts +136 -0
  716. package/src/admin/ui/src/lib/query-client.ts +1 -1
  717. package/src/admin/ui/src/lib/reward-campaigns.ts +136 -0
  718. package/src/admin/ui/src/lib/routes.test.ts +88 -0
  719. package/src/admin/ui/src/lib/routes.ts +304 -0
  720. package/src/admin/ui/src/lib/subsidies.ts +75 -0
  721. package/src/admin/ui/src/routeTree.gen.ts +63 -0
  722. package/src/admin/ui/src/routes/__root.tsx +12 -1
  723. package/src/admin/ui/src/routes/api-keys.tsx +196 -84
  724. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +105 -70
  725. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +334 -2
  726. package/src/admin/ui/src/routes/routes.tsx +1615 -0
  727. package/src/admin/ui/src/routes/routes_.support.tsx +248 -0
  728. package/src/admin/ui/src/routes/subsidies.tsx +799 -0
  729. package/src/admin/ui.generated.ts +144 -69
  730. package/src/analytics/Analytics.test.ts +108 -18
  731. package/src/analytics/Analytics.ts +38 -6
  732. package/src/analytics/tables/requestEvents.test.ts +100 -0
  733. package/src/analytics/tables/requestEvents.ts +10 -1
  734. package/src/analytics/tables/routesLifecycleIntervals.ts +140 -0
  735. package/src/apps/Zones.test.ts +18 -3
  736. package/src/apps/Zones.ts +55 -8
  737. package/src/apps/composition.test.ts +68 -59
  738. package/src/apps/data/App.test.ts +154 -2
  739. package/src/apps/data/App.ts +102 -33
  740. package/src/apps/data/routes/activities.test.ts +419 -7
  741. package/src/apps/data/routes/activities.ts +683 -216
  742. package/src/apps/data/routes/balances.test.ts +2 -2
  743. package/src/apps/data/routes/blocks.test.ts +46 -1
  744. package/src/apps/data/routes/coingecko.test.ts +419 -1
  745. package/src/apps/data/routes/coingecko.ts +309 -253
  746. package/src/apps/data/routes/earn.discovery.test.ts +274 -0
  747. package/src/apps/data/routes/earn.test.ts +1661 -29
  748. package/src/apps/data/routes/earn.ts +2314 -328
  749. package/src/apps/data/routes/exchanges.test.ts +752 -30
  750. package/src/apps/data/routes/exchanges.ts +954 -753
  751. package/src/apps/data/routes/fee-amm.test.ts +224 -0
  752. package/src/apps/data/routes/fee-amm.ts +208 -178
  753. package/src/apps/data/routes/indexer.test.ts +389 -0
  754. package/src/apps/data/routes/indexer.ts +165 -69
  755. package/src/apps/data/routes/receipts.test.ts +1 -1
  756. package/src/apps/data/routes/rpc.test.ts +352 -8
  757. package/src/apps/data/routes/rpc.ts +407 -219
  758. package/src/apps/data/routes/rpc.zone.test.ts +340 -0
  759. package/src/apps/data/routes/tokenlist.test.ts +285 -0
  760. package/src/apps/data/routes/tokenlist.ts +173 -88
  761. package/src/apps/data/routes/tokens.test.ts +93 -3
  762. package/src/apps/data/routes/tokens.ts +39 -23
  763. package/src/apps/data/routes/transactions.test.ts +1 -1
  764. package/src/apps/data/routes/transfers.test.ts +56 -24
  765. package/src/apps/data/routes/transfers.ts +19 -8
  766. package/src/apps/data/routes/valuation.test.ts +1 -1
  767. package/src/apps/data/routes/verified-tokens.test.ts +345 -0
  768. package/src/apps/data/routes/verified-tokens.ts +99 -29
  769. package/src/apps/data/routes/webhooks.test.ts +659 -81
  770. package/src/apps/data/routes/webhooks.ts +1104 -817
  771. package/src/apps/data/routes/zones.test.ts +148 -71
  772. package/src/apps/data/routes/zones.ts +71 -55
  773. package/src/apps/docs/reference.ts +2 -2
  774. package/src/apps/index.ts +1 -1
  775. package/src/apps/management/App.ts +9 -51
  776. package/src/apps/management/Billing.test.ts +375 -14
  777. package/src/apps/management/Billing.ts +283 -34
  778. package/src/apps/management/routes/api-keys.test.ts +269 -7
  779. package/src/apps/management/routes/api-keys.ts +61 -20
  780. package/src/apps/management/routes/billing.test.ts +477 -15
  781. package/src/apps/management/routes/billing.ts +377 -50
  782. package/src/apps/management/routes/faucet.test.ts +1 -1
  783. package/src/apps/management/routes/faucet.ts +1 -1
  784. package/src/apps/management/routes/invitations.test.ts +270 -3
  785. package/src/apps/management/routes/invitations.ts +185 -15
  786. package/src/apps/management/routes/invoicePreview.test.ts +549 -0
  787. package/src/apps/management/routes/me.test.ts +246 -5
  788. package/src/apps/management/routes/me.ts +7 -2
  789. package/src/apps/management/routes/members.test.ts +108 -0
  790. package/src/apps/management/routes/orgs.test.ts +191 -3
  791. package/src/apps/management/routes/orgs.ts +58 -11
  792. package/src/apps/management/routes/projects.test.ts +33 -3
  793. package/src/apps/management/routes/projects.ts +6 -1
  794. package/src/apps/management/routes/scopes.test.ts +30 -2
  795. package/src/apps/management/routes/scopes.ts +4 -1
  796. package/src/apps/management/routes/usage.test.ts +32 -0
  797. package/src/apps/management/routes/usage.ts +22 -4
  798. package/src/apps/management/routes/webhooks.test.ts +49 -26
  799. package/src/apps/management/routes/webhooks.ts +93 -38
  800. package/src/apps/mcp.test.ts +6 -6
  801. package/src/apps/mcp.ts +7 -7
  802. package/src/apps/mpp/App.ts +37 -7
  803. package/src/apps/mpp/Mpp.test.ts +49 -8
  804. package/src/apps/mpp/Mpp.zone.test.ts +219 -0
  805. package/src/apps/mpp/internal/Adapter.ts +34 -0
  806. package/src/apps/mpp/internal/Policy.test.ts +86 -31
  807. package/src/apps/mpp/internal/Policy.ts +49 -7
  808. package/src/apps/mpp/internal/Sponsorship.test.ts +207 -0
  809. package/src/apps/mpp/internal/Sponsorship.ts +9 -3
  810. package/src/apps/relay/App.test.ts +1024 -38
  811. package/src/apps/relay/App.ts +228 -32
  812. package/src/apps/relay/App.zone-billing.test.ts +257 -0
  813. package/src/apps/relay/Sponsorships.test.ts +67 -4
  814. package/src/apps/relay/Sponsorships.ts +253 -29
  815. package/src/apps/relay/Sponsorships.zone.test.ts +102 -0
  816. package/src/apps/{funding → routes}/Access.ts +6 -6
  817. package/src/apps/routes/App.test.ts +165 -0
  818. package/src/apps/routes/App.ts +96 -0
  819. package/src/apps/{funding → routes}/Inventory.ts +2 -2
  820. package/src/apps/routes/index.ts +1 -0
  821. package/src/apps/{funding → routes}/routes/chains.test.ts +66 -66
  822. package/src/apps/{funding → routes}/routes/chains.ts +23 -23
  823. package/src/apps/{funding → routes}/routes/deposit-addresses.test.ts +1362 -462
  824. package/src/apps/{funding → routes}/routes/deposit-addresses.ts +568 -248
  825. package/src/apps/{funding → routes}/routes/providers.test.ts +27 -33
  826. package/src/apps/{funding → routes}/routes/providers.ts +23 -23
  827. package/src/apps/{funding → routes}/routes/quotes.test.ts +298 -41
  828. package/src/apps/{funding → routes}/routes/quotes.ts +57 -40
  829. package/src/apps/routes/routes/transfers.test.ts +2876 -0
  830. package/src/apps/routes/routes/transfers.ts +1332 -0
  831. package/src/cli/Cli.test.ts +1 -1
  832. package/src/cli/commands/admin.test.ts +748 -1
  833. package/src/cli/commands/admin.ts +278 -0
  834. package/src/cloudflare.ts +52 -47
  835. package/src/db/Db.test.ts +245 -2
  836. package/src/db/Db.ts +1511 -34
  837. package/src/db/Schema.ts +744 -228
  838. package/src/db/tables/apiKeyAdmissionBootstraps.ts +4 -0
  839. package/src/db/tables/apiKeyAdmissions.ts +218 -0
  840. package/src/db/tables/apiKeyOwnerAdmissions.ts +4 -0
  841. package/src/db/tables/apiKeyOwnerTombstones.ts +81 -0
  842. package/src/db/tables/apiKeyRevocations.test.ts +74 -0
  843. package/src/db/tables/apiKeyRevocations.ts +121 -0
  844. package/src/db/tables/authAccounts.ts +105 -0
  845. package/src/db/tables/authSessions.ts +13 -0
  846. package/src/db/tables/authVerifications.ts +13 -0
  847. package/src/db/tables/invitations.ts +142 -45
  848. package/src/db/tables/memberships.ts +79 -3
  849. package/src/db/tables/organizations.test.ts +725 -7
  850. package/src/db/tables/organizations.ts +182 -49
  851. package/src/db/tables/projects.test.ts +71 -0
  852. package/src/db/tables/projects.ts +59 -4
  853. package/src/db/tables/requestUsage.ts +4 -1
  854. package/src/db/tables/rewardAccounts.ts +178 -0
  855. package/src/db/tables/rewardCampaignDistributors.ts +68 -0
  856. package/src/db/tables/rewardCampaigns.test.ts +1388 -0
  857. package/src/db/tables/rewardCampaigns.ts +647 -0
  858. package/src/db/tables/rewardCredits.ts +110 -0
  859. package/src/db/tables/rewardEligibilityAssociations.test.ts +271 -0
  860. package/src/db/tables/rewardEligibilityAssociations.ts +184 -0
  861. package/src/db/tables/rewardRuns.ts +514 -0
  862. package/src/db/tables/rewardTransactionAttempts.ts +272 -0
  863. package/src/db/tables/routesCatalog.test.ts +185 -0
  864. package/src/db/tables/routesCatalog.ts +163 -0
  865. package/src/db/tables/routesDepositAddresses.test.ts +1048 -0
  866. package/src/db/tables/routesDepositAddresses.ts +1008 -0
  867. package/src/db/tables/{fundingDepositRequestObservations.test.ts → routesDepositRequestObservations.test.ts} +13 -14
  868. package/src/db/tables/{fundingDepositRequestObservations.ts → routesDepositRequestObservations.ts} +10 -10
  869. package/src/db/tables/{fundingDeposits.test.ts → routesDeposits.test.ts} +316 -46
  870. package/src/db/tables/routesDeposits.ts +1062 -0
  871. package/src/db/tables/routesIdempotency.test.ts +796 -0
  872. package/src/db/tables/routesIdempotency.ts +496 -0
  873. package/src/db/tables/routesSubsidies.test.ts +120 -0
  874. package/src/db/tables/routesSubsidies.ts +71 -0
  875. package/src/db/tables/{fundingTransferEvents.ts → routesTransferEvents.ts} +4 -4
  876. package/src/db/tables/routesTransferSubsidies.ts +38 -0
  877. package/src/db/tables/routesTransferSubsidyNonces.ts +124 -0
  878. package/src/db/tables/routesTransferTransactions.test.ts +195 -0
  879. package/src/db/tables/routesTransferTransactions.ts +158 -0
  880. package/src/db/tables/routesTransfers.test.ts +338 -0
  881. package/src/db/tables/routesTransfers.ts +662 -0
  882. package/src/db/tables/sponsoredTransactions.test.ts +563 -1
  883. package/src/db/tables/sponsoredTransactions.ts +386 -42
  884. package/src/db/tables/sponsorshipAttributions.test.ts +160 -0
  885. package/src/db/tables/sponsorshipAttributions.ts +168 -0
  886. package/src/db/tables/sponsorshipReconciliationCursors.test.ts +115 -0
  887. package/src/db/tables/sponsorshipReconciliationCursors.ts +67 -0
  888. package/src/db/tables/stripeCustomers.test.ts +85 -0
  889. package/src/db/tables/stripeCustomers.ts +24 -0
  890. package/src/db/tables/users.test.ts +129 -0
  891. package/src/db/tables/users.ts +49 -3
  892. package/src/db/tables/webhookQueueEvents.ts +8 -1
  893. package/src/db/tables/webhookSubscriptions.ts +103 -21
  894. package/src/handlers/internal/executionError.ts +3 -4
  895. package/src/handlers/internal/multisig.ts +13 -816
  896. package/src/handlers/internal/sponsorship.ts +26 -10
  897. package/src/handlers/relay.test-d.ts +9 -1
  898. package/src/handlers/relay.test.ts +823 -3
  899. package/src/handlers/relay.ts +127 -107
  900. package/src/index.test-d.ts +7 -0
  901. package/src/index.ts +0 -17
  902. package/src/internal/AssetResponse.ts +26 -0
  903. package/src/internal/Auth.test.ts +1564 -9
  904. package/src/internal/Auth.ts +833 -239
  905. package/src/internal/BetterAuth.test.ts +242 -0
  906. package/src/internal/BetterAuth.ts +349 -0
  907. package/src/internal/Cache.ts +2 -0
  908. package/src/internal/EarnRates.test.ts +17 -0
  909. package/src/internal/EarnRates.ts +124 -31
  910. package/src/internal/EarnSharePrices.test.ts +182 -0
  911. package/src/internal/EarnSharePrices.ts +313 -0
  912. package/src/internal/EarnVaults.test.ts +21 -0
  913. package/src/internal/EarnVaults.ts +37 -15
  914. package/src/internal/Email.ts +54 -0
  915. package/src/internal/Idempotency.test.ts +2 -2
  916. package/src/internal/Log.test-d.ts +10 -7
  917. package/src/internal/Log.test.ts +114 -16
  918. package/src/internal/Log.ts +55 -40
  919. package/src/internal/MetricSink.test.ts +313 -26
  920. package/src/internal/MetricSink.ts +73 -8
  921. package/src/internal/Mpp.test.ts +31 -0
  922. package/src/internal/Mpp.ts +21 -24
  923. package/src/internal/OpenApi.ts +45 -12
  924. package/src/internal/Provider.test.ts +1 -1
  925. package/src/internal/Provider.ts +1 -1
  926. package/src/internal/RateLimit.test.ts +21 -3
  927. package/src/internal/RateLimit.ts +12 -1
  928. package/src/internal/Store.test-d.ts +1 -1
  929. package/src/internal/Store.test.ts +151 -8
  930. package/src/internal/Store.ts +76 -9
  931. package/src/internal/Tidx.test.ts +59 -8
  932. package/src/internal/Tidx.ts +86 -14
  933. package/src/internal/Timing.test.ts +77 -0
  934. package/src/internal/Timing.ts +83 -6
  935. package/src/internal/VercelOidc.test.ts +188 -0
  936. package/src/internal/VercelOidc.ts +193 -0
  937. package/src/internal/VerifiedTokens.test.ts +60 -6
  938. package/src/internal/VerifiedTokens.ts +21 -24
  939. package/src/internal/Viem.batch.test.ts +80 -0
  940. package/src/internal/Viem.test.ts +201 -2
  941. package/src/internal/Viem.ts +249 -17
  942. package/src/internal/Webhooks.test.ts +125 -1
  943. package/src/internal/Webhooks.ts +22 -4
  944. package/src/internal/ZoneRpc.ts +50 -0
  945. package/src/internal/exchange/Provider.test.ts +2 -2
  946. package/src/internal/index.test.ts +3 -1
  947. package/src/internal/index.ts +3 -1
  948. package/src/internal/rewards/Audit.ts +231 -0
  949. package/src/internal/rewards/Campaigns.test.ts +1234 -0
  950. package/src/internal/rewards/Campaigns.ts +1205 -0
  951. package/src/internal/rewards/Credits.ts +165 -0
  952. package/src/internal/rewards/Events.local.test.ts +113 -0
  953. package/src/internal/rewards/Events.test.ts +152 -0
  954. package/src/internal/rewards/Events.ts +468 -0
  955. package/src/internal/rewards/Projection.test.ts +681 -0
  956. package/src/internal/rewards/Projection.ts +987 -0
  957. package/src/internal/rewards/Rates.test.ts +171 -0
  958. package/src/internal/rewards/Rates.ts +110 -0
  959. package/src/internal/rewards/Read.test.ts +501 -0
  960. package/src/internal/rewards/Read.ts +476 -0
  961. package/src/internal/rewards/Runner.checkpoint.test.ts +80 -0
  962. package/src/internal/rewards/Runner.states.test.ts +188 -0
  963. package/src/internal/rewards/Runner.test.ts +90 -0
  964. package/src/internal/rewards/Runner.ts +2229 -0
  965. package/src/internal/rewards/Signer.test.ts +79 -0
  966. package/src/internal/rewards/Signer.ts +180 -0
  967. package/src/internal/rewards/index.ts +14 -0
  968. package/src/internal/{funding → routes}/Action.test.ts +63 -14
  969. package/src/internal/{funding → routes}/Action.ts +35 -8
  970. package/src/internal/{funding → routes}/Catalog.test.ts +3 -3
  971. package/src/internal/{funding → routes}/Catalog.ts +39 -39
  972. package/src/internal/{funding → routes}/Chain.test.ts +1 -1
  973. package/src/internal/{funding → routes}/Chain.ts +11 -11
  974. package/src/internal/{funding → routes}/Deposit.test.ts +1 -1
  975. package/src/internal/{funding → routes}/Deposit.ts +93 -45
  976. package/src/internal/{funding → routes}/DepositAddress.test.ts +11 -3
  977. package/src/internal/{funding → routes}/DepositAddress.ts +132 -53
  978. package/src/internal/{funding → routes}/DepositWebhook.test.ts +61 -18
  979. package/src/internal/{funding → routes}/DepositWebhook.ts +9 -8
  980. package/src/internal/routes/Economics.test.ts +42 -0
  981. package/src/internal/routes/Economics.ts +47 -0
  982. package/src/internal/{funding → routes}/Evidence.test.ts +6 -6
  983. package/src/internal/{funding → routes}/Evidence.ts +11 -22
  984. package/src/internal/routes/Observability.test.ts +636 -0
  985. package/src/internal/routes/Observability.ts +668 -0
  986. package/src/internal/{funding → routes}/Provider.test.ts +489 -153
  987. package/src/internal/{funding → routes}/Provider.ts +531 -185
  988. package/src/internal/{funding → routes}/Reconciliation.local.test.ts +84 -12
  989. package/src/internal/{funding → routes}/Reconciliation.test.ts +1213 -279
  990. package/src/internal/{funding → routes}/Reconciliation.ts +501 -203
  991. package/src/internal/routes/Reconciliation.unattributed.test.ts +250 -0
  992. package/src/internal/{funding → routes}/Route.ts +7 -7
  993. package/src/internal/{funding → routes}/SourceObservation.test.ts +13 -14
  994. package/src/internal/{funding → routes}/SourceObservation.ts +18 -22
  995. package/src/internal/{funding → routes}/Subsidy.local.test.ts +7 -7
  996. package/src/internal/routes/Subsidy.test.ts +169 -0
  997. package/src/internal/{funding → routes}/Subsidy.ts +86 -6
  998. package/src/internal/{funding → routes}/Token.test.ts +1 -1
  999. package/src/internal/{funding → routes}/Token.ts +5 -5
  1000. package/src/internal/routes/Transfer.test.ts +1199 -0
  1001. package/src/internal/routes/Transfer.ts +1206 -0
  1002. package/src/internal/routes/TransferReconciliation.test.ts +731 -0
  1003. package/src/internal/routes/TransferReconciliation.ts +527 -0
  1004. package/src/internal/routes/TransferSubsidy.test.ts +172 -0
  1005. package/src/internal/routes/TransferSubsidy.ts +447 -0
  1006. package/src/internal/routes/TransferWebhook.test.ts +128 -0
  1007. package/src/internal/routes/TransferWebhook.ts +67 -0
  1008. package/src/internal/{funding → routes}/index.test.ts +6 -3
  1009. package/src/internal/{funding → routes}/index.ts +3 -0
  1010. package/src/internal/{funding → routes}/providers/across.ts +16 -16
  1011. package/src/internal/{funding → routes}/providers/index.test.ts +157 -44
  1012. package/src/internal/{funding → routes}/providers/relay.test.ts +165 -32
  1013. package/src/internal/{funding → routes}/providers/relay.ts +231 -136
  1014. package/src/internal/{funding → routes}/providers/rhino.ts +16 -16
  1015. package/src/internal/{funding → routes}/providers/squid.ts +17 -17
  1016. package/src/internal/routes/providers/stargate.test.ts +728 -0
  1017. package/src/internal/routes/providers/stargate.ts +1276 -0
  1018. package/src/internal/{funding → routes}/providers/symbiosis.ts +64 -24
  1019. package/src/internal/webhookDestinations/slack.ts +20 -5
  1020. package/src/providers/index.ts +13 -13
  1021. package/src/server.ts +18 -0
  1022. package/dist/apps/funding/Access.d.ts.map +0 -1
  1023. package/dist/apps/funding/Access.js.map +0 -1
  1024. package/dist/apps/funding/App.js.map +0 -1
  1025. package/dist/apps/funding/Inventory.d.ts.map +0 -1
  1026. package/dist/apps/funding/Inventory.js.map +0 -1
  1027. package/dist/apps/funding/ProviderAttempts.d.ts +0 -5
  1028. package/dist/apps/funding/ProviderAttempts.d.ts.map +0 -1
  1029. package/dist/apps/funding/ProviderAttempts.js +0 -24
  1030. package/dist/apps/funding/ProviderAttempts.js.map +0 -1
  1031. package/dist/apps/funding/index.d.ts +0 -2
  1032. package/dist/apps/funding/index.d.ts.map +0 -1
  1033. package/dist/apps/funding/index.js +0 -2
  1034. package/dist/apps/funding/index.js.map +0 -1
  1035. package/dist/apps/funding/routes/chains.d.ts.map +0 -1
  1036. package/dist/apps/funding/routes/chains.js.map +0 -1
  1037. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +0 -1
  1038. package/dist/apps/funding/routes/deposit-addresses.js.map +0 -1
  1039. package/dist/apps/funding/routes/providers.d.ts.map +0 -1
  1040. package/dist/apps/funding/routes/providers.js +0 -57
  1041. package/dist/apps/funding/routes/providers.js.map +0 -1
  1042. package/dist/apps/funding/routes/quotes.d.ts.map +0 -1
  1043. package/dist/apps/funding/routes/quotes.js.map +0 -1
  1044. package/dist/apps/funding/routes/transfers.d.ts.map +0 -1
  1045. package/dist/apps/funding/routes/transfers.js +0 -622
  1046. package/dist/apps/funding/routes/transfers.js.map +0 -1
  1047. package/dist/db/tables/fundingCatalog.d.ts +0 -58
  1048. package/dist/db/tables/fundingCatalog.d.ts.map +0 -1
  1049. package/dist/db/tables/fundingCatalog.js.map +0 -1
  1050. package/dist/db/tables/fundingDepositAddresses.d.ts +0 -192
  1051. package/dist/db/tables/fundingDepositAddresses.d.ts.map +0 -1
  1052. package/dist/db/tables/fundingDepositAddresses.js +0 -235
  1053. package/dist/db/tables/fundingDepositAddresses.js.map +0 -1
  1054. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +0 -1
  1055. package/dist/db/tables/fundingDepositRequestObservations.js.map +0 -1
  1056. package/dist/db/tables/fundingDeposits.d.ts.map +0 -1
  1057. package/dist/db/tables/fundingDeposits.js +0 -295
  1058. package/dist/db/tables/fundingDeposits.js.map +0 -1
  1059. package/dist/db/tables/fundingIdempotency.d.ts +0 -91
  1060. package/dist/db/tables/fundingIdempotency.d.ts.map +0 -1
  1061. package/dist/db/tables/fundingIdempotency.js +0 -103
  1062. package/dist/db/tables/fundingIdempotency.js.map +0 -1
  1063. package/dist/db/tables/fundingTransferEvents.d.ts.map +0 -1
  1064. package/dist/db/tables/fundingTransferEvents.js.map +0 -1
  1065. package/dist/db/tables/fundingTransferTransactions.d.ts +0 -15
  1066. package/dist/db/tables/fundingTransferTransactions.d.ts.map +0 -1
  1067. package/dist/db/tables/fundingTransferTransactions.js +0 -27
  1068. package/dist/db/tables/fundingTransferTransactions.js.map +0 -1
  1069. package/dist/db/tables/fundingTransfers.d.ts +0 -82
  1070. package/dist/db/tables/fundingTransfers.d.ts.map +0 -1
  1071. package/dist/db/tables/fundingTransfers.js +0 -89
  1072. package/dist/db/tables/fundingTransfers.js.map +0 -1
  1073. package/dist/internal/funding/Action.d.ts.map +0 -1
  1074. package/dist/internal/funding/Action.js.map +0 -1
  1075. package/dist/internal/funding/Catalog.d.ts.map +0 -1
  1076. package/dist/internal/funding/Catalog.js.map +0 -1
  1077. package/dist/internal/funding/Chain.d.ts.map +0 -1
  1078. package/dist/internal/funding/Chain.js.map +0 -1
  1079. package/dist/internal/funding/Deposit.d.ts.map +0 -1
  1080. package/dist/internal/funding/Deposit.js.map +0 -1
  1081. package/dist/internal/funding/DepositAddress.d.ts.map +0 -1
  1082. package/dist/internal/funding/DepositAddress.js.map +0 -1
  1083. package/dist/internal/funding/DepositWebhook.d.ts.map +0 -1
  1084. package/dist/internal/funding/DepositWebhook.js.map +0 -1
  1085. package/dist/internal/funding/Evidence.d.ts.map +0 -1
  1086. package/dist/internal/funding/Evidence.js.map +0 -1
  1087. package/dist/internal/funding/Provider.d.ts.map +0 -1
  1088. package/dist/internal/funding/Provider.js.map +0 -1
  1089. package/dist/internal/funding/Reconciliation.d.ts.map +0 -1
  1090. package/dist/internal/funding/Reconciliation.js.map +0 -1
  1091. package/dist/internal/funding/Route.d.ts +0 -21
  1092. package/dist/internal/funding/Route.d.ts.map +0 -1
  1093. package/dist/internal/funding/Route.js.map +0 -1
  1094. package/dist/internal/funding/SourceObservation.d.ts.map +0 -1
  1095. package/dist/internal/funding/SourceObservation.js.map +0 -1
  1096. package/dist/internal/funding/Subsidy.d.ts.map +0 -1
  1097. package/dist/internal/funding/Subsidy.js.map +0 -1
  1098. package/dist/internal/funding/Token.d.ts.map +0 -1
  1099. package/dist/internal/funding/Token.js.map +0 -1
  1100. package/dist/internal/funding/Transfer.d.ts.map +0 -1
  1101. package/dist/internal/funding/Transfer.js +0 -334
  1102. package/dist/internal/funding/Transfer.js.map +0 -1
  1103. package/dist/internal/funding/index.d.ts.map +0 -1
  1104. package/dist/internal/funding/index.js.map +0 -1
  1105. package/dist/internal/funding/providers/across.d.ts.map +0 -1
  1106. package/dist/internal/funding/providers/across.js.map +0 -1
  1107. package/dist/internal/funding/providers/relay.d.ts.map +0 -1
  1108. package/dist/internal/funding/providers/relay.js.map +0 -1
  1109. package/dist/internal/funding/providers/rhino.d.ts.map +0 -1
  1110. package/dist/internal/funding/providers/rhino.js.map +0 -1
  1111. package/dist/internal/funding/providers/squid.d.ts.map +0 -1
  1112. package/dist/internal/funding/providers/squid.js.map +0 -1
  1113. package/dist/internal/funding/providers/stargate.d.ts +0 -38
  1114. package/dist/internal/funding/providers/stargate.d.ts.map +0 -1
  1115. package/dist/internal/funding/providers/stargate.js +0 -277
  1116. package/dist/internal/funding/providers/stargate.js.map +0 -1
  1117. package/dist/internal/funding/providers/symbiosis.d.ts.map +0 -1
  1118. package/dist/internal/funding/providers/symbiosis.js.map +0 -1
  1119. package/src/apps/funding/App.test.ts +0 -78
  1120. package/src/apps/funding/App.ts +0 -78
  1121. package/src/apps/funding/ProviderAttempts.ts +0 -26
  1122. package/src/apps/funding/index.ts +0 -1
  1123. package/src/apps/funding/routes/transfers.test.ts +0 -1638
  1124. package/src/apps/funding/routes/transfers.ts +0 -721
  1125. package/src/db/tables/fundingCatalog.test.ts +0 -122
  1126. package/src/db/tables/fundingCatalog.ts +0 -163
  1127. package/src/db/tables/fundingDepositAddresses.test.ts +0 -608
  1128. package/src/db/tables/fundingDepositAddresses.ts +0 -443
  1129. package/src/db/tables/fundingDeposits.ts +0 -572
  1130. package/src/db/tables/fundingIdempotency.test.ts +0 -182
  1131. package/src/db/tables/fundingIdempotency.ts +0 -180
  1132. package/src/db/tables/fundingTransferTransactions.test.ts +0 -69
  1133. package/src/db/tables/fundingTransferTransactions.ts +0 -37
  1134. package/src/db/tables/fundingTransfers.test.ts +0 -89
  1135. package/src/db/tables/fundingTransfers.ts +0 -153
  1136. package/src/handlers/internal/multisig.test.ts +0 -818
  1137. package/src/internal/funding/Subsidy.test.ts +0 -75
  1138. package/src/internal/funding/Transfer.test.ts +0 -369
  1139. package/src/internal/funding/Transfer.ts +0 -545
  1140. package/src/internal/funding/providers/stargate.test.ts +0 -163
  1141. package/src/internal/funding/providers/stargate.ts +0 -409
  1142. /package/dist/apps/{funding → routes}/Inventory.d.ts +0 -0
  1143. /package/src/internal/{funding → routes}/Route.test.ts +0 -0
@@ -2,39 +2,47 @@ import { Hash, Hex } from 'ox'
2
2
 
3
3
  import { tempoMainnet } from 'viem/tempo/chains'
4
4
 
5
- import * as FundingDepositAddresses from '../../../db/tables/fundingDepositAddresses.js'
5
+ import * as RoutesDepositAddresses from '../../../db/tables/routesDepositAddresses.js'
6
6
 
7
- import * as FundingIdempotencyTable from '../../../db/tables/fundingIdempotency.js'
7
+ import * as RoutesIdempotencyTable from '../../../db/tables/routesIdempotency.js'
8
+
9
+ import * as Organizations from '../../../db/tables/organizations.js'
10
+
11
+ import * as RoutesSubsidies from '../../../db/tables/routesSubsidies.js'
12
+
13
+ import * as StripeCustomers from '../../../db/tables/stripeCustomers.js'
8
14
 
9
15
  import * as Cache from '../../../internal/Cache.js'
10
16
 
11
17
  import * as Cursor from '../../../internal/Cursor.js'
12
18
 
13
- import * as FundingDeposit from '../../../internal/funding/Deposit.js'
19
+ import * as RoutesDeposit from '../../../internal/routes/Deposit.js'
14
20
 
15
- import * as FundingDepositAddress from '../../../internal/funding/DepositAddress.js'
21
+ import * as RoutesDepositAddress from '../../../internal/routes/DepositAddress.js'
16
22
 
17
- import * as FundingProvider from '../../../internal/funding/Provider.js'
23
+ import * as RoutesProvider from '../../../internal/routes/Provider.js'
18
24
 
19
25
  import * as Idempotency from '../../../internal/Idempotency.js'
20
26
 
21
- import * as Across from '../../../internal/funding/providers/across.js'
27
+ import * as Across from '../../../internal/routes/providers/across.js'
22
28
 
23
- import * as Relay from '../../../internal/funding/providers/relay.js'
29
+ import * as Relay from '../../../internal/routes/providers/relay.js'
24
30
 
25
- import * as Rhino from '../../../internal/funding/providers/rhino.js'
31
+ import * as Rhino from '../../../internal/routes/providers/rhino.js'
26
32
 
27
- import * as Squid from '../../../internal/funding/providers/squid.js'
33
+ import * as Squid from '../../../internal/routes/providers/squid.js'
28
34
 
29
- import * as Symbiosis from '../../../internal/funding/providers/symbiosis.js'
35
+ import * as Symbiosis from '../../../internal/routes/providers/symbiosis.js'
30
36
 
31
37
  import type * as Log from '../../../internal/Log.js'
32
38
 
39
+ import * as Metrics from '../../../Metrics.js'
40
+
33
41
  import * as TestApp from '../../../../test/App.js'
34
42
 
35
- import * as TestFunding from '../../../../test/Funding.js'
43
+ import * as TestRoutes from '../../../../test/Routes.js'
36
44
 
37
- import * as Funding from './deposit-addresses.js'
45
+ import * as Routes from './deposit-addresses.js'
38
46
 
39
47
  const db = TestApp.database()
40
48
  const relayApiKey = process.env.RELAY_API_KEY
@@ -45,7 +53,7 @@ const providers = [
45
53
  integratorId: '0xdead',
46
54
  userAddress: '0x1111111111111111111111111111111111111111',
47
55
  }),
48
- Relay.relay({ userAddresses: TestFunding.relayQuoteUsers }),
56
+ Relay.relay({ userAddresses: TestRoutes.relayQuoteUsers }),
49
57
  Rhino.rhino(),
50
58
  Squid.squid({
51
59
  integratorId: 'squid-integrator-id',
@@ -54,7 +62,7 @@ const providers = [
54
62
  Symbiosis.symbiosis({ userAddress: '0x1111111111111111111111111111111111111111' }),
55
63
  ] as const
56
64
 
57
- beforeAll(() => TestFunding.publish(db))
65
+ beforeAll(() => TestRoutes.publish(db))
58
66
 
59
67
  function create(options: TestApp.create.Options = {}) {
60
68
  return TestApp.create({ ...options, db })
@@ -80,21 +88,21 @@ function dereference(spec: ComponentSpec, schema: JsonSchema): JsonSchema {
80
88
  return spec.components.schemas[name]!
81
89
  }
82
90
 
83
- test('publishes generator-ready funding deposit contracts', async () => {
91
+ test('publishes generator-ready route deposit contracts', async () => {
84
92
  const spec = await (await create({ auth: false }).request('/openapi.json')).json()
85
93
  const depositAddressPath = Object.keys(spec.paths).find(
86
- (path) => path.includes('/v1/funding/deposit-addresses/{') && !path.endsWith('/reconcile'),
94
+ (path) => path.includes('/v1/routes/deposit-addresses/{') && !path.endsWith('/reconcile'),
87
95
  )!
88
96
  const depositPath = Object.keys(spec.paths).find((path) =>
89
- path.includes('/v1/funding/deposits/{'),
97
+ path.includes('/v1/routes/deposits/{'),
90
98
  )!
91
99
  const reconcilePath = Object.keys(spec.paths).find((path) => path.endsWith('/reconcile'))!
92
100
  const operations = {
93
- createAddress: spec.paths['/v1/funding/deposit-addresses'].post,
101
+ createAddress: spec.paths['/v1/routes/deposit-addresses'].post,
94
102
  getAddress: spec.paths[depositAddressPath].get,
95
103
  getDeposit: spec.paths[depositPath].get,
96
- listAddresses: spec.paths['/v1/funding/deposit-addresses'].get,
97
- listDeposits: spec.paths['/v1/funding/deposits'].get,
104
+ listAddresses: spec.paths['/v1/routes/deposit-addresses'].get,
105
+ listDeposits: spec.paths['/v1/routes/deposits'].get,
98
106
  reconcileAddress: spec.paths[reconcilePath].post,
99
107
  }
100
108
  const summarize = (operation: (typeof operations)[keyof typeof operations]) => ({
@@ -115,47 +123,47 @@ test('publishes generator-ready funding deposit contracts', async () => {
115
123
 
116
124
  expect({
117
125
  components: [
118
- 'CreateFundingDepositAddressRequest',
119
- 'CreateFundingDepositAddressResponse',
120
- 'CreatedFundingDepositAddress',
121
- 'FundingDeposit',
122
- 'FundingDepositAddress',
123
- 'FundingDepositAddressList',
124
- 'FundingDepositList',
125
- 'FundingDepositStatusReason',
126
+ 'CreateRoutesDepositAddressRequest',
127
+ 'CreateRoutesDepositAddressResponse',
128
+ 'CreatedRoutesDepositAddress',
129
+ 'RoutesDeposit',
130
+ 'RoutesDepositAddress',
131
+ 'RoutesDepositAddressList',
132
+ 'RoutesDepositList',
133
+ 'RoutesDepositStatusReason',
126
134
  ].filter((name) => spec.components.schemas[name]),
127
135
  formats: {
128
- addressCreatedAt: spec.components.schemas.FundingDepositAddress.properties.createdAt.format,
129
- addressUpdatedAt: spec.components.schemas.FundingDepositAddress.properties.updatedAt.format,
130
- depositCreatedAt: spec.components.schemas.FundingDeposit.properties.createdAt.format,
131
- depositUpdatedAt: spec.components.schemas.FundingDeposit.properties.updatedAt.format,
136
+ addressCreatedAt: spec.components.schemas.RoutesDepositAddress.properties.createdAt.format,
137
+ addressUpdatedAt: spec.components.schemas.RoutesDepositAddress.properties.updatedAt.format,
138
+ depositCreatedAt: spec.components.schemas.RoutesDeposit.properties.createdAt.format,
139
+ depositUpdatedAt: spec.components.schemas.RoutesDeposit.properties.updatedAt.format,
132
140
  },
133
141
  models: {
134
142
  address: {
135
- destinationChain: spec.components.schemas.FundingDepositAddress.properties.destinationChain,
136
- destinationToken: spec.components.schemas.FundingDepositAddress.properties.destinationToken,
137
- provider: spec.components.schemas.FundingDepositAddress.properties.provider,
138
- sourceChain: spec.components.schemas.FundingDepositAddress.properties.sourceChain,
139
- sourceToken: spec.components.schemas.FundingDepositAddress.properties.sourceToken,
143
+ destinationChain: spec.components.schemas.RoutesDepositAddress.properties.destinationChain,
144
+ destinationToken: spec.components.schemas.RoutesDepositAddress.properties.destinationToken,
145
+ provider: spec.components.schemas.RoutesDepositAddress.properties.provider,
146
+ sourceChain: spec.components.schemas.RoutesDepositAddress.properties.sourceChain,
147
+ sourceToken: spec.components.schemas.RoutesDepositAddress.properties.sourceToken,
140
148
  },
141
- addressList: spec.components.schemas.FundingDepositAddressList.properties.data.items,
142
- createResponse: spec.components.schemas.CreateFundingDepositAddressResponse.anyOf,
149
+ addressList: spec.components.schemas.RoutesDepositAddressList.properties.data.items,
150
+ createResponse: spec.components.schemas.CreateRoutesDepositAddressResponse.anyOf,
143
151
  createdAddress: {
144
152
  feeToken: dereference(
145
153
  spec,
146
- spec.components.schemas.CreatedFundingDepositAddress.properties.fees.items,
154
+ spec.components.schemas.CreatedRoutesDepositAddress.properties.fees.items,
147
155
  ).properties!['token'],
148
- quote: spec.components.schemas.CreatedFundingDepositAddress.properties.quote,
156
+ quote: spec.components.schemas.CreatedRoutesDepositAddress.properties.quote,
149
157
  },
150
158
  deposit: {
151
- destinationChain: spec.components.schemas.FundingDeposit.properties.destinationChain,
152
- destinationToken: spec.components.schemas.FundingDeposit.properties.destinationToken,
153
- provider: spec.components.schemas.FundingDeposit.properties.provider,
154
- sourceChain: spec.components.schemas.FundingDeposit.properties.sourceChain,
155
- sourceToken: spec.components.schemas.FundingDeposit.properties.sourceToken,
156
- statusReason: spec.components.schemas.FundingDeposit.properties.statusReason,
159
+ destinationChain: spec.components.schemas.RoutesDeposit.properties.destinationChain,
160
+ destinationToken: spec.components.schemas.RoutesDeposit.properties.destinationToken,
161
+ provider: spec.components.schemas.RoutesDeposit.properties.provider,
162
+ sourceChain: spec.components.schemas.RoutesDeposit.properties.sourceChain,
163
+ sourceToken: spec.components.schemas.RoutesDeposit.properties.sourceToken,
164
+ statusReason: spec.components.schemas.RoutesDeposit.properties.statusReason,
157
165
  },
158
- depositList: spec.components.schemas.FundingDepositList.properties.data.items,
166
+ depositList: spec.components.schemas.RoutesDepositList.properties.data.items,
159
167
  },
160
168
  operations: {
161
169
  createAddress: summarize(operations.createAddress),
@@ -167,19 +175,19 @@ test('publishes generator-ready funding deposit contracts', async () => {
167
175
  },
168
176
  sharedErrorCodes: {
169
177
  addressNotActive:
170
- spec.components.schemas.FundingDepositAddressNotActiveError.properties.error.properties.code
178
+ spec.components.schemas.RoutesDepositAddressNotActiveError.properties.error.properties.code
171
179
  .enum,
172
180
  addressNotAvailable:
173
181
  spec.components.schemas.DepositAddressNotAvailableError.properties.error.properties.code
174
182
  .enum,
175
183
  addressNotFound:
176
- spec.components.schemas.FundingDepositAddressNotFoundError.properties.error.properties.code
184
+ spec.components.schemas.RoutesDepositAddressNotFoundError.properties.error.properties.code
177
185
  .enum,
178
186
  createInvalid:
179
187
  spec.components.schemas.ApiKeyMalformedOrBodyInvalidOrIdempotencyKeyRequiredError.properties
180
188
  .error.properties.code.enum,
181
189
  depositNotFound:
182
- spec.components.schemas.FundingDepositNotFoundError.properties.error.properties.code.enum,
190
+ spec.components.schemas.RoutesDepositNotFoundError.properties.error.properties.code.enum,
183
191
  idempotencyConflict:
184
192
  spec.components.schemas.IdempotencyConflictOrIdempotencyInProgressError.properties.error
185
193
  .properties.code.enum,
@@ -191,18 +199,22 @@ test('publishes generator-ready funding deposit contracts', async () => {
191
199
  queryInvalid:
192
200
  spec.components.schemas.ApiKeyMalformedOrQueryInvalidError.properties.error.properties.code
193
201
  .enum,
202
+ subsidyRejected:
203
+ spec.components.schemas.CreateRoutesDepositAddressForbiddenError.properties.error.properties
204
+ .code.enum,
194
205
  },
206
+ statusReasons: spec.components.schemas.RoutesDepositStatusReason.properties.code.enum,
195
207
  }).toMatchInlineSnapshot(`
196
208
  {
197
209
  "components": [
198
- "CreateFundingDepositAddressRequest",
199
- "CreateFundingDepositAddressResponse",
200
- "CreatedFundingDepositAddress",
201
- "FundingDeposit",
202
- "FundingDepositAddress",
203
- "FundingDepositAddressList",
204
- "FundingDepositList",
205
- "FundingDepositStatusReason",
210
+ "CreateRoutesDepositAddressRequest",
211
+ "CreateRoutesDepositAddressResponse",
212
+ "CreatedRoutesDepositAddress",
213
+ "RoutesDeposit",
214
+ "RoutesDepositAddress",
215
+ "RoutesDepositAddressList",
216
+ "RoutesDepositList",
217
+ "RoutesDepositStatusReason",
206
218
  ],
207
219
  "formats": {
208
220
  "addressCreatedAt": "date-time",
@@ -213,62 +225,62 @@ test('publishes generator-ready funding deposit contracts', async () => {
213
225
  "models": {
214
226
  "address": {
215
227
  "destinationChain": {
216
- "$ref": "#/components/schemas/FundingChain",
228
+ "$ref": "#/components/schemas/RoutesChain",
217
229
  },
218
230
  "destinationToken": {
219
- "$ref": "#/components/schemas/FundingToken",
231
+ "$ref": "#/components/schemas/RoutesToken",
220
232
  },
221
233
  "provider": {
222
- "$ref": "#/components/schemas/FundingProvider",
234
+ "$ref": "#/components/schemas/RoutesProvider",
223
235
  },
224
236
  "sourceChain": {
225
- "$ref": "#/components/schemas/FundingChain",
237
+ "$ref": "#/components/schemas/RoutesChain",
226
238
  },
227
239
  "sourceToken": {
228
- "$ref": "#/components/schemas/FundingToken",
240
+ "$ref": "#/components/schemas/RoutesToken",
229
241
  },
230
242
  },
231
243
  "addressList": {
232
- "$ref": "#/components/schemas/FundingDepositAddress",
244
+ "$ref": "#/components/schemas/RoutesDepositAddress",
233
245
  },
234
246
  "createResponse": [
235
247
  {
236
- "$ref": "#/components/schemas/CreatedFundingDepositAddress",
248
+ "$ref": "#/components/schemas/CreatedRoutesDepositAddress",
237
249
  },
238
250
  {
239
- "$ref": "#/components/schemas/FundingDepositAddress",
251
+ "$ref": "#/components/schemas/RoutesDepositAddress",
240
252
  },
241
253
  ],
242
254
  "createdAddress": {
243
255
  "feeToken": {
244
- "$ref": "#/components/schemas/FundingToken",
256
+ "$ref": "#/components/schemas/RoutesToken",
245
257
  },
246
258
  "quote": {
247
- "$ref": "#/components/schemas/FundingQuoteDetails",
259
+ "$ref": "#/components/schemas/RoutesQuoteDetails",
248
260
  },
249
261
  },
250
262
  "deposit": {
251
263
  "destinationChain": {
252
- "$ref": "#/components/schemas/FundingChain",
264
+ "$ref": "#/components/schemas/RoutesChain",
253
265
  },
254
266
  "destinationToken": {
255
- "$ref": "#/components/schemas/FundingToken",
267
+ "$ref": "#/components/schemas/RoutesToken",
256
268
  },
257
269
  "provider": {
258
- "$ref": "#/components/schemas/FundingProvider",
270
+ "$ref": "#/components/schemas/RoutesProvider",
259
271
  },
260
272
  "sourceChain": {
261
- "$ref": "#/components/schemas/FundingChain",
273
+ "$ref": "#/components/schemas/RoutesChain",
262
274
  },
263
275
  "sourceToken": {
264
- "$ref": "#/components/schemas/FundingToken",
276
+ "$ref": "#/components/schemas/RoutesToken",
265
277
  },
266
278
  "statusReason": {
267
- "$ref": "#/components/schemas/FundingDepositStatusReason",
279
+ "$ref": "#/components/schemas/RoutesDepositStatusReason",
268
280
  },
269
281
  },
270
282
  "depositList": {
271
- "$ref": "#/components/schemas/FundingDeposit",
283
+ "$ref": "#/components/schemas/RoutesDeposit",
272
284
  },
273
285
  },
274
286
  "operations": {
@@ -281,7 +293,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
281
293
  "$ref": "#/components/schemas/AuthenticationError",
282
294
  },
283
295
  "403": {
284
- "$ref": "#/components/schemas/ForbiddenError",
296
+ "$ref": "#/components/schemas/CreateRoutesDepositAddressForbiddenError",
285
297
  },
286
298
  "404": {
287
299
  "$ref": "#/components/schemas/DepositAddressNotAvailableError",
@@ -296,12 +308,12 @@ test('publishes generator-ready funding deposit contracts', async () => {
296
308
  },
297
309
  "504": "#/components/responses/RequestTimeout",
298
310
  },
299
- "operationId": "createFundingDepositAddress",
311
+ "operationId": "createRoutesDepositAddress",
300
312
  "request": {
301
- "$ref": "#/components/schemas/CreateFundingDepositAddressRequest",
313
+ "$ref": "#/components/schemas/CreateRoutesDepositAddressRequest",
302
314
  },
303
315
  "response": {
304
- "$ref": "#/components/schemas/CreateFundingDepositAddressResponse",
316
+ "$ref": "#/components/schemas/CreateRoutesDepositAddressResponse",
305
317
  },
306
318
  },
307
319
  "getAddress": {
@@ -316,7 +328,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
316
328
  "$ref": "#/components/schemas/ForbiddenError",
317
329
  },
318
330
  "404": {
319
- "$ref": "#/components/schemas/FundingDepositAddressNotFoundError",
331
+ "$ref": "#/components/schemas/RoutesDepositAddressNotFoundError",
320
332
  },
321
333
  "429": "#/components/responses/RateLimited",
322
334
  "500": "#/components/responses/InternalError",
@@ -325,10 +337,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
325
337
  },
326
338
  "504": "#/components/responses/RequestTimeout",
327
339
  },
328
- "operationId": "getFundingDepositAddress",
340
+ "operationId": "getRoutesDepositAddress",
329
341
  "request": undefined,
330
342
  "response": {
331
- "$ref": "#/components/schemas/FundingDepositAddress",
343
+ "$ref": "#/components/schemas/RoutesDepositAddress",
332
344
  },
333
345
  },
334
346
  "getDeposit": {
@@ -343,7 +355,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
343
355
  "$ref": "#/components/schemas/ForbiddenError",
344
356
  },
345
357
  "404": {
346
- "$ref": "#/components/schemas/FundingDepositNotFoundError",
358
+ "$ref": "#/components/schemas/RoutesDepositNotFoundError",
347
359
  },
348
360
  "429": "#/components/responses/RateLimited",
349
361
  "500": "#/components/responses/InternalError",
@@ -352,10 +364,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
352
364
  },
353
365
  "504": "#/components/responses/RequestTimeout",
354
366
  },
355
- "operationId": "getFundingDeposit",
367
+ "operationId": "getRoutesDeposit",
356
368
  "request": undefined,
357
369
  "response": {
358
- "$ref": "#/components/schemas/FundingDeposit",
370
+ "$ref": "#/components/schemas/RoutesDeposit",
359
371
  },
360
372
  },
361
373
  "listAddresses": {
@@ -376,10 +388,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
376
388
  },
377
389
  "504": "#/components/responses/RequestTimeout",
378
390
  },
379
- "operationId": "listFundingDepositAddresses",
391
+ "operationId": "listRoutesDepositAddresses",
380
392
  "request": undefined,
381
393
  "response": {
382
- "$ref": "#/components/schemas/FundingDepositAddressList",
394
+ "$ref": "#/components/schemas/RoutesDepositAddressList",
383
395
  },
384
396
  },
385
397
  "listDeposits": {
@@ -400,10 +412,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
400
412
  },
401
413
  "504": "#/components/responses/RequestTimeout",
402
414
  },
403
- "operationId": "listFundingDeposits",
415
+ "operationId": "listRoutesDeposits",
404
416
  "request": undefined,
405
417
  "response": {
406
- "$ref": "#/components/schemas/FundingDepositList",
418
+ "$ref": "#/components/schemas/RoutesDepositList",
407
419
  },
408
420
  },
409
421
  "reconcileAddress": {
@@ -418,10 +430,10 @@ test('publishes generator-ready funding deposit contracts', async () => {
418
430
  "$ref": "#/components/schemas/ForbiddenError",
419
431
  },
420
432
  "404": {
421
- "$ref": "#/components/schemas/FundingDepositAddressNotFoundError",
433
+ "$ref": "#/components/schemas/RoutesDepositAddressNotFoundError",
422
434
  },
423
435
  "409": {
424
- "$ref": "#/components/schemas/FundingDepositAddressNotActiveError",
436
+ "$ref": "#/components/schemas/RoutesDepositAddressNotActiveError",
425
437
  },
426
438
  "429": "#/components/responses/RateLimited",
427
439
  "500": "#/components/responses/InternalError",
@@ -433,20 +445,20 @@ test('publishes generator-ready funding deposit contracts', async () => {
433
445
  },
434
446
  "504": "#/components/responses/RequestTimeout",
435
447
  },
436
- "operationId": "reconcileFundingDepositAddress",
448
+ "operationId": "reconcileRoutesDepositAddress",
437
449
  "request": undefined,
438
450
  "response": undefined,
439
451
  },
440
452
  },
441
453
  "sharedErrorCodes": {
442
454
  "addressNotActive": [
443
- "funding_deposit_address_not_active",
455
+ "routes_deposit_address_not_active",
444
456
  ],
445
457
  "addressNotAvailable": [
446
458
  "deposit_address_not_available",
447
459
  ],
448
460
  "addressNotFound": [
449
- "funding_deposit_address_not_found",
461
+ "routes_deposit_address_not_found",
450
462
  ],
451
463
  "createInvalid": [
452
464
  "api_key_malformed",
@@ -454,7 +466,7 @@ test('publishes generator-ready funding deposit contracts', async () => {
454
466
  "idempotency_key_required",
455
467
  ],
456
468
  "depositNotFound": [
457
- "funding_deposit_not_found",
469
+ "routes_deposit_not_found",
458
470
  ],
459
471
  "idempotencyConflict": [
460
472
  "idempotency_conflict",
@@ -471,18 +483,41 @@ test('publishes generator-ready funding deposit contracts', async () => {
471
483
  "api_key_malformed",
472
484
  "query_invalid",
473
485
  ],
486
+ "subsidyRejected": [
487
+ "api_key_forbidden",
488
+ "api_key_ip_forbidden",
489
+ "billing_past_due",
490
+ "billing_required",
491
+ "forbidden",
492
+ "routes_deposit_address_limit_exceeded",
493
+ "routes_subsidy_not_enabled",
494
+ ],
474
495
  },
496
+ "statusReasons": [
497
+ "billing_past_due",
498
+ "billing_required",
499
+ "delivery_failed",
500
+ "delivery_liquidity_unavailable",
501
+ "manual_recovery_required",
502
+ "refund_failed",
503
+ "routes_subsidy_limit_exceeded",
504
+ "routes_subsidy_not_enabled",
505
+ "source_amount_not_supported",
506
+ "source_token_mismatch",
507
+ "subsidy_balance_unavailable",
508
+ "subsidy_failed",
509
+ ],
475
510
  }
476
511
  `)
477
512
  })
478
513
 
479
- describe('POST /funding/deposit-addresses', () => {
480
- test('requires funding:write and an idempotency key', async () => {
514
+ describe('POST /routes/deposit-addresses', () => {
515
+ test('requires routes:write and an idempotency key', async () => {
481
516
  const app = transfersApp({ providers: [depositAddressProvider()] })
482
517
  expect((await postDepositAddress(app, { headers: {} })).status).toBe(401)
483
- expect((await postDepositAddress(app, { key: fundingReader })).status).toBe(403)
518
+ expect((await postDepositAddress(app, { key: routesReader })).status).toBe(403)
484
519
  const response = await postDepositAddress(app, {
485
- headers: { authorization: `Bearer ${fundingWriter.token}` },
520
+ headers: { authorization: `Bearer ${routesWriter.token}` },
486
521
  })
487
522
  expect(response.status).toBe(400)
488
523
  expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
@@ -524,11 +559,289 @@ describe('POST /funding/deposit-addresses', () => {
524
559
  )
525
560
  })
526
561
 
562
+ test('supports a legacy organization-less API key', async () => {
563
+ const response = await postDepositAddress(
564
+ transfersApp({
565
+ providers: [depositAddressProvider('TNWSLbWRWwZmFR2P1EV5ba53B5by2eqUkF')],
566
+ }),
567
+ { key: routesLegacyWriter },
568
+ )
569
+
570
+ expect(response.status).toBe(200)
571
+ expect(await Organizations.get(db, routesLegacyWriter.id)).toMatchObject({
572
+ id: routesLegacyWriter.id,
573
+ userId: null,
574
+ })
575
+ })
576
+
577
+ test('rejects a missing policy, records its bounded reason, and releases the claim', async () => {
578
+ await Organizations.upsert(db, {
579
+ id: routesSubsidyDisabledWriter.orgId,
580
+ name: 'Routes subsidy disabled',
581
+ })
582
+ const counts: Parameters<Metrics.Metrics['count']>[] = []
583
+ const metrics = Metrics.from({
584
+ count(name, value, tags) {
585
+ counts.push([name, value, tags])
586
+ },
587
+ flush() {},
588
+ gauge() {},
589
+ histogram() {},
590
+ })
591
+ const app = transfersApp({
592
+ metrics,
593
+ providers: [depositAddressProvider('TFvF6WzyeRKMM8NcbddxL88mZXTeuUWA8Z')],
594
+ })
595
+ const body = { ...depositAddressBody, subsidize: true }
596
+ const idempotencyKey = nextDepositAddressKey()
597
+ const rejected = await postDepositAddress(app, {
598
+ body,
599
+ idempotencyKey,
600
+ key: routesSubsidyDisabledWriter,
601
+ })
602
+
603
+ expect({ body: await rejected.json(), status: rejected.status }).toMatchInlineSnapshot(
604
+ {
605
+ body: { requestId: expect.any(String) },
606
+ },
607
+ `
608
+ {
609
+ "body": {
610
+ "error": {
611
+ "code": "routes_subsidy_not_enabled",
612
+ "message": "Routes subsidies are not enabled for this organization.",
613
+ },
614
+ "requestId": Any<String>,
615
+ },
616
+ "status": 403,
617
+ }
618
+ `,
619
+ )
620
+ expect(counts.find(([name]) => name === 'routes_subsidy_request_rejection_count')).toEqual([
621
+ 'routes_subsidy_request_rejection_count',
622
+ 1,
623
+ {
624
+ reason: 'routes_subsidy_not_enabled',
625
+ routes_environment: 'production',
626
+ },
627
+ ])
628
+
629
+ await enableRoutesSubsidy(routesSubsidyDisabledWriter, 'active')
630
+ expect(
631
+ (
632
+ await postDepositAddress(app, {
633
+ body,
634
+ idempotencyKey,
635
+ key: routesSubsidyDisabledWriter,
636
+ })
637
+ ).status,
638
+ ).toBe(200)
639
+ })
640
+
641
+ test('requires active production billing for an enabled policy', async () => {
642
+ await enableRoutesSubsidy(routesSubsidyBillingWriter)
643
+ await enableRoutesSubsidy(routesSubsidyPastDueWriter, 'past_due')
644
+ const app = transfersApp({ providers: [depositAddressProvider()] })
645
+
646
+ const required = await postDepositAddress(app, {
647
+ body: { ...depositAddressBody, subsidize: true },
648
+ key: routesSubsidyBillingWriter,
649
+ })
650
+ const pastDue = await postDepositAddress(app, {
651
+ body: { ...depositAddressBody, subsidize: true },
652
+ key: routesSubsidyPastDueWriter,
653
+ })
654
+
655
+ expect([
656
+ { body: await required.json(), status: required.status },
657
+ { body: await pastDue.json(), status: pastDue.status },
658
+ ]).toMatchInlineSnapshot(
659
+ [{ body: { requestId: expect.any(String) } }, { body: { requestId: expect.any(String) } }],
660
+ `
661
+ [
662
+ {
663
+ "body": {
664
+ "error": {
665
+ "code": "billing_required",
666
+ "message": "Billing required.",
667
+ },
668
+ "requestId": Any<String>,
669
+ },
670
+ "status": 403,
671
+ },
672
+ {
673
+ "body": {
674
+ "error": {
675
+ "code": "billing_past_due",
676
+ "message": "Billing past due.",
677
+ },
678
+ "requestId": Any<String>,
679
+ },
680
+ "status": 403,
681
+ },
682
+ ]
683
+ `,
684
+ )
685
+ })
686
+
687
+ test('replays a completed subsidy after policy and billing change', async () => {
688
+ await enableRoutesSubsidy(routesSubsidyReplayWriter, 'active')
689
+ const app = transfersApp({
690
+ providers: [depositAddressProvider('TG1YyTqihYBVjbzaoEm5gUdiZDNwHndhRg')],
691
+ })
692
+ const body = { ...depositAddressBody, subsidize: true }
693
+ const idempotencyKey = nextDepositAddressKey()
694
+ const first = await postDepositAddress(app, {
695
+ body,
696
+ idempotencyKey,
697
+ key: routesSubsidyReplayWriter,
698
+ })
699
+ const firstBody = await first.json()
700
+ await RoutesSubsidies.removeOrganization(db, routesSubsidyReplayWriter.orgId)
701
+ await StripeCustomers.setStatus(db, routesSubsidyReplayWriter.orgId, 'past_due')
702
+ const replay = await postDepositAddress(app, {
703
+ body,
704
+ idempotencyKey,
705
+ key: routesSubsidyReplayWriter,
706
+ })
707
+
708
+ expect({ body: await replay.json(), status: replay.status }).toEqual({ body: firstBody, status: 200 }) // prettier-ignore
709
+ })
710
+
711
+ test('preserves a subsidized claim after an ambiguous provider failure', async () => {
712
+ await enableRoutesSubsidy(routesSubsidyReplayWriter, 'active')
713
+ const app = transfersApp({
714
+ providers: [
715
+ depositAddressProvider(undefined, () => {
716
+ throw new Error('connection closed after dispatch')
717
+ }),
718
+ ],
719
+ })
720
+ const body = {
721
+ ...depositAddressBody,
722
+ recipient: `0x${'22'.repeat(20)}`,
723
+ subsidize: true,
724
+ }
725
+ const idempotencyKey = nextDepositAddressKey()
726
+ const first = await postDepositAddress(app, {
727
+ body,
728
+ idempotencyKey,
729
+ key: routesSubsidyReplayWriter,
730
+ })
731
+ const retry = await postDepositAddress(app, {
732
+ body,
733
+ idempotencyKey,
734
+ key: routesSubsidyReplayWriter,
735
+ })
736
+
737
+ expect([first.status, retry.status]).toEqual([502, 409])
738
+ await expect(
739
+ db.kysely
740
+ .selectFrom('routes_idempotency_requests')
741
+ .select(['irrevocable', 'status'])
742
+ .where('apiKeyId', '=', routesSubsidyReplayWriter.id)
743
+ .where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
744
+ .executeTakeFirstOrThrow(),
745
+ ).resolves.toEqual({ irrevocable: true, status: 'pending' })
746
+ })
747
+
748
+ test('resumes an expired provisioned subsidy without replaying stale quote terms', async () => {
749
+ await Organizations.upsert(db, {
750
+ id: routesSubsidyResumeWriter.orgId,
751
+ name: 'Routes subsidy resume',
752
+ })
753
+ const histograms: Parameters<Metrics.Metrics['histogram']>[] = []
754
+ const metrics = Metrics.from({
755
+ count() {},
756
+ flush() {},
757
+ gauge() {},
758
+ histogram(name, value, tags) {
759
+ histograms.push([name, value, tags])
760
+ },
761
+ })
762
+ const body = { ...depositAddressBody, subsidize: true }
763
+ const idempotencyKey = nextDepositAddressKey()
764
+ const identity = {
765
+ apiKeyId: routesSubsidyResumeWriter.id,
766
+ keyHash: Idempotency.inputHash(idempotencyKey),
767
+ requestHash: Idempotency.inputHash({
768
+ body,
769
+ endpoint: 'POST /v1/routes/deposit-addresses',
770
+ }),
771
+ }
772
+ const claim = await RoutesIdempotencyTable.claim(db, {
773
+ ...identity,
774
+ irrevocable: true,
775
+ operation: RoutesIdempotencyTable.operations.depositAddress,
776
+ orgId: routesSubsidyResumeWriter.orgId,
777
+ ttlMs: 60_000,
778
+ })
779
+ if (claim.type !== 'claimed') throw new Error('Expected a fresh idempotency claim.')
780
+ const snapshot = TestRoutes.depositAddressSnapshot({
781
+ address: 'TG6rrQgTkf3e85cYzqtD2q8fYuJDdM99Rx',
782
+ subsidize: true,
783
+ })
784
+ await RoutesIdempotencyTable.checkpoint(db, {
785
+ apiKeyId: identity.apiKeyId,
786
+ createdAt: claim.createdAt,
787
+ keyHash: identity.keyHash,
788
+ replayTtlMs: 86_400_000,
789
+ response: JSON.stringify({
790
+ candidate: {
791
+ destinationChain: snapshot.destinationChain,
792
+ destinationToken: snapshot.destinationToken,
793
+ sourceChain: snapshot.sourceChain,
794
+ sourceToken: snapshot.sourceToken,
795
+ },
796
+ provider: snapshot.provider,
797
+ recipient: snapshot.recipient,
798
+ refundAddress: snapshot.refundAddress,
799
+ result: {
800
+ address: snapshot.address,
801
+ correlation: { requestId: 'relay_resume_request' },
802
+ destinationAmount: '1000000',
803
+ destinationAmountMin: '1000000',
804
+ fees: [],
805
+ sampledAt: '2026-08-04T00:00:00.000Z',
806
+ },
807
+ }),
808
+ })
809
+ await db.kysely
810
+ .updateTable('routes_idempotency_requests')
811
+ .set({ expiresAt: new Date(0).toISOString() })
812
+ .where('apiKeyId', '=', identity.apiKeyId)
813
+ .where('keyHash', '=', identity.keyHash)
814
+ .execute()
815
+
816
+ const response = await postDepositAddress(transfersApp({ metrics, providers: [] }), {
817
+ body,
818
+ idempotencyKey,
819
+ key: routesSubsidyResumeWriter,
820
+ })
821
+
822
+ expect(response.status).toBe(200)
823
+ const responseBody = await TestApp.json(
824
+ response,
825
+ Routes.schema.createRoutesDepositAddress.Response,
826
+ )
827
+ expect(responseBody.subsidize).toBe(true)
828
+ expect(responseBody).not.toHaveProperty('quote')
829
+ expect(
830
+ histograms.filter(
831
+ ([name]) =>
832
+ name.startsWith('routes_customer_') ||
833
+ name.startsWith('routes_tempo_provider_fee_') ||
834
+ name === 'routes_selection_delta_bps',
835
+ ),
836
+ ).toEqual([])
837
+ })
838
+
527
839
  test('creates a reusable address and persists private provider correlation', async () => {
528
- let seen: FundingProvider.createDepositAddress.Parameters | undefined
529
- const registered: FundingDepositAddress.Public[] = []
840
+ await Organizations.upsert(db, { id: routesWriter.orgId, name: 'Routes' })
841
+ let seen: RoutesProvider.createDepositAddress.Parameters | undefined
842
+ const registered: RoutesDepositAddress.Public[] = []
530
843
  const app = transfersApp({
531
- funding: {
844
+ routes: {
532
845
  registerDepositAddress: async (address) => {
533
846
  registered.push(address)
534
847
  },
@@ -544,7 +857,7 @@ describe('POST /funding/deposit-addresses', () => {
544
857
  })
545
858
  expect(response.status).toBe(200)
546
859
  expect(response.headers.get('cache-control')).toBe('no-store')
547
- const body = await TestApp.json(response, Funding.schema.createFundingDepositAddress.Response)
860
+ const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
548
861
  expect(body).toMatchObject({
549
862
  address: 'TBXSw8fM4jpQkGc6zZjsVABFpVN7UvXPdV',
550
863
  destinationToken: { symbol: 'USDT0' },
@@ -559,7 +872,7 @@ describe('POST /funding/deposit-addresses', () => {
559
872
  recipient: depositAddressBody.recipient,
560
873
  refundAddress: depositAddressBody.refundAddress,
561
874
  })
562
- const record = await FundingDepositAddresses.get(db, body.id)
875
+ const record = await RoutesDepositAddresses.get(db, body.id)
563
876
  expect(record).toMatchObject({
564
877
  deliveryStrategy: 'provider',
565
878
  providerOutputToken: body.destinationToken,
@@ -655,7 +968,7 @@ describe('POST /funding/deposit-addresses', () => {
655
968
  sourceToken: identifier.sourceToken,
656
969
  },
657
970
  })
658
- const body = await TestApp.json(response, Funding.schema.createFundingDepositAddress.Response)
971
+ const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
659
972
  results.push({
660
973
  destinationToken: body.destinationToken.symbol,
661
974
  name: identifier.name,
@@ -700,14 +1013,14 @@ describe('POST /funding/deposit-addresses', () => {
700
1013
  })
701
1014
  const first = await TestApp.json(
702
1015
  await postDepositAddress(app, { body, idempotencyKey: nextDepositAddressKey() }),
703
- Funding.schema.createFundingDepositAddress.Response,
1016
+ Routes.schema.createRoutesDepositAddress.Response,
704
1017
  )
705
1018
  const second = await TestApp.json(
706
1019
  await postDepositAddress(app, {
707
1020
  body: { ...body, amount: '200000000' },
708
1021
  idempotencyKey: nextDepositAddressKey(),
709
1022
  }),
710
- Funding.schema.createFundingDepositAddress.Response,
1023
+ Routes.schema.createRoutesDepositAddress.Response,
711
1024
  )
712
1025
  if (!('sourceAmount' in first)) throw new Error('Expected newly provisioned terms.')
713
1026
 
@@ -725,7 +1038,7 @@ describe('POST /funding/deposit-addresses', () => {
725
1038
  },
726
1039
  `
727
1040
  {
728
- "calls": 2,
1041
+ "calls": 1,
729
1042
  "firstHasQuote": true,
730
1043
  "firstId": Any<String>,
731
1044
  "firstSourceAmount": "100000000",
@@ -738,7 +1051,8 @@ describe('POST /funding/deposit-addresses', () => {
738
1051
  })
739
1052
 
740
1053
  test('stores subsidized addresses as a separate reusable identity', async () => {
741
- const inputs: FundingProvider.createDepositAddress.Parameters[] = []
1054
+ await enableRoutesSubsidy(routesSubsidyWriter, 'active')
1055
+ const inputs: RoutesProvider.createDepositAddress.Parameters[] = []
742
1056
  const app = transfersApp({
743
1057
  providers: [
744
1058
  withCreateDepositAddress('relay', async (input) => {
@@ -761,12 +1075,15 @@ describe('POST /funding/deposit-addresses', () => {
761
1075
  sourceToken: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
762
1076
  }
763
1077
  const standard = await TestApp.json(
764
- await postDepositAddress(app, { body }),
765
- Funding.schema.createFundingDepositAddress.Response,
1078
+ await postDepositAddress(app, { body, key: routesSubsidyWriter }),
1079
+ Routes.schema.createRoutesDepositAddress.Response,
766
1080
  )
767
1081
  const subsidized = await TestApp.json(
768
- await postDepositAddress(app, { body: { ...body, subsidize: true } }),
769
- Funding.schema.createFundingDepositAddress.Response,
1082
+ await postDepositAddress(app, {
1083
+ body: { ...body, subsidize: true },
1084
+ key: routesSubsidyWriter,
1085
+ }),
1086
+ Routes.schema.createRoutesDepositAddress.Response,
770
1087
  )
771
1088
 
772
1089
  expect({
@@ -787,8 +1104,37 @@ describe('POST /funding/deposit-addresses', () => {
787
1104
  `)
788
1105
  })
789
1106
 
1107
+ test('reuses a subsidized address across API keys in one organization', async () => {
1108
+ await enableRoutesSubsidy(routesSubsidyWriter, 'active')
1109
+ let calls = 0
1110
+ const app = transfersApp({
1111
+ providers: [
1112
+ depositAddressProvider(`0x${'34'.repeat(20)}`, () => {
1113
+ calls += 1
1114
+ }),
1115
+ ],
1116
+ })
1117
+ const body = {
1118
+ ...depositAddressBody,
1119
+ refundAddress: `0x${'35'.repeat(20)}`,
1120
+ sourceChain: 'base',
1121
+ sourceToken: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
1122
+ subsidize: true,
1123
+ }
1124
+ const first = await TestApp.json(
1125
+ await postDepositAddress(app, { body, key: routesSubsidyWriter }),
1126
+ Routes.schema.createRoutesDepositAddress.Response,
1127
+ )
1128
+ const second = await TestApp.json(
1129
+ await postDepositAddress(app, { body, key: routesSubsidyWriterSecond }),
1130
+ Routes.schema.createRoutesDepositAddress.Response,
1131
+ )
1132
+
1133
+ expect({ calls, reused: first.id === second.id }).toEqual({ calls: 1, reused: true })
1134
+ })
1135
+
790
1136
  test('normalizes EVM accounts before provisioning and matching', async () => {
791
- const inputs: FundingProvider.createDepositAddress.Parameters[] = []
1137
+ const inputs: RoutesProvider.createDepositAddress.Parameters[] = []
792
1138
  const recipient = '0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD'
793
1139
  const refundAddress = '0x1234567890AbcdEF1234567890aBcdef12345678'
794
1140
  const body = {
@@ -807,7 +1153,7 @@ describe('POST /funding/deposit-addresses', () => {
807
1153
  })
808
1154
  const first = await TestApp.json(
809
1155
  await postDepositAddress(app, { body, idempotencyKey: nextDepositAddressKey() }),
810
- Funding.schema.createFundingDepositAddress.Response,
1156
+ Routes.schema.createRoutesDepositAddress.Response,
811
1157
  )
812
1158
  const second = await TestApp.json(
813
1159
  await postDepositAddress(app, {
@@ -818,7 +1164,7 @@ describe('POST /funding/deposit-addresses', () => {
818
1164
  },
819
1165
  idempotencyKey: nextDepositAddressKey(),
820
1166
  }),
821
- Funding.schema.createFundingDepositAddress.Response,
1167
+ Routes.schema.createRoutesDepositAddress.Response,
822
1168
  )
823
1169
 
824
1170
  expect({
@@ -837,10 +1183,6 @@ describe('POST /funding/deposit-addresses', () => {
837
1183
  "recipient": "0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD",
838
1184
  "refundAddress": "0x1234567890AbcdEF1234567890aBcdef12345678",
839
1185
  },
840
- {
841
- "recipient": "0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD",
842
- "refundAddress": "0x1234567890AbcdEF1234567890aBcdef12345678",
843
- },
844
1186
  ],
845
1187
  "reused": true,
846
1188
  "second": {
@@ -860,7 +1202,7 @@ describe('POST /funding/deposit-addresses', () => {
860
1202
  }),
861
1203
  { body, idempotencyKey: nextDepositAddressKey() },
862
1204
  ),
863
- Funding.schema.createFundingDepositAddress.Response,
1205
+ Routes.schema.createRoutesDepositAddress.Response,
864
1206
  )
865
1207
 
866
1208
  let calls = 0
@@ -876,7 +1218,7 @@ describe('POST /funding/deposit-addresses', () => {
876
1218
  body: { ...body, amount: '200000000' },
877
1219
  idempotencyKey,
878
1220
  })
879
- const second = await TestApp.json(response, Funding.schema.createFundingDepositAddress.Response)
1221
+ const second = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
880
1222
 
881
1223
  expect({
882
1224
  address: second.address,
@@ -891,7 +1233,7 @@ describe('POST /funding/deposit-addresses', () => {
891
1233
  `
892
1234
  {
893
1235
  "address": Any<String>,
894
- "calls": 1,
1236
+ "calls": 0,
895
1237
  "hasQuote": false,
896
1238
  "reused": true,
897
1239
  "status": 200,
@@ -905,10 +1247,118 @@ describe('POST /funding/deposit-addresses', () => {
905
1247
  body: { ...body, amount: '200000000' },
906
1248
  idempotencyKey,
907
1249
  }),
908
- Funding.schema.createFundingDepositAddress.Response,
1250
+ Routes.schema.createRoutesDepositAddress.Response,
909
1251
  ),
910
1252
  ).toEqual(second)
911
- expect(calls).toBe(1)
1253
+ expect(calls).toBe(0)
1254
+ })
1255
+
1256
+ test('retains the provider checkpoint when address persistence fails', async () => {
1257
+ const address = 'TKJebW6SdoJhgkKU13BeKCbrMzT6HeQhJ6'
1258
+ const body = { ...depositAddressBody, recipient: `0x${'66'.repeat(20)}` }
1259
+ const counts: Parameters<Metrics.Metrics['count']>[] = []
1260
+ const histograms: Parameters<Metrics.Metrics['histogram']>[] = []
1261
+ const metrics = Metrics.from({
1262
+ count(name, value, tags) {
1263
+ counts.push([name, value, tags])
1264
+ },
1265
+ flush() {},
1266
+ gauge() {},
1267
+ histogram(name, value, tags) {
1268
+ histograms.push([name, value, tags])
1269
+ },
1270
+ })
1271
+ await db.kysely.deleteFrom('routes_deposit_addresses').where('address', '=', address).execute()
1272
+ await seedDepositAddress({
1273
+ orgId: routesForeignWriter.orgId,
1274
+ snapshot: TestRoutes.depositAddressSnapshot({
1275
+ address,
1276
+ provider: { id: 'relay', name: 'Relay' },
1277
+ recipient: `0x${'33'.repeat(20)}`,
1278
+ }),
1279
+ })
1280
+ const idempotencyKey = nextDepositAddressKey()
1281
+ let calls = 0
1282
+ const app = transfersApp({
1283
+ metrics,
1284
+ providers: [
1285
+ depositAddressProvider(address, () => {
1286
+ calls += 1
1287
+ }),
1288
+ ],
1289
+ })
1290
+ const response = await postDepositAddress(app, { body, idempotencyKey })
1291
+
1292
+ expect(response.status).toBe(502)
1293
+ await expect(
1294
+ db.kysely
1295
+ .selectFrom('routes_idempotency_requests')
1296
+ .select(['response', 'status'])
1297
+ .where('apiKeyId', '=', routesWriter.id)
1298
+ .where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
1299
+ .executeTakeFirstOrThrow(),
1300
+ ).resolves.toEqual({ response: expect.any(String), status: 'provisioned' })
1301
+
1302
+ await db.kysely
1303
+ .deleteFrom('routes_deposit_addresses')
1304
+ .where('orgId', '=', routesForeignWriter.orgId)
1305
+ .where('address', '=', address)
1306
+ .execute()
1307
+ const recoveredIdempotencyKey = nextDepositAddressKey()
1308
+ const recovered = await postDepositAddress(app, {
1309
+ body: { ...body, amount: '200000000' },
1310
+ idempotencyKey: recoveredIdempotencyKey,
1311
+ key: routesWriterSecond,
1312
+ })
1313
+ expect({ calls, status: recovered.status }).toEqual({ calls: 1, status: 200 })
1314
+ const recoveredBody = await TestApp.json(
1315
+ recovered,
1316
+ Routes.schema.createRoutesDepositAddress.Response,
1317
+ )
1318
+ expect(recoveredBody).toMatchObject({
1319
+ address,
1320
+ })
1321
+ expect(recoveredBody).not.toHaveProperty('quote')
1322
+ expect(counts.filter(([name]) => name === 'routes_resource_transition_count')).toEqual([
1323
+ [
1324
+ 'routes_resource_transition_count',
1325
+ 1,
1326
+ {
1327
+ from_status: 'none',
1328
+ method: 'deposit_address',
1329
+ provider: 'relay',
1330
+ reason: 'none',
1331
+ resource: 'deposit_address',
1332
+ routes_environment: 'production',
1333
+ to_status: 'active',
1334
+ },
1335
+ ],
1336
+ ])
1337
+ expect(
1338
+ histograms.filter(
1339
+ ([name]) =>
1340
+ name.startsWith('routes_customer_') ||
1341
+ name.startsWith('routes_tempo_provider_fee_') ||
1342
+ name === 'routes_selection_delta_bps',
1343
+ ),
1344
+ ).toEqual([])
1345
+ const original = await postDepositAddress(app, { body, idempotencyKey })
1346
+ expect(
1347
+ await TestApp.json(original, Routes.schema.createRoutesDepositAddress.Response),
1348
+ ).toMatchObject({ sourceAmount: { baseUnits: '100000000' } })
1349
+ await expect(
1350
+ db.kysely
1351
+ .selectFrom('routes_idempotency_requests')
1352
+ .select('status')
1353
+ .where('apiKeyId', 'in', [routesWriter.id, routesWriterSecond.id])
1354
+ .where('keyHash', 'in', [
1355
+ Idempotency.inputHash(idempotencyKey),
1356
+ Idempotency.inputHash(recoveredIdempotencyKey),
1357
+ ])
1358
+ .where('operation', '=', RoutesIdempotencyTable.operations.depositAddress)
1359
+ .orderBy('apiKeyId')
1360
+ .execute(),
1361
+ ).resolves.toEqual([{ status: 'completed' }, { status: 'completed' }])
912
1362
  })
913
1363
 
914
1364
  test('rejects a refund address from another chain', async () => {
@@ -969,12 +1419,12 @@ describe('POST /funding/deposit-addresses', () => {
969
1419
  }
970
1420
  const idempotencyKey = nextDepositAddressKey()
971
1421
  const first = await postDepositAddress(app, { body: requestBody, idempotencyKey })
972
- const response = await TestApp.json(first, Funding.schema.createFundingDepositAddress.Response)
1422
+ const response = await TestApp.json(first, Routes.schema.createRoutesDepositAddress.Response)
973
1423
  const { subsidize: _, ...legacy } = response
974
1424
  await db.kysely
975
- .updateTable('funding_idempotency_requests')
1425
+ .updateTable('routes_idempotency_requests')
976
1426
  .set({ response: JSON.stringify(legacy) })
977
- .where('apiKeyId', '=', fundingWriter.id)
1427
+ .where('apiKeyId', '=', routesWriter.id)
978
1428
  .where('keyHash', '=', Idempotency.inputHash(idempotencyKey))
979
1429
  .returningAll()
980
1430
  .executeTakeFirstOrThrow()
@@ -982,7 +1432,7 @@ describe('POST /funding/deposit-addresses', () => {
982
1432
  const replay = await postDepositAddress(app, { body: requestBody, idempotencyKey })
983
1433
  const response_replay = await TestApp.json(
984
1434
  replay,
985
- Funding.schema.createFundingDepositAddress.Response,
1435
+ Routes.schema.createRoutesDepositAddress.Response,
986
1436
  )
987
1437
 
988
1438
  expect({ status: replay.status, subsidize: response_replay.subsidize }).toMatchInlineSnapshot(`
@@ -995,12 +1445,15 @@ describe('POST /funding/deposit-addresses', () => {
995
1445
 
996
1446
  test('preserves the idempotency fingerprint when subsidize is omitted', async () => {
997
1447
  const idempotencyKey = nextDepositAddressKey()
998
- await FundingIdempotencyTable.claim(db, {
999
- apiKeyId: fundingWriter.id,
1448
+ await RoutesIdempotencyTable.claim(db, {
1449
+ apiKeyId: routesWriter.id,
1450
+ irrevocable: false,
1000
1451
  keyHash: Idempotency.inputHash(idempotencyKey),
1452
+ operation: RoutesIdempotencyTable.operations.depositAddress,
1453
+ orgId: routesWriter.orgId,
1001
1454
  requestHash: Idempotency.inputHash({
1002
1455
  body: depositAddressBody,
1003
- endpoint: 'POST /v1/funding/deposit-addresses',
1456
+ endpoint: 'POST /v1/routes/deposit-addresses',
1004
1457
  }),
1005
1458
  ttlMs: 60_000,
1006
1459
  })
@@ -1016,7 +1469,7 @@ describe('POST /funding/deposit-addresses', () => {
1016
1469
  "body": {
1017
1470
  "error": {
1018
1471
  "code": "idempotency_in_progress",
1019
- "message": "An equivalent funding deposit address creation is still running.",
1472
+ "message": "An equivalent route deposit address creation is still running.",
1020
1473
  },
1021
1474
  "requestId": Any<String>,
1022
1475
  },
@@ -1028,9 +1481,12 @@ describe('POST /funding/deposit-addresses', () => {
1028
1481
 
1029
1482
  test('includes the creation endpoint in the idempotency fingerprint', async () => {
1030
1483
  const idempotencyKey = nextDepositAddressKey()
1031
- await FundingIdempotencyTable.claim(db, {
1032
- apiKeyId: fundingWriter.id,
1484
+ await RoutesIdempotencyTable.claim(db, {
1485
+ apiKeyId: routesWriter.id,
1486
+ irrevocable: false,
1033
1487
  keyHash: Idempotency.inputHash(idempotencyKey),
1488
+ operation: RoutesIdempotencyTable.operations.depositAddress,
1489
+ orgId: routesWriter.orgId,
1034
1490
  requestHash: Idempotency.inputHash(depositAddressBody),
1035
1491
  ttlMs: 60_000,
1036
1492
  })
@@ -1081,19 +1537,355 @@ describe('POST /funding/deposit-addresses', () => {
1081
1537
  status: 502,
1082
1538
  })
1083
1539
  })
1540
+
1541
+ test('caps new addresses before provisioning while allowing reusable matches', async () => {
1542
+ await Organizations.upsert(db, { id: routesLimitWriter.orgId, name: 'Routes limit' })
1543
+ await seedDepositAddress({
1544
+ orgId: routesLimitWriter.orgId,
1545
+ snapshot: TestRoutes.depositAddressSnapshot({
1546
+ address: 'limit-existing-address',
1547
+ provider: { id: 'relay', name: 'Relay' },
1548
+ recipient: depositAddressBody.recipient,
1549
+ }),
1550
+ })
1551
+ for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
1552
+ await seedDepositAddress({
1553
+ orgId: routesLimitWriter.orgId,
1554
+ snapshot: TestRoutes.depositAddressSnapshot({
1555
+ address: `limit-address-${index}`,
1556
+ provider: { id: 'relay', name: 'Relay' },
1557
+ recipient: `0x${index.toString(16).padStart(40, '0')}`,
1558
+ }),
1559
+ })
1560
+ const counts: Parameters<Metrics.Metrics['count']>[] = []
1561
+ const metrics = Metrics.from({
1562
+ count(name, value, tags) {
1563
+ counts.push([name, value, tags])
1564
+ },
1565
+ flush() {},
1566
+ gauge() {},
1567
+ histogram() {},
1568
+ })
1569
+ let provisions = 0
1570
+ const app = transfersApp({
1571
+ metrics,
1572
+ providers: [
1573
+ depositAddressProvider(undefined, () => {
1574
+ provisions++
1575
+ }),
1576
+ ],
1577
+ })
1578
+ const response = await postDepositAddress(app, {
1579
+ body: { ...depositAddressBody, recipient: `0x${'22'.repeat(20)}` },
1580
+ key: routesLimitWriter,
1581
+ })
1582
+
1583
+ expect({
1584
+ body: await response.json(),
1585
+ metric: counts.find(([name]) => name === 'routes_deposit_address_limit_rejection_count'),
1586
+ provisions,
1587
+ status: response.status,
1588
+ }).toMatchInlineSnapshot(
1589
+ { body: { requestId: expect.any(String) } },
1590
+ `
1591
+ {
1592
+ "body": {
1593
+ "error": {
1594
+ "code": "routes_deposit_address_limit_exceeded",
1595
+ "message": "Route deposit address limit reached (100).",
1596
+ },
1597
+ "requestId": Any<String>,
1598
+ },
1599
+ "metric": [
1600
+ "routes_deposit_address_limit_rejection_count",
1601
+ 1,
1602
+ {
1603
+ "routes_environment": "production",
1604
+ },
1605
+ ],
1606
+ "provisions": 0,
1607
+ "status": 403,
1608
+ }
1609
+ `,
1610
+ )
1611
+ const reused = await postDepositAddress(app, { key: routesLimitWriter })
1612
+ expect(reused.status).toBe(200)
1613
+ expect(provisions).toBe(0)
1614
+ expect(await RoutesDepositAddresses.countByOrganization(db, routesLimitWriter.orgId)).toBe(
1615
+ RoutesDepositAddress.maximumPerCreator,
1616
+ )
1617
+
1618
+ const recoveryBody = {
1619
+ ...depositAddressBody,
1620
+ recipient: `0x${'33'.repeat(20)}`,
1621
+ subsidize: true,
1622
+ }
1623
+ const recoverySourceKey = nextDepositAddressKey()
1624
+ const recoveryRetryKey = nextDepositAddressKey()
1625
+ const recoveryIdentity = {
1626
+ apiKeyId: routesLimitWriter.id,
1627
+ keyHash: Idempotency.inputHash(recoverySourceKey),
1628
+ requestHash: Idempotency.inputHash({
1629
+ body: recoveryBody,
1630
+ endpoint: 'POST /v1/routes/deposit-addresses',
1631
+ }),
1632
+ }
1633
+ const recoveryClaim = await RoutesIdempotencyTable.claim(db, {
1634
+ ...recoveryIdentity,
1635
+ irrevocable: true,
1636
+ operation: RoutesIdempotencyTable.operations.depositAddress,
1637
+ orgId: routesLimitWriter.orgId,
1638
+ ttlMs: 60_000,
1639
+ })
1640
+ if (recoveryClaim.type !== 'claimed') throw new Error('Expected a recovery claim.')
1641
+ const recoverySnapshot = TestRoutes.depositAddressSnapshot({
1642
+ address: 'TPnd4mS1qPSySdshZ9BuS2mGtWuxBq4uc5',
1643
+ recipient: recoveryBody.recipient,
1644
+ subsidize: true,
1645
+ })
1646
+ await RoutesIdempotencyTable.checkpoint(db, {
1647
+ apiKeyId: recoveryIdentity.apiKeyId,
1648
+ createdAt: recoveryClaim.createdAt,
1649
+ keyHash: recoveryIdentity.keyHash,
1650
+ replayTtlMs: 86_400_000,
1651
+ response: JSON.stringify({
1652
+ candidate: {
1653
+ destinationChain: recoverySnapshot.destinationChain,
1654
+ destinationToken: recoverySnapshot.destinationToken,
1655
+ sourceChain: recoverySnapshot.sourceChain,
1656
+ sourceToken: recoverySnapshot.sourceToken,
1657
+ },
1658
+ provider: recoverySnapshot.provider,
1659
+ recipient: recoverySnapshot.recipient,
1660
+ refundAddress: recoverySnapshot.refundAddress,
1661
+ result: {
1662
+ address: recoverySnapshot.address,
1663
+ correlation: { requestId: 'relay_limit_recovery' },
1664
+ destinationAmount: '1000000',
1665
+ destinationAmountMin: '1000000',
1666
+ fees: [],
1667
+ sampledAt: '2026-09-04T00:00:00.000Z',
1668
+ },
1669
+ }),
1670
+ })
1671
+
1672
+ const recovered = await postDepositAddress(transfersApp({ providers: [] }), {
1673
+ body: recoveryBody,
1674
+ idempotencyKey: recoveryRetryKey,
1675
+ key: routesLimitWriterSecond,
1676
+ })
1677
+ expect(recovered.status).toBe(200)
1678
+ expect(await RoutesDepositAddresses.countByOrganization(db, routesLimitWriter.orgId)).toBe(
1679
+ RoutesDepositAddress.maximumPerCreator + 1,
1680
+ )
1681
+ await expect(
1682
+ db.kysely
1683
+ .selectFrom('routes_idempotency_requests')
1684
+ .select('status')
1685
+ .where('keyHash', 'in', [recoveryIdentity.keyHash, Idempotency.inputHash(recoveryRetryKey)])
1686
+ .orderBy('apiKeyId')
1687
+ .execute(),
1688
+ ).resolves.toEqual([{ status: 'completed' }, { status: 'completed' }])
1689
+ })
1690
+
1691
+ test('reserves the final address slot before provider provisioning', async () => {
1692
+ await Organizations.upsert(db, { id: routesRaceWriter.orgId, name: 'Routes race' })
1693
+ for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
1694
+ await seedDepositAddress({
1695
+ orgId: routesRaceWriter.orgId,
1696
+ snapshot: TestRoutes.depositAddressSnapshot({
1697
+ provider: { id: `relay_race_${index}`, name: 'Relay' },
1698
+ recipient: `0x${index.toString(16).padStart(40, '0')}`,
1699
+ }),
1700
+ })
1701
+ const entered = Promise.withResolvers<void>()
1702
+ const release = Promise.withResolvers<void>()
1703
+ let provisions = 0
1704
+ const app = transfersApp({
1705
+ providers: [
1706
+ depositAddressProvider('TRXcKoEvHr6Y38VMcDYGBEYKznvH3XUX4g', async () => {
1707
+ provisions++
1708
+ entered.resolve()
1709
+ await release.promise
1710
+ }),
1711
+ ],
1712
+ })
1713
+ const first = postDepositAddress(app, { key: routesRaceWriter })
1714
+ await entered.promise
1715
+
1716
+ const rejected = await postDepositAddress(app, {
1717
+ body: { ...depositAddressBody, recipient: `0x${'99'.repeat(20)}` },
1718
+ key: routesRaceWriter,
1719
+ })
1720
+ expect(rejected.status).toBe(403)
1721
+ expect(provisions).toBe(1)
1722
+
1723
+ release.resolve()
1724
+ expect((await first).status).toBe(200)
1725
+ expect(await RoutesDepositAddresses.countByOrganization(db, routesRaceWriter.orgId)).toBe(
1726
+ RoutesDepositAddress.maximumPerCreator,
1727
+ )
1728
+ await db.kysely
1729
+ .deleteFrom('routes_deposit_addresses')
1730
+ .where('orgId', '=', routesRaceWriter.orgId)
1731
+ .execute()
1732
+ })
1733
+
1734
+ test('joins concurrent reusable-match provisioning across idempotency keys', async () => {
1735
+ await Organizations.upsert(db, { id: routesRaceWriter.orgId, name: 'Routes match race' })
1736
+ const entered = Promise.withResolvers<void>()
1737
+ const release = Promise.withResolvers<void>()
1738
+ let provisions = 0
1739
+ const app = transfersApp({
1740
+ providers: [
1741
+ depositAddressProvider('TT5rFsXYCrnzdE2q1WdR9F2SuVY59A4hoM', async () => {
1742
+ provisions++
1743
+ entered.resolve()
1744
+ await release.promise
1745
+ }),
1746
+ ],
1747
+ })
1748
+ const first = postDepositAddress(app, {
1749
+ idempotencyKey: 'routes_match_race_first',
1750
+ key: routesRaceWriter,
1751
+ })
1752
+ await entered.promise
1753
+
1754
+ const joined = await postDepositAddress(app, {
1755
+ body: { ...depositAddressBody, amount: '200000000' },
1756
+ idempotencyKey: 'routes_match_race_second',
1757
+ key: routesRaceWriter,
1758
+ })
1759
+ expect({ body: await joined.json(), provisions, status: joined.status }).toMatchInlineSnapshot(
1760
+ { body: { requestId: expect.any(String) } },
1761
+ `
1762
+ {
1763
+ "body": {
1764
+ "error": {
1765
+ "code": "idempotency_in_progress",
1766
+ "message": "An equivalent route deposit address creation is still running.",
1767
+ },
1768
+ "requestId": Any<String>,
1769
+ },
1770
+ "provisions": 1,
1771
+ "status": 409,
1772
+ }
1773
+ `,
1774
+ )
1775
+
1776
+ release.resolve()
1777
+ expect((await first).status).toBe(200)
1778
+ const retried = await postDepositAddress(app, {
1779
+ body: { ...depositAddressBody, amount: '200000000' },
1780
+ idempotencyKey: 'routes_match_race_second',
1781
+ key: routesRaceWriter,
1782
+ })
1783
+ expect(retried.status).toBe(200)
1784
+ expect(provisions).toBe(1)
1785
+ })
1786
+
1787
+ test('shares the final address slot across sibling organizations', async () => {
1788
+ const userId = 'usr_routes_owner_race'
1789
+ await Organizations.create(db, {
1790
+ id: routesOwnerRaceWriter.orgId,
1791
+ name: 'Routes owner race',
1792
+ userId,
1793
+ })
1794
+ await Organizations.create(db, {
1795
+ id: routesOwnerRaceSiblingWriter.orgId,
1796
+ name: 'Routes owner race sibling',
1797
+ userId,
1798
+ })
1799
+ for (let index = 0; index < RoutesDepositAddress.maximumPerCreator - 1; index++)
1800
+ await seedDepositAddress({
1801
+ orgId: routesOwnerRaceWriter.orgId,
1802
+ snapshot: TestRoutes.depositAddressSnapshot({
1803
+ provider: { id: `relay_owner_race_${index}`, name: 'Relay' },
1804
+ recipient: `0x${index.toString(16).padStart(40, '0')}`,
1805
+ }),
1806
+ })
1807
+ const entered = Promise.withResolvers<void>()
1808
+ const release = Promise.withResolvers<void>()
1809
+ let provisions = 0
1810
+ const app = transfersApp({
1811
+ providers: [
1812
+ depositAddressProvider('TUe6BwpA7sVTDKaJQoia7FWZpC9sK8WM2t', async () => {
1813
+ provisions++
1814
+ entered.resolve()
1815
+ await release.promise
1816
+ }),
1817
+ ],
1818
+ })
1819
+ const first = postDepositAddress(app, { key: routesOwnerRaceSiblingWriter })
1820
+ await entered.promise
1821
+
1822
+ const rejected = await postDepositAddress(app, { key: routesOwnerRaceWriter })
1823
+ expect(rejected.status).toBe(403)
1824
+ expect(provisions).toBe(1)
1825
+
1826
+ release.resolve()
1827
+ expect((await first).status).toBe(200)
1828
+ expect(
1829
+ (await RoutesDepositAddresses.countByOrganization(db, routesOwnerRaceWriter.orgId)) +
1830
+ (await RoutesDepositAddresses.countByOrganization(db, routesOwnerRaceSiblingWriter.orgId)),
1831
+ ).toBe(RoutesDepositAddress.maximumPerCreator)
1832
+
1833
+ expect(await Organizations.deleteOrganization(db, routesOwnerRaceWriter.orgId)).toBe(true)
1834
+ await Organizations.create(db, {
1835
+ id: routesOwnerRaceReplacementWriter.orgId,
1836
+ name: 'Routes owner race replacement',
1837
+ userId,
1838
+ })
1839
+ const replacement = await postDepositAddress(app, {
1840
+ key: routesOwnerRaceReplacementWriter,
1841
+ })
1842
+ expect(replacement.status).toBe(403)
1843
+ expect(provisions).toBe(1)
1844
+ })
1845
+
1846
+ test('fences organization deletion while subsidized provider provisioning is in flight', async () => {
1847
+ await enableRoutesSubsidy(routesSubsidyRaceWriter, 'active')
1848
+ const entered = Promise.withResolvers<void>()
1849
+ const release = Promise.withResolvers<void>()
1850
+ const app = transfersApp({
1851
+ providers: [
1852
+ depositAddressProvider('TWCL826n2tBuoR7mp6oj5FzgitmfWSwCGZ', async () => {
1853
+ entered.resolve()
1854
+ await release.promise
1855
+ }),
1856
+ ],
1857
+ })
1858
+ const creation = postDepositAddress(app, {
1859
+ body: { ...depositAddressBody, subsidize: true },
1860
+ key: routesSubsidyRaceWriter,
1861
+ })
1862
+ await entered.promise
1863
+
1864
+ await expect(
1865
+ Organizations.deleteOrganization(db, routesSubsidyRaceWriter.orgId),
1866
+ ).rejects.toThrow(Organizations.IrrevocableDepositAddressError)
1867
+ expect(await Organizations.get(db, routesSubsidyRaceWriter.orgId)).toBeDefined()
1868
+
1869
+ release.resolve()
1870
+ expect((await creation).status).toBe(200)
1871
+ })
1084
1872
  })
1085
1873
 
1086
- describe('POST /webhooks/funding/relay', () => {
1874
+ describe('POST /webhooks/routes/relay', () => {
1087
1875
  test('authenticates and enqueues a bounded reconciliation hint', async () => {
1088
1876
  const secret = 'relay-webhook-secret'
1089
1877
  const address = await seedDepositAddress({
1090
- snapshot: TestFunding.depositAddressSnapshot({
1878
+ snapshot: TestRoutes.depositAddressSnapshot({
1091
1879
  provider: { id: 'relay', name: 'Relay' },
1092
1880
  recipient: `0x${'99'.repeat(20)}`,
1093
1881
  }),
1094
1882
  })
1095
- const dispatched: FundingProvider.Webhook.receive.Dispatchable[] = []
1883
+ const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
1884
+ const entries: Log.Entry[] = []
1096
1885
  const app = transfersApp({
1886
+ logger: (entry) => {
1887
+ entries.push(entry)
1888
+ },
1097
1889
  providers: [
1098
1890
  Relay.relay({
1099
1891
  apiKey: secret,
@@ -1121,7 +1913,7 @@ describe('POST /webhooks/funding/relay', () => {
1121
1913
  Hex.fromString(secret),
1122
1914
  Hex.fromString(`${timestamp}.${body}`),
1123
1915
  ).slice(2)
1124
- const response = await app.request('/webhooks/funding/relay', {
1916
+ const response = await app.request('/webhooks/routes/relay', {
1125
1917
  body,
1126
1918
  headers: {
1127
1919
  'x-signature-sha256': signature,
@@ -1130,8 +1922,13 @@ describe('POST /webhooks/funding/relay', () => {
1130
1922
  method: 'POST',
1131
1923
  })
1132
1924
 
1133
- expect({ dispatched, status: response.status }).toMatchInlineSnapshot(
1925
+ expect({
1926
+ attempt: entries.at(-1)?.routesProviderAttempts?.[0],
1927
+ dispatched,
1928
+ status: response.status,
1929
+ }).toMatchInlineSnapshot(
1134
1930
  {
1931
+ attempt: { durationMs: expect.any(Number) },
1135
1932
  dispatched: [
1136
1933
  {
1137
1934
  webhookTiming: {
@@ -1145,12 +1942,18 @@ describe('POST /webhooks/funding/relay', () => {
1145
1942
  },
1146
1943
  `
1147
1944
  {
1945
+ "attempt": {
1946
+ "durationMs": Any<Number>,
1947
+ "id": "relay",
1948
+ "operation": "receiveWebhook",
1949
+ "outcome": "success",
1950
+ },
1148
1951
  "dispatched": [
1149
1952
  {
1150
1953
  "addressId": "${address.id}",
1151
1954
  "requestId": "relay-child-request",
1152
1955
  "trigger": "webhook",
1153
- "type": "funding:deposit-address:reconcile",
1956
+ "type": "routes:deposit-address:reconcile",
1154
1957
  "webhookTiming": {
1155
1958
  "enqueuedAt": Any<String>,
1156
1959
  "providerStatus": "pending",
@@ -1175,16 +1978,46 @@ describe('POST /webhooks/funding/relay', () => {
1175
1978
  }),
1176
1979
  ],
1177
1980
  })
1178
- const response = await app.request('/webhooks/funding/relay', {
1981
+ const response = await app.request('/webhooks/routes/relay', {
1179
1982
  body: '{}',
1180
1983
  method: 'POST',
1181
1984
  })
1182
1985
 
1183
1986
  expect(response.status).toMatchInlineSnapshot('401')
1184
1987
  })
1988
+
1989
+ test('rejects oversized events before signature verification', async () => {
1990
+ const app = transfersApp({
1991
+ providers: [
1992
+ Relay.relay({
1993
+ apiKey: 'relay-webhook-secret',
1994
+ webhook: { db, dispatch: async () => {} },
1995
+ }),
1996
+ ],
1997
+ })
1998
+ const response = await app.request('/webhooks/routes/relay', {
1999
+ body: 'x'.repeat(64 * 1_024 + 1),
2000
+ headers: {
2001
+ 'x-signature-sha256': 'a'.repeat(64),
2002
+ 'x-signature-timestamp': String(Date.now()),
2003
+ },
2004
+ method: 'POST',
2005
+ })
2006
+
2007
+ expect(response.status).toMatchInlineSnapshot('413')
2008
+ })
2009
+
2010
+ test('rejects unknown providers before reading oversized events', async () => {
2011
+ const response = await transfersApp().request('/webhooks/routes/unknown', {
2012
+ body: 'x'.repeat(64 * 1_024 + 1),
2013
+ method: 'POST',
2014
+ })
2015
+
2016
+ expect(response.status).toMatchInlineSnapshot('404')
2017
+ })
1185
2018
  })
1186
2019
 
1187
- describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
2020
+ describe.skipIf(!relayApiKey)('POST /routes/deposit-addresses (relay)', () => {
1188
2021
  test('provisions and persists a reusable address through Relay', async () => {
1189
2022
  const app = transfersApp({
1190
2023
  providers: [Relay.relay({ apiKey: relayApiKey })],
@@ -1194,96 +2027,14 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
1194
2027
  })
1195
2028
 
1196
2029
  expect(response.status).toBe(200)
1197
- const body = await TestApp.json(response, Funding.schema.createFundingDepositAddress.Response)
1198
- expect(body).toMatchInlineSnapshot(
1199
- {
1200
- address: expect.any(String),
1201
- createdAt: expect.any(String),
1202
- destinationAmount: {
1203
- baseUnits: expect.any(String),
1204
- formatted: expect.any(String),
1205
- },
1206
- destinationAmountMin: {
1207
- baseUnits: expect.any(String),
1208
- formatted: expect.any(String),
1209
- },
1210
- fees: expect.any(Array),
1211
- id: expect.any(String),
1212
- quote: { sampledAt: expect.any(String) },
1213
- updatedAt: expect.any(String),
1214
- },
1215
- `
1216
- {
1217
- "address": Any<String>,
1218
- "createdAt": Any<String>,
1219
- "destinationAmount": {
1220
- "baseUnits": Any<String>,
1221
- "currency": "USD",
1222
- "decimals": 6,
1223
- "formatted": Any<String>,
1224
- },
1225
- "destinationAmountMin": {
1226
- "baseUnits": Any<String>,
1227
- "currency": "USD",
1228
- "decimals": 6,
1229
- "formatted": Any<String>,
1230
- },
1231
- "destinationChain": {
1232
- "addressFormat": "hex",
1233
- "id": "eip155:4217",
1234
- "kind": "evm",
1235
- "name": "Tempo",
1236
- },
1237
- "destinationToken": {
1238
- "address": "0x20c00000000000000000000014f22ca97301eb73",
1239
- "currency": "USD",
1240
- "decimals": 6,
1241
- "name": "USDT0",
1242
- "standard": "TIP-20",
1243
- "symbol": "USDT0",
1244
- "tokenKey": "eip155:4217/erc20:0x20c00000000000000000000014f22ca97301eb73",
1245
- "verified": true,
1246
- },
1247
- "fees": Any<Array>,
1248
- "id": Any<String>,
1249
- "provider": {
1250
- "id": "relay",
1251
- "name": "Relay",
1252
- },
1253
- "quote": {
1254
- "sampledAt": Any<String>,
1255
- },
1256
- "recipient": "0x7777777777777777777777777777777777777777",
1257
- "refundAddress": "TJRabPrwbZy45sbavfcjinPJC18kjpRTv8",
1258
- "sourceAmount": {
1259
- "baseUnits": "100000000",
1260
- "currency": "USD",
1261
- "decimals": 6,
1262
- "formatted": "100",
1263
- },
1264
- "sourceChain": {
1265
- "addressFormat": "base58check",
1266
- "id": "tron:0x2b6653dc",
1267
- "kind": "tron",
1268
- "name": "Tron",
1269
- },
1270
- "sourceToken": {
1271
- "address": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
1272
- "currency": "USD",
1273
- "decimals": 6,
1274
- "name": "Tether USD",
1275
- "standard": "TRC-20",
1276
- "symbol": "USDT",
1277
- "tokenKey": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
1278
- "verified": true,
1279
- },
1280
- "status": "active",
1281
- "subsidize": false,
1282
- "updatedAt": Any<String>,
1283
- }
1284
- `,
1285
- )
1286
- const record = await FundingDepositAddresses.get(db, body.id)
2030
+ const body = await TestApp.json(response, Routes.schema.createRoutesDepositAddress.Response)
2031
+ expect(body).toMatchObject({
2032
+ address: expect.any(String),
2033
+ id: expect.any(String),
2034
+ provider: { id: 'relay' },
2035
+ status: 'active',
2036
+ })
2037
+ const record = await RoutesDepositAddresses.get(db, body.id)
1287
2038
  expect(record).toMatchInlineSnapshot(
1288
2039
  {
1289
2040
  address: expect.any(String),
@@ -1293,20 +2044,21 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
1293
2044
  providerRequestIds: [expect.any(String)],
1294
2045
  providerState: expect.any(Object),
1295
2046
  snapshot: { address: expect.any(String) },
2047
+ statusUpdatedAt: expect.any(String),
1296
2048
  updatedAt: expect.any(String),
1297
2049
  },
1298
2050
  `
1299
2051
  {
1300
2052
  "address": Any<String>,
1301
- "apiKeyId": "key_funding_writer",
1302
2053
  "createdAt": Any<String>,
2054
+ "creatorUserId": null,
1303
2055
  "deliveryStrategy": "provider",
1304
2056
  "destinationTokenKey": "eip155:4217/erc20:0x20c00000000000000000000014f22ca97301eb73",
1305
2057
  "environment": "production",
1306
2058
  "id": Any<String>,
1307
2059
  "lastPolledAt": null,
1308
2060
  "nextPollAt": Any<String>,
1309
- "orgId": "org_funding",
2061
+ "orgId": "org_routes",
1310
2062
  "pollFailureCount": 0,
1311
2063
  "pollLeaseUntil": null,
1312
2064
  "pollLeaseVersion": 0,
@@ -1373,6 +2125,7 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
1373
2125
  "sourceChainId": "tron:0x2b6653dc",
1374
2126
  "sourceTokenKey": "tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
1375
2127
  "status": "active",
2128
+ "statusUpdatedAt": Any<String>,
1376
2129
  "subsidize": false,
1377
2130
  "updatedAt": Any<String>,
1378
2131
  "version": 1,
@@ -1382,32 +2135,32 @@ describe.skipIf(!relayApiKey)('POST /funding/deposit-addresses (relay)', () => {
1382
2135
  })
1383
2136
  })
1384
2137
 
1385
- describe('GET /funding/deposit-addresses', () => {
2138
+ describe('GET /routes/deposit-addresses', () => {
1386
2139
  test('pages organization addresses and narrows project-attributed keys', async () => {
1387
2140
  const app = transfersApp()
1388
- const first = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
1389
- const second = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
1390
- const third = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
2141
+ const first = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
2142
+ const second = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
2143
+ const third = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
1391
2144
  const project = await seedDepositAddress({
1392
- orgId: fundingAddressListReader.orgId,
1393
- projectId: fundingAddressListProjectReader.projectId,
2145
+ orgId: routesAddressListReader.orgId,
2146
+ projectId: routesAddressListProjectReader.projectId,
1394
2147
  })
1395
2148
  const sibling = await seedDepositAddress({
1396
- orgId: fundingAddressListReader.orgId,
1397
- projectId: 'prj_funding_address_list_sibling',
2149
+ orgId: routesAddressListReader.orgId,
2150
+ projectId: 'prj_routes_address_list_sibling',
1398
2151
  })
1399
- const sixth = await seedDepositAddress({ orgId: fundingAddressListReader.orgId })
1400
- await seedDepositAddress({ orgId: fundingForeign.orgId })
2152
+ const sixth = await seedDepositAddress({ orgId: routesAddressListReader.orgId })
2153
+ await seedDepositAddress({ orgId: routesForeign.orgId })
1401
2154
  await seedDepositAddress({
1402
2155
  environment: 'sandbox',
1403
- orgId: fundingAddressListReader.orgId,
2156
+ orgId: routesAddressListReader.orgId,
1404
2157
  })
1405
2158
 
1406
- const path = '/v1/funding/deposit-addresses'
2159
+ const path = '/v1/routes/deposit-addresses'
1407
2160
  expect((await app.request(path)).status).toBe(401)
1408
2161
  expect((await app.request(path, as(TestApp.key))).status).toBe(403)
1409
2162
 
1410
- const response = await app.request(`${path}?limit=5`, as(fundingAddressListReader))
2163
+ const response = await app.request(`${path}?limit=5`, as(routesAddressListReader))
1411
2164
  expect(response.status).toBe(200)
1412
2165
  expect({
1413
2166
  cacheControl: response.headers.get('cache-control'),
@@ -1418,7 +2171,7 @@ describe('GET /funding/deposit-addresses', () => {
1418
2171
  etag: null,
1419
2172
  vary: 'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
1420
2173
  })
1421
- const body = await TestApp.json(response, Funding.schema.listFundingDepositAddresses.Response)
2174
+ const body = await TestApp.json(response, Routes.schema.listRoutesDepositAddresses.Response)
1422
2175
  expect(body.data.map((address) => address.id)).toEqual([
1423
2176
  sixth.id,
1424
2177
  sibling.id,
@@ -1429,29 +2182,29 @@ describe('GET /funding/deposit-addresses', () => {
1429
2182
  expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
1430
2183
 
1431
2184
  const next = await TestApp.json(
1432
- await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(fundingAddressListReader)),
1433
- Funding.schema.listFundingDepositAddresses.Response,
2185
+ await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(routesAddressListReader)),
2186
+ Routes.schema.listRoutesDepositAddresses.Response,
1434
2187
  )
1435
2188
  expect(next.data.map((address) => address.id)).toEqual([first.id])
1436
2189
  expect(next.nextCursor).toBeNull()
1437
2190
 
1438
2191
  const projectBody = await TestApp.json(
1439
- await app.request(path, as(fundingAddressListProjectReader)),
1440
- Funding.schema.listFundingDepositAddresses.Response,
2192
+ await app.request(path, as(routesAddressListProjectReader)),
2193
+ Routes.schema.listRoutesDepositAddresses.Response,
1441
2194
  )
1442
2195
  expect(projectBody.data.map((address) => address.id)).toEqual([project.id])
1443
2196
  })
1444
2197
  })
1445
2198
 
1446
- describe('GET /funding/deposit-addresses/:id', () => {
1447
- test('requires funding:read and returns the owned address', async () => {
2199
+ describe('GET /routes/deposit-addresses/:id', () => {
2200
+ test('requires routes:read and returns the owned address', async () => {
1448
2201
  const app = transfersApp()
1449
2202
  const record = await seedDepositAddress()
1450
- const path = `/v1/funding/deposit-addresses/${record.id}`
2203
+ const path = `/v1/routes/deposit-addresses/${record.id}`
1451
2204
  expect((await app.request(path)).status).toBe(401)
1452
2205
  expect((await app.request(path, as(TestApp.key))).status).toBe(403)
1453
2206
 
1454
- const response = await app.request(path, as(fundingReader))
2207
+ const response = await app.request(path, as(routesReader))
1455
2208
  expect(response.status).toBe(200)
1456
2209
  expect({
1457
2210
  cacheControl: response.headers.get('cache-control'),
@@ -1465,8 +2218,8 @@ describe('GET /funding/deposit-addresses/:id', () => {
1465
2218
  expect(response.headers.get('vary')).toBe(
1466
2219
  'Accept-Encoding, Authorization, Tempo-API-Key, X-API-Key',
1467
2220
  )
1468
- const body = await TestApp.json(response, Funding.schema.getFundingDepositAddress.Response)
1469
- expect(body).toEqual(FundingDepositAddress.toPublic(record))
2221
+ const body = await TestApp.json(response, Routes.schema.getRoutesDepositAddress.Response)
2222
+ expect(body).toEqual(RoutesDepositAddress.toPublic(record))
1470
2223
  expect(body).not.toHaveProperty('providerOutputToken')
1471
2224
  expect(body).not.toHaveProperty('providerRequestIds')
1472
2225
  })
@@ -1474,40 +2227,40 @@ describe('GET /funding/deposit-addresses/:id', () => {
1474
2227
  test('hides foreign, project-inaccessible, and absent addresses', async () => {
1475
2228
  const app = transfersApp()
1476
2229
  const record = await seedDepositAddress()
1477
- const path = `/v1/funding/deposit-addresses/${record.id}`
2230
+ const path = `/v1/routes/deposit-addresses/${record.id}`
1478
2231
 
1479
- for (const key of [fundingForeign, fundingProjectReader]) {
2232
+ for (const key of [routesForeign, routesProjectReader]) {
1480
2233
  const response = await app.request(path, as(key))
1481
2234
  expect(response.status).toBe(404)
1482
2235
  expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
1483
- 'funding_deposit_address_not_found',
2236
+ 'routes_deposit_address_not_found',
1484
2237
  )
1485
2238
  }
1486
2239
 
1487
2240
  const absent = await app.request(
1488
- '/v1/funding/deposit-addresses/fda_000000000000000_000000000000000000000000',
1489
- as(fundingReader),
2241
+ '/v1/routes/deposit-addresses/rda_000000000000000_000000000000000000000000',
2242
+ as(routesReader),
1490
2243
  )
1491
2244
  expect(absent.status).toBe(404)
1492
2245
  })
1493
2246
  })
1494
2247
 
1495
- describe('POST /funding/deposit-addresses/:id/reconcile', () => {
1496
- test('requires funding:write and queues the owned active address', async () => {
1497
- const dispatched: FundingProvider.Webhook.receive.Dispatchable[] = []
2248
+ describe('POST /routes/deposit-addresses/:id/reconcile', () => {
2249
+ test('requires routes:write and queues the owned active address', async () => {
2250
+ const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
1498
2251
  const app = transfersApp({
1499
- funding: {
1500
- dispatchReconciliation: async (message) => {
2252
+ routes: {
2253
+ dispatchDepositReconciliation: async (message) => {
1501
2254
  dispatched.push(message)
1502
2255
  },
1503
2256
  },
1504
2257
  })
1505
2258
  const record = await seedDepositAddress()
1506
- const path = `/v1/funding/deposit-addresses/${record.id}/reconcile`
2259
+ const path = `/v1/routes/deposit-addresses/${record.id}/reconcile`
1507
2260
  expect((await app.request(path, { method: 'POST' })).status).toBe(401)
1508
- expect((await app.request(path, { ...as(fundingReader), method: 'POST' })).status).toBe(403)
2261
+ expect((await app.request(path, { ...as(routesReader), method: 'POST' })).status).toBe(403)
1509
2262
 
1510
- const response = await app.request(path, { ...as(fundingWriter), method: 'POST' })
2263
+ const response = await app.request(path, { ...as(routesWriter), method: 'POST' })
1511
2264
  expect({
1512
2265
  body: await response.text(),
1513
2266
  cacheControl: response.headers.get('cache-control'),
@@ -1527,60 +2280,60 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
1527
2280
  {
1528
2281
  "addressId": "${record.id}",
1529
2282
  "trigger": "manual",
1530
- "type": "funding:deposit-address:reconcile",
2283
+ "type": "routes:deposit-address:reconcile",
1531
2284
  },
1532
2285
  ],
1533
2286
  "rateLimit": {
1534
2287
  "limit": "10",
1535
2288
  "remaining": "9",
1536
- "scope": "funding:write",
2289
+ "scope": "routes:write",
1537
2290
  },
1538
2291
  "status": 202,
1539
2292
  "vary": "Accept-Encoding, Authorization, Tempo-API-Key",
1540
2293
  }
1541
2294
  `)
1542
- expect(await FundingDepositAddresses.get(db, record.id)).toEqual(record)
2295
+ expect(await RoutesDepositAddresses.get(db, record.id)).toEqual(record)
1543
2296
  })
1544
2297
 
1545
2298
  test('hides foreign, project-inaccessible, and absent addresses', async () => {
1546
- const dispatched: FundingProvider.Webhook.receive.Dispatchable[] = []
2299
+ const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
1547
2300
  const app = transfersApp({
1548
- funding: {
1549
- dispatchReconciliation: async (message) => {
2301
+ routes: {
2302
+ dispatchDepositReconciliation: async (message) => {
1550
2303
  dispatched.push(message)
1551
2304
  },
1552
2305
  },
1553
2306
  })
1554
2307
  const record = await seedDepositAddress()
1555
- const path = `/v1/funding/deposit-addresses/${record.id}/reconcile`
2308
+ const path = `/v1/routes/deposit-addresses/${record.id}/reconcile`
1556
2309
 
1557
- for (const key of [fundingForeignWriter, fundingProjectWriter]) {
2310
+ for (const key of [routesForeignWriter, routesProjectWriter]) {
1558
2311
  const response = await app.request(path, { ...as(key), method: 'POST' })
1559
2312
  expect(response.status).toBe(404)
1560
2313
  expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
1561
- 'funding_deposit_address_not_found',
2314
+ 'routes_deposit_address_not_found',
1562
2315
  )
1563
2316
  }
1564
2317
 
1565
2318
  const absent = await app.request(
1566
- '/v1/funding/deposit-addresses/fda_000000000000000_000000000000000000000000/reconcile',
1567
- { ...as(fundingWriter), method: 'POST' },
2319
+ '/v1/routes/deposit-addresses/rda_000000000000000_000000000000000000000000/reconcile',
2320
+ { ...as(routesWriter), method: 'POST' },
1568
2321
  )
1569
2322
  expect(absent.status).toBe(404)
1570
2323
  expect(dispatched).toEqual([])
1571
2324
  })
1572
2325
 
1573
2326
  test('rejects inactive addresses and unavailable reconciliation', async () => {
1574
- const dispatched: FundingProvider.Webhook.receive.Dispatchable[] = []
2327
+ const dispatched: RoutesProvider.Webhook.receive.Dispatchable[] = []
1575
2328
  const configured = transfersApp({
1576
- funding: {
1577
- dispatchReconciliation: async (message) => {
2329
+ routes: {
2330
+ dispatchDepositReconciliation: async (message) => {
1578
2331
  dispatched.push(message)
1579
2332
  },
1580
2333
  },
1581
2334
  })
1582
2335
  const record = await seedDepositAddress()
1583
- const transition = await FundingDepositAddress.transition(db, {
2336
+ const transition = await RoutesDepositAddress.transition(db, {
1584
2337
  expectedVersion: record.version,
1585
2338
  id: record.id,
1586
2339
  status: 'action-required',
@@ -1588,18 +2341,18 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
1588
2341
  expect(transition.type).toBe('applied')
1589
2342
 
1590
2343
  const inactive = await configured.request(
1591
- `/v1/funding/deposit-addresses/${record.id}/reconcile`,
1592
- { ...as(fundingWriter), method: 'POST' },
2344
+ `/v1/routes/deposit-addresses/${record.id}/reconcile`,
2345
+ { ...as(routesWriter), method: 'POST' },
1593
2346
  )
1594
2347
  expect({
1595
2348
  code: ((await inactive.json()) as { error: { code: string } }).error.code,
1596
2349
  status: inactive.status,
1597
- }).toEqual({ code: 'funding_deposit_address_not_active', status: 409 })
2350
+ }).toEqual({ code: 'routes_deposit_address_not_active', status: 409 })
1598
2351
 
1599
2352
  const active = await seedDepositAddress()
1600
2353
  const unavailable = await transfersApp().request(
1601
- `/v1/funding/deposit-addresses/${active.id}/reconcile`,
1602
- { ...as(fundingWriter), method: 'POST' },
2354
+ `/v1/routes/deposit-addresses/${active.id}/reconcile`,
2355
+ { ...as(routesWriter), method: 'POST' },
1603
2356
  )
1604
2357
  expect({
1605
2358
  code: ((await unavailable.json()) as { error: { code: string } }).error.code,
@@ -1610,15 +2363,15 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
1610
2363
 
1611
2364
  test('returns an upstream error when the queue rejects the message', async () => {
1612
2365
  const app = transfersApp({
1613
- funding: {
1614
- dispatchReconciliation: async () => {
2366
+ routes: {
2367
+ dispatchDepositReconciliation: async () => {
1615
2368
  throw new Error('queue unavailable')
1616
2369
  },
1617
2370
  },
1618
2371
  })
1619
2372
  const record = await seedDepositAddress()
1620
- const response = await app.request(`/v1/funding/deposit-addresses/${record.id}/reconcile`, {
1621
- ...as(fundingWriter),
2373
+ const response = await app.request(`/v1/routes/deposit-addresses/${record.id}/reconcile`, {
2374
+ ...as(routesWriter),
1622
2375
  method: 'POST',
1623
2376
  })
1624
2377
 
@@ -1629,11 +2382,11 @@ describe('POST /funding/deposit-addresses/:id/reconcile', () => {
1629
2382
  })
1630
2383
  })
1631
2384
 
1632
- describe('GET /funding/deposits?depositAddress', () => {
2385
+ describe('GET /routes/deposits?depositAddress', () => {
1633
2386
  test('pages deposits newest-first under an owned address', async () => {
1634
2387
  const app = transfersApp()
1635
2388
  const address = await seedDepositAddress({
1636
- snapshot: TestFunding.depositAddressSnapshot({
2389
+ snapshot: TestRoutes.depositAddressSnapshot({
1637
2390
  address: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE',
1638
2391
  provider: { id: 'relay_list_deposit_address', name: 'Relay' },
1639
2392
  recipient: `0x${'41'.repeat(20)}`,
@@ -1647,8 +2400,8 @@ describe('GET /funding/deposits?depositAddress', () => {
1647
2400
  const sixth = await seedDeposit(address)
1648
2401
 
1649
2402
  const response = await app.request(
1650
- `/v1/funding/deposits?depositAddress=${address.address}&limit=5`,
1651
- as(fundingReader),
2403
+ `/v1/routes/deposits?depositAddress=${address.address}&limit=5`,
2404
+ as(routesReader),
1652
2405
  )
1653
2406
  expect(response.status).toBe(200)
1654
2407
  expect({
@@ -1660,7 +2413,7 @@ describe('GET /funding/deposits?depositAddress', () => {
1660
2413
  "etag": null,
1661
2414
  }
1662
2415
  `)
1663
- const body = await TestApp.json(response, Funding.schema.listFundingDeposits.Response)
2416
+ const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
1664
2417
  expect(body.data.map((deposit) => deposit.id)).toEqual([
1665
2418
  sixth.id,
1666
2419
  fifth.id,
@@ -1672,10 +2425,10 @@ describe('GET /funding/deposits?depositAddress', () => {
1672
2425
 
1673
2426
  const next = await TestApp.json(
1674
2427
  await app.request(
1675
- `/v1/funding/deposits?depositAddress=${address.address}&limit=5&cursor=${body.nextCursor}`,
1676
- as(fundingReader),
2428
+ `/v1/routes/deposits?depositAddress=${address.address}&limit=5&cursor=${body.nextCursor}`,
2429
+ as(routesReader),
1677
2430
  ),
1678
- Funding.schema.listFundingDeposits.Response,
2431
+ Routes.schema.listRoutesDeposits.Response,
1679
2432
  )
1680
2433
  expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
1681
2434
  expect(next.nextCursor).toBeNull()
@@ -1684,14 +2437,14 @@ describe('GET /funding/deposits?depositAddress', () => {
1684
2437
  test('returns a provider-observed deposit before source verification', async () => {
1685
2438
  const app = transfersApp()
1686
2439
  const address = await seedDepositAddress({
1687
- snapshot: TestFunding.depositAddressSnapshot({
2440
+ snapshot: TestRoutes.depositAddressSnapshot({
1688
2441
  address: 'TF17BgPaZYbz8oxbjhriubPDsA7ArKoLX3',
1689
2442
  provider: { id: 'relay_observed', name: 'Relay' },
1690
2443
  recipient: `0x${'31'.repeat(20)}`,
1691
2444
  }),
1692
2445
  })
1693
2446
  const sourceTransactionHash = `0x${'ab'.repeat(32)}`
1694
- await FundingDeposit.create(db, {
2447
+ await RoutesDeposit.create(db, {
1695
2448
  now: new Date('2026-01-04T00:00:00.000Z'),
1696
2449
  providerRequestId: 'relay-observed-request',
1697
2450
  snapshot: {
@@ -1709,11 +2462,11 @@ describe('GET /funding/deposits?depositAddress', () => {
1709
2462
  })
1710
2463
 
1711
2464
  const response = await app.request(
1712
- `/v1/funding/deposits?depositAddress=${address.address}`,
1713
- as(fundingReader),
2465
+ `/v1/routes/deposits?depositAddress=${address.address}`,
2466
+ as(routesReader),
1714
2467
  )
1715
2468
  expect(response.status).toBe(200)
1716
- const body = await TestApp.json(response, Funding.schema.listFundingDeposits.Response)
2469
+ const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
1717
2470
  expect(body).toMatchInlineSnapshot(
1718
2471
  {
1719
2472
  data: [
@@ -1786,8 +2539,8 @@ describe('GET /funding/deposits?depositAddress', () => {
1786
2539
  test('hides a foreign deposit address', async () => {
1787
2540
  const app = transfersApp()
1788
2541
  const address = await seedDepositAddress({
1789
- orgId: fundingForeign.orgId,
1790
- snapshot: TestFunding.depositAddressSnapshot({
2542
+ orgId: routesForeign.orgId,
2543
+ snapshot: TestRoutes.depositAddressSnapshot({
1791
2544
  address: 'TWd4WrZ9wn84f5x1hZhL4DHvk738ns5jwb',
1792
2545
  provider: { id: 'relay_foreign_deposit_address', name: 'Relay' },
1793
2546
  recipient: `0x${'42'.repeat(20)}`,
@@ -1795,50 +2548,50 @@ describe('GET /funding/deposits?depositAddress', () => {
1795
2548
  })
1796
2549
  await seedDeposit(address)
1797
2550
  const response = await app.request(
1798
- `/v1/funding/deposits?depositAddress=${address.address}`,
1799
- as(fundingReader),
2551
+ `/v1/routes/deposits?depositAddress=${address.address}`,
2552
+ as(routesReader),
1800
2553
  )
1801
2554
  expect(response.status).toBe(200)
1802
- expect(await TestApp.json(response, Funding.schema.listFundingDeposits.Response)).toEqual({
2555
+ expect(await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)).toEqual({
1803
2556
  data: [],
1804
2557
  nextCursor: null,
1805
2558
  })
1806
2559
  })
1807
2560
  })
1808
2561
 
1809
- describe('GET /funding/deposits', () => {
2562
+ describe('GET /routes/deposits', () => {
1810
2563
  test('pages organization deposits and narrows project-attributed keys', async () => {
1811
2564
  const app = transfersApp()
1812
- const firstAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
1813
- const secondAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
1814
- const thirdAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
2565
+ const firstAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
2566
+ const secondAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
2567
+ const thirdAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
1815
2568
  const projectAddress = await seedDepositAddress({
1816
- orgId: fundingDepositListReader.orgId,
1817
- projectId: fundingDepositListProjectReader.projectId,
2569
+ orgId: routesDepositListReader.orgId,
2570
+ projectId: routesDepositListProjectReader.projectId,
1818
2571
  })
1819
2572
  const siblingAddress = await seedDepositAddress({
1820
- orgId: fundingDepositListReader.orgId,
1821
- projectId: 'prj_funding_deposit_list_sibling',
2573
+ orgId: routesDepositListReader.orgId,
2574
+ projectId: 'prj_routes_deposit_list_sibling',
1822
2575
  })
1823
- const sixthAddress = await seedDepositAddress({ orgId: fundingDepositListReader.orgId })
2576
+ const sixthAddress = await seedDepositAddress({ orgId: routesDepositListReader.orgId })
1824
2577
  const first = await seedDeposit(firstAddress)
1825
2578
  const second = await seedDeposit(secondAddress)
1826
2579
  const third = await seedDeposit(thirdAddress)
1827
2580
  const project = await seedDeposit(projectAddress)
1828
2581
  const sibling = await seedDeposit(siblingAddress)
1829
2582
  const sixth = await seedDeposit(sixthAddress)
1830
- const foreignAddress = await seedDepositAddress({ orgId: fundingForeign.orgId })
2583
+ const foreignAddress = await seedDepositAddress({ orgId: routesForeign.orgId })
1831
2584
  await seedDeposit(foreignAddress)
1832
2585
  const sandboxAddress = await seedDepositAddress({
1833
2586
  environment: 'sandbox',
1834
- orgId: fundingDepositListReader.orgId,
2587
+ orgId: routesDepositListReader.orgId,
1835
2588
  })
1836
2589
  await seedDeposit(sandboxAddress)
1837
2590
 
1838
- const path = '/v1/funding/deposits'
1839
- const response = await app.request(`${path}?limit=5`, as(fundingDepositListReader))
2591
+ const path = '/v1/routes/deposits'
2592
+ const response = await app.request(`${path}?limit=5`, as(routesDepositListReader))
1840
2593
  expect(response.status).toBe(200)
1841
- const body = await TestApp.json(response, Funding.schema.listFundingDeposits.Response)
2594
+ const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
1842
2595
  expect(body.data.map((deposit) => deposit.id)).toEqual([
1843
2596
  sixth.id,
1844
2597
  sibling.id,
@@ -1849,47 +2602,47 @@ describe('GET /funding/deposits', () => {
1849
2602
  expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
1850
2603
 
1851
2604
  const next = await TestApp.json(
1852
- await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(fundingDepositListReader)),
1853
- Funding.schema.listFundingDeposits.Response,
2605
+ await app.request(`${path}?limit=5&cursor=${body.nextCursor}`, as(routesDepositListReader)),
2606
+ Routes.schema.listRoutesDeposits.Response,
1854
2607
  )
1855
2608
  expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
1856
2609
  expect(next.nextCursor).toBeNull()
1857
2610
 
1858
2611
  const projectBody = await TestApp.json(
1859
- await app.request(path, as(fundingDepositListProjectReader)),
1860
- Funding.schema.listFundingDeposits.Response,
2612
+ await app.request(path, as(routesDepositListProjectReader)),
2613
+ Routes.schema.listRoutesDeposits.Response,
1861
2614
  )
1862
2615
  expect(projectBody.data.map((deposit) => deposit.id)).toEqual([project.id])
1863
2616
  })
1864
2617
  })
1865
2618
 
1866
- describe('GET /funding/deposits?recipient', () => {
1867
- test('requires funding:read and pages recipient deposits across addresses', async () => {
2619
+ describe('GET /routes/deposits?recipient', () => {
2620
+ test('requires routes:read and pages recipient deposits across addresses', async () => {
1868
2621
  const app = transfersApp()
1869
2622
  const recipient = '0xABcdEFABcdEFabcdEfAbCdefabcdeFABcDEFabCD'
1870
- const path = `/v1/funding/deposits?recipient=${recipient.toLowerCase()}`
2623
+ const path = `/v1/routes/deposits?recipient=${recipient.toLowerCase()}`
1871
2624
  expect((await app.request(path)).status).toBe(401)
1872
2625
  expect((await app.request(path, as(TestApp.key))).status).toBe(403)
1873
2626
  expect(
1874
- (await app.request('/v1/funding/deposits?depositAddress=', as(fundingReader))).status,
2627
+ (await app.request('/v1/routes/deposits?depositAddress=', as(routesReader))).status,
1875
2628
  ).toBe(400)
1876
2629
  expect(
1877
2630
  (
1878
2631
  await app.request(
1879
2632
  `${path}&depositAddress=TJRabPrwbZy45sbavfcjinPJC18kjpRTv8`,
1880
- as(fundingReader),
2633
+ as(routesReader),
1881
2634
  )
1882
2635
  ).status,
1883
2636
  ).toBe(200)
1884
2637
 
1885
2638
  const firstAddress = await seedDepositAddress({
1886
- snapshot: TestFunding.depositAddressSnapshot({
2639
+ snapshot: TestRoutes.depositAddressSnapshot({
1887
2640
  provider: { id: 'relay_account_first', name: 'Relay' },
1888
2641
  recipient,
1889
2642
  }),
1890
2643
  })
1891
2644
  const secondAddress = await seedDepositAddress({
1892
- snapshot: TestFunding.depositAddressSnapshot({
2645
+ snapshot: TestRoutes.depositAddressSnapshot({
1893
2646
  provider: { id: 'relay_account_second', name: 'Relay' },
1894
2647
  recipient,
1895
2648
  subsidize: true,
@@ -1904,15 +2657,15 @@ describe('GET /funding/deposits?recipient', () => {
1904
2657
  const unrelatedAddress = await seedDepositAddress()
1905
2658
  await seedDeposit(unrelatedAddress)
1906
2659
  const foreignAddress = await seedDepositAddress({
1907
- orgId: fundingForeign.orgId,
1908
- snapshot: TestFunding.depositAddressSnapshot({
2660
+ orgId: routesForeign.orgId,
2661
+ snapshot: TestRoutes.depositAddressSnapshot({
1909
2662
  provider: { id: 'relay_account_foreign', name: 'Relay' },
1910
2663
  recipient,
1911
2664
  }),
1912
2665
  })
1913
2666
  await seedDeposit(foreignAddress)
1914
2667
 
1915
- const response = await app.request(`${path}&limit=5`, as(fundingReader))
2668
+ const response = await app.request(`${path}&limit=5`, as(routesReader))
1916
2669
  expect(response.status).toBe(200)
1917
2670
  expect({
1918
2671
  cacheControl: response.headers.get('cache-control'),
@@ -1925,7 +2678,7 @@ describe('GET /funding/deposits?recipient', () => {
1925
2678
  "vary": "Accept-Encoding, Authorization, Tempo-API-Key",
1926
2679
  }
1927
2680
  `)
1928
- const body = await TestApp.json(response, Funding.schema.listFundingDeposits.Response)
2681
+ const body = await TestApp.json(response, Routes.schema.listRoutesDeposits.Response)
1929
2682
  expect(body.data.map((deposit) => deposit.id)).toEqual([
1930
2683
  sixth.id,
1931
2684
  fifth.id,
@@ -1936,8 +2689,8 @@ describe('GET /funding/deposits?recipient', () => {
1936
2689
  expect(body.nextCursor).toBe(Cursor.encode([second.createdAt, second.id]))
1937
2690
 
1938
2691
  const next = await TestApp.json(
1939
- await app.request(`${path}&limit=5&cursor=${body.nextCursor}`, as(fundingReader)),
1940
- Funding.schema.listFundingDeposits.Response,
2692
+ await app.request(`${path}&limit=5&cursor=${body.nextCursor}`, as(routesReader)),
2693
+ Routes.schema.listRoutesDeposits.Response,
1941
2694
  )
1942
2695
  expect(next.data.map((deposit) => deposit.id)).toEqual([first.id])
1943
2696
  expect(next.nextCursor).toBeNull()
@@ -1947,15 +2700,15 @@ describe('GET /funding/deposits?recipient', () => {
1947
2700
  const app = transfersApp()
1948
2701
  const recipient = `0x${'ab'.repeat(20)}`
1949
2702
  const projectAddress = await seedDepositAddress({
1950
- projectId: fundingProjectReader.projectId,
1951
- snapshot: TestFunding.depositAddressSnapshot({
2703
+ projectId: routesProjectReader.projectId,
2704
+ snapshot: TestRoutes.depositAddressSnapshot({
1952
2705
  provider: { id: 'relay_account_project', name: 'Relay' },
1953
2706
  recipient,
1954
2707
  }),
1955
2708
  })
1956
2709
  const siblingAddress = await seedDepositAddress({
1957
- projectId: 'prj_funding_other',
1958
- snapshot: TestFunding.depositAddressSnapshot({
2710
+ projectId: 'prj_routes_other',
2711
+ snapshot: TestRoutes.depositAddressSnapshot({
1959
2712
  provider: { id: 'relay_account_sibling', name: 'Relay' },
1960
2713
  recipient,
1961
2714
  }),
@@ -1964,27 +2717,27 @@ describe('GET /funding/deposits?recipient', () => {
1964
2717
  await seedDeposit(siblingAddress)
1965
2718
 
1966
2719
  const body = await TestApp.json(
1967
- await app.request(`/v1/funding/deposits?recipient=${recipient}`, as(fundingProjectReader)),
1968
- Funding.schema.listFundingDeposits.Response,
2720
+ await app.request(`/v1/routes/deposits?recipient=${recipient}`, as(routesProjectReader)),
2721
+ Routes.schema.listRoutesDeposits.Response,
1969
2722
  )
1970
2723
  expect(body.data.map((deposit) => deposit.id)).toEqual([projectDeposit.id])
1971
2724
  })
1972
2725
  })
1973
2726
 
1974
- describe('GET /funding/deposits?filters', () => {
2727
+ describe('GET /routes/deposits?filters', () => {
1975
2728
  test('AND-combines canonical aliases and includes the matching count', async () => {
1976
2729
  const app = transfersApp()
1977
- const snapshot = TestFunding.depositAddressSnapshot({
2730
+ const snapshot = TestRoutes.depositAddressSnapshot({
1978
2731
  address: 'TQn9Y2khEsLJW1ChVWFMSMeRDow5KcbLSE',
1979
2732
  })
1980
2733
  const address = await seedDepositAddress({
1981
- orgId: fundingDepositFilterReader.orgId,
2734
+ orgId: routesDepositFilterReader.orgId,
1982
2735
  snapshot,
1983
2736
  })
1984
2737
  const deposit = await seedDeposit(address)
1985
2738
  const unrelatedAddress = await seedDepositAddress({
1986
- orgId: fundingDepositFilterReader.orgId,
1987
- snapshot: TestFunding.depositAddressSnapshot({
2739
+ orgId: routesDepositFilterReader.orgId,
2740
+ snapshot: TestRoutes.depositAddressSnapshot({
1988
2741
  provider: { id: 'relay_unrelated', name: 'Relay' },
1989
2742
  recipient: `0x${'22'.repeat(20)}`,
1990
2743
  }),
@@ -2002,21 +2755,21 @@ describe('GET /funding/deposits?filters', () => {
2002
2755
  })
2003
2756
 
2004
2757
  const body = await TestApp.json(
2005
- await app.request(`/v1/funding/deposits?${query}`, as(fundingDepositFilterReader)),
2006
- Funding.schema.listFundingDeposits.Response,
2758
+ await app.request(`/v1/routes/deposits?${query}`, as(routesDepositFilterReader)),
2759
+ Routes.schema.listRoutesDeposits.Response,
2007
2760
  )
2008
2761
  expect(body).toEqual({
2009
- data: [FundingDeposit.toPublic(deposit)],
2762
+ data: [RoutesDeposit.toPublic(deposit)],
2010
2763
  meta: { totalCount: 1, totalCountCapped: false },
2011
2764
  nextCursor: null,
2012
2765
  })
2013
2766
 
2014
2767
  const empty = await TestApp.json(
2015
2768
  await app.request(
2016
- '/v1/funding/deposits?sourceToken=unknown&include=totalCount',
2017
- as(fundingDepositFilterReader),
2769
+ '/v1/routes/deposits?sourceToken=unknown&include=totalCount',
2770
+ as(routesDepositFilterReader),
2018
2771
  ),
2019
- Funding.schema.listFundingDeposits.Response,
2772
+ Routes.schema.listRoutesDeposits.Response,
2020
2773
  )
2021
2774
  expect(empty).toEqual({
2022
2775
  data: [],
@@ -2026,7 +2779,7 @@ describe('GET /funding/deposits?filters', () => {
2026
2779
  })
2027
2780
  })
2028
2781
 
2029
- describe('GET /funding/deposits/:id', () => {
2782
+ describe('GET /routes/deposits/:id', () => {
2030
2783
  test('returns the owned deposit without private reconciliation state', async () => {
2031
2784
  const app = transfersApp()
2032
2785
  const address = await seedDepositAddress()
@@ -2034,11 +2787,11 @@ describe('GET /funding/deposits/:id', () => {
2034
2787
  providerRequestIds: ['relay-private'],
2035
2788
  providerState: { request: 'private' },
2036
2789
  })
2037
- const response = await app.request(`/v1/funding/deposits/${record.id}`, as(fundingReader))
2790
+ const response = await app.request(`/v1/routes/deposits/${record.id}`, as(routesReader))
2038
2791
  expect(response.status).toBe(200)
2039
2792
  expect(response.headers.get('cache-control')).toBe(Cache.policies.state)
2040
- const body = await TestApp.json(response, Funding.schema.getFundingDeposit.Response)
2041
- expect(body).toEqual(FundingDeposit.toPublic(record))
2793
+ const body = await TestApp.json(response, Routes.schema.getRoutesDeposit.Response)
2794
+ expect(body).toEqual(RoutesDeposit.toPublic(record))
2042
2795
  expect(body).not.toHaveProperty('providerRequestIds')
2043
2796
  expect(body).not.toHaveProperty('providerState')
2044
2797
  })
@@ -2047,14 +2800,14 @@ describe('GET /funding/deposits/:id', () => {
2047
2800
  const app = transfersApp()
2048
2801
  const address = await seedDepositAddress()
2049
2802
  const record = await seedDeposit(address)
2050
- expect(
2051
- (await app.request(`/v1/funding/deposits/${record.id}`, as(fundingForeign))).status,
2052
- ).toBe(404)
2803
+ expect((await app.request(`/v1/routes/deposits/${record.id}`, as(routesForeign))).status).toBe(
2804
+ 404,
2805
+ )
2053
2806
  expect(
2054
2807
  (
2055
2808
  await app.request(
2056
- '/v1/funding/deposits/fdp_000000000000000_000000000000000000000000',
2057
- as(fundingReader),
2809
+ '/v1/routes/deposits/rdp_000000000000000_000000000000000000000000',
2810
+ as(routesReader),
2058
2811
  )
2059
2812
  ).status,
2060
2813
  ).toBe(404)
@@ -2073,7 +2826,7 @@ const depositAddressBody = {
2073
2826
  let depositAddressIdempotencySequence = 0
2074
2827
 
2075
2828
  function nextDepositAddressKey() {
2076
- return `funding_deposit_address_${depositAddressIdempotencySequence++}`
2829
+ return `routes_deposit_address_${depositAddressIdempotencySequence++}`
2077
2830
  }
2078
2831
 
2079
2832
  function postDepositAddress(
@@ -2085,10 +2838,10 @@ function postDepositAddress(
2085
2838
  key?: { token: string } | undefined
2086
2839
  } = {},
2087
2840
  ) {
2088
- return app.request('/v1/funding/deposit-addresses', {
2841
+ return app.request('/v1/routes/deposit-addresses', {
2089
2842
  body: JSON.stringify(options.body ?? depositAddressBody),
2090
2843
  headers: options.headers ?? {
2091
- authorization: `Bearer ${(options.key ?? fundingWriter).token}`,
2844
+ authorization: `Bearer ${(options.key ?? routesWriter).token}`,
2092
2845
  'content-type': 'application/json',
2093
2846
  'idempotency-key': options.idempotencyKey ?? nextDepositAddressKey(),
2094
2847
  },
@@ -2097,20 +2850,22 @@ function postDepositAddress(
2097
2850
  }
2098
2851
 
2099
2852
  function withCreateDepositAddress(
2100
- id: FundingProvider.ProviderId,
2101
- createDepositAddress: NonNullable<FundingProvider.Provider['createDepositAddress']>,
2853
+ id: RoutesProvider.ProviderId,
2854
+ createDepositAddress: NonNullable<RoutesProvider.Provider['createDepositAddress']>,
2102
2855
  ) {
2103
2856
  const provider = providers.find((entry) => entry.id === id)
2104
2857
  if (!provider) throw new Error(`Missing ${id} provider`)
2105
- return FundingProvider.from({ ...provider, createDepositAddress })
2858
+ return RoutesProvider.from({ ...provider, createDepositAddress })
2106
2859
  }
2107
2860
 
2108
2861
  function depositAddressProvider(
2109
2862
  address = 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8',
2110
- onCreate: (input: FundingProvider.createDepositAddress.Parameters) => void = () => {},
2863
+ onCreate: (
2864
+ input: RoutesProvider.createDepositAddress.Parameters,
2865
+ ) => void | Promise<void> = () => {},
2111
2866
  ) {
2112
2867
  return withCreateDepositAddress('relay', async (input) => {
2113
- onCreate(input)
2868
+ await onCreate(input)
2114
2869
  return {
2115
2870
  address,
2116
2871
  correlation: {
@@ -2125,87 +2880,199 @@ function depositAddressProvider(
2125
2880
  })
2126
2881
  }
2127
2882
 
2128
- const fundingReader = {
2129
- id: 'key_funding',
2130
- orgId: 'org_funding',
2131
- scopes: ['funding:read'],
2132
- token: 'secret_funding_reader',
2883
+ const routesReader = {
2884
+ id: 'key_routes',
2885
+ orgId: 'org_routes',
2886
+ scopes: ['routes:read'],
2887
+ token: 'secret_routes_reader',
2888
+ } satisfies TestApp.kvStore.Key
2889
+
2890
+ const routesAddressListReader = {
2891
+ id: 'key_routes_address_list',
2892
+ orgId: 'org_routes_address_list',
2893
+ scopes: ['routes:read'],
2894
+ token: 'secret_routes_address_list',
2133
2895
  } satisfies TestApp.kvStore.Key
2134
2896
 
2135
- const fundingAddressListReader = {
2136
- id: 'key_funding_address_list',
2137
- orgId: 'org_funding_address_list',
2138
- scopes: ['funding:read'],
2139
- token: 'secret_funding_address_list',
2897
+ const routesAddressListProjectReader = {
2898
+ id: 'key_routes_address_list_project',
2899
+ orgId: routesAddressListReader.orgId,
2900
+ projectId: 'prj_routes_address_list',
2901
+ scopes: ['routes:read'],
2902
+ token: 'secret_routes_address_list_project',
2140
2903
  } satisfies TestApp.kvStore.Key
2141
2904
 
2142
- const fundingAddressListProjectReader = {
2143
- id: 'key_funding_address_list_project',
2144
- orgId: fundingAddressListReader.orgId,
2145
- projectId: 'prj_funding_address_list',
2146
- scopes: ['funding:read'],
2147
- token: 'secret_funding_address_list_project',
2905
+ const routesDepositListReader = {
2906
+ id: 'key_routes_deposit_list',
2907
+ orgId: 'org_routes_deposit_list',
2908
+ scopes: ['routes:read'],
2909
+ token: 'secret_routes_deposit_list',
2148
2910
  } satisfies TestApp.kvStore.Key
2149
2911
 
2150
- const fundingDepositListReader = {
2151
- id: 'key_funding_deposit_list',
2152
- orgId: 'org_funding_deposit_list',
2153
- scopes: ['funding:read'],
2154
- token: 'secret_funding_deposit_list',
2912
+ const routesDepositFilterReader = {
2913
+ id: 'key_routes_deposit_filter',
2914
+ orgId: 'org_routes_deposit_filter',
2915
+ scopes: ['routes:read'],
2916
+ token: 'secret_routes_deposit_filter',
2155
2917
  } satisfies TestApp.kvStore.Key
2156
2918
 
2157
- const fundingDepositFilterReader = {
2158
- id: 'key_funding_deposit_filter',
2159
- orgId: 'org_funding_deposit_filter',
2160
- scopes: ['funding:read'],
2161
- token: 'secret_funding_deposit_filter',
2919
+ const routesDepositListProjectReader = {
2920
+ id: 'key_routes_deposit_list_project',
2921
+ orgId: routesDepositListReader.orgId,
2922
+ projectId: 'prj_routes_deposit_list',
2923
+ scopes: ['routes:read'],
2924
+ token: 'secret_routes_deposit_list_project',
2162
2925
  } satisfies TestApp.kvStore.Key
2163
2926
 
2164
- const fundingDepositListProjectReader = {
2165
- id: 'key_funding_deposit_list_project',
2166
- orgId: fundingDepositListReader.orgId,
2167
- projectId: 'prj_funding_deposit_list',
2168
- scopes: ['funding:read'],
2169
- token: 'secret_funding_deposit_list_project',
2927
+ const routesProjectReader = {
2928
+ id: 'key_routes_project',
2929
+ orgId: 'org_routes',
2930
+ projectId: 'prj_routes',
2931
+ scopes: ['routes:read'],
2932
+ token: 'secret_routes_project',
2170
2933
  } satisfies TestApp.kvStore.Key
2171
2934
 
2172
- const fundingProjectReader = {
2173
- id: 'key_funding_project',
2174
- orgId: 'org_funding',
2175
- projectId: 'prj_funding',
2176
- scopes: ['funding:read'],
2177
- token: 'secret_funding_project',
2935
+ const routesForeign = {
2936
+ id: 'key_routes_other',
2937
+ orgId: 'org_routes_other',
2938
+ scopes: ['routes:read'],
2939
+ token: 'secret_routes_other',
2178
2940
  } satisfies TestApp.kvStore.Key
2179
2941
 
2180
- const fundingForeign = {
2181
- id: 'key_funding_other',
2182
- orgId: 'org_funding_other',
2183
- scopes: ['funding:read'],
2184
- token: 'secret_funding_other',
2942
+ /** Key with routes write access in a different organization. */
2943
+ const routesForeignWriter = {
2944
+ id: 'key_routes_other_writer',
2945
+ orgId: routesForeign.orgId,
2946
+ scopes: ['routes:write'],
2947
+ token: 'secret_routes_other_writer',
2185
2948
  } satisfies TestApp.kvStore.Key
2186
2949
 
2187
- /** Key with funding write access in a different organization. */
2188
- const fundingForeignWriter = {
2189
- id: 'key_funding_other_writer',
2190
- orgId: fundingForeign.orgId,
2191
- scopes: ['funding:write'],
2192
- token: 'secret_funding_other_writer',
2950
+ /** Project-attributed routes writer in the owning organization. */
2951
+ const routesProjectWriter = {
2952
+ id: 'key_routes_project_writer',
2953
+ orgId: routesReader.orgId,
2954
+ projectId: routesProjectReader.projectId,
2955
+ scopes: ['routes:write'],
2956
+ token: 'secret_routes_project_writer',
2193
2957
  } satisfies TestApp.kvStore.Key
2194
2958
 
2195
- /** Project-attributed funding writer in the owning organization. */
2196
- const fundingProjectWriter = {
2197
- id: 'key_funding_project_writer',
2198
- orgId: fundingReader.orgId,
2199
- projectId: fundingProjectReader.projectId,
2200
- scopes: ['funding:write'],
2201
- token: 'secret_funding_project_writer',
2959
+ const routesSubsidyBillingWriter = {
2960
+ id: 'key_routes_subsidy_billing',
2961
+ orgId: 'org_routes_subsidy_billing',
2962
+ scopes: ['routes:write'],
2963
+ token: 'secret_routes_subsidy_billing',
2202
2964
  } satisfies TestApp.kvStore.Key
2203
2965
 
2204
- const fundingWriter = {
2205
- id: 'key_funding_writer',
2206
- orgId: 'org_funding',
2207
- scopes: ['funding:read', 'funding:write'],
2208
- token: 'secret_funding_writer',
2966
+ const routesSubsidyDisabledWriter = {
2967
+ id: 'key_routes_subsidy_disabled',
2968
+ orgId: 'org_routes_subsidy_disabled',
2969
+ scopes: ['routes:write'],
2970
+ token: 'secret_routes_subsidy_disabled',
2971
+ } satisfies TestApp.kvStore.Key
2972
+
2973
+ const routesSubsidyPastDueWriter = {
2974
+ id: 'key_routes_subsidy_past_due',
2975
+ orgId: 'org_routes_subsidy_past_due',
2976
+ scopes: ['routes:write'],
2977
+ token: 'secret_routes_subsidy_past_due',
2978
+ } satisfies TestApp.kvStore.Key
2979
+
2980
+ const routesSubsidyReplayWriter = {
2981
+ id: 'key_routes_subsidy_replay',
2982
+ orgId: 'org_routes_subsidy_replay',
2983
+ scopes: ['routes:write'],
2984
+ token: 'secret_routes_subsidy_replay',
2985
+ } satisfies TestApp.kvStore.Key
2986
+
2987
+ const routesSubsidyResumeWriter = {
2988
+ id: 'key_routes_subsidy_resume',
2989
+ orgId: 'org_routes_subsidy_resume',
2990
+ scopes: ['routes:write'],
2991
+ token: 'secret_routes_subsidy_resume',
2992
+ } satisfies TestApp.kvStore.Key
2993
+
2994
+ const routesSubsidyWriter = {
2995
+ id: 'key_routes_subsidy',
2996
+ orgId: 'org_routes_subsidy',
2997
+ scopes: ['routes:write'],
2998
+ token: 'secret_routes_subsidy',
2999
+ } satisfies TestApp.kvStore.Key
3000
+
3001
+ const routesSubsidyWriterSecond = {
3002
+ id: 'key_routes_subsidy_second',
3003
+ orgId: routesSubsidyWriter.orgId,
3004
+ scopes: ['routes:write'],
3005
+ token: 'secret_routes_subsidy_second',
3006
+ } satisfies TestApp.kvStore.Key
3007
+
3008
+ const routesWriter = {
3009
+ id: 'key_routes_writer',
3010
+ orgId: 'org_routes',
3011
+ scopes: ['routes:read', 'routes:write'],
3012
+ token: 'secret_routes_writer',
3013
+ } satisfies TestApp.kvStore.Key
3014
+
3015
+ const routesWriterSecond = {
3016
+ id: 'key_routes_writer_second',
3017
+ orgId: routesWriter.orgId,
3018
+ scopes: ['routes:read', 'routes:write'],
3019
+ token: 'secret_routes_writer_second',
3020
+ } satisfies TestApp.kvStore.Key
3021
+
3022
+ const routesLimitWriter = {
3023
+ id: 'key_routes_limit_writer',
3024
+ orgId: 'org_routes_limit',
3025
+ scopes: ['routes:write'],
3026
+ token: 'secret_routes_limit_writer',
3027
+ } satisfies TestApp.kvStore.Key
3028
+
3029
+ const routesLimitWriterSecond = {
3030
+ id: 'key_routes_limit_writer_second',
3031
+ orgId: routesLimitWriter.orgId,
3032
+ scopes: ['routes:write'],
3033
+ token: 'secret_routes_limit_writer_second',
3034
+ } satisfies TestApp.kvStore.Key
3035
+
3036
+ const routesLegacyWriter = {
3037
+ id: 'key_routes_legacy_writer',
3038
+ orgId: 'key_routes_legacy_writer',
3039
+ scopes: ['routes:write'],
3040
+ token: 'secret_routes_legacy_writer',
3041
+ } satisfies TestApp.kvStore.Key
3042
+
3043
+ const routesRaceWriter = {
3044
+ id: 'key_routes_race_writer',
3045
+ orgId: 'org_routes_race',
3046
+ scopes: ['routes:write'],
3047
+ token: 'secret_routes_race_writer',
3048
+ } satisfies TestApp.kvStore.Key
3049
+
3050
+ const routesOwnerRaceWriter = {
3051
+ id: 'key_routes_owner_race_writer',
3052
+ orgId: 'org_routes_owner_race',
3053
+ scopes: ['routes:write'],
3054
+ token: 'secret_routes_owner_race_writer',
3055
+ } satisfies TestApp.kvStore.Key
3056
+
3057
+ const routesOwnerRaceSiblingWriter = {
3058
+ id: 'key_routes_owner_race_sibling_writer',
3059
+ orgId: 'org_routes_owner_race_sibling',
3060
+ scopes: ['routes:write'],
3061
+ token: 'secret_routes_owner_race_sibling_writer',
3062
+ } satisfies TestApp.kvStore.Key
3063
+
3064
+ const routesOwnerRaceReplacementWriter = {
3065
+ id: 'key_routes_owner_race_replacement_writer',
3066
+ orgId: 'org_routes_owner_race_replacement',
3067
+ scopes: ['routes:write'],
3068
+ token: 'secret_routes_owner_race_replacement_writer',
3069
+ } satisfies TestApp.kvStore.Key
3070
+
3071
+ const routesSubsidyRaceWriter = {
3072
+ id: 'key_routes_subsidy_race_writer',
3073
+ orgId: 'org_routes_subsidy_race',
3074
+ scopes: ['routes:write'],
3075
+ token: 'secret_routes_subsidy_race_writer',
2209
3076
  } satisfies TestApp.kvStore.Key
2210
3077
 
2211
3078
  function transfersApp(options: TestApp.create.Options = {}) {
@@ -2214,41 +3081,74 @@ function transfersApp(options: TestApp.create.Options = {}) {
2214
3081
  auth: {
2215
3082
  keys: [
2216
3083
  TestApp.key,
2217
- fundingAddressListProjectReader,
2218
- fundingAddressListReader,
2219
- fundingDepositFilterReader,
2220
- fundingDepositListProjectReader,
2221
- fundingDepositListReader,
2222
- fundingForeign,
2223
- fundingForeignWriter,
2224
- fundingProjectReader,
2225
- fundingProjectWriter,
2226
- fundingReader,
2227
- fundingWriter,
3084
+ routesAddressListProjectReader,
3085
+ routesAddressListReader,
3086
+ routesDepositFilterReader,
3087
+ routesDepositListProjectReader,
3088
+ routesDepositListReader,
3089
+ routesForeign,
3090
+ routesForeignWriter,
3091
+ routesProjectReader,
3092
+ routesProjectWriter,
3093
+ routesReader,
3094
+ routesLegacyWriter,
3095
+ routesLimitWriter,
3096
+ routesLimitWriterSecond,
3097
+ routesOwnerRaceReplacementWriter,
3098
+ routesOwnerRaceSiblingWriter,
3099
+ routesOwnerRaceWriter,
3100
+ routesRaceWriter,
3101
+ routesSubsidyBillingWriter,
3102
+ routesSubsidyDisabledWriter,
3103
+ routesSubsidyPastDueWriter,
3104
+ routesSubsidyRaceWriter,
3105
+ routesSubsidyReplayWriter,
3106
+ routesSubsidyResumeWriter,
3107
+ routesSubsidyWriter,
3108
+ routesSubsidyWriterSecond,
3109
+ routesWriter,
3110
+ routesWriterSecond,
2228
3111
  ],
2229
3112
  },
2230
3113
  defaultChainId: options.defaultChainId ?? tempoMainnet.id,
2231
3114
  })
2232
3115
  }
2233
3116
 
3117
+ async function enableRoutesSubsidy(
3118
+ key: TestApp.kvStore.Key,
3119
+ billingStatus?: StripeCustomers.Status,
3120
+ ) {
3121
+ await Organizations.upsert(db, { id: key.orgId, name: key.orgId })
3122
+ await RoutesSubsidies.upsertOrganization(db, {
3123
+ frequency: 'tx',
3124
+ maxAmount: '5',
3125
+ orgId: key.orgId,
3126
+ })
3127
+ if (!billingStatus) return
3128
+ await StripeCustomers.create(db, {
3129
+ orgId: key.orgId,
3130
+ stripeCustomerId: `cus_${key.id}`,
3131
+ })
3132
+ await StripeCustomers.setStatus(db, key.orgId, billingStatus)
3133
+ }
3134
+
2234
3135
  function as(key: { token: string }) {
2235
3136
  return { headers: { authorization: `Bearer ${key.token}` } } as const
2236
3137
  }
2237
3138
 
2238
3139
  let seedDepositAddressSecond = 0
2239
3140
 
2240
- function seedDepositAddress(input: Partial<FundingDepositAddress.create.Input> = {}) {
3141
+ function seedDepositAddress(input: Partial<RoutesDepositAddress.create.Input> = {}) {
2241
3142
  const index = seedDepositAddressSecond++
2242
3143
  const now = new Date(Date.UTC(2026, 0, 3, 0, 0, index))
2243
- return FundingDepositAddress.create(db, {
2244
- apiKeyId: fundingReader.id,
3144
+ return RoutesDepositAddress.create(db, {
2245
3145
  deliveryStrategy: 'provider',
2246
3146
  environment: 'production',
2247
- id: FundingDepositAddress.generateId(now),
3147
+ id: RoutesDepositAddress.generateId(now),
2248
3148
  now,
2249
- orgId: fundingReader.orgId,
2250
- providerOutputToken: TestFunding.providerOutputToken(),
2251
- snapshot: TestFunding.depositAddressSnapshot({
3149
+ orgId: routesReader.orgId,
3150
+ providerOutputToken: TestRoutes.providerOutputToken(),
3151
+ snapshot: TestRoutes.depositAddressSnapshot({
2252
3152
  provider: { id: `relay_route_${index}`, name: 'Relay' },
2253
3153
  recipient: `0x${index.toString(16).padStart(40, '0')}`,
2254
3154
  }),
@@ -2260,15 +3160,15 @@ let seedDepositSecond = 0
2260
3160
 
2261
3161
  function seedDeposit(
2262
3162
  address: Awaited<ReturnType<typeof seedDepositAddress>>,
2263
- input: Partial<FundingDeposit.create.Input> = {},
3163
+ input: Partial<RoutesDeposit.create.Input> = {},
2264
3164
  ) {
2265
3165
  const index = seedDepositSecond++
2266
3166
  const now = new Date(Date.UTC(2026, 0, 4, 0, 0, index))
2267
3167
  const sourceTransactionHash = index.toString(16).padStart(64, '0')
2268
- return FundingDeposit.create(db, {
3168
+ return RoutesDeposit.create(db, {
2269
3169
  now,
2270
3170
  providerRequestId: `relay_request_${index}`,
2271
- snapshot: TestFunding.depositSnapshot(address.id, {
3171
+ snapshot: TestRoutes.depositSnapshot(address.id, {
2272
3172
  provider: address.snapshot.provider,
2273
3173
  sourceTransactionHashes: [sourceTransactionHash],
2274
3174
  }),