tapimo 0.7.1 → 0.7.2

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 (681) hide show
  1. package/dist/ApiKeys.d.ts +24 -7
  2. package/dist/ApiKeys.d.ts.map +1 -1
  3. package/dist/ApiKeys.js +17 -5
  4. package/dist/ApiKeys.js.map +1 -1
  5. package/dist/App.d.ts +12104 -7861
  6. package/dist/App.d.ts.map +1 -1
  7. package/dist/App.js +191 -128
  8. package/dist/App.js.map +1 -1
  9. package/dist/Assets.d.ts +10 -0
  10. package/dist/Assets.d.ts.map +1 -1
  11. package/dist/Assets.js +17 -4
  12. package/dist/Assets.js.map +1 -1
  13. package/dist/Scope.d.ts +19 -8
  14. package/dist/Scope.d.ts.map +1 -1
  15. package/dist/Scope.js +25 -9
  16. package/dist/Scope.js.map +1 -1
  17. package/dist/Webhooks.d.ts +1 -1
  18. package/dist/admin/App.d.ts +601 -20
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/App.js +12 -2
  21. package/dist/admin/App.js.map +1 -1
  22. package/dist/admin/apps/api-keys.d.ts +94 -11
  23. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  24. package/dist/admin/apps/api-keys.js +141 -32
  25. package/dist/admin/apps/api-keys.js.map +1 -1
  26. package/dist/admin/apps/earn-vaults.d.ts +1069 -0
  27. package/dist/admin/apps/earn-vaults.d.ts.map +1 -0
  28. package/dist/admin/apps/earn-vaults.js +409 -0
  29. package/dist/admin/apps/earn-vaults.js.map +1 -0
  30. package/dist/admin/apps/verified-tokens.d.ts +166 -166
  31. package/dist/admin/ui.generated.d.ts +1 -1
  32. package/dist/admin/ui.generated.d.ts.map +1 -1
  33. package/dist/admin/ui.generated.js +99 -43
  34. package/dist/admin/ui.generated.js.map +1 -1
  35. package/dist/analytics/Analytics.d.ts +2 -0
  36. package/dist/analytics/Analytics.d.ts.map +1 -1
  37. package/dist/analytics/Analytics.js +18 -2
  38. package/dist/analytics/Analytics.js.map +1 -1
  39. package/dist/analytics/tables/requestEvents.d.ts +22 -1
  40. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  41. package/dist/analytics/tables/requestEvents.js +59 -39
  42. package/dist/analytics/tables/requestEvents.js.map +1 -1
  43. package/dist/apps/Zones.d.ts +8335 -0
  44. package/dist/apps/Zones.d.ts.map +1 -0
  45. package/dist/apps/Zones.js +38 -0
  46. package/dist/apps/Zones.js.map +1 -0
  47. package/dist/apps/data/App.d.ts +12125 -7913
  48. package/dist/apps/data/App.d.ts.map +1 -1
  49. package/dist/apps/data/App.js +91 -19
  50. package/dist/apps/data/App.js.map +1 -1
  51. package/dist/apps/data/FxOracle.d.ts +1 -1
  52. package/dist/apps/data/FxOracle.d.ts.map +1 -1
  53. package/dist/apps/data/index.d.ts +0 -1
  54. package/dist/apps/data/index.d.ts.map +1 -1
  55. package/dist/apps/data/index.js +0 -1
  56. package/dist/apps/data/index.js.map +1 -1
  57. package/dist/apps/data/routes/activities.d.ts +32 -32
  58. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  59. package/dist/apps/data/routes/activities.js +130 -65
  60. package/dist/apps/data/routes/activities.js.map +1 -1
  61. package/dist/apps/data/routes/addresses.d.ts +312 -312
  62. package/dist/apps/data/routes/balances.d.ts +18 -18
  63. package/dist/apps/data/routes/balances.js +5 -5
  64. package/dist/apps/data/routes/balances.js.map +1 -1
  65. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  66. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  67. package/dist/apps/data/routes/coingecko.js +62 -35
  68. package/dist/apps/data/routes/coingecko.js.map +1 -1
  69. package/dist/apps/data/routes/earn.d.ts +2144 -0
  70. package/dist/apps/data/routes/earn.d.ts.map +1 -0
  71. package/dist/apps/data/routes/earn.js +947 -0
  72. package/dist/apps/data/routes/earn.js.map +1 -0
  73. package/dist/apps/data/routes/exchanges.d.ts +1625 -718
  74. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  75. package/dist/apps/data/routes/exchanges.js +656 -193
  76. package/dist/apps/data/routes/exchanges.js.map +1 -1
  77. package/dist/apps/data/routes/fee-amm.d.ts +108 -108
  78. package/dist/apps/data/routes/fee-amm.d.ts.map +1 -1
  79. package/dist/apps/data/routes/fee-amm.js +59 -8
  80. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  81. package/dist/apps/data/routes/funding.d.ts +4092 -387
  82. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  83. package/dist/apps/data/routes/funding.js +1403 -256
  84. package/dist/apps/data/routes/funding.js.map +1 -1
  85. package/dist/apps/data/routes/indexer.d.ts +30 -30
  86. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  87. package/dist/apps/data/routes/indexer.js +19 -2
  88. package/dist/apps/data/routes/indexer.js.map +1 -1
  89. package/dist/apps/data/routes/receipts.d.ts +263 -263
  90. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  91. package/dist/apps/data/routes/receipts.js +11 -11
  92. package/dist/apps/data/routes/receipts.js.map +1 -1
  93. package/dist/apps/data/routes/rpc.d.ts +5 -5
  94. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  95. package/dist/apps/data/routes/rpc.js +211 -22
  96. package/dist/apps/data/routes/rpc.js.map +1 -1
  97. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  98. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  99. package/dist/apps/data/routes/tokenlist.js +39 -8
  100. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  101. package/dist/apps/data/routes/tokens.d.ts +114 -86
  102. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  103. package/dist/apps/data/routes/tokens.js +194 -91
  104. package/dist/apps/data/routes/tokens.js.map +1 -1
  105. package/dist/apps/data/routes/transactions.d.ts +53 -53
  106. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  107. package/dist/apps/data/routes/transactions.js +78 -39
  108. package/dist/apps/data/routes/transactions.js.map +1 -1
  109. package/dist/apps/data/routes/transfers.d.ts +76 -27
  110. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  111. package/dist/apps/data/routes/transfers.js +165 -67
  112. package/dist/apps/data/routes/transfers.js.map +1 -1
  113. package/dist/apps/data/routes/valuation.d.ts +42 -42
  114. package/dist/apps/data/routes/valuation.js +2 -2
  115. package/dist/apps/data/routes/valuation.js.map +1 -1
  116. package/dist/apps/data/routes/webhooks.d.ts +369 -367
  117. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  118. package/dist/apps/data/routes/webhooks.js +161 -59
  119. package/dist/apps/data/routes/webhooks.js.map +1 -1
  120. package/dist/apps/data/routes/zones.d.ts +281 -0
  121. package/dist/apps/data/routes/zones.d.ts.map +1 -0
  122. package/dist/apps/data/routes/zones.js +252 -0
  123. package/dist/apps/data/routes/zones.js.map +1 -0
  124. package/dist/apps/docs/reference.js +6 -5
  125. package/dist/apps/docs/reference.js.map +1 -1
  126. package/dist/apps/index.d.ts +2 -1
  127. package/dist/apps/index.d.ts.map +1 -1
  128. package/dist/apps/index.js +2 -1
  129. package/dist/apps/index.js.map +1 -1
  130. package/dist/apps/management/App.d.ts +670 -670
  131. package/dist/apps/management/Billing.d.ts +8 -0
  132. package/dist/apps/management/Billing.d.ts.map +1 -1
  133. package/dist/apps/management/Billing.js +12 -0
  134. package/dist/apps/management/Billing.js.map +1 -1
  135. package/dist/apps/management/Error.d.ts +12 -0
  136. package/dist/apps/management/Error.d.ts.map +1 -0
  137. package/dist/apps/management/Error.js +10 -0
  138. package/dist/apps/management/Error.js.map +1 -0
  139. package/dist/apps/management/routes/api-keys.d.ts +5 -5
  140. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  141. package/dist/apps/management/routes/api-keys.js +2 -8
  142. package/dist/apps/management/routes/api-keys.js.map +1 -1
  143. package/dist/apps/management/routes/billing.d.ts +119 -119
  144. package/dist/apps/management/routes/faucet.d.ts +2 -2
  145. package/dist/apps/management/routes/invitations.d.ts +62 -62
  146. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  147. package/dist/apps/management/routes/invitations.js +4 -10
  148. package/dist/apps/management/routes/invitations.js.map +1 -1
  149. package/dist/apps/management/routes/invite-links.d.ts +30 -30
  150. package/dist/apps/management/routes/me.d.ts +6 -6
  151. package/dist/apps/management/routes/members.d.ts +2 -2
  152. package/dist/apps/management/routes/orgs.d.ts +48 -48
  153. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  154. package/dist/apps/management/routes/orgs.js +2 -8
  155. package/dist/apps/management/routes/orgs.js.map +1 -1
  156. package/dist/apps/management/routes/projects.d.ts +9 -9
  157. package/dist/apps/management/routes/scopes.js +2 -2
  158. package/dist/apps/management/routes/scopes.js.map +1 -1
  159. package/dist/apps/management/routes/verified-token-requests.d.ts +36 -36
  160. package/dist/apps/management/routes/webhooks.d.ts +50 -50
  161. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  162. package/dist/apps/management/routes/webhooks.js +15 -3
  163. package/dist/apps/management/routes/webhooks.js.map +1 -1
  164. package/dist/apps/mpp/App.d.ts +55 -56
  165. package/dist/apps/mpp/App.d.ts.map +1 -1
  166. package/dist/apps/mpp/App.js +192 -27
  167. package/dist/apps/mpp/App.js.map +1 -1
  168. package/dist/apps/mpp/Mpp.d.ts +0 -20
  169. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  170. package/dist/apps/mpp/Mpp.js +0 -24
  171. package/dist/apps/mpp/Mpp.js.map +1 -1
  172. package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
  173. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
  174. package/dist/apps/mpp/internal/Adapter.js +66 -0
  175. package/dist/apps/mpp/internal/Adapter.js.map +1 -0
  176. package/dist/apps/mpp/internal/Error.d.ts +4 -0
  177. package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
  178. package/dist/apps/mpp/internal/Error.js +41 -0
  179. package/dist/apps/mpp/internal/Error.js.map +1 -0
  180. package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
  181. package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
  182. package/dist/apps/mpp/internal/Idempotency.js +28 -0
  183. package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
  184. package/dist/apps/mpp/internal/Policy.d.ts +46 -0
  185. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
  186. package/dist/apps/mpp/internal/Policy.js +57 -0
  187. package/dist/apps/mpp/internal/Policy.js.map +1 -0
  188. package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
  189. package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
  190. package/dist/apps/mpp/internal/ScreenManager.js +18 -0
  191. package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
  192. package/dist/apps/mpp/internal/Screening.d.ts +35 -0
  193. package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
  194. package/dist/apps/mpp/internal/Screening.js +20 -0
  195. package/dist/apps/mpp/internal/Screening.js.map +1 -0
  196. package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
  197. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
  198. package/dist/apps/mpp/internal/Sponsorship.js +103 -0
  199. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
  200. package/dist/apps/mpp/internal/Utils.d.ts +7 -0
  201. package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
  202. package/dist/apps/mpp/internal/Utils.js +24 -0
  203. package/dist/apps/mpp/internal/Utils.js.map +1 -0
  204. package/dist/apps/relay/App.js +183 -23
  205. package/dist/apps/relay/App.js.map +1 -1
  206. package/dist/apps/relay/Sponsorships.d.ts +4 -0
  207. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  208. package/dist/apps/relay/Sponsorships.js +15 -6
  209. package/dist/apps/relay/Sponsorships.js.map +1 -1
  210. package/dist/db/Db.d.ts +20 -0
  211. package/dist/db/Db.d.ts.map +1 -1
  212. package/dist/db/Db.js +342 -0
  213. package/dist/db/Db.js.map +1 -1
  214. package/dist/db/Schema.d.ts +921 -1
  215. package/dist/db/Schema.d.ts.map +1 -1
  216. package/dist/db/Schema.js +269 -1
  217. package/dist/db/Schema.js.map +1 -1
  218. package/dist/db/tables/earnVaults.d.ts +68 -0
  219. package/dist/db/tables/earnVaults.d.ts.map +1 -0
  220. package/dist/db/tables/earnVaults.js +72 -0
  221. package/dist/db/tables/earnVaults.js.map +1 -0
  222. package/dist/db/tables/fundingCatalog.d.ts +56 -0
  223. package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
  224. package/dist/db/tables/fundingCatalog.js +85 -0
  225. package/dist/db/tables/fundingCatalog.js.map +1 -0
  226. package/dist/db/tables/fundingDepositAddresses.d.ts +159 -0
  227. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
  228. package/dist/db/tables/fundingDepositAddresses.js +206 -0
  229. package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
  230. package/dist/db/tables/fundingDeposits.d.ts +115 -0
  231. package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
  232. package/dist/db/tables/fundingDeposits.js +100 -0
  233. package/dist/db/tables/fundingDeposits.js.map +1 -0
  234. package/dist/db/tables/fundingIdempotency.d.ts +91 -0
  235. package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
  236. package/dist/db/tables/fundingIdempotency.js +103 -0
  237. package/dist/db/tables/fundingIdempotency.js.map +1 -0
  238. package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
  239. package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
  240. package/dist/db/tables/fundingTransferEvents.js +18 -0
  241. package/dist/db/tables/fundingTransferEvents.js.map +1 -0
  242. package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
  243. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
  244. package/dist/db/tables/fundingTransferTransactions.js +27 -0
  245. package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
  246. package/dist/db/tables/fundingTransfers.d.ts +82 -0
  247. package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
  248. package/dist/db/tables/fundingTransfers.js +89 -0
  249. package/dist/db/tables/fundingTransfers.js.map +1 -0
  250. package/dist/db/tables/organizations.d.ts +8 -0
  251. package/dist/db/tables/organizations.d.ts.map +1 -1
  252. package/dist/db/tables/organizations.js +16 -0
  253. package/dist/db/tables/organizations.js.map +1 -1
  254. package/dist/db/tables/projects.d.ts +8 -0
  255. package/dist/db/tables/projects.d.ts.map +1 -1
  256. package/dist/db/tables/projects.js +16 -0
  257. package/dist/db/tables/projects.js.map +1 -1
  258. package/dist/db/tables/requestUsage.d.ts +13 -0
  259. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  260. package/dist/db/tables/requestUsage.js +16 -0
  261. package/dist/db/tables/requestUsage.js.map +1 -1
  262. package/dist/db/tables/sponsoredTransactions.d.ts +2 -2
  263. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  264. package/dist/db/tables/sponsoredTransactions.js +1 -1
  265. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  266. package/dist/db/tables/users.d.ts +8 -0
  267. package/dist/db/tables/users.d.ts.map +1 -1
  268. package/dist/db/tables/users.js +16 -0
  269. package/dist/db/tables/users.js.map +1 -1
  270. package/dist/db/tables/verifiedTokens.d.ts +14 -7
  271. package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
  272. package/dist/db/tables/verifiedTokens.js +9 -7
  273. package/dist/db/tables/verifiedTokens.js.map +1 -1
  274. package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
  275. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  276. package/dist/db/tables/webhookSubscriptions.js +24 -3
  277. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  278. package/dist/handlers/relay.js +108 -108
  279. package/dist/handlers/relay.js.map +1 -1
  280. package/dist/internal/Auth.d.ts +26 -0
  281. package/dist/internal/Auth.d.ts.map +1 -1
  282. package/dist/internal/Auth.js +35 -2
  283. package/dist/internal/Auth.js.map +1 -1
  284. package/dist/internal/Cache.d.ts.map +1 -1
  285. package/dist/internal/Cache.js +16 -10
  286. package/dist/internal/Cache.js.map +1 -1
  287. package/dist/internal/Cursor.js +1 -1
  288. package/dist/internal/Cursor.js.map +1 -1
  289. package/dist/internal/EarnRates.d.ts +89 -0
  290. package/dist/internal/EarnRates.d.ts.map +1 -0
  291. package/dist/internal/EarnRates.js +266 -0
  292. package/dist/internal/EarnRates.js.map +1 -0
  293. package/dist/internal/EarnVaults.d.ts +171 -0
  294. package/dist/internal/EarnVaults.d.ts.map +1 -0
  295. package/dist/internal/EarnVaults.js +547 -0
  296. package/dist/internal/EarnVaults.js.map +1 -0
  297. package/dist/internal/EdgeCache.d.ts +8 -1
  298. package/dist/internal/EdgeCache.d.ts.map +1 -1
  299. package/dist/internal/EdgeCache.js +33 -7
  300. package/dist/internal/EdgeCache.js.map +1 -1
  301. package/dist/internal/Id.d.ts +11 -0
  302. package/dist/internal/Id.d.ts.map +1 -1
  303. package/dist/internal/Id.js +13 -0
  304. package/dist/internal/Id.js.map +1 -1
  305. package/dist/internal/Idempotency.d.ts +83 -0
  306. package/dist/internal/Idempotency.d.ts.map +1 -0
  307. package/dist/internal/Idempotency.js +113 -0
  308. package/dist/internal/Idempotency.js.map +1 -0
  309. package/dist/internal/Log.d.ts +64 -9
  310. package/dist/internal/Log.d.ts.map +1 -1
  311. package/dist/internal/Log.js +29 -7
  312. package/dist/internal/Log.js.map +1 -1
  313. package/dist/internal/MetricSink.d.ts.map +1 -1
  314. package/dist/internal/MetricSink.js +47 -1
  315. package/dist/internal/MetricSink.js.map +1 -1
  316. package/dist/internal/OpenApi.d.ts +1 -1
  317. package/dist/internal/OpenApi.d.ts.map +1 -1
  318. package/dist/internal/OpenApi.js +3 -0
  319. package/dist/internal/OpenApi.js.map +1 -1
  320. package/dist/internal/Provider.d.ts +14 -0
  321. package/dist/internal/Provider.d.ts.map +1 -0
  322. package/dist/internal/Provider.js +5 -0
  323. package/dist/internal/Provider.js.map +1 -0
  324. package/dist/internal/Schema.d.ts +6 -1
  325. package/dist/internal/Schema.d.ts.map +1 -1
  326. package/dist/internal/Schema.js +20 -11
  327. package/dist/internal/Schema.js.map +1 -1
  328. package/dist/internal/Store.d.ts +6 -0
  329. package/dist/internal/Store.d.ts.map +1 -1
  330. package/dist/internal/Store.js +35 -0
  331. package/dist/internal/Store.js.map +1 -1
  332. package/dist/internal/Tidx.d.ts +43 -24
  333. package/dist/internal/Tidx.d.ts.map +1 -1
  334. package/dist/internal/Tidx.js +79 -11
  335. package/dist/internal/Tidx.js.map +1 -1
  336. package/dist/internal/Viem.d.ts +82 -65
  337. package/dist/internal/Viem.d.ts.map +1 -1
  338. package/dist/internal/Viem.js +83 -12
  339. package/dist/internal/Viem.js.map +1 -1
  340. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  341. package/dist/internal/WebhookDestination.js +34 -28
  342. package/dist/internal/WebhookDestination.js.map +1 -1
  343. package/dist/internal/Webhooks.d.ts +9 -0
  344. package/dist/internal/Webhooks.d.ts.map +1 -1
  345. package/dist/internal/Webhooks.js +15 -10
  346. package/dist/internal/Webhooks.js.map +1 -1
  347. package/dist/internal/exchange/Provider.d.ts +219 -0
  348. package/dist/internal/exchange/Provider.d.ts.map +1 -0
  349. package/dist/internal/exchange/Provider.js +117 -0
  350. package/dist/internal/exchange/Provider.js.map +1 -0
  351. package/dist/internal/exchange/index.d.ts +2 -0
  352. package/dist/internal/exchange/index.d.ts.map +1 -0
  353. package/dist/internal/exchange/index.js +2 -0
  354. package/dist/internal/exchange/index.js.map +1 -0
  355. package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
  356. package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
  357. package/dist/internal/exchange/providers/uniswap.js +553 -0
  358. package/dist/internal/exchange/providers/uniswap.js.map +1 -0
  359. package/dist/internal/funding/Action.d.ts +55 -0
  360. package/dist/internal/funding/Action.d.ts.map +1 -0
  361. package/dist/internal/funding/Action.js +74 -0
  362. package/dist/internal/funding/Action.js.map +1 -0
  363. package/dist/internal/funding/Catalog.d.ts +107 -0
  364. package/dist/internal/funding/Catalog.d.ts.map +1 -0
  365. package/dist/internal/funding/Catalog.js +270 -0
  366. package/dist/internal/funding/Catalog.js.map +1 -0
  367. package/dist/internal/funding/Chain.d.ts +76 -0
  368. package/dist/internal/funding/Chain.d.ts.map +1 -0
  369. package/dist/internal/funding/Chain.js +38 -0
  370. package/dist/internal/funding/Chain.js.map +1 -0
  371. package/dist/internal/funding/Deposit.d.ts +366 -0
  372. package/dist/internal/funding/Deposit.d.ts.map +1 -0
  373. package/dist/internal/funding/Deposit.js +286 -0
  374. package/dist/internal/funding/Deposit.js.map +1 -0
  375. package/dist/internal/funding/DepositAddress.d.ts +345 -0
  376. package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
  377. package/dist/internal/funding/DepositAddress.js +189 -0
  378. package/dist/internal/funding/DepositAddress.js.map +1 -0
  379. package/dist/internal/funding/Evidence.d.ts +52 -0
  380. package/dist/internal/funding/Evidence.d.ts.map +1 -0
  381. package/dist/internal/funding/Evidence.js +314 -0
  382. package/dist/internal/funding/Evidence.js.map +1 -0
  383. package/dist/internal/funding/Provider.d.ts +1186 -0
  384. package/dist/internal/funding/Provider.d.ts.map +1 -0
  385. package/dist/internal/funding/Provider.js +1081 -0
  386. package/dist/internal/funding/Provider.js.map +1 -0
  387. package/dist/internal/funding/Reconciliation.d.ts +113 -0
  388. package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
  389. package/dist/internal/funding/Reconciliation.js +676 -0
  390. package/dist/internal/funding/Reconciliation.js.map +1 -0
  391. package/dist/internal/funding/Route.d.ts +21 -0
  392. package/dist/internal/funding/Route.d.ts.map +1 -0
  393. package/dist/internal/funding/Route.js +5 -0
  394. package/dist/internal/funding/Route.js.map +1 -0
  395. package/dist/internal/funding/Subsidy.d.ts +113 -0
  396. package/dist/internal/funding/Subsidy.d.ts.map +1 -0
  397. package/dist/internal/funding/Subsidy.js +138 -0
  398. package/dist/internal/funding/Subsidy.js.map +1 -0
  399. package/dist/internal/funding/Token.d.ts +41 -0
  400. package/dist/internal/funding/Token.d.ts.map +1 -0
  401. package/dist/internal/funding/Token.js +22 -0
  402. package/dist/internal/funding/Token.js.map +1 -0
  403. package/dist/internal/funding/Transfer.d.ts +643 -0
  404. package/dist/internal/funding/Transfer.d.ts.map +1 -0
  405. package/dist/internal/funding/Transfer.js +332 -0
  406. package/dist/internal/funding/Transfer.js.map +1 -0
  407. package/dist/internal/funding/index.d.ts +13 -0
  408. package/dist/internal/funding/index.d.ts.map +1 -0
  409. package/dist/internal/funding/index.js +13 -0
  410. package/dist/internal/funding/index.js.map +1 -0
  411. package/dist/internal/funding/providers/across.d.ts +21 -0
  412. package/dist/internal/funding/providers/across.d.ts.map +1 -0
  413. package/dist/internal/funding/providers/across.js +117 -0
  414. package/dist/internal/funding/providers/across.js.map +1 -0
  415. package/dist/internal/funding/providers/relay.d.ts +46 -0
  416. package/dist/internal/funding/providers/relay.d.ts.map +1 -0
  417. package/dist/internal/funding/providers/relay.js +464 -0
  418. package/dist/internal/funding/providers/relay.js.map +1 -0
  419. package/dist/internal/funding/providers/rhino.d.ts +15 -0
  420. package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
  421. package/dist/internal/funding/providers/rhino.js +116 -0
  422. package/dist/internal/funding/providers/rhino.js.map +1 -0
  423. package/dist/internal/funding/providers/squid.d.ts +19 -0
  424. package/dist/internal/funding/providers/squid.d.ts.map +1 -0
  425. package/dist/internal/funding/providers/squid.js +120 -0
  426. package/dist/internal/funding/providers/squid.js.map +1 -0
  427. package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
  428. package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
  429. package/dist/internal/funding/providers/symbiosis.js +176 -0
  430. package/dist/internal/funding/providers/symbiosis.js.map +1 -0
  431. package/dist/internal/index.d.ts +5 -1
  432. package/dist/internal/index.d.ts.map +1 -1
  433. package/dist/internal/index.js +5 -1
  434. package/dist/internal/index.js.map +1 -1
  435. package/dist/internal/webhookDestinations/url.js +61 -57
  436. package/dist/internal/webhookDestinations/url.js.map +1 -1
  437. package/dist/providers/index.d.ts +43 -0
  438. package/dist/providers/index.d.ts.map +1 -0
  439. package/dist/providers/index.js +19 -0
  440. package/dist/providers/index.js.map +1 -0
  441. package/package.json +9 -4
  442. package/src/ApiKeys.test.ts +11 -7
  443. package/src/ApiKeys.ts +37 -9
  444. package/src/App.test.ts +85 -10
  445. package/src/App.ts +224 -137
  446. package/src/Assets.ts +29 -4
  447. package/src/Client.test-d.ts +650 -30
  448. package/src/Scope.test.ts +19 -0
  449. package/src/Scope.ts +28 -11
  450. package/src/Webhooks.test.ts +25 -0
  451. package/src/Webhooks.ts +1 -1
  452. package/src/admin/App.test.ts +9 -2
  453. package/src/admin/App.ts +32 -9
  454. package/src/admin/apps/api-keys.test.ts +167 -23
  455. package/src/admin/apps/api-keys.ts +166 -28
  456. package/src/admin/apps/earn-vaults.test.ts +338 -0
  457. package/src/admin/apps/earn-vaults.ts +572 -0
  458. package/src/admin/apps/scopes.test.ts +16 -1
  459. package/src/admin/ui/plugin.ts +2 -2
  460. package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
  461. package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
  462. package/src/admin/ui/src/components/Page.tsx +1 -1
  463. package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
  464. package/src/admin/ui/src/lib/api-keys.ts +37 -7
  465. package/src/admin/ui/src/lib/client.ts +1 -1
  466. package/src/admin/ui/src/lib/config.ts +1 -1
  467. package/src/admin/ui/src/lib/early-access.ts +8 -9
  468. package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
  469. package/src/admin/ui/src/lib/format.ts +13 -0
  470. package/src/admin/ui/src/lib/organizations.test.ts +14 -4
  471. package/src/admin/ui/src/lib/organizations.ts +7 -1
  472. package/src/admin/ui/src/lib/response.ts +22 -0
  473. package/src/admin/ui/src/lib/scopes.test.ts +19 -11
  474. package/src/admin/ui/src/lib/scopes.ts +28 -7
  475. package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
  476. package/src/admin/ui/src/routeTree.gen.ts +70 -7
  477. package/src/admin/ui/src/router.tsx +2 -2
  478. package/src/admin/ui/src/routes/__root.tsx +9 -8
  479. package/src/admin/ui/src/routes/api-keys.tsx +475 -64
  480. package/src/admin/ui/src/routes/early-access.tsx +5 -12
  481. package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
  482. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
  483. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
  484. package/src/admin/ui/src/routes/organizations.tsx +4 -7
  485. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
  486. package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
  487. package/src/admin/ui/vite.config.ts +4 -1
  488. package/src/admin/ui.generated.ts +113 -43
  489. package/src/analytics/Analytics.test.ts +69 -10
  490. package/src/analytics/Analytics.ts +20 -1
  491. package/src/analytics/tables/requestEvents.ts +79 -37
  492. package/src/apps/Zones.test.ts +33 -0
  493. package/src/apps/Zones.ts +40 -0
  494. package/src/apps/composition.test.ts +84 -1
  495. package/src/apps/data/App.test.ts +28 -11
  496. package/src/apps/data/App.ts +96 -33
  497. package/src/apps/data/FxOracle.ts +1 -1
  498. package/src/apps/data/index.ts +0 -1
  499. package/src/apps/data/routes/activities.test.ts +82 -6
  500. package/src/apps/data/routes/activities.ts +131 -71
  501. package/src/apps/data/routes/balances.test.ts +50 -37
  502. package/src/apps/data/routes/balances.ts +5 -5
  503. package/src/apps/data/routes/blocks.test.ts +2 -0
  504. package/src/apps/data/routes/coingecko.test.ts +22 -0
  505. package/src/apps/data/routes/coingecko.ts +84 -48
  506. package/src/apps/data/routes/earn.test.ts +1108 -0
  507. package/src/apps/data/routes/earn.ts +1391 -0
  508. package/src/apps/data/routes/exchanges.test.ts +82 -33
  509. package/src/apps/data/routes/exchanges.ts +842 -227
  510. package/src/apps/data/routes/fee-amm.test.ts +4 -6
  511. package/src/apps/data/routes/fee-amm.ts +69 -12
  512. package/src/apps/data/routes/funding.test.ts +2712 -221
  513. package/src/apps/data/routes/funding.ts +1604 -387
  514. package/src/apps/data/routes/indexer.test.ts +43 -34
  515. package/src/apps/data/routes/indexer.ts +19 -2
  516. package/src/apps/data/routes/receipts.test.ts +5 -3
  517. package/src/apps/data/routes/receipts.ts +13 -11
  518. package/src/apps/data/routes/rpc.test.ts +446 -28
  519. package/src/apps/data/routes/rpc.ts +243 -25
  520. package/src/apps/data/routes/tokenlist.ts +72 -19
  521. package/src/apps/data/routes/tokens.ts +258 -86
  522. package/src/apps/data/routes/transactions.test.ts +2 -0
  523. package/src/apps/data/routes/transactions.ts +77 -42
  524. package/src/apps/data/routes/transfers.test.ts +166 -4
  525. package/src/apps/data/routes/transfers.ts +216 -78
  526. package/src/apps/data/routes/valuation.test.ts +62 -9
  527. package/src/apps/data/routes/valuation.ts +2 -2
  528. package/src/apps/data/routes/webhooks.test.ts +386 -43
  529. package/src/apps/data/routes/webhooks.ts +172 -71
  530. package/src/apps/data/routes/zones.test.ts +473 -0
  531. package/src/apps/data/routes/zones.ts +338 -0
  532. package/src/apps/docs/reference.ts +8 -6
  533. package/src/apps/index.ts +2 -1
  534. package/src/apps/management/Billing.test.ts +29 -0
  535. package/src/apps/management/Billing.ts +23 -0
  536. package/src/apps/management/Error.ts +12 -0
  537. package/src/apps/management/routes/api-keys.test.ts +5 -3
  538. package/src/apps/management/routes/api-keys.ts +2 -9
  539. package/src/apps/management/routes/invitations.ts +4 -11
  540. package/src/apps/management/routes/orgs.ts +2 -9
  541. package/src/apps/management/routes/scopes.test.ts +7 -2
  542. package/src/apps/management/routes/scopes.ts +2 -2
  543. package/src/apps/management/routes/webhooks.test.ts +6 -1
  544. package/src/apps/management/routes/webhooks.ts +15 -3
  545. package/src/apps/mpp/App.ts +276 -29
  546. package/src/apps/mpp/Mpp.test.ts +631 -26
  547. package/src/apps/mpp/Mpp.ts +0 -42
  548. package/src/apps/mpp/internal/Adapter.ts +108 -3
  549. package/src/apps/mpp/internal/Error.test.ts +33 -0
  550. package/src/apps/mpp/internal/Error.ts +44 -6
  551. package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
  552. package/src/apps/mpp/internal/Idempotency.ts +59 -5
  553. package/src/apps/mpp/internal/Policy.test.ts +122 -0
  554. package/src/apps/mpp/internal/Policy.ts +98 -0
  555. package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
  556. package/src/apps/mpp/internal/ScreenManager.ts +41 -0
  557. package/src/apps/mpp/internal/Screening.ts +40 -3
  558. package/src/apps/mpp/internal/Sponsorship.ts +144 -0
  559. package/src/apps/mpp/internal/Utils.ts +30 -0
  560. package/src/apps/relay/App.test.ts +493 -62
  561. package/src/apps/relay/App.ts +233 -23
  562. package/src/apps/relay/Sponsorships.test.ts +49 -0
  563. package/src/apps/relay/Sponsorships.ts +18 -6
  564. package/src/db/Db.ts +439 -0
  565. package/src/db/Schema.ts +325 -2
  566. package/src/db/tables/earnVaults.test.ts +185 -0
  567. package/src/db/tables/earnVaults.ts +151 -0
  568. package/src/db/tables/fundingCatalog.test.ts +108 -0
  569. package/src/db/tables/fundingCatalog.ts +157 -0
  570. package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
  571. package/src/db/tables/fundingDepositAddresses.ts +376 -0
  572. package/src/db/tables/fundingDeposits.test.ts +261 -0
  573. package/src/db/tables/fundingDeposits.ts +229 -0
  574. package/src/db/tables/fundingIdempotency.test.ts +182 -0
  575. package/src/db/tables/fundingIdempotency.ts +180 -0
  576. package/src/db/tables/fundingTransferEvents.ts +28 -0
  577. package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
  578. package/src/db/tables/fundingTransferTransactions.ts +37 -0
  579. package/src/db/tables/fundingTransfers.test.ts +89 -0
  580. package/src/db/tables/fundingTransfers.ts +153 -0
  581. package/src/db/tables/organizations.ts +16 -0
  582. package/src/db/tables/projects.ts +16 -0
  583. package/src/db/tables/requestUsage.ts +23 -0
  584. package/src/db/tables/sponsoredTransactions.test.ts +11 -0
  585. package/src/db/tables/sponsoredTransactions.ts +3 -3
  586. package/src/db/tables/users.ts +16 -0
  587. package/src/db/tables/verifiedTokens.ts +19 -14
  588. package/src/db/tables/webhookSubscriptions.ts +58 -3
  589. package/src/handlers/relay.test.ts +2 -0
  590. package/src/handlers/relay.ts +95 -99
  591. package/src/internal/Auth.test.ts +48 -0
  592. package/src/internal/Auth.ts +61 -2
  593. package/src/internal/Cache.ts +13 -9
  594. package/src/internal/Cursor.test.ts +2 -2
  595. package/src/internal/Cursor.ts +1 -1
  596. package/src/internal/EarnRates.test.ts +125 -0
  597. package/src/internal/EarnRates.ts +409 -0
  598. package/src/internal/EarnVaults.test.ts +195 -0
  599. package/src/internal/EarnVaults.ts +876 -0
  600. package/src/internal/EdgeCache.test.ts +19 -0
  601. package/src/internal/EdgeCache.ts +35 -5
  602. package/src/internal/Id.ts +14 -0
  603. package/src/internal/Idempotency.test.ts +109 -0
  604. package/src/internal/Idempotency.ts +237 -0
  605. package/src/internal/Log.test-d.ts +41 -8
  606. package/src/internal/Log.test.ts +189 -8
  607. package/src/internal/Log.ts +124 -17
  608. package/src/internal/MetricSink.test.ts +244 -4
  609. package/src/internal/MetricSink.ts +51 -1
  610. package/src/internal/OpenApi.ts +3 -0
  611. package/src/internal/Provider.test.ts +17 -0
  612. package/src/internal/Provider.ts +17 -0
  613. package/src/internal/Schema.ts +27 -17
  614. package/src/internal/Store.test.ts +25 -0
  615. package/src/internal/Store.ts +46 -0
  616. package/src/internal/Tidx.local.test.ts +78 -3
  617. package/src/internal/Tidx.test.ts +212 -18
  618. package/src/internal/Tidx.ts +112 -32
  619. package/src/internal/VerifiedTokens.test.ts +15 -0
  620. package/src/internal/Viem.test.ts +170 -17
  621. package/src/internal/Viem.ts +111 -28
  622. package/src/internal/WebhookDestination.ts +25 -23
  623. package/src/internal/Webhooks.test.ts +59 -0
  624. package/src/internal/Webhooks.ts +34 -10
  625. package/src/internal/exchange/Provider.test.ts +216 -0
  626. package/src/internal/exchange/Provider.ts +326 -0
  627. package/src/internal/exchange/index.test.ts +6 -0
  628. package/src/internal/exchange/index.ts +1 -0
  629. package/src/internal/exchange/providers/uniswap.test.ts +122 -0
  630. package/src/internal/exchange/providers/uniswap.ts +682 -0
  631. package/src/internal/funding/Action.test.ts +138 -0
  632. package/src/internal/funding/Action.ts +117 -0
  633. package/src/internal/funding/Catalog.test.ts +311 -0
  634. package/src/internal/funding/Catalog.ts +347 -0
  635. package/src/internal/funding/Chain.test.ts +79 -0
  636. package/src/internal/funding/Chain.ts +120 -0
  637. package/src/internal/funding/Deposit.test.ts +26 -0
  638. package/src/internal/funding/Deposit.ts +453 -0
  639. package/src/internal/funding/DepositAddress.test.ts +18 -0
  640. package/src/internal/funding/DepositAddress.ts +312 -0
  641. package/src/internal/funding/Evidence.test.ts +297 -0
  642. package/src/internal/funding/Evidence.ts +430 -0
  643. package/src/internal/funding/Provider.test.ts +1328 -0
  644. package/src/internal/funding/Provider.ts +1796 -0
  645. package/src/internal/funding/Reconciliation.local.test.ts +504 -0
  646. package/src/internal/funding/Reconciliation.test.ts +2020 -0
  647. package/src/internal/funding/Reconciliation.ts +930 -0
  648. package/src/internal/funding/Route.test.ts +66 -0
  649. package/src/internal/funding/Route.ts +29 -0
  650. package/src/internal/funding/Subsidy.local.test.ts +152 -0
  651. package/src/internal/funding/Subsidy.test.ts +75 -0
  652. package/src/internal/funding/Subsidy.ts +260 -0
  653. package/src/internal/funding/Token.test.ts +47 -0
  654. package/src/internal/funding/Token.ts +59 -0
  655. package/src/internal/funding/Transfer.test.ts +369 -0
  656. package/src/internal/funding/Transfer.ts +522 -0
  657. package/src/internal/funding/index.test.ts +20 -0
  658. package/src/internal/funding/index.ts +12 -0
  659. package/src/internal/funding/providers/across.ts +149 -0
  660. package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
  661. package/src/internal/funding/providers/relay.test.ts +474 -0
  662. package/src/internal/funding/providers/relay.ts +559 -0
  663. package/src/internal/funding/providers/rhino.ts +139 -0
  664. package/src/internal/funding/providers/squid.ts +151 -0
  665. package/src/internal/funding/providers/symbiosis.ts +221 -0
  666. package/src/internal/index.test.ts +5 -1
  667. package/src/internal/index.ts +5 -1
  668. package/src/internal/webhookDestinations/url.ts +49 -45
  669. package/src/providers/index.test.ts +14 -0
  670. package/src/providers/index.ts +54 -0
  671. package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
  672. package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
  673. package/dist/apps/data/FundingQuoteProviders.js +0 -775
  674. package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
  675. package/dist/internal/FundingQuotes.d.ts +0 -864
  676. package/dist/internal/FundingQuotes.d.ts.map +0 -1
  677. package/dist/internal/FundingQuotes.js +0 -672
  678. package/dist/internal/FundingQuotes.js.map +0 -1
  679. package/src/apps/data/FundingQuoteProviders.ts +0 -1043
  680. package/src/internal/FundingQuotes.test.ts +0 -456
  681. package/src/internal/FundingQuotes.ts +0 -944
@@ -1,141 +1,43 @@
1
1
  import { Hono } from 'hono';
2
+ import { etag } from 'hono/etag';
2
3
  import * as z from 'zod/mini';
4
+ import * as Db from '../../../db/Db.js';
5
+ import * as FundingDepositAddresses from '../../../db/tables/fundingDepositAddresses.js';
6
+ import * as FundingDeposits from '../../../db/tables/fundingDeposits.js';
7
+ import * as FundingIdempotency from '../../../db/tables/fundingIdempotency.js';
8
+ import * as FundingTransfers from '../../../db/tables/fundingTransfers.js';
3
9
  import * as Auth from '../../../internal/Auth.js';
4
10
  import * as Cache from '../../../internal/Cache.js';
5
- import * as FundingQuotes from '../../../internal/FundingQuotes.js';
11
+ import * as Cursor from '../../../internal/Cursor.js';
12
+ import * as FundingCatalog from '../../../internal/funding/Catalog.js';
13
+ import * as FundingDeposit from '../../../internal/funding/Deposit.js';
14
+ import * as FundingDepositAddress from '../../../internal/funding/DepositAddress.js';
15
+ import * as FundingProvider from '../../../internal/funding/Provider.js';
16
+ import * as FundingTransfer from '../../../internal/funding/Transfer.js';
17
+ import * as Idempotency from '../../../internal/Idempotency.js';
6
18
  import * as OpenApi from '../../../internal/OpenApi.js';
7
19
  import * as Response from '../../../internal/Response.js';
8
20
  import * as Schema from '../../../internal/Schema.js';
9
21
  import * as Value from '../../../internal/Value.js';
10
- import * as FundingQuoteProviders from '../FundingQuoteProviders.js';
11
22
  /** Zod schemas owned by funding quote resources. */
12
23
  export var schema;
13
24
  (function (schema) {
14
25
  /** Source or destination chain reference. */
15
- schema.Chain = Schema.describe(z.object({
16
- addressFormat: z
17
- .enum(['base58', 'base58check', 'evm'])
18
- .check(z.describe('Address family used by accounts and token identifiers on this chain.'), z.meta({ examples: ['evm'] })),
19
- id: z
20
- .string()
21
- .check(z.describe('Stable chain id. Uses CAIP-2 where standardized and a Tempo-defined compatible id otherwise.'), z.meta({ examples: ['eip155:8453'] })),
22
- kind: z
23
- .enum(['evm', 'solana', 'tron'])
24
- .check(z.describe('Chain execution family used for provider routing.'), z.meta({ examples: ['evm'] })),
25
- name: z
26
- .string()
27
- .check(z.describe('Human-readable chain name.'), z.meta({ examples: ['Base'] })),
28
- providerIds: z
29
- .optional(z.record(z.string(), z.string()))
30
- .check(z.describe('Provider-specific chain ids Tempo uses when requesting quotes.'), z.meta({ examples: [{ across: '8453', relay: '8453', rhino: 'BASE' }] })),
31
- }), 'A normalized chain reference for funding quotes.');
26
+ schema.Chain = FundingProvider.schema.ChainRef;
32
27
  /** Source or destination token reference. */
33
- schema.Token = Schema.describe(z.object({
34
- address: z
35
- .string()
36
- .check(z.describe('Contract address, mint, or issuer address on the token chain.'), z.meta({ examples: ['0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] })),
37
- currency: z
38
- .string()
39
- .check(z.describe('Monetary denomination represented by this token.'), z.meta({ examples: ['USD'] })),
40
- decimals: z
41
- .number()
42
- .check(z.int(), z.gte(0), z.describe('Number of decimal places this token uses.'), z.meta({ examples: [6] })),
43
- metadata: z
44
- .record(z.string(), z.string())
45
- .check(z.describe('Curated display or lookup metadata for this token.'), z.meta({ examples: [{ coingeckoId: 'usd-coin' }] })),
46
- name: z
47
- .string()
48
- .check(z.describe('Human-readable token name.'), z.meta({ examples: ['USD Coin'] })),
49
- standard: z
50
- .string()
51
- .check(z.describe('Token standard on the token chain.'), z.meta({ examples: ['ERC-20'] })),
52
- symbol: z
53
- .string()
54
- .check(z.describe('Short token ticker symbol.'), z.meta({ examples: ['USDC'] })),
55
- tokenKey: z.string().check(z.describe('Stable Tempo token key scoped to the token chain.'), z.meta({
56
- examples: ['eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'],
57
- })),
58
- verified: z
59
- .boolean()
60
- .check(z.describe('Whether Tempo recognizes this token in its funding quote inventory.'), z.meta({ examples: [true] })),
61
- }), 'A normalized token reference for funding quotes.');
28
+ schema.Token = FundingProvider.schema.TokenRef;
62
29
  /** Self-contained source or destination amount in a funding quote. */
63
30
  schema.TokenAmount = Schema.describe(Schema.TokenAmount, 'A funding amount in base units and human-readable form.');
64
31
  /** Provider summary embedded in a funding quote. */
65
- schema.ProviderRef = Schema.describe(z.object({
66
- id: z
67
- .enum(['across', 'relay', 'rhino', 'squid', 'symbiosis'])
68
- .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
69
- kind: z
70
- .string()
71
- .check(z.describe('Provider category, such as a solver network or aggregator.'), z.meta({ examples: ['solverNetwork'] })),
72
- name: z
73
- .string()
74
- .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Relay'] })),
75
- requiresApiKey: z
76
- .boolean()
77
- .check(z.describe('Whether Tempo needs provider credentials to query or use this provider.'), z.meta({ examples: [false] })),
78
- }), 'Provider metadata embedded in a funding quote.');
32
+ schema.ProviderRef = FundingProvider.schema.ProviderRef;
79
33
  /** Quote quality signals exposed directly instead of implied by list order. */
80
- schema.Quality = Schema.describe(z.object({
81
- estimatedSeconds: z
82
- .optional(z.number().check(z.int(), z.nonnegative()))
83
- .check(z.describe('Estimated settlement time in seconds, when known.'), z.meta({ examples: [2] })),
84
- liquiditySource: z
85
- .string()
86
- .check(z.describe('Provider source for the live quote quality signal.'), z.meta({ examples: ['providerQuote'] })),
87
- sourceDetail: z
88
- .optional(z.string())
89
- .check(z.describe('Provider-specific source or endpoint detail for the quality signal.'), z.meta({ examples: ['providerEndpoint'] })),
90
- tier: z
91
- .enum(['liquid', 'thin'])
92
- .check(z.describe('Machine-readable quality tier for a successful quote.'), z.meta({ examples: ['liquid'] })),
93
- }), 'Machine-readable liquidity, fee, and source signals for a successful quote.');
34
+ schema.Quality = FundingProvider.schema.FundingQuoteQuality;
94
35
  /** Provider quote freshness data. */
95
- schema.QuoteDetails = Schema.describe(z.object({
96
- expiresAt: z
97
- .optional(z.iso.datetime())
98
- .check(z.describe('Timestamp after which the provider quote is no longer valid.'), z.meta({ examples: ['2026-01-01T00:01:00Z'] })),
99
- sampledAt: z.iso
100
- .datetime()
101
- .check(z.describe('Timestamp for the live quote probe.'), z.meta({ examples: ['2026-01-01T00:00:00Z'] })),
102
- }), 'Freshness data for a provider funding quote.');
36
+ schema.QuoteDetails = FundingProvider.schema.QuoteDetails;
103
37
  /** Successful live funding quote. */
104
- schema.FundingQuote = Schema.describe(z.object({
105
- destinationAmount: schema.TokenAmount.check(z.describe('Expected destination amount.')),
106
- destinationAmountMin: z
107
- .optional(schema.TokenAmount)
108
- .check(z.describe('Provider-derived minimum destination amount. Symbiosis and Squid quotes use a fixed 1% slippage tolerance.')),
109
- destinationChain: schema.Chain.check(z.describe('Destination chain, always Tempo mainnet in V1.')),
110
- destinationToken: schema.Token.check(z.describe('Tempo token expected from this quote.')),
111
- id: z
112
- .string()
113
- .check(z.describe('Stable deterministic funding quote id.'), z.meta({ examples: ['base-usdc-tempo-usdce-relay'] })),
114
- provider: schema.ProviderRef,
115
- quality: schema.Quality,
116
- quote: schema.QuoteDetails,
117
- sourceAmount: schema.TokenAmount,
118
- sourceChain: schema.Chain.check(z.describe('Chain where the caller currently holds funds.')),
119
- sourceToken: schema.Token.check(z.describe('Token the caller currently holds.')),
120
- }), 'One successful provider-specific funding quote.');
38
+ schema.FundingQuote = FundingProvider.schema.FundingQuote;
121
39
  /** Funding quote provider catalog entry. */
122
- schema.Provider = Schema.describe(z.object({
123
- id: z
124
- .enum(['across', 'relay', 'rhino', 'squid', 'symbiosis'])
125
- .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
126
- kind: z
127
- .string()
128
- .check(z.describe('Provider category.'), z.meta({ examples: ['solverNetwork'] })),
129
- name: z
130
- .string()
131
- .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Relay'] })),
132
- requiresApiKey: z
133
- .boolean()
134
- .check(z.describe('Whether Tempo needs provider credentials to query or use this provider.'), z.meta({ examples: [false] })),
135
- status: z
136
- .enum(['configured', 'unconfigured'])
137
- .check(z.describe('`configured` means live quotes are enabled for this deployment. `unconfigured` means the provider is supported but unavailable here.'), z.meta({ examples: ['configured', 'unconfigured'] })),
138
- }), 'One funding quote provider.');
40
+ schema.Provider = Schema.describe(schema.ProviderRef, 'One funding quote provider.');
139
41
  /** Chain inventory entry returned by the funding chains endpoint. */
140
42
  schema.ChainInventory = Schema.describe(z.extend(schema.Chain, {
141
43
  tokens: z.array(schema.Token).check(z.describe('Stablecoins known on this source chain.')),
@@ -144,116 +46,528 @@ export var schema;
144
46
  let quoteFunding;
145
47
  (function (quoteFunding) {
146
48
  /** Query parameters for live funding quotes. */
147
- quoteFunding.Query = z
148
- .strictObject({
149
- destinationToken: z
150
- .optional(z.string())
151
- .check(z.describe('Tempo destination token symbol, address, or token key. Defaults to USDC.e.'), z.meta({ examples: ['USDC.e'] })),
152
- provider: z
153
- .optional(z.enum(['across', 'relay', 'rhino', 'squid', 'symbiosis']))
154
- .check(z.describe('Only request a quote from this provider. Supported ids are `across`, `relay`, `rhino`, `squid`, and `symbiosis`; omit it to query every configured provider.'), z.meta({ examples: ['relay'] })),
155
- sourceAmount: z
156
- .string()
157
- .check(z.regex(/^(?=.*[1-9])\d+(\.\d+)?$/), z.describe('Positive source token amount. Base units by default, so 1 USDC is `1000000`.'), z.meta({ examples: ['1000000'] })),
158
- sourceAmountUnits: z
159
- ._default(z.enum(['baseUnits', 'decimal']), 'baseUnits')
160
- .check(z.describe('Whether `sourceAmount` is base units or a human-readable decimal.'), z.meta({ examples: ['baseUnits', 'decimal'] })),
161
- sourceChain: z
162
- .string()
163
- .check(z.minLength(1), z.describe('Source chain alias or stable id, such as `base`, `solana`, or `eip155:8453`.'), z.meta({ examples: ['base', 'eip155:8453'] })),
164
- sourceToken: z
165
- .string()
166
- .check(z.minLength(1), z.describe('Source token symbol, contract address, or Tempo token key. Lookup is scoped to `sourceChain`; non-EVM addresses are case-sensitive. An unknown token returns an empty list.'), z.meta({ examples: ['USDC', '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] })),
167
- })
168
- .check(z.describe('Query parameters for live funding quotes into Tempo.'));
49
+ quoteFunding.Query = FundingProvider.schema.QuoteRequest;
169
50
  /** Non-paginated list of successful funding quotes. */
170
51
  quoteFunding.Response = Schema.describe(z.object({
171
52
  data: z.array(schema.FundingQuote).check(z.describe('Successful live funding quotes.')),
172
53
  }), 'A non-paginated list of successful live funding quotes.');
173
54
  })(quoteFunding = schema.quoteFunding || (schema.quoteFunding = {}));
174
- /** Schemas for the listFundingChains operation. */
175
- let listFundingChains;
176
- (function (listFundingChains) {
55
+ /** Schemas for the getFundingChains operation. */
56
+ let getFundingChains;
57
+ (function (getFundingChains) {
177
58
  /** Non-paginated source-chain inventory. */
178
- listFundingChains.Response = Schema.describe(z.object({
59
+ getFundingChains.Response = Schema.describe(z.object({
179
60
  data: z
180
61
  .array(schema.ChainInventory)
181
62
  .check(z.describe('Source chains and stablecoins supported by funding quotes.')),
182
63
  }), 'A non-paginated list of source chains and stablecoin inventory.');
183
- })(listFundingChains = schema.listFundingChains || (schema.listFundingChains = {}));
184
- /** Schemas for the listProviders operation. */
185
- let listProviders;
186
- (function (listProviders) {
64
+ })(getFundingChains = schema.getFundingChains || (schema.getFundingChains = {}));
65
+ /** Schemas for the getFundingProviders operation. */
66
+ let getFundingProviders;
67
+ (function (getFundingProviders) {
187
68
  /** Non-paginated funding quote provider catalog. */
188
- listProviders.Response = Schema.describe(z.object({
69
+ getFundingProviders.Response = Schema.describe(z.object({
189
70
  data: z.array(schema.Provider).check(z.describe("Providers in Tempo's funding quote catalog.")),
190
71
  }), 'A non-paginated list of funding quote providers.');
191
- })(listProviders = schema.listProviders || (schema.listProviders = {}));
72
+ })(getFundingProviders = schema.getFundingProviders || (schema.getFundingProviders = {}));
73
+ /** A durable funding transfer. Reads never include the executable `action`. */
74
+ schema.Transfer = FundingTransfer.schema.FundingTransfer;
75
+ /** One reusable funding deposit address. */
76
+ schema.DepositAddress = FundingDepositAddress.schema.FundingDepositAddress;
77
+ /** One detected funding deposit. */
78
+ schema.Deposit = FundingDeposit.schema.FundingDeposit;
79
+ /** Schemas for the createFundingDepositAddress operation. */
80
+ let createFundingDepositAddress;
81
+ (function (createFundingDepositAddress) {
82
+ /** Funding deposit address creation request body. */
83
+ createFundingDepositAddress.Body = z
84
+ .strictObject({
85
+ amount: FundingTransfer.schema.CreateRequest.shape.amount,
86
+ destinationToken: z
87
+ .string()
88
+ .check(z.minLength(1), z.describe('Tempo destination token symbol, contract address, or token key.'), z.meta({ examples: ['usdt0'] })),
89
+ recipient: z
90
+ .string()
91
+ .check(z.regex(/^0x[0-9a-fA-F]{40}$/), z.describe('Tempo account that receives completed deposits.'), z.meta({ examples: [`0x${'11'.repeat(20)}`] })),
92
+ refundAddress: z
93
+ .string()
94
+ .check(z.minLength(1), z.describe('Source-chain account that receives refunds.'), z.meta({ examples: ['TJRabPrwbZy45sbavfcjinPJC18kjpRTv8'] })),
95
+ sourceChain: z
96
+ .string()
97
+ .check(z.minLength(1), z.describe('Source chain CAIP-2 id, slug, or alias.'), z.meta({ examples: ['tron', 'tron:0x2b6653dc'] })),
98
+ sourceToken: z
99
+ .string()
100
+ .check(z.minLength(1), z.describe('Source token symbol, contract address, or token key.'), z.meta({ examples: ['usdt'] })),
101
+ subsidize: z
102
+ .optional(z.boolean())
103
+ .check(z.describe('Guarantees normalized 1:1 delivery through a Tempo-funded subsidy.'), z.meta({ examples: [false] })),
104
+ })
105
+ .check(z.describe('Reusable funding deposit address creation request.'));
106
+ /** Required headers for funding deposit address creation. */
107
+ createFundingDepositAddress.Headers = z.object({
108
+ 'idempotency-key': z
109
+ .string()
110
+ .check(z.minLength(1), z.describe('Opaque retry key scoped to the API key. Matching requests replay successful responses for 24 hours; changed input conflicts, in-flight requests block, and failed attempts release the key.'), z.meta({ examples: ['funding_01k1c5j8q8p0be6j5v9m6d1e4r'] })),
111
+ });
112
+ /** The reusable address, with quoted terms only when the provider address was newly stored. */
113
+ createFundingDepositAddress.Response = z
114
+ .union([
115
+ FundingDepositAddress.schema.CreatedFundingDepositAddress,
116
+ FundingDepositAddress.schema.FundingDepositAddress,
117
+ ])
118
+ .check(z.describe('A reusable funding deposit address, including terms sampled for a newly stored provider address.'));
119
+ })(createFundingDepositAddress = schema.createFundingDepositAddress || (schema.createFundingDepositAddress = {}));
120
+ /** Schemas for the getFundingDepositAddress operation. */
121
+ let getFundingDepositAddress;
122
+ (function (getFundingDepositAddress) {
123
+ /** Path parameters for reading a funding deposit address. */
124
+ getFundingDepositAddress.Params = z
125
+ .object({
126
+ id: z
127
+ .string()
128
+ .check(z.regex(/^fda_[A-Za-z0-9_-]+$/), z.describe('Funding deposit address ID (`fda_…`).'), z.meta({ examples: ['fda_001785792000000_2ZPE2gvateYEQ0dQslgvkhjx'] })),
129
+ })
130
+ .check(z.describe('Path parameters for reading a funding deposit address.'));
131
+ /** One reusable funding deposit address. */
132
+ getFundingDepositAddress.Response = schema.DepositAddress;
133
+ })(getFundingDepositAddress = schema.getFundingDepositAddress || (schema.getFundingDepositAddress = {}));
134
+ /** Schemas for the listFundingDepositAddressDeposits operation. */
135
+ let listFundingDepositAddressDeposits;
136
+ (function (listFundingDepositAddressDeposits) {
137
+ /** Path parameters for listing one address's deposits. */
138
+ listFundingDepositAddressDeposits.Params = getFundingDepositAddress.Params;
139
+ /** Query parameters for listing one address's deposits. */
140
+ listFundingDepositAddressDeposits.Query = z
141
+ .object({ cursor: Schema.Cursor, limit: Schema.Limit })
142
+ .check(z.describe('Paging parameters for one funding deposit address.'));
143
+ /** One page of detected deposits. */
144
+ listFundingDepositAddressDeposits.Response = z
145
+ .object({
146
+ data: z.array(schema.Deposit).check(z.describe('Detected deposits on this page, newest first.')),
147
+ nextCursor: Schema.NextCursor,
148
+ })
149
+ .check(z.describe('A page of deposits detected for one funding deposit address.'));
150
+ })(listFundingDepositAddressDeposits = schema.listFundingDepositAddressDeposits || (schema.listFundingDepositAddressDeposits = {}));
151
+ /** Schemas for the getFundingDeposit operation. */
152
+ let getFundingDeposit;
153
+ (function (getFundingDeposit) {
154
+ /** Path parameters for reading a funding deposit. */
155
+ getFundingDeposit.Params = z
156
+ .object({
157
+ id: z
158
+ .string()
159
+ .check(z.regex(/^fdp_[A-Za-z0-9_-]+$/), z.describe('Funding deposit id (`fdp_…`).'), z.meta({ examples: ['fdp_001785792060000_2ZPE2gvateYEQ0dQslgvkhjx'] })),
160
+ })
161
+ .check(z.describe('Path parameters for reading a funding deposit.'));
162
+ /** One detected funding deposit. */
163
+ getFundingDeposit.Response = schema.Deposit;
164
+ })(getFundingDeposit = schema.getFundingDeposit || (schema.getFundingDeposit = {}));
165
+ /** Schemas for the listFundingTransfers operation. */
166
+ let listFundingTransfers;
167
+ (function (listFundingTransfers) {
168
+ /** Query parameters for listing funding transfers. */
169
+ listFundingTransfers.Query = z
170
+ .object({
171
+ cursor: Schema.Cursor,
172
+ include: Schema.totalCountInclude,
173
+ limit: Schema.Limit,
174
+ status: z.optional(FundingTransfer.schema.Status),
175
+ })
176
+ .check(z.describe('Query parameters for listing funding transfers.'));
177
+ /** Paginated funding transfer list. */
178
+ listFundingTransfers.Response = z
179
+ .object({
180
+ data: z.array(schema.Transfer).check(z.describe('Funding transfers on this page, newest first.')),
181
+ meta: z
182
+ .optional(Schema.CountMeta)
183
+ .check(z.describe('Extra response metadata requested with `include`.')),
184
+ nextCursor: Schema.NextCursor,
185
+ })
186
+ .check(z.describe('A page of funding transfers.'));
187
+ })(listFundingTransfers = schema.listFundingTransfers || (schema.listFundingTransfers = {}));
188
+ /** Schemas for the createFundingTransfer operation. */
189
+ let createFundingTransfer;
190
+ (function (createFundingTransfer) {
191
+ /** Funding transfer creation request body. */
192
+ createFundingTransfer.Body = FundingTransfer.schema.CreateRequest;
193
+ /** Required headers for funding transfer creation. */
194
+ createFundingTransfer.Headers = z.object({
195
+ 'idempotency-key': z
196
+ .string()
197
+ .check(z.minLength(1), z.describe('Opaque retry key scoped to the API key. Matching requests replay successful responses for 24 hours; changed input conflicts, in-flight requests block, and failed attempts release the key.'), z.meta({ examples: ['funding_01k1c5j8q8p0be6j5v9m6d1e4r'] })),
198
+ });
199
+ /** The created transfer with its one-time executable action. */
200
+ createFundingTransfer.Response = FundingTransfer.schema.CreatedFundingTransfer;
201
+ })(createFundingTransfer = schema.createFundingTransfer || (schema.createFundingTransfer = {}));
202
+ const destinationCreateFields = {
203
+ amount: FundingTransfer.schema.CreateRequest.shape.amount,
204
+ mode: FundingTransfer.schema.CreateRequest.shape.mode,
205
+ recipient: FundingTransfer.schema.CreateRequest.shape.recipient,
206
+ sender: FundingTransfer.schema.CreateRequest.shape.sender,
207
+ slippageBps: FundingTransfer.schema.CreateRequest.shape.slippageBps,
208
+ sourceChain: FundingTransfer.schema.CreateRequest.shape.sourceChain,
209
+ sourceToken: FundingTransfer.schema.CreateRequest.shape.sourceToken,
210
+ };
211
+ /** Schemas for the createFundingTransferVault operation. */
212
+ let createFundingTransferVault;
213
+ (function (createFundingTransferVault) {
214
+ /** Funding transfer creation request for an Earn vault destination. */
215
+ createFundingTransferVault.Body = z
216
+ .strictObject({
217
+ ...destinationCreateFields,
218
+ vaultAddress: z
219
+ .string()
220
+ .check(z.regex(/^0x[0-9a-fA-F]{40}$/), z.describe('Tempo Earn vault contract address.'), z.meta({ examples: [`0x${'f4'.repeat(20)}`] })),
221
+ })
222
+ .check(z.describe('Vault funding transfer creation request.'));
223
+ /** Required headers for vault funding transfer creation. */
224
+ createFundingTransferVault.Headers = createFundingTransfer.Headers;
225
+ })(createFundingTransferVault = schema.createFundingTransferVault || (schema.createFundingTransferVault = {}));
226
+ /** Schemas for the createFundingTransferZone operation. */
227
+ let createFundingTransferZone;
228
+ (function (createFundingTransferZone) {
229
+ /** Funding transfer creation request for a Zone destination. */
230
+ createFundingTransferZone.Body = z
231
+ .strictObject({
232
+ amount: destinationCreateFields.amount,
233
+ destinationChain: z
234
+ .string()
235
+ .check(z.regex(/^eip155:\d+$/), z.describe('Configured Zone CAIP-2 id.'), z.meta({ examples: ['eip155:421700001'] })),
236
+ destinationToken: FundingTransfer.schema.CreateRequest.shape.destinationToken,
237
+ mode: destinationCreateFields.mode,
238
+ recipient: destinationCreateFields.recipient,
239
+ recipientFallback: z
240
+ .string()
241
+ .check(z.regex(/^0x[0-9a-fA-F]{40}$/), z.describe('Public Tempo recipient used if the Zone credit cannot complete.'), z.meta({ examples: [`0x${'22'.repeat(20)}`] })),
242
+ sender: destinationCreateFields.sender,
243
+ slippageBps: destinationCreateFields.slippageBps,
244
+ sourceChain: destinationCreateFields.sourceChain,
245
+ sourceToken: destinationCreateFields.sourceToken,
246
+ })
247
+ .check(z.describe('Zone funding transfer creation request.'));
248
+ /** Required headers for Zone funding transfer creation. */
249
+ createFundingTransferZone.Headers = createFundingTransfer.Headers;
250
+ })(createFundingTransferZone = schema.createFundingTransferZone || (schema.createFundingTransferZone = {}));
251
+ /** Schemas for the getFundingTransfer operation. */
252
+ let getFundingTransfer;
253
+ (function (getFundingTransfer) {
254
+ /** Path parameters for a funding transfer read. */
255
+ getFundingTransfer.Params = z
256
+ .object({
257
+ id: z
258
+ .string()
259
+ .check(z.describe('Funding transfer ID (`ftr_…`).'), z.meta({ examples: ['ftr_001785729600000_2ZPE2gvateYEQ0dQslgvkhjx'] })),
260
+ })
261
+ .check(z.describe('Path parameters for a funding transfer request.'));
262
+ /** The funding transfer resource, returned directly. */
263
+ getFundingTransfer.Response = schema.Transfer;
264
+ })(getFundingTransfer = schema.getFundingTransfer || (schema.getFundingTransfer = {}));
192
265
  })(schema || (schema = {}));
193
- const fundingQuoteResponseExample = (() => {
194
- const [candidate] = FundingQuotes.listQuoteCandidates({
195
- provider: 'relay',
196
- sourceAmount: '1000000',
197
- sourceAmountUnits: 'baseUnits',
198
- sourceChain: 'base',
199
- sourceToken: 'USDC',
200
- });
201
- if (!candidate)
202
- throw new Error('Missing Relay funding quote example candidate');
203
- return {
204
- data: [
205
- {
206
- destinationAmount: Value.tokenAmount({
207
- baseUnits: '979295',
208
- currency: candidate.destinationToken.currency,
209
- decimals: candidate.destinationToken.decimals,
210
- }),
211
- destinationAmountMin: Value.tokenAmount({
212
- baseUnits: '939242',
213
- currency: candidate.destinationToken.currency,
214
- decimals: candidate.destinationToken.decimals,
215
- }),
216
- destinationChain: candidate.destinationChain,
217
- destinationToken: candidate.destinationToken,
218
- id: candidate.id,
219
- provider: candidate.provider,
220
- quality: {
221
- estimatedSeconds: 1,
222
- liquiditySource: 'providerQuote',
223
- sourceDetail: 'relay:quote-v2',
224
- tier: 'liquid',
225
- },
226
- quote: {
227
- sampledAt: '2026-01-01T00:00:00.000Z',
228
- },
229
- sourceAmount: Value.tokenAmount({
230
- baseUnits: candidate.sourceAmount.amount,
231
- currency: candidate.sourceToken.currency,
232
- decimals: candidate.sourceToken.decimals,
233
- }),
234
- sourceChain: candidate.sourceChain,
235
- sourceToken: candidate.sourceToken,
266
+ const baseChainExample = {
267
+ addressFormat: 'hex',
268
+ id: 'eip155:8453',
269
+ kind: 'evm',
270
+ name: 'Base',
271
+ };
272
+ const baseUsdcExample = {
273
+ address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
274
+ currency: 'USD',
275
+ decimals: 6,
276
+ name: 'USD Coin',
277
+ standard: 'ERC-20',
278
+ symbol: 'USDC',
279
+ tokenKey: 'eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
280
+ verified: true,
281
+ };
282
+ const fundingQuoteResponseExample = {
283
+ data: [
284
+ {
285
+ destinationAmount: Value.tokenAmount({
286
+ baseUnits: '979295',
287
+ currency: 'USD',
288
+ decimals: 6,
289
+ }),
290
+ destinationAmountMin: Value.tokenAmount({
291
+ baseUnits: '939242',
292
+ currency: 'USD',
293
+ decimals: 6,
294
+ }),
295
+ destinationChain: {
296
+ addressFormat: 'hex',
297
+ id: 'eip155:4217',
298
+ kind: 'evm',
299
+ name: 'Tempo',
236
300
  },
237
- ],
238
- };
239
- })();
301
+ destinationToken: {
302
+ address: '0x20c000000000000000000000b9537d11c60e8b50',
303
+ currency: 'USD',
304
+ decimals: 6,
305
+ name: 'Bridged USDC (Stargate)',
306
+ standard: 'TIP-20',
307
+ symbol: 'USDC.e',
308
+ tokenKey: 'eip155:4217/erc20:0x20c000000000000000000000b9537d11c60e8b50',
309
+ verified: true,
310
+ },
311
+ id: 'base-usdc-tempo-usdce-relay',
312
+ provider: { id: 'relay', name: 'Relay' },
313
+ quality: {
314
+ estimatedSeconds: 1,
315
+ liquiditySource: 'providerQuote',
316
+ sourceDetail: 'relay:quote-v2',
317
+ tier: 'liquid',
318
+ },
319
+ quote: {
320
+ sampledAt: '2026-01-01T00:00:00.000Z',
321
+ },
322
+ sourceAmount: Value.tokenAmount({
323
+ baseUnits: '1000000',
324
+ currency: 'USD',
325
+ decimals: 6,
326
+ }),
327
+ sourceChain: baseChainExample,
328
+ sourceToken: baseUsdcExample,
329
+ },
330
+ ],
331
+ };
240
332
  const fundingChainsResponseExample = {
241
- data: FundingQuotes.listChains(),
333
+ data: [{ ...baseChainExample, tokens: [baseUsdcExample] }],
242
334
  };
243
335
  const providersResponseExample = {
244
- data: FundingQuotes.listProviders().map((provider) => ({
245
- ...provider,
246
- status: 'configured',
247
- })),
336
+ data: [{ id: 'relay', name: 'Relay' }],
337
+ };
338
+ const tronChainExample = {
339
+ addressFormat: 'base58check',
340
+ id: 'tron:0x2b6653dc',
341
+ kind: 'tron',
342
+ name: 'Tron',
343
+ };
344
+ const tronUsdtExample = {
345
+ address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
346
+ currency: 'USD',
347
+ decimals: 6,
348
+ name: 'Tether USD',
349
+ standard: 'TRC-20',
350
+ symbol: 'USDT',
351
+ tokenKey: 'tron:0x2b6653dc/trc20:TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
352
+ verified: true,
353
+ };
354
+ const tempoChainExample = {
355
+ addressFormat: 'hex',
356
+ id: 'eip155:4217',
357
+ kind: 'evm',
358
+ name: 'Tempo',
359
+ };
360
+ const tempoUsdt0Example = {
361
+ address: '0x20c00000000000000000000014f22ca97301eb73',
362
+ currency: 'USD',
363
+ decimals: 6,
364
+ name: 'USDT0',
365
+ standard: 'TIP-20',
366
+ symbol: 'USDT0',
367
+ tokenKey: 'eip155:4217/erc20:0x20c00000000000000000000014f22ca97301eb73',
368
+ verified: true,
369
+ };
370
+ const fundingDepositAddressExample = {
371
+ address: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8',
372
+ createdAt: '2026-08-04T00:00:00.000Z',
373
+ destinationChain: tempoChainExample,
374
+ destinationToken: tempoUsdt0Example,
375
+ id: 'fda_001785792000000_2ZPE2gvateYEQ0dQslgvkhjx',
376
+ provider: { id: 'relay', name: 'Relay' },
377
+ recipient: `0x${'11'.repeat(20)}`,
378
+ refundAddress: 'TJRabPrwbZy45sbavfcjinPJC18kjpRTv8',
379
+ sourceChain: tronChainExample,
380
+ sourceToken: tronUsdtExample,
381
+ status: 'active',
382
+ subsidize: false,
383
+ updatedAt: '2026-08-04T00:00:00.000Z',
384
+ };
385
+ const createdFundingDepositAddressExample = {
386
+ ...fundingDepositAddressExample,
387
+ destinationAmount: Value.tokenAmount({ baseUnits: '1000000', currency: 'USD', decimals: 6 }),
388
+ destinationAmountMin: Value.tokenAmount({
389
+ baseUnits: '1000000',
390
+ currency: 'USD',
391
+ decimals: 6,
392
+ }),
393
+ fees: [],
394
+ quote: { sampledAt: '2026-08-04T00:00:00.000Z' },
395
+ sourceAmount: Value.tokenAmount({ baseUnits: '1000000', currency: 'USD', decimals: 6 }),
396
+ };
397
+ const fundingDepositExample = {
398
+ createdAt: '2026-08-04T00:01:00.000Z',
399
+ depositAddressId: fundingDepositAddressExample.id,
400
+ destinationChain: tempoChainExample,
401
+ destinationToken: tempoUsdt0Example,
402
+ id: 'fdp_001785792060000_2ZPE2gvateYEQ0dQslgvkhjx',
403
+ provider: { id: 'relay', name: 'Relay' },
404
+ recipient: fundingDepositAddressExample.recipient,
405
+ refundAddress: fundingDepositAddressExample.refundAddress,
406
+ sourceChain: tronChainExample,
407
+ sourceToken: tronUsdtExample,
408
+ sourceTransactionHashes: ['9f2c4c80dbb468878baa8c07ff523e0464bf6437f2a486268508485d83f14d12'],
409
+ status: 'detected',
410
+ updatedAt: '2026-08-04T00:01:00.000Z',
411
+ };
412
+ const fundingDepositAddressDepositsExample = {
413
+ data: [fundingDepositExample],
414
+ nextCursor: null,
415
+ };
416
+ const fundingTransferExample = {
417
+ createdAt: '2026-01-01T00:00:00.000Z',
418
+ destinationAmount: Value.tokenAmount({ baseUnits: '979295', currency: 'USD', decimals: 6 }),
419
+ destinationAmountMin: Value.tokenAmount({ baseUnits: '939242', currency: 'USD', decimals: 6 }),
420
+ destinationChain: {
421
+ addressFormat: 'hex',
422
+ id: 'eip155:4217',
423
+ kind: 'evm',
424
+ name: 'Tempo',
425
+ },
426
+ destinationToken: {
427
+ address: '0x20c0000000000000000000000000000000000000',
428
+ currency: 'USD',
429
+ decimals: 6,
430
+ name: 'PathUSD',
431
+ standard: 'TIP-20',
432
+ symbol: 'pathUSD',
433
+ tokenKey: 'eip155:4217/erc20:0x20c0000000000000000000000000000000000000',
434
+ verified: true,
435
+ },
436
+ fees: [
437
+ {
438
+ amount: Value.tokenAmount({ baseUnits: '20705', currency: 'USD', decimals: 6 }),
439
+ side: 'source',
440
+ token: baseUsdcExample,
441
+ type: 'provider',
442
+ },
443
+ ],
444
+ id: 'ftr_001767225600000_2ZPE2gvateYEQ0dQslgvkhjx',
445
+ method: 'transaction',
446
+ mode: 'exactSource',
447
+ provider: { id: 'relay', name: 'Relay' },
448
+ quote: {
449
+ expiresAt: '2026-01-01T00:01:00.000Z',
450
+ sampledAt: '2026-01-01T00:00:00.000Z',
451
+ },
452
+ recipient: `0x${'11'.repeat(20)}`,
453
+ sender: `0x${'22'.repeat(20)}`,
454
+ sourceAmount: Value.tokenAmount({ baseUnits: '1000000', currency: 'USD', decimals: 6 }),
455
+ sourceChain: baseChainExample,
456
+ sourceToken: baseUsdcExample,
457
+ status: 'awaiting-source',
458
+ updatedAt: '2026-01-01T00:00:00.000Z',
459
+ version: 1,
248
460
  };
461
+ const listFundingTransfersResponseExample = {
462
+ data: [fundingTransferExample],
463
+ nextCursor: null,
464
+ };
465
+ const createdFundingTransferExample = {
466
+ action: {
467
+ calls: [
468
+ {
469
+ data: `0x095ea7b3000000000000000000000000${'44'.repeat(20)}00000000000000000000000000000000000000000000000000000000000f4240`,
470
+ to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
471
+ value: '0x0',
472
+ },
473
+ {
474
+ data: '0xe8017952',
475
+ to: `0x${'44'.repeat(20)}`,
476
+ value: '0x0',
477
+ },
478
+ ],
479
+ type: 'evm:calls',
480
+ },
481
+ ...fundingTransferExample,
482
+ };
483
+ const unimplementedFundingTransferResponses = (() => {
484
+ const responses = OpenApi.responses({
485
+ errors: {
486
+ 400: { codes: ['body_invalid', 'idempotency_key_required'] },
487
+ 501: {
488
+ codes: ['not_implemented'],
489
+ description: 'This funding transfer destination is not implemented.',
490
+ },
491
+ },
492
+ success: {
493
+ description: 'Unused until this destination is implemented.',
494
+ schema: z.never(),
495
+ },
496
+ });
497
+ const { 200: success, 502: upstream, ...errors } = responses;
498
+ void success;
499
+ void upstream;
500
+ return errors;
501
+ })();
502
+ // Replay the exact successful creation response for 24 hours.
503
+ const idempotencyReplayTtlMs = 86_400_000;
504
+ // Pending claims only cover the bounded provider preparation window.
505
+ const idempotencyPendingTtlMs = 60_000;
506
+ const depositAddressCheckpoint = Schema.describe(z.object({
507
+ candidate: Schema.describe(z.object({
508
+ destinationChain: FundingProvider.schema.ChainRef,
509
+ destinationToken: FundingProvider.schema.TokenRef,
510
+ sourceChain: FundingProvider.schema.ChainRef,
511
+ sourceToken: FundingProvider.schema.TokenRef,
512
+ }), 'Normalized route retained after provider provisioning.'),
513
+ provider: FundingProvider.schema.ProviderRef,
514
+ recipient: z.string().check(z.describe('Normalized Tempo recipient.')),
515
+ refundAddress: z.string().check(z.describe('Normalized source-chain refund account.')),
516
+ result: FundingProvider.schema.DepositAddressResult,
517
+ }), 'Provider result retained until deposit address creation completes.');
518
+ const inventorySourceScopes = new WeakMap();
519
+ let nextInventorySourceScope = 0;
520
+ const fundingEtag = etag();
521
+ function inventorySourceScope(source) {
522
+ const current = inventorySourceScopes.get(source);
523
+ if (current !== undefined)
524
+ return current;
525
+ // A production isolate's source is consistently zero, while multi-app runtimes receive distinct scopes.
526
+ const scope = nextInventorySourceScope++;
527
+ inventorySourceScopes.set(source, scope);
528
+ return scope;
529
+ }
249
530
  /** Mounts live funding quotes and their supporting inventory endpoints. */
250
- export function funding(options = {}) {
531
+ export function funding() {
532
+ const inventoryKey = (c) => {
533
+ const url = new URL(c.req.url);
534
+ const providers = c
535
+ .get('providers')
536
+ .filter(FundingProvider.is)
537
+ .map((provider) => provider.id)
538
+ .sort();
539
+ url.searchParams.set('__tempo_database', String(inventorySourceScope(c.get('dbCached'))));
540
+ url.searchParams.set('__tempo_providers', providers.join(','));
541
+ return url.toString();
542
+ };
251
543
  return new Hono()
544
+ .post('/webhooks/funding/:providerId', async (c) => {
545
+ const provider = c
546
+ .get('providers')
547
+ .filter(FundingProvider.is)
548
+ .find((candidate) => candidate.id === c.req.param('providerId'));
549
+ if (!provider || !FundingProvider.canReceiveWebhook(provider))
550
+ return c.body(null, 404);
551
+ try {
552
+ await provider.webhook.receive({
553
+ body: await c.req.text(),
554
+ headers: c.req.raw.headers,
555
+ });
556
+ return c.body(null, 204);
557
+ }
558
+ catch (cause) {
559
+ if (cause instanceof FundingProvider.WebhookAuthenticationError)
560
+ return c.body(null, 401);
561
+ if (cause instanceof FundingProvider.WebhookPayloadError)
562
+ return c.body(null, 400);
563
+ throw cause;
564
+ }
565
+ })
252
566
  .get('/v1/funding/quotes', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.quoteFunding.Query, {
253
567
  code: 'query_invalid',
254
568
  message: 'Invalid query parameters',
255
569
  }), OpenApi.describeRoute({
256
- description: 'Returns live quotes for funding Tempo with a stablecoin. Omit `provider` to query all configured providers. Provider minimums can use provider-specific slippage policies; Symbiosis and Squid use 1%. This endpoint does not execute a transfer.',
570
+ description: 'Returns live quotes for transferring stablecoins to Tempo.',
257
571
  operationId: 'quoteFunding',
258
572
  responses: OpenApi.responses({
259
573
  errors: {
@@ -269,7 +583,7 @@ export function funding(options = {}) {
269
583
  schema: schema.quoteFunding.Response,
270
584
  },
271
585
  }),
272
- summary: 'Get funding quotes',
586
+ summary: 'Get quotes',
273
587
  tags: ['Funding'],
274
588
  }), async (c) => {
275
589
  if (Auth.narrowAccess)
@@ -281,34 +595,39 @@ export function funding(options = {}) {
281
595
  });
282
596
  const query = c.req.valid('query');
283
597
  const attempts = [];
598
+ const catalog = await FundingCatalog.snapshot(c);
599
+ const providers = c.get('providers').filter(FundingProvider.is);
284
600
  try {
285
601
  c.header('Cache-Control', 'no-store');
602
+ const data = await FundingProvider.getQuotes({
603
+ cache: { bypass: cacheBypass(c.req.raw) },
604
+ catalog,
605
+ destinationToken: query.destinationToken,
606
+ onAttempt: (attempt) => attempts.push(attempt),
607
+ provider: query.provider,
608
+ providers,
609
+ sourceAmount: query.sourceAmount,
610
+ sourceAmountUnits: query.sourceAmountUnits,
611
+ sourceChain: query.sourceChain,
612
+ sourceToken: query.sourceToken,
613
+ });
614
+ if (attempts.length > 0)
615
+ c.set('fundingProviderAttempts', attempts.map(formatAttempt));
286
616
  return c.json(Response.validated(schema.quoteFunding.Response, {
287
- data: await FundingQuotes.listQuotes({
288
- adapters: options.adapters,
289
- adapterTimeoutMs: options.adapterTimeoutMs,
290
- cache: { bypass: cacheBypass(c.req.raw) },
291
- destinationToken: query.destinationToken,
292
- onAttempt: (attempt) => attempts.push(attempt),
293
- provider: query.provider,
294
- sourceAmount: query.sourceAmount,
295
- sourceAmountUnits: query.sourceAmountUnits,
296
- sourceChain: query.sourceChain,
297
- sourceToken: query.sourceToken,
298
- }),
617
+ data,
299
618
  }), 200);
300
619
  }
301
620
  catch (cause) {
302
621
  const message = requestErrorMessage(cause);
303
622
  if (message)
304
623
  return Response.error(c, { code: 'query_invalid', message, status: 400 });
305
- if (cause instanceof FundingQuotes.ProviderQuoteError) {
306
- const failures = cause.failures.map(FundingQuoteProviders.providerFailure);
307
- const failure = failures[0];
308
- if (failure)
309
- c.set('providerFailure', failure);
310
- if (failures.length > 1)
311
- c.set('providerFailures', failures);
624
+ if (cause instanceof FundingProvider.ProviderQuoteError) {
625
+ if (cause.fundingProviderAttempts.length > 0)
626
+ c.set('fundingProviderAttempts', cause.fundingProviderAttempts);
627
+ if (cause.providerFailure)
628
+ c.set('providerFailure', cause.providerFailure);
629
+ if (cause.providerFailures)
630
+ c.set('providerFailures', cause.providerFailures);
312
631
  return Response.error(c, {
313
632
  code: 'upstream_error',
314
633
  message: 'Quote providers could not complete the request.',
@@ -317,87 +636,912 @@ export function funding(options = {}) {
317
636
  }
318
637
  throw cause;
319
638
  }
320
- finally {
321
- if (attempts.length > 0)
322
- c.set('fundingProviderAttempts', attempts.map(fundingProviderAttempt));
323
- }
324
639
  })
325
640
  .get('/v1/funding/chains', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.describeRoute({
326
- description: 'Lists the source chains and stablecoins you can use when requesting a funding quote.',
327
- operationId: 'listFundingChains',
641
+ description: 'Lists supported source chains and tokens.',
642
+ operationId: 'getFundingChains',
328
643
  responses: OpenApi.responses({
329
644
  success: {
330
645
  description: 'Supported source chains and stablecoins.',
331
646
  example: fundingChainsResponseExample,
332
- schema: schema.listFundingChains.Response,
647
+ schema: schema.getFundingChains.Response,
333
648
  },
334
649
  }),
335
- summary: 'List funding chains',
650
+ summary: 'Get chains',
336
651
  tags: ['Funding'],
337
652
  }), Cache.response({
338
653
  cacheControl: Cache.policies.stable,
339
- name: 'tempo-api:funding-chains:v2',
340
- key: (c) => c.req.url,
341
- }), (c) => {
654
+ key: inventoryKey,
655
+ name: 'tempo-api:funding-chains:v5',
656
+ }), async (c) => {
342
657
  if (Auth.narrowAccess)
343
658
  return Auth.paidAccessError(c);
344
- return c.json(Response.validated(schema.listFundingChains.Response, {
345
- data: FundingQuotes.listChains(),
659
+ const catalog = await FundingCatalog.snapshot(c);
660
+ const providers = c.get('providers').filter(FundingProvider.is);
661
+ return c.json(Response.validated(schema.getFundingChains.Response, {
662
+ data: FundingProvider.getChains({ catalog, providers }),
346
663
  }), 200);
347
664
  })
348
665
  .get('/v1/funding/providers', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.describeRoute({
349
- description: 'Lists funding quote providers and whether live quoting is configured for this deployment.',
350
- operationId: 'listFundingProviders',
666
+ description: 'Lists available transfer providers.',
667
+ operationId: 'getFundingProviders',
351
668
  responses: OpenApi.responses({
352
669
  success: {
353
670
  description: 'Funding quote providers supported by Tempo.',
354
671
  example: providersResponseExample,
355
- schema: schema.listProviders.Response,
672
+ schema: schema.getFundingProviders.Response,
356
673
  },
357
674
  }),
358
- summary: 'List funding providers',
675
+ summary: 'Get providers',
359
676
  tags: ['Funding'],
360
677
  }), Cache.response({
361
678
  cacheControl: Cache.policies.stable,
362
- name: 'tempo-api:funding-providers:v1',
363
- key: (c) => c.req.url,
364
- }), (c) => {
679
+ key: inventoryKey,
680
+ name: 'tempo-api:funding-providers:v4',
681
+ }), async (c) => {
365
682
  if (Auth.narrowAccess)
366
683
  return Auth.paidAccessError(c);
367
- return c.json(Response.validated(schema.listProviders.Response, {
368
- data: FundingQuotes.listProviders({ adapters: options.adapters }),
684
+ const catalog = await FundingCatalog.snapshot(c);
685
+ const providers = c.get('providers').filter(FundingProvider.is);
686
+ return c.json(Response.validated(schema.getFundingProviders.Response, {
687
+ data: FundingProvider.getProviders({ catalog, providers }),
369
688
  }), 200);
689
+ })
690
+ .post('/v1/funding/deposit-addresses', Auth.policy({ apiKey: { scopes: ['funding:write'] } }), OpenApi.validate('header', schema.createFundingDepositAddress.Headers, {
691
+ code: 'idempotency_key_required',
692
+ message: 'Funding deposit address creation requires an `Idempotency-Key` header.',
693
+ }), OpenApi.validate('json', schema.createFundingDepositAddress.Body, {
694
+ code: 'body_invalid',
695
+ message: 'Check the request body and try again.',
696
+ }), OpenApi.describeRoute({
697
+ description: 'Creates or returns a reusable deposit address for funding a Tempo account.',
698
+ operationId: 'createFundingDepositAddress',
699
+ responses: OpenApi.responses({
700
+ errors: {
701
+ 400: { codes: ['body_invalid', 'idempotency_key_required'] },
702
+ 404: {
703
+ codes: ['deposit_address_not_available'],
704
+ description: 'No provider can provision the requested reusable address route.',
705
+ },
706
+ 409: {
707
+ codes: ['idempotency_conflict', 'idempotency_in_progress'],
708
+ description: 'The Idempotency-Key conflicts with an existing or in-flight request.',
709
+ },
710
+ 502: {
711
+ codes: ['upstream_error'],
712
+ description: 'The selected provider could not provision the address.',
713
+ },
714
+ },
715
+ success: {
716
+ description: 'The created or matching reusable funding deposit address and quote.',
717
+ example: createdFundingDepositAddressExample,
718
+ schema: schema.createFundingDepositAddress.Response,
719
+ },
720
+ }),
721
+ summary: 'Create deposit address',
722
+ tags: ['Funding'],
723
+ }), async (c) => {
724
+ if (Auth.narrowAccess)
725
+ return Auth.accessError(c);
726
+ if (OpenApi.narrowValidation)
727
+ return OpenApi.validationError(c, {
728
+ code: 'body_invalid',
729
+ message: 'Check the request body and try again.',
730
+ });
731
+ const principal = Auth.getPrincipal(c);
732
+ const owner = fundingOwner(c);
733
+ if (!owner || principal?.type !== 'api_key')
734
+ return fundingUnauthorized(c);
735
+ c.header('Cache-Control', 'no-store');
736
+ const body = c.req.valid('json');
737
+ const subsidize = body.subsidize ?? false;
738
+ const db = Db.get(c.get('db'));
739
+ const identity = {
740
+ apiKeyId: principal.id,
741
+ keyHash: Idempotency.inputHash(c.req.valid('header')['idempotency-key']),
742
+ requestHash: Idempotency.inputHash({
743
+ body,
744
+ endpoint: 'POST /v1/funding/deposit-addresses',
745
+ }),
746
+ };
747
+ const claim = await FundingIdempotency.claim(db, {
748
+ ...identity,
749
+ ttlMs: idempotencyPendingTtlMs,
750
+ });
751
+ if (claim.type === 'mismatch')
752
+ return Response.error(c, {
753
+ code: 'idempotency_conflict',
754
+ message: 'This Idempotency-Key was already used with different input.',
755
+ status: 409,
756
+ });
757
+ if (claim.type === 'pending')
758
+ return Response.error(c, {
759
+ code: 'idempotency_in_progress',
760
+ message: 'An equivalent funding deposit address creation is still running.',
761
+ status: 409,
762
+ });
763
+ if (claim.type === 'replay') {
764
+ const response = JSON.parse(claim.response);
765
+ return c.json(Response.validated(schema.createFundingDepositAddress.Response, {
766
+ ...response,
767
+ subsidize: response['subsidize'] ?? false,
768
+ }), 200);
769
+ }
770
+ const release = async () => {
771
+ try {
772
+ await FundingIdempotency.release(db, {
773
+ apiKeyId: identity.apiKeyId,
774
+ createdAt: claim.createdAt,
775
+ keyHash: identity.keyHash,
776
+ });
777
+ }
778
+ catch {
779
+ // The pending claim expires on its own; the response stays authoritative.
780
+ }
781
+ };
782
+ const complete = async (database, response) => {
783
+ const validated = Response.validated(schema.createFundingDepositAddress.Response, response);
784
+ const completion = await FundingIdempotency.complete(database, {
785
+ apiKeyId: identity.apiKeyId,
786
+ createdAt: claim.createdAt,
787
+ keyHash: identity.keyHash,
788
+ replayTtlMs: idempotencyReplayTtlMs,
789
+ response: JSON.stringify(validated),
790
+ });
791
+ if (!completion)
792
+ throw new IdempotencyLeaseLostError('Funding deposit address creation lease was lost.');
793
+ return validated;
794
+ };
795
+ const attempts = [];
796
+ const provisioning = { succeeded: claim.type === 'resume' };
797
+ try {
798
+ const selected = await (async () => {
799
+ if (claim.type === 'resume')
800
+ return depositAddressCheckpoint.parse(JSON.parse(claim.response));
801
+ const catalog = await FundingCatalog.snapshot(c);
802
+ const providers = c.get('providers').filter(FundingProvider.is);
803
+ const provisioned = await FundingProvider.createDepositAddress({
804
+ amount: body.amount,
805
+ catalog,
806
+ destinationChainId: c.get('chainId'),
807
+ destinationToken: body.destinationToken,
808
+ onAttempt: (attempt) => attempts.push(attempt),
809
+ providers,
810
+ recipient: body.recipient,
811
+ refundAddress: body.refundAddress,
812
+ sourceChain: body.sourceChain,
813
+ sourceToken: body.sourceToken,
814
+ subsidize,
815
+ });
816
+ if (!provisioned)
817
+ return undefined;
818
+ provisioning.succeeded = true;
819
+ const checkpoint = depositAddressCheckpoint.parse({
820
+ candidate: provisioned.candidate,
821
+ provider: provisioned.provider,
822
+ recipient: provisioned.recipient,
823
+ refundAddress: provisioned.refundAddress,
824
+ result: provisioned.result,
825
+ });
826
+ const stored = await FundingIdempotency.checkpoint(db, {
827
+ apiKeyId: identity.apiKeyId,
828
+ createdAt: claim.createdAt,
829
+ keyHash: identity.keyHash,
830
+ replayTtlMs: idempotencyReplayTtlMs,
831
+ response: JSON.stringify(checkpoint),
832
+ });
833
+ if (!stored)
834
+ throw new IdempotencyLeaseLostError('Funding deposit address creation lease was lost.');
835
+ return checkpoint;
836
+ })();
837
+ if (attempts.length > 0)
838
+ c.set('fundingProviderAttempts', attempts.map(formatAttempt));
839
+ if (!selected) {
840
+ await release();
841
+ return depositAddressNotAvailable(c);
842
+ }
843
+ const { candidate: selectedCandidate, provider, recipient, refundAddress, result, } = selected;
844
+ const feeToken = (side) => side === 'source' ? selectedCandidate.sourceToken : selectedCandidate.destinationToken;
845
+ const created = await db.transaction(async (tx) => {
846
+ const stored = await FundingDepositAddress.createOrGet(tx, {
847
+ apiKeyId: principal.id,
848
+ deliveryStrategy: 'provider',
849
+ environment: owner.environment,
850
+ orgId: owner.orgId,
851
+ ...(owner.projectId === undefined ? {} : { projectId: owner.projectId }),
852
+ providerOutputToken: selectedCandidate.destinationToken,
853
+ providerRequestIds: [result.correlation.requestId],
854
+ providerState: result.correlation.checkEndpoint === undefined
855
+ ? undefined
856
+ : { checkEndpoint: result.correlation.checkEndpoint },
857
+ snapshot: {
858
+ address: result.address,
859
+ destinationChain: selectedCandidate.destinationChain,
860
+ destinationToken: selectedCandidate.destinationToken,
861
+ provider,
862
+ recipient,
863
+ refundAddress,
864
+ sourceChain: selectedCandidate.sourceChain,
865
+ sourceToken: selectedCandidate.sourceToken,
866
+ subsidize,
867
+ },
868
+ });
869
+ const record = FundingDepositAddress.toPublic(stored.record);
870
+ if (stored.type === 'existing')
871
+ return complete(tx, record);
872
+ return complete(tx, {
873
+ ...record,
874
+ destinationAmount: Value.tokenAmount({
875
+ baseUnits: result.destinationAmount,
876
+ currency: selectedCandidate.destinationToken.currency,
877
+ decimals: selectedCandidate.destinationToken.decimals,
878
+ }),
879
+ destinationAmountMin: Value.tokenAmount({
880
+ baseUnits: result.destinationAmountMin,
881
+ currency: selectedCandidate.destinationToken.currency,
882
+ decimals: selectedCandidate.destinationToken.decimals,
883
+ }),
884
+ fees: result.fees.map((fee) => ({
885
+ amount: Value.tokenAmount({
886
+ baseUnits: fee.amount,
887
+ currency: feeToken(fee.side).currency,
888
+ decimals: feeToken(fee.side).decimals,
889
+ }),
890
+ side: fee.side,
891
+ token: feeToken(fee.side),
892
+ type: 'provider',
893
+ })),
894
+ quote: {
895
+ ...(result.expiresAt === undefined ? {} : { expiresAt: result.expiresAt }),
896
+ sampledAt: result.sampledAt,
897
+ },
898
+ sourceAmount: Value.tokenAmount({
899
+ baseUnits: body.amount,
900
+ currency: selectedCandidate.sourceToken.currency,
901
+ decimals: selectedCandidate.sourceToken.decimals,
902
+ }),
903
+ });
904
+ });
905
+ return c.json(created, 200);
906
+ }
907
+ catch (cause) {
908
+ if (!provisioning.succeeded)
909
+ await release();
910
+ if (cause instanceof FundingProvider.InvalidRefundAddressError)
911
+ return Response.error(c, {
912
+ code: 'body_invalid',
913
+ message: 'Invalid `refundAddress`.',
914
+ status: 400,
915
+ });
916
+ if (cause instanceof FundingProvider.UnsupportedSourceChainError)
917
+ return depositAddressNotAvailable(c);
918
+ if (cause instanceof FundingDepositAddress.ConflictError ||
919
+ cause instanceof FundingProvider.ProviderQuoteError) {
920
+ if (cause instanceof FundingDepositAddress.ConflictError)
921
+ return Response.error(c, {
922
+ code: 'upstream_error',
923
+ message: 'The funding provider returned a conflicting deposit address.',
924
+ status: 502,
925
+ });
926
+ if (cause.fundingProviderAttempts.length > 0)
927
+ c.set('fundingProviderAttempts', cause.fundingProviderAttempts);
928
+ if (cause.providerFailure)
929
+ c.set('providerFailure', cause.providerFailure);
930
+ if (cause.providerFailures)
931
+ c.set('providerFailures', cause.providerFailures);
932
+ return Response.error(c, {
933
+ code: 'upstream_error',
934
+ message: 'The funding provider could not provision the deposit address.',
935
+ status: 502,
936
+ });
937
+ }
938
+ throw cause;
939
+ }
940
+ })
941
+ .get('/v1/funding/deposit-addresses/:id{fda_[A-Za-z0-9_-]+}/deposits', Auth.policy({ apiKey: { scopes: ['funding:read'] } }), OpenApi.validate('param', schema.listFundingDepositAddressDeposits.Params, {
942
+ code: 'param_invalid',
943
+ message: 'Check the path parameters and try again.',
944
+ }), OpenApi.validate('query', schema.listFundingDepositAddressDeposits.Query, {
945
+ code: 'query_invalid',
946
+ message: 'Check the query parameters and try again.',
947
+ }), OpenApi.describeRoute({
948
+ description: 'Lists deposits detected for one funding deposit address, newest first.',
949
+ operationId: 'listFundingDepositAddressDeposits',
950
+ responses: OpenApi.responses({
951
+ errors: {
952
+ 400: { codes: ['param_invalid', 'query_invalid'] },
953
+ 404: {
954
+ codes: ['funding_deposit_address_not_found'],
955
+ description: 'No visible funding deposit address exists for the identifier.',
956
+ },
957
+ },
958
+ success: {
959
+ description: 'A page of deposits detected for the address.',
960
+ example: fundingDepositAddressDepositsExample,
961
+ schema: schema.listFundingDepositAddressDeposits.Response,
962
+ },
963
+ }),
964
+ summary: 'List deposits',
965
+ tags: ['Funding'],
966
+ }), async (c) => {
967
+ if (Auth.narrowAccess)
968
+ return Auth.accessError(c);
969
+ if (OpenApi.narrowValidation)
970
+ return OpenApi.validationError(c, {
971
+ code: 'query_invalid',
972
+ message: 'Check the request parameters and try again.',
973
+ });
974
+ const owner = fundingOwner(c);
975
+ if (!owner)
976
+ return fundingUnauthorized(c);
977
+ const db = Db.get(c.get('db'));
978
+ const { id } = c.req.valid('param');
979
+ const { cursor, limit } = c.req.valid('query');
980
+ const decoded = cursor ? Cursor.decode(cursor, ['timestamp', 'id']) : undefined;
981
+ try {
982
+ const address = await FundingDepositAddresses.getOwned(db, owner, id);
983
+ if (!address)
984
+ return Response.error(c, {
985
+ code: 'funding_deposit_address_not_found',
986
+ message: 'Funding deposit address not found',
987
+ status: 404,
988
+ });
989
+ const rows = await FundingDeposits.listByAddress(db, owner, id, {
990
+ ...(decoded
991
+ ? { cursor: { createdAt: String(decoded[0]), id: String(decoded[1]) } }
992
+ : {}),
993
+ limit: limit + 1,
994
+ });
995
+ const page = Cursor.paginate({
996
+ key: (record) => [record.createdAt, record.id],
997
+ limit,
998
+ rows,
999
+ });
1000
+ const data = page.rows.map(FundingDeposit.toPublic);
1001
+ c.header('Cache-Control', Cache.policies.noStore);
1002
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key');
1003
+ return c.json(Response.validated(schema.listFundingDepositAddressDeposits.Response, {
1004
+ data,
1005
+ nextCursor: page.nextCursor,
1006
+ }), 200);
1007
+ }
1008
+ catch (cause) {
1009
+ return Response.upstream(c, cause);
1010
+ }
1011
+ })
1012
+ .get('/v1/funding/deposit-addresses/:id{fda_[A-Za-z0-9_-]+}', Auth.policy({ apiKey: { scopes: ['funding:read'] } }), OpenApi.validate('param', schema.getFundingDepositAddress.Params, {
1013
+ code: 'param_invalid',
1014
+ message: 'Check the path parameters and try again.',
1015
+ }), OpenApi.describeRoute({
1016
+ description: 'Returns one reusable funding deposit address.',
1017
+ operationId: 'getFundingDepositAddress',
1018
+ responses: OpenApi.responses({
1019
+ errors: {
1020
+ 400: { codes: ['param_invalid'] },
1021
+ 404: {
1022
+ codes: ['funding_deposit_address_not_found'],
1023
+ description: 'No visible funding deposit address exists for the identifier.',
1024
+ },
1025
+ },
1026
+ success: {
1027
+ description: 'The requested funding deposit address.',
1028
+ example: fundingDepositAddressExample,
1029
+ schema: schema.getFundingDepositAddress.Response,
1030
+ },
1031
+ }),
1032
+ summary: 'Get deposit address',
1033
+ tags: ['Funding'],
1034
+ }), async (c) => {
1035
+ if (Auth.narrowAccess)
1036
+ return Auth.accessError(c);
1037
+ if (OpenApi.narrowValidation)
1038
+ return OpenApi.validationError(c, {
1039
+ code: 'param_invalid',
1040
+ message: 'Check the path parameters and try again.',
1041
+ });
1042
+ const owner = fundingOwner(c);
1043
+ if (!owner)
1044
+ return fundingUnauthorized(c);
1045
+ const db = Db.get(c.get('db'));
1046
+ const { id } = c.req.valid('param');
1047
+ try {
1048
+ const record = await FundingDepositAddresses.getOwned(db, owner, id);
1049
+ if (!record)
1050
+ return Response.error(c, {
1051
+ code: 'funding_deposit_address_not_found',
1052
+ message: 'Funding deposit address not found',
1053
+ status: 404,
1054
+ });
1055
+ c.header('Cache-Control', Cache.policies.noStore);
1056
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key');
1057
+ return c.json(Response.validated(schema.getFundingDepositAddress.Response, FundingDepositAddress.toPublic(record)), 200);
1058
+ }
1059
+ catch (cause) {
1060
+ return Response.upstream(c, cause);
1061
+ }
1062
+ })
1063
+ .get('/v1/funding/deposits/:id{fdp_[A-Za-z0-9_-]+}', Auth.policy({ apiKey: { scopes: ['funding:read'] } }), OpenApi.validate('param', schema.getFundingDeposit.Params, {
1064
+ code: 'param_invalid',
1065
+ message: 'Check the path parameters and try again.',
1066
+ }), OpenApi.describeRoute({
1067
+ description: 'Returns one detected deposit and its delivery status.',
1068
+ operationId: 'getFundingDeposit',
1069
+ responses: OpenApi.responses({
1070
+ errors: {
1071
+ 400: { codes: ['param_invalid'] },
1072
+ 404: {
1073
+ codes: ['funding_deposit_not_found'],
1074
+ description: 'No visible funding deposit exists for the identifier.',
1075
+ },
1076
+ },
1077
+ success: {
1078
+ description: 'The requested funding deposit.',
1079
+ example: fundingDepositExample,
1080
+ schema: schema.getFundingDeposit.Response,
1081
+ },
1082
+ }),
1083
+ summary: 'Get deposit',
1084
+ tags: ['Funding'],
1085
+ }), fundingEtag, async (c) => {
1086
+ if (Auth.narrowAccess)
1087
+ return Auth.accessError(c);
1088
+ if (OpenApi.narrowValidation)
1089
+ return OpenApi.validationError(c, {
1090
+ code: 'param_invalid',
1091
+ message: 'Check the path parameters and try again.',
1092
+ });
1093
+ const owner = fundingOwner(c);
1094
+ if (!owner)
1095
+ return fundingUnauthorized(c);
1096
+ const db = Db.get(c.get('db'));
1097
+ const { id } = c.req.valid('param');
1098
+ try {
1099
+ const record = await FundingDeposits.getOwned(db, owner, id);
1100
+ if (!record)
1101
+ return Response.error(c, {
1102
+ code: 'funding_deposit_not_found',
1103
+ message: 'Funding deposit not found',
1104
+ status: 404,
1105
+ });
1106
+ c.header('Cache-Control', Cache.policies.state);
1107
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key');
1108
+ return c.json(Response.validated(schema.getFundingDeposit.Response, FundingDeposit.toPublic(record)), 200);
1109
+ }
1110
+ catch (cause) {
1111
+ return Response.upstream(c, cause);
1112
+ }
1113
+ })
1114
+ .get('/v1/funding/transfers', Auth.policy({ apiKey: { scopes: ['funding:read'] } }), OpenApi.validate('query', schema.listFundingTransfers.Query, {
1115
+ code: 'query_invalid',
1116
+ message: 'Check the query parameters and try again.',
1117
+ }), OpenApi.describeRoute({
1118
+ description: 'Lists transfers from newest to oldest.',
1119
+ operationId: 'listFundingTransfers',
1120
+ responses: OpenApi.responses({
1121
+ errors: {
1122
+ 400: { codes: ['query_invalid'] },
1123
+ },
1124
+ success: {
1125
+ description: 'A page of funding transfers.',
1126
+ example: listFundingTransfersResponseExample,
1127
+ schema: schema.listFundingTransfers.Response,
1128
+ },
1129
+ }),
1130
+ summary: 'List transfers',
1131
+ tags: ['Funding'],
1132
+ }), fundingEtag, async (c) => {
1133
+ if (Auth.narrowAccess)
1134
+ return Auth.accessError(c);
1135
+ if (OpenApi.narrowValidation)
1136
+ return OpenApi.validationError(c, {
1137
+ code: 'query_invalid',
1138
+ message: 'Check the query parameters and try again.',
1139
+ });
1140
+ const owner = fundingOwner(c);
1141
+ if (!owner)
1142
+ return fundingUnauthorized(c);
1143
+ const db = Db.get(c.get('db'));
1144
+ const { cursor, include, limit, status } = c.req.valid('query');
1145
+ try {
1146
+ // `totalCount` is opt-in and capped (a capped subquery shares the
1147
+ // list filter); run it concurrently with the page list. Best-effort:
1148
+ // a failure omits `meta` rather than failing the page.
1149
+ const countPromise = include.includes('totalCount')
1150
+ ? FundingTransfers.count(db, owner, { cap: Schema.countCap, status }).catch(() => {
1151
+ c.set('fundingTransferCountFailed', true);
1152
+ return undefined;
1153
+ })
1154
+ : undefined;
1155
+ // Fetch one extra to detect a further page without a second round-trip.
1156
+ const rows = await FundingTransfers.list(db, owner, { cursor, limit: limit + 1, status });
1157
+ const hasMore = rows.length > limit;
1158
+ const data = (hasMore ? rows.slice(0, limit) : rows).map(FundingTransfer.toPublic);
1159
+ const nextCursor = hasMore ? (data[data.length - 1]?.id ?? null) : null;
1160
+ const count = countPromise ? await countPromise : undefined;
1161
+ c.header('Cache-Control', Cache.policies.feed);
1162
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key');
1163
+ return c.json(Response.validated(schema.listFundingTransfers.Response, {
1164
+ data,
1165
+ ...(count !== undefined
1166
+ ? {
1167
+ meta: {
1168
+ totalCountCapped: count > Schema.countCap,
1169
+ totalCount: Math.min(count, Schema.countCap),
1170
+ },
1171
+ }
1172
+ : {}),
1173
+ nextCursor,
1174
+ }), 200);
1175
+ }
1176
+ catch (cause) {
1177
+ return Response.upstream(c, cause);
1178
+ }
1179
+ })
1180
+ .get('/v1/funding/transfers/:id{ftr_[A-Za-z0-9_-]+}', Auth.policy({ apiKey: { scopes: ['funding:read'] } }), OpenApi.validate('param', schema.getFundingTransfer.Params, {
1181
+ code: 'param_invalid',
1182
+ message: 'Check the path parameters and try again.',
1183
+ }), OpenApi.describeRoute({
1184
+ description: 'Returns a transfer by ID.',
1185
+ operationId: 'getFundingTransfer',
1186
+ responses: OpenApi.responses({
1187
+ errors: {
1188
+ 400: { codes: ['param_invalid'] },
1189
+ 404: {
1190
+ codes: ['funding_transfer_not_found'],
1191
+ description: 'No visible funding transfer exists for the identifier.',
1192
+ },
1193
+ },
1194
+ success: {
1195
+ description: 'The requested funding transfer.',
1196
+ example: fundingTransferExample,
1197
+ schema: schema.getFundingTransfer.Response,
1198
+ },
1199
+ }),
1200
+ summary: 'Get transfer',
1201
+ tags: ['Funding'],
1202
+ }), async (c) => {
1203
+ if (Auth.narrowAccess)
1204
+ return Auth.accessError(c);
1205
+ if (OpenApi.narrowValidation)
1206
+ return OpenApi.validationError(c, {
1207
+ code: 'param_invalid',
1208
+ message: 'Check the path parameters and try again.',
1209
+ });
1210
+ const owner = fundingOwner(c);
1211
+ if (!owner)
1212
+ return fundingUnauthorized(c);
1213
+ const db = Db.get(c.get('db'));
1214
+ const { id } = c.req.valid('param');
1215
+ try {
1216
+ // Ownership filters in SQL, so absent and foreign rows are the same 404.
1217
+ const record = await FundingTransfers.getOwned(db, owner, id);
1218
+ if (!record)
1219
+ return Response.error(c, {
1220
+ code: 'funding_transfer_not_found',
1221
+ message: 'Funding transfer not found',
1222
+ status: 404,
1223
+ });
1224
+ c.header('Cache-Control', Cache.policies.noStore);
1225
+ c.header('Vary', 'Accept-Encoding, Authorization, Tempo-API-Key');
1226
+ return c.json(Response.validated(schema.getFundingTransfer.Response, FundingTransfer.toPublic(record)), 200);
1227
+ }
1228
+ catch (cause) {
1229
+ return Response.upstream(c, cause);
1230
+ }
1231
+ })
1232
+ .post('/v1/funding/transfers', Auth.policy({ apiKey: { scopes: ['funding:write'] } }), OpenApi.validate('header', schema.createFundingTransfer.Headers, {
1233
+ code: 'idempotency_key_required',
1234
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
1235
+ }), OpenApi.validate('json', schema.createFundingTransfer.Body, {
1236
+ code: 'body_invalid',
1237
+ message: 'Check the request body and try again.',
1238
+ }), OpenApi.describeRoute({
1239
+ description: 'Creates a transfer to a Tempo account.',
1240
+ operationId: 'createFundingTransfer',
1241
+ responses: OpenApi.responses({
1242
+ errors: {
1243
+ 400: { codes: ['body_invalid', 'idempotency_key_required'] },
1244
+ 404: {
1245
+ codes: ['quote_not_available'],
1246
+ description: 'No provider can prepare the requested route.',
1247
+ },
1248
+ 409: {
1249
+ codes: ['idempotency_conflict', 'idempotency_in_progress'],
1250
+ description: 'The Idempotency-Key conflicts with an existing or in-flight request.',
1251
+ },
1252
+ 502: {
1253
+ codes: ['upstream_error'],
1254
+ description: 'No provider succeeded and at least one failed unexpectedly.',
1255
+ },
1256
+ },
1257
+ success: {
1258
+ description: 'The created funding transfer with its one-time executable action.',
1259
+ example: createdFundingTransferExample,
1260
+ schema: schema.createFundingTransfer.Response,
1261
+ },
1262
+ }),
1263
+ summary: 'Create transfer',
1264
+ tags: ['Funding'],
1265
+ }), async (c) => {
1266
+ if (Auth.narrowAccess)
1267
+ return Auth.accessError(c);
1268
+ if (OpenApi.narrowValidation)
1269
+ return OpenApi.validationError(c, {
1270
+ code: 'body_invalid',
1271
+ message: 'Check the request body and try again.',
1272
+ });
1273
+ const principal = Auth.getPrincipal(c);
1274
+ const owner = fundingOwner(c);
1275
+ if (!owner || principal?.type !== 'api_key')
1276
+ return fundingUnauthorized(c);
1277
+ c.header('Cache-Control', 'no-store');
1278
+ const idempotencyKey = c.req.valid('header')['idempotency-key'];
1279
+ const body = c.req.valid('json');
1280
+ const db = Db.get(c.get('db'));
1281
+ const identity = {
1282
+ apiKeyId: principal.id,
1283
+ keyHash: Idempotency.inputHash(idempotencyKey),
1284
+ requestHash: Idempotency.inputHash(body),
1285
+ };
1286
+ const claim = await FundingIdempotency.claim(db, {
1287
+ ...identity,
1288
+ ttlMs: idempotencyPendingTtlMs,
1289
+ });
1290
+ if (claim.type === 'mismatch')
1291
+ return Response.error(c, {
1292
+ code: 'idempotency_conflict',
1293
+ message: 'This Idempotency-Key was already used with different input.',
1294
+ status: 409,
1295
+ });
1296
+ if (claim.type === 'pending')
1297
+ return Response.error(c, {
1298
+ code: 'idempotency_in_progress',
1299
+ message: 'An equivalent funding transfer creation is still running.',
1300
+ status: 409,
1301
+ });
1302
+ if (claim.type === 'replay')
1303
+ return c.json(JSON.parse(claim.response), 200);
1304
+ const release = async () => {
1305
+ try {
1306
+ await FundingIdempotency.release(db, {
1307
+ apiKeyId: identity.apiKeyId,
1308
+ createdAt: claim.createdAt,
1309
+ keyHash: identity.keyHash,
1310
+ });
1311
+ }
1312
+ catch {
1313
+ // The pending claim expires on its own; the response stays authoritative.
1314
+ }
1315
+ };
1316
+ try {
1317
+ const attempts = [];
1318
+ const catalog = await FundingCatalog.snapshot(c);
1319
+ const providers = c.get('providers').filter(FundingProvider.is);
1320
+ const selected = await FundingProvider.prepareTransfer({
1321
+ catalog,
1322
+ destinationChainId: c.get('chainId'),
1323
+ destinationToken: body.destinationToken,
1324
+ method: 'transaction',
1325
+ mode: body.mode,
1326
+ onAttempt: (attempt) => attempts.push(attempt),
1327
+ providers,
1328
+ recipient: body.recipient,
1329
+ sender: body.sender,
1330
+ slippageBps: body.slippageBps,
1331
+ sourceAmount: body.amount,
1332
+ sourceChain: body.sourceChain,
1333
+ sourceToken: body.sourceToken,
1334
+ });
1335
+ if (attempts.length > 0)
1336
+ c.set('fundingProviderAttempts', attempts.map(formatAttempt));
1337
+ if (!selected) {
1338
+ await release();
1339
+ return quoteNotAvailable(c);
1340
+ }
1341
+ const { candidate, result } = selected;
1342
+ const feeToken = (side) => side === 'source' ? candidate.sourceToken : candidate.destinationToken;
1343
+ const snapshot = {
1344
+ destinationAmount: Value.tokenAmount({
1345
+ baseUnits: result.destinationAmount,
1346
+ currency: candidate.destinationToken.currency,
1347
+ decimals: candidate.destinationToken.decimals,
1348
+ }),
1349
+ destinationAmountMin: Value.tokenAmount({
1350
+ baseUnits: result.destinationAmountMin,
1351
+ currency: candidate.destinationToken.currency,
1352
+ decimals: candidate.destinationToken.decimals,
1353
+ }),
1354
+ destinationChain: candidate.destinationChain,
1355
+ destinationToken: candidate.destinationToken,
1356
+ fees: result.fees.map((fee) => ({
1357
+ amount: Value.tokenAmount({
1358
+ baseUnits: fee.amount,
1359
+ currency: feeToken(fee.side).currency,
1360
+ decimals: feeToken(fee.side).decimals,
1361
+ }),
1362
+ side: fee.side,
1363
+ token: feeToken(fee.side),
1364
+ type: 'provider',
1365
+ })),
1366
+ method: 'transaction',
1367
+ mode: body.mode,
1368
+ provider: candidate.provider,
1369
+ quote: { expiresAt: result.expiresAt, sampledAt: result.sampledAt },
1370
+ recipient: body.recipient,
1371
+ sender: body.sender,
1372
+ sourceAmount: Value.tokenAmount({
1373
+ baseUnits: candidate.sourceAmount.amount,
1374
+ currency: candidate.sourceToken.currency,
1375
+ decimals: candidate.sourceToken.decimals,
1376
+ }),
1377
+ sourceChain: candidate.sourceChain,
1378
+ sourceToken: candidate.sourceToken,
1379
+ };
1380
+ // The transfer row, its version-1 event, and the replay body commit
1381
+ // atomically so a crash cannot leave a claimed key without a replay.
1382
+ const created = await db.transaction(async (tx) => {
1383
+ const record = await FundingTransfer.createIn(tx, {
1384
+ apiKeyId: principal.id,
1385
+ environment: owner.environment,
1386
+ orgId: owner.orgId,
1387
+ projectId: owner.projectId,
1388
+ providerState: result.correlation,
1389
+ snapshot,
1390
+ });
1391
+ const validated = Response.validated(schema.createFundingTransfer.Response, FundingTransfer.toCreated(record, result.action));
1392
+ const completion = await FundingIdempotency.complete(tx, {
1393
+ apiKeyId: identity.apiKeyId,
1394
+ createdAt: claim.createdAt,
1395
+ keyHash: identity.keyHash,
1396
+ replayTtlMs: idempotencyReplayTtlMs,
1397
+ response: JSON.stringify(validated),
1398
+ transferId: record.id,
1399
+ });
1400
+ if (!completion)
1401
+ throw new IdempotencyLeaseLostError('Funding transfer creation lease was lost.');
1402
+ return validated;
1403
+ });
1404
+ return c.json(created, 200);
1405
+ }
1406
+ catch (cause) {
1407
+ await release();
1408
+ if (cause instanceof FundingProvider.InvalidAmountError)
1409
+ return Response.error(c, { code: 'body_invalid', message: 'Invalid `amount`.', status: 400 }); // prettier-ignore
1410
+ if (cause instanceof FundingProvider.UnsupportedSourceChainError)
1411
+ return quoteNotAvailable(c);
1412
+ if (cause instanceof FundingProvider.ProviderQuoteError) {
1413
+ if (cause.fundingProviderAttempts.length > 0)
1414
+ c.set('fundingProviderAttempts', cause.fundingProviderAttempts);
1415
+ if (cause.providerFailure)
1416
+ c.set('providerFailure', cause.providerFailure);
1417
+ if (cause.providerFailures)
1418
+ c.set('providerFailures', cause.providerFailures);
1419
+ return Response.error(c, {
1420
+ code: 'upstream_error',
1421
+ message: 'No funding provider could prepare the transfer.',
1422
+ status: 502,
1423
+ });
1424
+ }
1425
+ throw cause;
1426
+ }
1427
+ })
1428
+ .post('/v1/funding/transfers/vault', Auth.policy({ apiKey: { scopes: ['funding:write'] } }), OpenApi.validate('header', schema.createFundingTransferVault.Headers, {
1429
+ code: 'idempotency_key_required',
1430
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
1431
+ }), OpenApi.validate('json', schema.createFundingTransferVault.Body, {
1432
+ code: 'body_invalid',
1433
+ message: 'Check the request body and try again.',
1434
+ }), OpenApi.describeRoute({
1435
+ description: 'Creates a transfer into a Tempo Earn vault.',
1436
+ operationId: 'createFundingTransferVault',
1437
+ responses: unimplementedFundingTransferResponses,
1438
+ summary: 'Create transfer into vault',
1439
+ tags: ['Funding'],
1440
+ }), (c) => {
1441
+ if (Auth.narrowAccess)
1442
+ return Auth.accessError(c);
1443
+ if (OpenApi.narrowValidation)
1444
+ return OpenApi.validationError(c, {
1445
+ code: 'body_invalid',
1446
+ message: 'Check the request body and try again.',
1447
+ });
1448
+ c.header('Cache-Control', 'no-store');
1449
+ return Response.error(c, {
1450
+ code: 'not_implemented',
1451
+ message: 'Vault funding transfers are not implemented.',
1452
+ status: 501,
1453
+ });
1454
+ })
1455
+ .post('/v1/funding/transfers/zone', Auth.policy({ apiKey: { scopes: ['funding:write'] } }), OpenApi.validate('header', schema.createFundingTransferZone.Headers, {
1456
+ code: 'idempotency_key_required',
1457
+ message: 'Funding transfer creation requires an `Idempotency-Key` header.',
1458
+ }), OpenApi.validate('json', schema.createFundingTransferZone.Body, {
1459
+ code: 'body_invalid',
1460
+ message: 'Check the request body and try again.',
1461
+ }), OpenApi.describeRoute({
1462
+ description: 'Creates a transfer into a Tempo Zone.',
1463
+ operationId: 'createFundingTransferZone',
1464
+ responses: unimplementedFundingTransferResponses,
1465
+ summary: 'Create transfer into zone',
1466
+ tags: ['Funding'],
1467
+ }), (c) => {
1468
+ if (Auth.narrowAccess)
1469
+ return Auth.accessError(c);
1470
+ if (OpenApi.narrowValidation)
1471
+ return OpenApi.validationError(c, {
1472
+ code: 'body_invalid',
1473
+ message: 'Check the request body and try again.',
1474
+ });
1475
+ c.header('Cache-Control', 'no-store');
1476
+ return Response.error(c, {
1477
+ code: 'not_implemented',
1478
+ message: 'Zone funding transfers are not implemented.',
1479
+ status: 501,
1480
+ });
1481
+ });
1482
+ }
1483
+ function quoteNotAvailable(c) {
1484
+ return Response.error(c, {
1485
+ code: 'quote_not_available',
1486
+ message: 'No provider can prepare the requested funding route.',
1487
+ status: 404,
370
1488
  });
371
1489
  }
372
- function fundingProviderAttempt(attempt) {
373
- const operation = FundingQuoteProviders.providerOperation(attempt.provider);
1490
+ function depositAddressNotAvailable(c) {
1491
+ return Response.error(c, {
1492
+ code: 'deposit_address_not_available',
1493
+ message: 'No provider can provision the requested reusable deposit address.',
1494
+ status: 404,
1495
+ });
1496
+ }
1497
+ /** Ownership filter from the API-key principal; other principals get no funding access. */
1498
+ function fundingOwner(c) {
1499
+ const principal = Auth.getPrincipal(c);
1500
+ if (principal?.type !== 'api_key')
1501
+ return null;
1502
+ return {
1503
+ environment: principal.environment,
1504
+ orgId: principal.orgId,
1505
+ projectId: principal.projectId,
1506
+ };
1507
+ }
1508
+ function fundingUnauthorized(c) {
1509
+ return Response.error(c, {
1510
+ code: 'unauthorized',
1511
+ message: 'Tempo could not determine which organization owns this funding resource.',
1512
+ status: 401,
1513
+ });
1514
+ }
1515
+ function formatAttempt(attempt) {
1516
+ const { id } = attempt.provider;
374
1517
  if (attempt.outcome !== 'failed')
375
1518
  return {
376
1519
  durationMs: attempt.durationMs,
377
- id: attempt.provider,
378
- operation,
1520
+ id,
1521
+ operation: attempt.operation,
379
1522
  outcome: attempt.outcome,
380
1523
  };
381
1524
  return {
382
1525
  durationMs: attempt.durationMs,
383
- failure: FundingQuoteProviders.providerFailure({
1526
+ failure: FundingProvider.failure({
384
1527
  cause: attempt.cause,
1528
+ operation: attempt.operation,
385
1529
  provider: attempt.provider,
386
1530
  }).failure,
387
- id: attempt.provider,
388
- operation,
1531
+ id,
1532
+ operation: attempt.operation,
389
1533
  outcome: attempt.outcome,
390
1534
  };
391
1535
  }
392
1536
  // Maps caller-input errors to a specific 400 message; anything else rethrows.
393
1537
  function requestErrorMessage(cause) {
394
- if (cause instanceof FundingQuotes.InvalidAmountError)
1538
+ if (cause instanceof FundingProvider.InvalidAmountError)
395
1539
  return 'Invalid `sourceAmount`.';
396
- if (cause instanceof FundingQuotes.UnsupportedDestinationTokenError)
1540
+ if (cause instanceof FundingProvider.UnsupportedDestinationTokenError)
397
1541
  return 'Unsupported `destinationToken`.';
398
- if (cause instanceof FundingQuotes.UnsupportedProviderError)
1542
+ if (cause instanceof FundingProvider.UnsupportedProviderError)
399
1543
  return 'Unsupported `provider`.';
400
- if (cause instanceof FundingQuotes.UnsupportedSourceChainError)
1544
+ if (cause instanceof FundingProvider.UnsupportedSourceChainError)
401
1545
  return 'Unsupported `sourceChain`.';
402
1546
  return undefined;
403
1547
  }
@@ -407,4 +1551,7 @@ function cacheBypass(request) {
407
1551
  '').toLowerCase();
408
1552
  return directives.includes('no-cache') || directives.includes('no-store');
409
1553
  }
1554
+ class IdempotencyLeaseLostError extends Error {
1555
+ name = 'Funding.IdempotencyLeaseLostError';
1556
+ }
410
1557
  //# sourceMappingURL=funding.js.map