tapimo 0.7.0 → 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 (689) 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 +151 -95
  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 +14377 -10165
  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 +1231 -324
  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.map +1 -1
  78. package/dist/apps/data/routes/fee-amm.js +59 -8
  79. package/dist/apps/data/routes/fee-amm.js.map +1 -1
  80. package/dist/apps/data/routes/funding.d.ts +4092 -387
  81. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  82. package/dist/apps/data/routes/funding.js +1403 -256
  83. package/dist/apps/data/routes/funding.js.map +1 -1
  84. package/dist/apps/data/routes/indexer.d.ts +5 -5
  85. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  86. package/dist/apps/data/routes/indexer.js +19 -2
  87. package/dist/apps/data/routes/indexer.js.map +1 -1
  88. package/dist/apps/data/routes/receipts.d.ts +265 -265
  89. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  90. package/dist/apps/data/routes/receipts.js +11 -11
  91. package/dist/apps/data/routes/receipts.js.map +1 -1
  92. package/dist/apps/data/routes/rpc.d.ts +5 -5
  93. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  94. package/dist/apps/data/routes/rpc.js +211 -22
  95. package/dist/apps/data/routes/rpc.js.map +1 -1
  96. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  97. package/dist/apps/data/routes/tokenlist.d.ts.map +1 -1
  98. package/dist/apps/data/routes/tokenlist.js +49 -9
  99. package/dist/apps/data/routes/tokenlist.js.map +1 -1
  100. package/dist/apps/data/routes/tokens.d.ts +116 -88
  101. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  102. package/dist/apps/data/routes/tokens.js +198 -91
  103. package/dist/apps/data/routes/tokens.js.map +1 -1
  104. package/dist/apps/data/routes/transactions.d.ts +55 -55
  105. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  106. package/dist/apps/data/routes/transactions.js +78 -39
  107. package/dist/apps/data/routes/transactions.js.map +1 -1
  108. package/dist/apps/data/routes/transfers.d.ts +78 -29
  109. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  110. package/dist/apps/data/routes/transfers.js +165 -67
  111. package/dist/apps/data/routes/transfers.js.map +1 -1
  112. package/dist/apps/data/routes/valuation.d.ts +10 -10
  113. package/dist/apps/data/routes/valuation.js +2 -2
  114. package/dist/apps/data/routes/valuation.js.map +1 -1
  115. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  116. package/dist/apps/data/routes/verified-tokens.js +34 -9
  117. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  118. package/dist/apps/data/routes/webhooks.d.ts +5 -3
  119. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  120. package/dist/apps/data/routes/webhooks.js +175 -65
  121. package/dist/apps/data/routes/webhooks.js.map +1 -1
  122. package/dist/apps/data/routes/zones.d.ts +281 -0
  123. package/dist/apps/data/routes/zones.d.ts.map +1 -0
  124. package/dist/apps/data/routes/zones.js +252 -0
  125. package/dist/apps/data/routes/zones.js.map +1 -0
  126. package/dist/apps/docs/reference.js +6 -5
  127. package/dist/apps/docs/reference.js.map +1 -1
  128. package/dist/apps/index.d.ts +2 -1
  129. package/dist/apps/index.d.ts.map +1 -1
  130. package/dist/apps/index.js +2 -1
  131. package/dist/apps/index.js.map +1 -1
  132. package/dist/apps/management/App.d.ts +670 -670
  133. package/dist/apps/management/Billing.d.ts +8 -0
  134. package/dist/apps/management/Billing.d.ts.map +1 -1
  135. package/dist/apps/management/Billing.js +12 -0
  136. package/dist/apps/management/Billing.js.map +1 -1
  137. package/dist/apps/management/Error.d.ts +12 -0
  138. package/dist/apps/management/Error.d.ts.map +1 -0
  139. package/dist/apps/management/Error.js +10 -0
  140. package/dist/apps/management/Error.js.map +1 -0
  141. package/dist/apps/management/routes/api-keys.d.ts +5 -5
  142. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  143. package/dist/apps/management/routes/api-keys.js +2 -8
  144. package/dist/apps/management/routes/api-keys.js.map +1 -1
  145. package/dist/apps/management/routes/billing.d.ts +119 -119
  146. package/dist/apps/management/routes/faucet.d.ts +35 -35
  147. package/dist/apps/management/routes/invitations.d.ts +62 -62
  148. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  149. package/dist/apps/management/routes/invitations.js +4 -10
  150. package/dist/apps/management/routes/invitations.js.map +1 -1
  151. package/dist/apps/management/routes/invite-links.d.ts +30 -30
  152. package/dist/apps/management/routes/me.d.ts +6 -6
  153. package/dist/apps/management/routes/members.d.ts +78 -78
  154. package/dist/apps/management/routes/orgs.d.ts +48 -48
  155. package/dist/apps/management/routes/orgs.d.ts.map +1 -1
  156. package/dist/apps/management/routes/orgs.js +2 -8
  157. package/dist/apps/management/routes/orgs.js.map +1 -1
  158. package/dist/apps/management/routes/projects.d.ts +9 -9
  159. package/dist/apps/management/routes/scopes.js +2 -2
  160. package/dist/apps/management/routes/scopes.js.map +1 -1
  161. package/dist/apps/management/routes/usage.d.ts +80 -80
  162. package/dist/apps/management/routes/verified-token-requests.d.ts +36 -36
  163. package/dist/apps/management/routes/webhooks.d.ts +50 -50
  164. package/dist/apps/management/routes/webhooks.d.ts.map +1 -1
  165. package/dist/apps/management/routes/webhooks.js +15 -3
  166. package/dist/apps/management/routes/webhooks.js.map +1 -1
  167. package/dist/apps/mpp/App.d.ts +55 -56
  168. package/dist/apps/mpp/App.d.ts.map +1 -1
  169. package/dist/apps/mpp/App.js +192 -27
  170. package/dist/apps/mpp/App.js.map +1 -1
  171. package/dist/apps/mpp/Mpp.d.ts +0 -20
  172. package/dist/apps/mpp/Mpp.d.ts.map +1 -1
  173. package/dist/apps/mpp/Mpp.js +0 -24
  174. package/dist/apps/mpp/Mpp.js.map +1 -1
  175. package/dist/apps/mpp/internal/Adapter.d.ts +40 -0
  176. package/dist/apps/mpp/internal/Adapter.d.ts.map +1 -0
  177. package/dist/apps/mpp/internal/Adapter.js +66 -0
  178. package/dist/apps/mpp/internal/Adapter.js.map +1 -0
  179. package/dist/apps/mpp/internal/Error.d.ts +4 -0
  180. package/dist/apps/mpp/internal/Error.d.ts.map +1 -0
  181. package/dist/apps/mpp/internal/Error.js +41 -0
  182. package/dist/apps/mpp/internal/Error.js.map +1 -0
  183. package/dist/apps/mpp/internal/Idempotency.d.ts +33 -0
  184. package/dist/apps/mpp/internal/Idempotency.d.ts.map +1 -0
  185. package/dist/apps/mpp/internal/Idempotency.js +28 -0
  186. package/dist/apps/mpp/internal/Idempotency.js.map +1 -0
  187. package/dist/apps/mpp/internal/Policy.d.ts +46 -0
  188. package/dist/apps/mpp/internal/Policy.d.ts.map +1 -0
  189. package/dist/apps/mpp/internal/Policy.js +57 -0
  190. package/dist/apps/mpp/internal/Policy.js.map +1 -0
  191. package/dist/apps/mpp/internal/ScreenManager.d.ts +27 -0
  192. package/dist/apps/mpp/internal/ScreenManager.d.ts.map +1 -0
  193. package/dist/apps/mpp/internal/ScreenManager.js +18 -0
  194. package/dist/apps/mpp/internal/ScreenManager.js.map +1 -0
  195. package/dist/apps/mpp/internal/Screening.d.ts +35 -0
  196. package/dist/apps/mpp/internal/Screening.d.ts.map +1 -0
  197. package/dist/apps/mpp/internal/Screening.js +20 -0
  198. package/dist/apps/mpp/internal/Screening.js.map +1 -0
  199. package/dist/apps/mpp/internal/Sponsorship.d.ts +36 -0
  200. package/dist/apps/mpp/internal/Sponsorship.d.ts.map +1 -0
  201. package/dist/apps/mpp/internal/Sponsorship.js +103 -0
  202. package/dist/apps/mpp/internal/Sponsorship.js.map +1 -0
  203. package/dist/apps/mpp/internal/Utils.d.ts +7 -0
  204. package/dist/apps/mpp/internal/Utils.d.ts.map +1 -0
  205. package/dist/apps/mpp/internal/Utils.js +24 -0
  206. package/dist/apps/mpp/internal/Utils.js.map +1 -0
  207. package/dist/apps/relay/App.js +184 -24
  208. package/dist/apps/relay/App.js.map +1 -1
  209. package/dist/apps/relay/Sponsorships.d.ts +4 -0
  210. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  211. package/dist/apps/relay/Sponsorships.js +16 -7
  212. package/dist/apps/relay/Sponsorships.js.map +1 -1
  213. package/dist/db/Db.d.ts +20 -0
  214. package/dist/db/Db.d.ts.map +1 -1
  215. package/dist/db/Db.js +342 -0
  216. package/dist/db/Db.js.map +1 -1
  217. package/dist/db/Schema.d.ts +921 -1
  218. package/dist/db/Schema.d.ts.map +1 -1
  219. package/dist/db/Schema.js +269 -1
  220. package/dist/db/Schema.js.map +1 -1
  221. package/dist/db/tables/earnVaults.d.ts +68 -0
  222. package/dist/db/tables/earnVaults.d.ts.map +1 -0
  223. package/dist/db/tables/earnVaults.js +72 -0
  224. package/dist/db/tables/earnVaults.js.map +1 -0
  225. package/dist/db/tables/fundingCatalog.d.ts +56 -0
  226. package/dist/db/tables/fundingCatalog.d.ts.map +1 -0
  227. package/dist/db/tables/fundingCatalog.js +85 -0
  228. package/dist/db/tables/fundingCatalog.js.map +1 -0
  229. package/dist/db/tables/fundingDepositAddresses.d.ts +159 -0
  230. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -0
  231. package/dist/db/tables/fundingDepositAddresses.js +206 -0
  232. package/dist/db/tables/fundingDepositAddresses.js.map +1 -0
  233. package/dist/db/tables/fundingDeposits.d.ts +115 -0
  234. package/dist/db/tables/fundingDeposits.d.ts.map +1 -0
  235. package/dist/db/tables/fundingDeposits.js +100 -0
  236. package/dist/db/tables/fundingDeposits.js.map +1 -0
  237. package/dist/db/tables/fundingIdempotency.d.ts +91 -0
  238. package/dist/db/tables/fundingIdempotency.d.ts.map +1 -0
  239. package/dist/db/tables/fundingIdempotency.js +103 -0
  240. package/dist/db/tables/fundingIdempotency.js.map +1 -0
  241. package/dist/db/tables/fundingTransferEvents.d.ts +12 -0
  242. package/dist/db/tables/fundingTransferEvents.d.ts.map +1 -0
  243. package/dist/db/tables/fundingTransferEvents.js +18 -0
  244. package/dist/db/tables/fundingTransferEvents.js.map +1 -0
  245. package/dist/db/tables/fundingTransferTransactions.d.ts +15 -0
  246. package/dist/db/tables/fundingTransferTransactions.d.ts.map +1 -0
  247. package/dist/db/tables/fundingTransferTransactions.js +27 -0
  248. package/dist/db/tables/fundingTransferTransactions.js.map +1 -0
  249. package/dist/db/tables/fundingTransfers.d.ts +82 -0
  250. package/dist/db/tables/fundingTransfers.d.ts.map +1 -0
  251. package/dist/db/tables/fundingTransfers.js +89 -0
  252. package/dist/db/tables/fundingTransfers.js.map +1 -0
  253. package/dist/db/tables/organizations.d.ts +8 -0
  254. package/dist/db/tables/organizations.d.ts.map +1 -1
  255. package/dist/db/tables/organizations.js +35 -0
  256. package/dist/db/tables/organizations.js.map +1 -1
  257. package/dist/db/tables/projects.d.ts +8 -0
  258. package/dist/db/tables/projects.d.ts.map +1 -1
  259. package/dist/db/tables/projects.js +16 -0
  260. package/dist/db/tables/projects.js.map +1 -1
  261. package/dist/db/tables/requestUsage.d.ts +13 -0
  262. package/dist/db/tables/requestUsage.d.ts.map +1 -1
  263. package/dist/db/tables/requestUsage.js +16 -0
  264. package/dist/db/tables/requestUsage.js.map +1 -1
  265. package/dist/db/tables/sponsoredTransactions.d.ts +4 -2
  266. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  267. package/dist/db/tables/sponsoredTransactions.js +14 -4
  268. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  269. package/dist/db/tables/users.d.ts +8 -0
  270. package/dist/db/tables/users.d.ts.map +1 -1
  271. package/dist/db/tables/users.js +16 -0
  272. package/dist/db/tables/users.js.map +1 -1
  273. package/dist/db/tables/verifiedTokens.d.ts +14 -7
  274. package/dist/db/tables/verifiedTokens.d.ts.map +1 -1
  275. package/dist/db/tables/verifiedTokens.js +9 -7
  276. package/dist/db/tables/verifiedTokens.js.map +1 -1
  277. package/dist/db/tables/webhookSubscriptions.d.ts +31 -1
  278. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  279. package/dist/db/tables/webhookSubscriptions.js +24 -3
  280. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  281. package/dist/handlers/relay.js +108 -108
  282. package/dist/handlers/relay.js.map +1 -1
  283. package/dist/internal/Auth.d.ts +26 -0
  284. package/dist/internal/Auth.d.ts.map +1 -1
  285. package/dist/internal/Auth.js +35 -2
  286. package/dist/internal/Auth.js.map +1 -1
  287. package/dist/internal/Cache.d.ts.map +1 -1
  288. package/dist/internal/Cache.js +16 -10
  289. package/dist/internal/Cache.js.map +1 -1
  290. package/dist/internal/Cursor.js +1 -1
  291. package/dist/internal/Cursor.js.map +1 -1
  292. package/dist/internal/EarnRates.d.ts +89 -0
  293. package/dist/internal/EarnRates.d.ts.map +1 -0
  294. package/dist/internal/EarnRates.js +266 -0
  295. package/dist/internal/EarnRates.js.map +1 -0
  296. package/dist/internal/EarnVaults.d.ts +171 -0
  297. package/dist/internal/EarnVaults.d.ts.map +1 -0
  298. package/dist/internal/EarnVaults.js +547 -0
  299. package/dist/internal/EarnVaults.js.map +1 -0
  300. package/dist/internal/EdgeCache.d.ts +9 -2
  301. package/dist/internal/EdgeCache.d.ts.map +1 -1
  302. package/dist/internal/EdgeCache.js +36 -9
  303. package/dist/internal/EdgeCache.js.map +1 -1
  304. package/dist/internal/Id.d.ts +11 -0
  305. package/dist/internal/Id.d.ts.map +1 -1
  306. package/dist/internal/Id.js +13 -0
  307. package/dist/internal/Id.js.map +1 -1
  308. package/dist/internal/Idempotency.d.ts +83 -0
  309. package/dist/internal/Idempotency.d.ts.map +1 -0
  310. package/dist/internal/Idempotency.js +113 -0
  311. package/dist/internal/Idempotency.js.map +1 -0
  312. package/dist/internal/Log.d.ts +64 -9
  313. package/dist/internal/Log.d.ts.map +1 -1
  314. package/dist/internal/Log.js +29 -7
  315. package/dist/internal/Log.js.map +1 -1
  316. package/dist/internal/MetricSink.d.ts.map +1 -1
  317. package/dist/internal/MetricSink.js +47 -1
  318. package/dist/internal/MetricSink.js.map +1 -1
  319. package/dist/internal/OpenApi.d.ts +1 -1
  320. package/dist/internal/OpenApi.d.ts.map +1 -1
  321. package/dist/internal/OpenApi.js +3 -0
  322. package/dist/internal/OpenApi.js.map +1 -1
  323. package/dist/internal/Provider.d.ts +14 -0
  324. package/dist/internal/Provider.d.ts.map +1 -0
  325. package/dist/internal/Provider.js +5 -0
  326. package/dist/internal/Provider.js.map +1 -0
  327. package/dist/internal/Schema.d.ts +8 -3
  328. package/dist/internal/Schema.d.ts.map +1 -1
  329. package/dist/internal/Schema.js +24 -13
  330. package/dist/internal/Schema.js.map +1 -1
  331. package/dist/internal/Store.d.ts +6 -0
  332. package/dist/internal/Store.d.ts.map +1 -1
  333. package/dist/internal/Store.js +35 -0
  334. package/dist/internal/Store.js.map +1 -1
  335. package/dist/internal/Tidx.d.ts +43 -24
  336. package/dist/internal/Tidx.d.ts.map +1 -1
  337. package/dist/internal/Tidx.js +79 -11
  338. package/dist/internal/Tidx.js.map +1 -1
  339. package/dist/internal/Viem.d.ts +82 -65
  340. package/dist/internal/Viem.d.ts.map +1 -1
  341. package/dist/internal/Viem.js +83 -12
  342. package/dist/internal/Viem.js.map +1 -1
  343. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  344. package/dist/internal/WebhookDestination.js +34 -28
  345. package/dist/internal/WebhookDestination.js.map +1 -1
  346. package/dist/internal/Webhooks.d.ts +9 -0
  347. package/dist/internal/Webhooks.d.ts.map +1 -1
  348. package/dist/internal/Webhooks.js +15 -10
  349. package/dist/internal/Webhooks.js.map +1 -1
  350. package/dist/internal/exchange/Provider.d.ts +219 -0
  351. package/dist/internal/exchange/Provider.d.ts.map +1 -0
  352. package/dist/internal/exchange/Provider.js +117 -0
  353. package/dist/internal/exchange/Provider.js.map +1 -0
  354. package/dist/internal/exchange/index.d.ts +2 -0
  355. package/dist/internal/exchange/index.d.ts.map +1 -0
  356. package/dist/internal/exchange/index.js +2 -0
  357. package/dist/internal/exchange/index.js.map +1 -0
  358. package/dist/internal/exchange/providers/uniswap.d.ts +57 -0
  359. package/dist/internal/exchange/providers/uniswap.d.ts.map +1 -0
  360. package/dist/internal/exchange/providers/uniswap.js +553 -0
  361. package/dist/internal/exchange/providers/uniswap.js.map +1 -0
  362. package/dist/internal/funding/Action.d.ts +55 -0
  363. package/dist/internal/funding/Action.d.ts.map +1 -0
  364. package/dist/internal/funding/Action.js +74 -0
  365. package/dist/internal/funding/Action.js.map +1 -0
  366. package/dist/internal/funding/Catalog.d.ts +107 -0
  367. package/dist/internal/funding/Catalog.d.ts.map +1 -0
  368. package/dist/internal/funding/Catalog.js +270 -0
  369. package/dist/internal/funding/Catalog.js.map +1 -0
  370. package/dist/internal/funding/Chain.d.ts +76 -0
  371. package/dist/internal/funding/Chain.d.ts.map +1 -0
  372. package/dist/internal/funding/Chain.js +38 -0
  373. package/dist/internal/funding/Chain.js.map +1 -0
  374. package/dist/internal/funding/Deposit.d.ts +366 -0
  375. package/dist/internal/funding/Deposit.d.ts.map +1 -0
  376. package/dist/internal/funding/Deposit.js +286 -0
  377. package/dist/internal/funding/Deposit.js.map +1 -0
  378. package/dist/internal/funding/DepositAddress.d.ts +345 -0
  379. package/dist/internal/funding/DepositAddress.d.ts.map +1 -0
  380. package/dist/internal/funding/DepositAddress.js +189 -0
  381. package/dist/internal/funding/DepositAddress.js.map +1 -0
  382. package/dist/internal/funding/Evidence.d.ts +52 -0
  383. package/dist/internal/funding/Evidence.d.ts.map +1 -0
  384. package/dist/internal/funding/Evidence.js +314 -0
  385. package/dist/internal/funding/Evidence.js.map +1 -0
  386. package/dist/internal/funding/Provider.d.ts +1186 -0
  387. package/dist/internal/funding/Provider.d.ts.map +1 -0
  388. package/dist/internal/funding/Provider.js +1081 -0
  389. package/dist/internal/funding/Provider.js.map +1 -0
  390. package/dist/internal/funding/Reconciliation.d.ts +113 -0
  391. package/dist/internal/funding/Reconciliation.d.ts.map +1 -0
  392. package/dist/internal/funding/Reconciliation.js +676 -0
  393. package/dist/internal/funding/Reconciliation.js.map +1 -0
  394. package/dist/internal/funding/Route.d.ts +21 -0
  395. package/dist/internal/funding/Route.d.ts.map +1 -0
  396. package/dist/internal/funding/Route.js +5 -0
  397. package/dist/internal/funding/Route.js.map +1 -0
  398. package/dist/internal/funding/Subsidy.d.ts +113 -0
  399. package/dist/internal/funding/Subsidy.d.ts.map +1 -0
  400. package/dist/internal/funding/Subsidy.js +138 -0
  401. package/dist/internal/funding/Subsidy.js.map +1 -0
  402. package/dist/internal/funding/Token.d.ts +41 -0
  403. package/dist/internal/funding/Token.d.ts.map +1 -0
  404. package/dist/internal/funding/Token.js +22 -0
  405. package/dist/internal/funding/Token.js.map +1 -0
  406. package/dist/internal/funding/Transfer.d.ts +643 -0
  407. package/dist/internal/funding/Transfer.d.ts.map +1 -0
  408. package/dist/internal/funding/Transfer.js +332 -0
  409. package/dist/internal/funding/Transfer.js.map +1 -0
  410. package/dist/internal/funding/index.d.ts +13 -0
  411. package/dist/internal/funding/index.d.ts.map +1 -0
  412. package/dist/internal/funding/index.js +13 -0
  413. package/dist/internal/funding/index.js.map +1 -0
  414. package/dist/internal/funding/providers/across.d.ts +21 -0
  415. package/dist/internal/funding/providers/across.d.ts.map +1 -0
  416. package/dist/internal/funding/providers/across.js +117 -0
  417. package/dist/internal/funding/providers/across.js.map +1 -0
  418. package/dist/internal/funding/providers/relay.d.ts +46 -0
  419. package/dist/internal/funding/providers/relay.d.ts.map +1 -0
  420. package/dist/internal/funding/providers/relay.js +464 -0
  421. package/dist/internal/funding/providers/relay.js.map +1 -0
  422. package/dist/internal/funding/providers/rhino.d.ts +15 -0
  423. package/dist/internal/funding/providers/rhino.d.ts.map +1 -0
  424. package/dist/internal/funding/providers/rhino.js +116 -0
  425. package/dist/internal/funding/providers/rhino.js.map +1 -0
  426. package/dist/internal/funding/providers/squid.d.ts +19 -0
  427. package/dist/internal/funding/providers/squid.d.ts.map +1 -0
  428. package/dist/internal/funding/providers/squid.js +120 -0
  429. package/dist/internal/funding/providers/squid.js.map +1 -0
  430. package/dist/internal/funding/providers/symbiosis.d.ts +20 -0
  431. package/dist/internal/funding/providers/symbiosis.d.ts.map +1 -0
  432. package/dist/internal/funding/providers/symbiosis.js +176 -0
  433. package/dist/internal/funding/providers/symbiosis.js.map +1 -0
  434. package/dist/internal/index.d.ts +5 -1
  435. package/dist/internal/index.d.ts.map +1 -1
  436. package/dist/internal/index.js +5 -1
  437. package/dist/internal/index.js.map +1 -1
  438. package/dist/internal/webhookDestinations/url.js +61 -57
  439. package/dist/internal/webhookDestinations/url.js.map +1 -1
  440. package/dist/providers/index.d.ts +43 -0
  441. package/dist/providers/index.d.ts.map +1 -0
  442. package/dist/providers/index.js +19 -0
  443. package/dist/providers/index.js.map +1 -0
  444. package/package.json +9 -4
  445. package/src/ApiKeys.test.ts +11 -7
  446. package/src/ApiKeys.ts +37 -9
  447. package/src/App.test.ts +85 -10
  448. package/src/App.ts +224 -137
  449. package/src/Assets.ts +29 -4
  450. package/src/Client.test-d.ts +650 -30
  451. package/src/Scope.test.ts +19 -0
  452. package/src/Scope.ts +28 -11
  453. package/src/Webhooks.test.ts +25 -0
  454. package/src/Webhooks.ts +1 -1
  455. package/src/admin/App.test.ts +9 -2
  456. package/src/admin/App.ts +32 -9
  457. package/src/admin/apps/api-keys.test.ts +167 -23
  458. package/src/admin/apps/api-keys.ts +166 -28
  459. package/src/admin/apps/earn-vaults.test.ts +338 -0
  460. package/src/admin/apps/earn-vaults.ts +572 -0
  461. package/src/admin/apps/scopes.test.ts +16 -1
  462. package/src/admin/ui/plugin.ts +2 -2
  463. package/src/admin/ui/src/components/EarnVaultForm.tsx +137 -0
  464. package/src/admin/ui/src/components/MobileProfile.tsx +2 -2
  465. package/src/admin/ui/src/components/Page.tsx +1 -1
  466. package/src/admin/ui/src/components/ThemeToggle.tsx +1 -1
  467. package/src/admin/ui/src/lib/api-keys.ts +37 -7
  468. package/src/admin/ui/src/lib/client.ts +1 -1
  469. package/src/admin/ui/src/lib/config.ts +1 -1
  470. package/src/admin/ui/src/lib/early-access.ts +8 -9
  471. package/src/admin/ui/src/lib/earn-vaults.ts +207 -0
  472. package/src/admin/ui/src/lib/format.ts +13 -0
  473. package/src/admin/ui/src/lib/organizations.test.ts +14 -4
  474. package/src/admin/ui/src/lib/organizations.ts +7 -1
  475. package/src/admin/ui/src/lib/response.ts +22 -0
  476. package/src/admin/ui/src/lib/scopes.test.ts +19 -11
  477. package/src/admin/ui/src/lib/scopes.ts +28 -7
  478. package/src/admin/ui/src/lib/verified-tokens.ts +10 -9
  479. package/src/admin/ui/src/routeTree.gen.ts +70 -7
  480. package/src/admin/ui/src/router.tsx +2 -2
  481. package/src/admin/ui/src/routes/__root.tsx +9 -8
  482. package/src/admin/ui/src/routes/api-keys.tsx +475 -64
  483. package/src/admin/ui/src/routes/early-access.tsx +5 -12
  484. package/src/admin/ui/src/routes/earn.vaults.tsx +348 -0
  485. package/src/admin/ui/src/routes/earn.vaults_.$vaultId.edit.tsx +154 -0
  486. package/src/admin/ui/src/routes/earn.vaults_.new.tsx +190 -0
  487. package/src/admin/ui/src/routes/organizations.tsx +4 -7
  488. package/src/admin/ui/src/routes/organizations_.$orgId.tsx +56 -54
  489. package/src/admin/ui/src/routes/verified-tokens.tsx +4 -4
  490. package/src/admin/ui/vite.config.ts +4 -1
  491. package/src/admin/ui.generated.ts +189 -95
  492. package/src/analytics/Analytics.test.ts +69 -10
  493. package/src/analytics/Analytics.ts +20 -1
  494. package/src/analytics/tables/requestEvents.ts +79 -37
  495. package/src/apps/Zones.test.ts +33 -0
  496. package/src/apps/Zones.ts +40 -0
  497. package/src/apps/composition.test.ts +84 -1
  498. package/src/apps/data/App.test.ts +38 -9
  499. package/src/apps/data/App.ts +96 -33
  500. package/src/apps/data/FxOracle.ts +1 -1
  501. package/src/apps/data/index.ts +0 -1
  502. package/src/apps/data/routes/activities.test.ts +82 -6
  503. package/src/apps/data/routes/activities.ts +131 -71
  504. package/src/apps/data/routes/balances.test.ts +50 -37
  505. package/src/apps/data/routes/balances.ts +5 -5
  506. package/src/apps/data/routes/blocks.test.ts +2 -0
  507. package/src/apps/data/routes/coingecko.test.ts +22 -0
  508. package/src/apps/data/routes/coingecko.ts +84 -48
  509. package/src/apps/data/routes/earn.test.ts +1108 -0
  510. package/src/apps/data/routes/earn.ts +1391 -0
  511. package/src/apps/data/routes/exchanges.test.ts +82 -33
  512. package/src/apps/data/routes/exchanges.ts +842 -227
  513. package/src/apps/data/routes/fee-amm.test.ts +4 -6
  514. package/src/apps/data/routes/fee-amm.ts +69 -12
  515. package/src/apps/data/routes/funding.test.ts +2712 -221
  516. package/src/apps/data/routes/funding.ts +1604 -387
  517. package/src/apps/data/routes/indexer.test.ts +43 -34
  518. package/src/apps/data/routes/indexer.ts +19 -2
  519. package/src/apps/data/routes/receipts.test.ts +5 -3
  520. package/src/apps/data/routes/receipts.ts +13 -11
  521. package/src/apps/data/routes/rpc.test.ts +446 -28
  522. package/src/apps/data/routes/rpc.ts +243 -25
  523. package/src/apps/data/routes/tokenlist.test.ts +15 -0
  524. package/src/apps/data/routes/tokenlist.ts +88 -22
  525. package/src/apps/data/routes/tokens.ts +262 -86
  526. package/src/apps/data/routes/transactions.test.ts +2 -0
  527. package/src/apps/data/routes/transactions.ts +77 -42
  528. package/src/apps/data/routes/transfers.test.ts +166 -4
  529. package/src/apps/data/routes/transfers.ts +216 -78
  530. package/src/apps/data/routes/valuation.test.ts +62 -9
  531. package/src/apps/data/routes/valuation.ts +2 -2
  532. package/src/apps/data/routes/verified-tokens.test.ts +51 -0
  533. package/src/apps/data/routes/verified-tokens.ts +52 -15
  534. package/src/apps/data/routes/webhooks.test.ts +432 -33
  535. package/src/apps/data/routes/webhooks.ts +189 -79
  536. package/src/apps/data/routes/zones.test.ts +473 -0
  537. package/src/apps/data/routes/zones.ts +338 -0
  538. package/src/apps/docs/reference.ts +8 -6
  539. package/src/apps/index.ts +2 -1
  540. package/src/apps/management/Billing.test.ts +29 -0
  541. package/src/apps/management/Billing.ts +23 -0
  542. package/src/apps/management/Error.ts +12 -0
  543. package/src/apps/management/routes/api-keys.test.ts +5 -3
  544. package/src/apps/management/routes/api-keys.ts +2 -9
  545. package/src/apps/management/routes/invitations.ts +4 -11
  546. package/src/apps/management/routes/orgs.ts +2 -9
  547. package/src/apps/management/routes/scopes.test.ts +7 -2
  548. package/src/apps/management/routes/scopes.ts +2 -2
  549. package/src/apps/management/routes/webhooks.test.ts +6 -1
  550. package/src/apps/management/routes/webhooks.ts +15 -3
  551. package/src/apps/mpp/App.ts +276 -29
  552. package/src/apps/mpp/Mpp.test.ts +631 -26
  553. package/src/apps/mpp/Mpp.ts +0 -42
  554. package/src/apps/mpp/internal/Adapter.ts +108 -3
  555. package/src/apps/mpp/internal/Error.test.ts +33 -0
  556. package/src/apps/mpp/internal/Error.ts +44 -6
  557. package/src/apps/mpp/internal/Idempotency.test.ts +213 -0
  558. package/src/apps/mpp/internal/Idempotency.ts +59 -5
  559. package/src/apps/mpp/internal/Policy.test.ts +122 -0
  560. package/src/apps/mpp/internal/Policy.ts +98 -0
  561. package/src/apps/mpp/internal/ScreenManager.test.ts +68 -0
  562. package/src/apps/mpp/internal/ScreenManager.ts +41 -0
  563. package/src/apps/mpp/internal/Screening.ts +40 -3
  564. package/src/apps/mpp/internal/Sponsorship.ts +144 -0
  565. package/src/apps/mpp/internal/Utils.ts +30 -0
  566. package/src/apps/relay/App.test.ts +495 -64
  567. package/src/apps/relay/App.ts +234 -24
  568. package/src/apps/relay/Sponsorships.test.ts +51 -0
  569. package/src/apps/relay/Sponsorships.ts +19 -7
  570. package/src/db/Db.ts +439 -0
  571. package/src/db/Schema.ts +325 -2
  572. package/src/db/tables/earnVaults.test.ts +185 -0
  573. package/src/db/tables/earnVaults.ts +151 -0
  574. package/src/db/tables/fundingCatalog.test.ts +108 -0
  575. package/src/db/tables/fundingCatalog.ts +157 -0
  576. package/src/db/tables/fundingDepositAddresses.test.ts +580 -0
  577. package/src/db/tables/fundingDepositAddresses.ts +376 -0
  578. package/src/db/tables/fundingDeposits.test.ts +261 -0
  579. package/src/db/tables/fundingDeposits.ts +229 -0
  580. package/src/db/tables/fundingIdempotency.test.ts +182 -0
  581. package/src/db/tables/fundingIdempotency.ts +180 -0
  582. package/src/db/tables/fundingTransferEvents.ts +28 -0
  583. package/src/db/tables/fundingTransferTransactions.test.ts +69 -0
  584. package/src/db/tables/fundingTransferTransactions.ts +37 -0
  585. package/src/db/tables/fundingTransfers.test.ts +89 -0
  586. package/src/db/tables/fundingTransfers.ts +153 -0
  587. package/src/db/tables/organizations.test.ts +88 -0
  588. package/src/db/tables/organizations.ts +42 -1
  589. package/src/db/tables/projects.ts +16 -0
  590. package/src/db/tables/requestUsage.ts +23 -0
  591. package/src/db/tables/sponsoredTransactions.test.ts +52 -2
  592. package/src/db/tables/sponsoredTransactions.ts +18 -6
  593. package/src/db/tables/users.ts +16 -0
  594. package/src/db/tables/verifiedTokens.ts +19 -14
  595. package/src/db/tables/webhookSubscriptions.ts +58 -3
  596. package/src/handlers/relay.test.ts +2 -0
  597. package/src/handlers/relay.ts +95 -99
  598. package/src/internal/Auth.test.ts +48 -0
  599. package/src/internal/Auth.ts +61 -2
  600. package/src/internal/Cache.ts +13 -9
  601. package/src/internal/Cursor.test.ts +2 -2
  602. package/src/internal/Cursor.ts +1 -1
  603. package/src/internal/EarnRates.test.ts +125 -0
  604. package/src/internal/EarnRates.ts +409 -0
  605. package/src/internal/EarnVaults.test.ts +195 -0
  606. package/src/internal/EarnVaults.ts +876 -0
  607. package/src/internal/EdgeCache.test.ts +37 -5
  608. package/src/internal/EdgeCache.ts +39 -7
  609. package/src/internal/Id.ts +14 -0
  610. package/src/internal/Idempotency.test.ts +109 -0
  611. package/src/internal/Idempotency.ts +237 -0
  612. package/src/internal/Log.test-d.ts +41 -8
  613. package/src/internal/Log.test.ts +189 -8
  614. package/src/internal/Log.ts +124 -17
  615. package/src/internal/MetricSink.test.ts +244 -4
  616. package/src/internal/MetricSink.ts +51 -1
  617. package/src/internal/OpenApi.ts +3 -0
  618. package/src/internal/Provider.test.ts +17 -0
  619. package/src/internal/Provider.ts +17 -0
  620. package/src/internal/Schema.test.ts +13 -0
  621. package/src/internal/Schema.ts +41 -24
  622. package/src/internal/Store.test.ts +25 -0
  623. package/src/internal/Store.ts +46 -0
  624. package/src/internal/Tidx.local.test.ts +78 -3
  625. package/src/internal/Tidx.test.ts +212 -18
  626. package/src/internal/Tidx.ts +112 -32
  627. package/src/internal/VerifiedTokens.test.ts +15 -0
  628. package/src/internal/Viem.test.ts +170 -17
  629. package/src/internal/Viem.ts +111 -28
  630. package/src/internal/WebhookDestination.ts +25 -23
  631. package/src/internal/Webhooks.test.ts +59 -0
  632. package/src/internal/Webhooks.ts +34 -10
  633. package/src/internal/exchange/Provider.test.ts +216 -0
  634. package/src/internal/exchange/Provider.ts +326 -0
  635. package/src/internal/exchange/index.test.ts +6 -0
  636. package/src/internal/exchange/index.ts +1 -0
  637. package/src/internal/exchange/providers/uniswap.test.ts +122 -0
  638. package/src/internal/exchange/providers/uniswap.ts +682 -0
  639. package/src/internal/funding/Action.test.ts +138 -0
  640. package/src/internal/funding/Action.ts +117 -0
  641. package/src/internal/funding/Catalog.test.ts +311 -0
  642. package/src/internal/funding/Catalog.ts +347 -0
  643. package/src/internal/funding/Chain.test.ts +79 -0
  644. package/src/internal/funding/Chain.ts +120 -0
  645. package/src/internal/funding/Deposit.test.ts +26 -0
  646. package/src/internal/funding/Deposit.ts +453 -0
  647. package/src/internal/funding/DepositAddress.test.ts +18 -0
  648. package/src/internal/funding/DepositAddress.ts +312 -0
  649. package/src/internal/funding/Evidence.test.ts +297 -0
  650. package/src/internal/funding/Evidence.ts +430 -0
  651. package/src/internal/funding/Provider.test.ts +1328 -0
  652. package/src/internal/funding/Provider.ts +1796 -0
  653. package/src/internal/funding/Reconciliation.local.test.ts +504 -0
  654. package/src/internal/funding/Reconciliation.test.ts +2020 -0
  655. package/src/internal/funding/Reconciliation.ts +930 -0
  656. package/src/internal/funding/Route.test.ts +66 -0
  657. package/src/internal/funding/Route.ts +29 -0
  658. package/src/internal/funding/Subsidy.local.test.ts +152 -0
  659. package/src/internal/funding/Subsidy.test.ts +75 -0
  660. package/src/internal/funding/Subsidy.ts +260 -0
  661. package/src/internal/funding/Token.test.ts +47 -0
  662. package/src/internal/funding/Token.ts +59 -0
  663. package/src/internal/funding/Transfer.test.ts +369 -0
  664. package/src/internal/funding/Transfer.ts +522 -0
  665. package/src/internal/funding/index.test.ts +20 -0
  666. package/src/internal/funding/index.ts +12 -0
  667. package/src/internal/funding/providers/across.ts +149 -0
  668. package/src/{apps/data/FundingQuoteProviders.test.ts → internal/funding/providers/index.test.ts} +178 -157
  669. package/src/internal/funding/providers/relay.test.ts +474 -0
  670. package/src/internal/funding/providers/relay.ts +559 -0
  671. package/src/internal/funding/providers/rhino.ts +139 -0
  672. package/src/internal/funding/providers/squid.ts +151 -0
  673. package/src/internal/funding/providers/symbiosis.ts +221 -0
  674. package/src/internal/index.test.ts +5 -1
  675. package/src/internal/index.ts +5 -1
  676. package/src/internal/webhookDestinations/url.ts +49 -45
  677. package/src/providers/index.test.ts +14 -0
  678. package/src/providers/index.ts +54 -0
  679. package/dist/apps/data/FundingQuoteProviders.d.ts +0 -174
  680. package/dist/apps/data/FundingQuoteProviders.d.ts.map +0 -1
  681. package/dist/apps/data/FundingQuoteProviders.js +0 -775
  682. package/dist/apps/data/FundingQuoteProviders.js.map +0 -1
  683. package/dist/internal/FundingQuotes.d.ts +0 -864
  684. package/dist/internal/FundingQuotes.d.ts.map +0 -1
  685. package/dist/internal/FundingQuotes.js +0 -672
  686. package/dist/internal/FundingQuotes.js.map +0 -1
  687. package/src/apps/data/FundingQuoteProviders.ts +0 -1043
  688. package/src/internal/FundingQuotes.test.ts +0 -456
  689. package/src/internal/FundingQuotes.ts +0 -944
@@ -1,11 +1,12 @@
1
1
  import { Hono } from 'hono';
2
2
  import { AbiError, AbiEvent } from 'ox';
3
- import { BaseError, ContractFunctionRevertedError, decodeFunctionData, parseAbi, } from 'viem';
3
+ import { BaseError, ContractFunctionRevertedError, decodeFunctionData, parseAbi, parseEventLogs, } from 'viem';
4
4
  import { Abis, Actions, Addresses, Tick } from 'viem/tempo';
5
5
  import * as z from 'zod/mini';
6
6
  import * as Auth from '../../../internal/Auth.js';
7
7
  import * as Cache from '../../../internal/Cache.js';
8
8
  import * as Cursor from '../../../internal/Cursor.js';
9
+ import * as ExchangeProvider from '../../../internal/exchange/Provider.js';
9
10
  import * as OpenApi from '../../../internal/OpenApi.js';
10
11
  import * as Response from '../../../internal/Response.js';
11
12
  import * as Schema from '../../../internal/Schema.js';
@@ -21,6 +22,8 @@ import * as Valuation from './valuation.js';
21
22
  // this address; the indexer pre-decodes those into the `dex_pairs` table.
22
23
  const stablecoinDex = Addresses.stablecoinDex.toLowerCase();
23
24
  const contractPausedSelector = AbiError.getSelector(AbiError.fromAbi(Abis.tip20, 'ContractPaused'));
25
+ /** Largest amount accepted by TIP-20 and external uint256 provider contracts. */
26
+ const maxProviderAmount = 2n ** 256n - 1n;
24
27
  // `OrderCancelled(uint128 orderId)` — emitted when a maker cancels a resting
25
28
  // order. Used by the orders endpoint to exclude cancelled orders from the
26
29
  // resting set.
@@ -181,19 +184,19 @@ export var schema;
181
184
  const ValuedAmount = z.extend(Schema.TokenAmount, {
182
185
  valuation: z
183
186
  .optional(z.nullable(Valuation.schema.Value))
184
- .check(z.describe('The amount’s nominal value in the requested `denomination`. `null` when the token is ' +
187
+ .check(z.describe('The amount’s nominal value in the requested `valuation.currency`. `null` when the token is ' +
185
188
  'unverified, its display currency has no rate, or rates were unavailable.')),
186
189
  });
187
- /** Schemas for creating an executable native DEX exchange quote. */
190
+ /** Schemas for creating an executable exchange quote. */
188
191
  let createQuote;
189
192
  (function (createQuote) {
190
193
  const DestinationTokenAddress = Schema.tokenAddress(exampleBase);
191
194
  const SourceTokenAddress = Schema.tokenAddress(exampleSourceToken);
192
- /** Positive token amount accepted by the DEX's uint128 arguments. */
195
+ /** Positive token amount accepted by exchange providers. */
193
196
  createQuote.Amount = Schema.DecimalString.check(z.refine((value) => {
194
197
  const amount = BigInt(value);
195
- return amount > 0n && amount <= maxSwapAmount;
196
- }, { error: 'Amount must be between 1 and the maximum uint128 value.' }), z.describe('Positive token amount in the token’s smallest unit, encoded as a decimal string.'), z.meta({ examples: ['1000000'] }));
198
+ return amount > 0n && amount <= maxProviderAmount;
199
+ }, { error: 'Amount must be a positive uint256.' }), z.describe('Positive token amount in the token’s smallest unit, encoded as a decimal string.'), z.meta({ examples: ['1000000'] }));
197
200
  /** Optional token fields that require sources beyond RPC metadata. */
198
201
  createQuote.Include = z
199
202
  .enum(tokenFields)
@@ -204,13 +207,16 @@ export var schema;
204
207
  createQuote.Query = z
205
208
  .strictObject({
206
209
  chainId: Schema.ChainIdQuery,
207
- denomination: Schema.Denomination,
208
210
  include: createQuote.includeQuery,
211
+ 'valuation.currency': Schema.Denomination,
209
212
  })
210
- .check(z.describe('Query parameters for creating a native DEX exchange quote.'));
213
+ .check(z.describe('Query parameters for creating an exchange quote.'));
211
214
  /** Quote request with one pinned side and caller-selected slippage. */
212
215
  createQuote.Request = z
213
216
  .strictObject({
217
+ account: z
218
+ .optional(Schema.Address)
219
+ .check(z.describe('Wallet that will sign and execute the swap.'), z.meta({ examples: ['0x1111111111111111111111111111111111111111'] })),
214
220
  amount: createQuote.Amount.check(z.describe('Pinned amount in base units: source amount for `exactSource`, destination amount for `exactDestination`.')),
215
221
  destinationToken: DestinationTokenAddress.check(z.describe('TIP-20 token the swap receives.')),
216
222
  mode: z
@@ -223,13 +229,13 @@ export var schema;
223
229
  })
224
230
  .check(z.refine((request) => request.sourceToken !== request.destinationToken, {
225
231
  error: 'Source and destination tokens must differ.',
226
- }), z.describe('Request for an executable quote on Tempo’s native stablecoin DEX.'));
232
+ }), z.describe('Request for an executable quote from the configured exchange providers.'));
227
233
  /** One call in the unsigned Tempo transaction plan. */
228
234
  createQuote.Call = z
229
235
  .object({
230
- data: Schema.Hex.check(z.describe('ABI-encoded call data.')),
231
- to: Schema.Address.check(z.describe('Contract or precompile that receives the call.')),
232
- value: Schema.Quantity.check(z.describe('Native token value sent with the call; native DEX swap calls use `0x0`.'), z.meta({ examples: ['0x0'] })),
236
+ data: Schema.Hex.check(z.describe('ABI-encoded call data.'), z.meta({ examples: ['0x095ea7b3'] })),
237
+ to: Schema.Address.check(z.describe('Contract or precompile that receives the call.'), z.meta({ examples: [Addresses.stablecoinDex] })),
238
+ value: Schema.Quantity.check(z.describe('Native token value sent with the call.'), z.meta({ examples: ['0x0'] })),
233
239
  })
234
240
  .check(z.describe('One unsigned call in the Tempo transaction plan.'));
235
241
  const QuoteToken = Schema.describe(z.partial(z.omit(Tokens.schema.Token, { id: true }), {
@@ -242,9 +248,9 @@ export var schema;
242
248
  const SourceToken = z.extend(QuoteToken, {
243
249
  address: SourceTokenAddress.check(z.describe('TIP-20 token the swap spends.')),
244
250
  });
245
- const Transaction = z
251
+ createQuote.Transaction = z
246
252
  .object({
247
- calls: z.array(createQuote.Call).check(z.length(2), z.describe('Approval followed by the native DEX swap call.'), z.meta({
253
+ calls: z.array(createQuote.Call).check(z.minLength(1), z.describe('Calls to execute in order.'), z.meta({
248
254
  examples: [
249
255
  [
250
256
  {
@@ -262,41 +268,161 @@ export var schema;
262
268
  /** Response-level valuation rate provenance. */
263
269
  createQuote.Meta = z
264
270
  .object({
265
- pricing: z
271
+ valuation: z
266
272
  .optional(Valuation.schema.Pricing)
267
273
  .check(z.describe('Rate provenance for amount valuations. Present when conversion rates were consulted.')),
268
274
  })
269
275
  .check(z.describe('Response-level resources attached to this quote.'));
270
- /** Native DEX quote plus the approval and swap calls needed to execute it. */
271
- createQuote.Response = z
272
- .discriminatedUnion('mode', [
273
- z.object({
274
- destinationAmount: ValuedAmount.check(z.describe('Quoted destination amount.')),
275
- destinationAmountMin: ValuedAmount.check(z.describe('Minimum destination amount after slippage.')),
276
- destinationToken: DestinationToken,
277
- meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
278
- mode: z
279
- .literal('exactSource')
280
- .check(z.describe('The source amount is fixed and the destination has a minimum.'), z.meta({ examples: ['exactSource'] })),
281
- sourceAmount: ValuedAmount.check(z.describe('Exact source amount.')),
282
- sourceToken: SourceToken.check(z.describe('Token spent by the swap.')),
283
- transaction: Transaction,
284
- }),
285
- z.object({
286
- destinationAmount: ValuedAmount.check(z.describe('Exact destination amount.')),
287
- destinationToken: DestinationToken.check(z.describe('Token received by the swap.')),
288
- meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
289
- mode: z
290
- .literal('exactDestination')
291
- .check(z.describe('The destination amount is fixed and the source has a maximum.'), z.meta({ examples: ['exactDestination'] })),
292
- sourceAmount: ValuedAmount.check(z.describe('Quoted source amount.')),
293
- sourceAmountMax: ValuedAmount.check(z.describe('Maximum source amount after slippage.')),
294
- sourceToken: SourceToken,
295
- transaction: Transaction,
276
+ /** Provider-neutral EIP-712 payload to sign before finalizing a quote. */
277
+ createQuote.TypedData = z
278
+ .object({
279
+ domain: z.record(z.string(), z.unknown()).check(z.describe('EIP-712 signing domain.'), z.meta({
280
+ examples: [
281
+ {
282
+ chainId: 4217,
283
+ name: 'Permit2',
284
+ verifyingContract: '0x000000000022d473030f116ddee9f6b43ac78ba3',
285
+ },
286
+ ],
287
+ })),
288
+ message: z.record(z.string(), z.unknown()).check(z.describe('Values encoded by the primary EIP-712 type.'), z.meta({
289
+ examples: [
290
+ {
291
+ details: {
292
+ amount: '1000000',
293
+ expiration: '4102444800',
294
+ nonce: '0',
295
+ token: exampleSourceToken,
296
+ },
297
+ sigDeadline: '4102444800',
298
+ spender: '0x1febb76be10aaf3a1402f04e8e835f2c382f7914',
299
+ },
300
+ ],
301
+ })),
302
+ primaryType: z
303
+ .string()
304
+ .check(z.minLength(1))
305
+ .check(z.describe('Root EIP-712 type.'), z.meta({ examples: ['PermitSingle'] })),
306
+ types: z
307
+ .record(z.string(), z.array(z.strictObject({
308
+ name: z.string(),
309
+ type: z.string(),
310
+ })))
311
+ .check(z.describe('EIP-712 type definitions keyed by type name.'), z.meta({
312
+ examples: [
313
+ {
314
+ PermitDetails: [
315
+ { name: 'token', type: 'address' },
316
+ { name: 'amount', type: 'uint160' },
317
+ { name: 'expiration', type: 'uint48' },
318
+ { name: 'nonce', type: 'uint48' },
319
+ ],
320
+ PermitSingle: [
321
+ { name: 'details', type: 'PermitDetails' },
322
+ { name: 'spender', type: 'address' },
323
+ { name: 'sigDeadline', type: 'uint256' },
324
+ ],
325
+ },
326
+ ],
327
+ })),
328
+ })
329
+ .check(z.describe('EIP-712 payload the wallet must sign before execution can continue.'));
330
+ const Provider = z
331
+ .string()
332
+ .check(z.describe('Provider selected for this route.'), z.meta({ examples: ['nativeDex'] }));
333
+ const Quote = {
334
+ gasEstimate: Schema.DecimalString.check(z.describe('Estimated network fee in the chain native token’s base unit.'), z.meta({ examples: ['150000000000000'] })),
335
+ provider: Provider,
336
+ };
337
+ const ApprovalRequired = {
338
+ approval: z.object({
339
+ calls: z.array(createQuote.Call).check(z.minLength(1), z.describe('Approval calls to confirm before requesting a fresh quote.'), z.meta({
340
+ examples: [
341
+ [
342
+ {
343
+ data: exampleApprovalCall.data,
344
+ to: exampleApprovalCall.to,
345
+ value: '0x0',
346
+ },
347
+ ],
348
+ ],
349
+ })),
296
350
  }),
351
+ status: z
352
+ .literal('approvalRequired')
353
+ .check(z.describe('Confirm the approvals, then request a fresh quote.'), z.meta({ examples: ['approvalRequired'] })),
354
+ };
355
+ const Ready = {
356
+ status: z
357
+ .literal('ready')
358
+ .check(z.describe('The returned calls can be executed now.'), z.meta({ examples: ['ready'] })),
359
+ transaction: createQuote.Transaction,
360
+ };
361
+ const SignatureRequired = {
362
+ continuation: z
363
+ .string()
364
+ .check(z.minLength(1), z.describe('Opaque state supplied to the finalization endpoint within 30 seconds.'), z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] })),
365
+ status: z
366
+ .literal('signatureRequired')
367
+ .check(z.describe('Sign the typed data before final calldata can be built.'), z.meta({ examples: ['signatureRequired'] })),
368
+ typedData: createQuote.TypedData,
369
+ };
370
+ const ExactSource = {
371
+ destinationAmount: ValuedAmount.check(z.describe('Quoted destination amount.')),
372
+ destinationAmountMin: ValuedAmount.check(z.describe('Minimum destination amount after slippage.')),
373
+ destinationToken: DestinationToken,
374
+ meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
375
+ mode: z
376
+ .literal('exactSource')
377
+ .check(z.describe('The source amount is fixed and the destination has a minimum.'), z.meta({ examples: ['exactSource'] })),
378
+ sourceAmount: ValuedAmount.check(z.describe('Exact source amount.')),
379
+ sourceToken: SourceToken.check(z.describe('Token spent by the swap.')),
380
+ };
381
+ const ExactDestination = {
382
+ destinationAmount: ValuedAmount.check(z.describe('Exact destination amount.')),
383
+ destinationToken: DestinationToken.check(z.describe('Token received by the swap.')),
384
+ meta: z.optional(createQuote.Meta).check(z.describe('Valuation rate provenance for this quote.')),
385
+ mode: z
386
+ .literal('exactDestination')
387
+ .check(z.describe('The destination amount is fixed and the source has a maximum.'), z.meta({ examples: ['exactDestination'] })),
388
+ sourceAmount: ValuedAmount.check(z.describe('Quoted source amount.')),
389
+ sourceAmountMax: ValuedAmount.check(z.describe('Maximum source amount after slippage.')),
390
+ sourceToken: SourceToken,
391
+ };
392
+ /** Provider-neutral quote and the action needed to execute it. */
393
+ createQuote.Response = z
394
+ .union([
395
+ z.object({ ...ApprovalRequired, ...ExactSource, ...Quote }),
396
+ z.object({ ...ExactSource, ...Quote, ...Ready }),
397
+ z.object({ ...ExactSource, ...Quote, ...SignatureRequired }),
398
+ z.object({ ...ApprovalRequired, ...ExactDestination, ...Quote }),
399
+ z.object({ ...ExactDestination, ...Quote, ...Ready }),
400
+ z.object({ ...ExactDestination, ...Quote, ...SignatureRequired }),
297
401
  ])
298
- .check(z.describe('Executable native DEX quote with slippage-protected calls.'));
402
+ .check(z.describe('Provider-neutral exchange quote with its next execution action.'));
299
403
  })(createQuote = schema.createQuote || (schema.createQuote = {}));
404
+ /** Schemas for finishing a quote after a provider-requested signature. */
405
+ let executeQuote;
406
+ (function (executeQuote) {
407
+ /** Signed continuation request. */
408
+ executeQuote.Request = z.strictObject({
409
+ account: Schema.Address.check(z.describe('Wallet that signed and will execute the swap.'), z.meta({ examples: ['0x1111111111111111111111111111111111111111'] })),
410
+ continuation: z
411
+ .string()
412
+ .check(z.minLength(1), z.maxLength(100_000), z.describe('Opaque state returned by the quote request.'), z.meta({ examples: ['eyJwcm92aWRlciI6InVuaXN3YXAifQ'] })),
413
+ provider: z
414
+ .string()
415
+ .check(z.minLength(1), z.describe('Provider that issued the continuation.'), z.meta({ examples: ['uniswap'] })),
416
+ signature: Schema.Hex.check(z.refine((value) => value.length === 132, { error: 'Signature must be 65 bytes.' }), z.describe('65-byte EIP-712 signature requested by the quote.'), z.meta({ examples: [`0x${'11'.repeat(65)}`] })),
417
+ });
418
+ /** Final transaction plan. */
419
+ executeQuote.Response = z.object({
420
+ provider: z
421
+ .string()
422
+ .check(z.describe('Provider that built the transaction.'), z.meta({ examples: ['uniswap'] })),
423
+ transaction: createQuote.Transaction,
424
+ });
425
+ })(executeQuote = schema.executeQuote || (schema.executeQuote = {}));
300
426
  /** Schemas for the getPairs operation. */
301
427
  let getPairs;
302
428
  (function (getPairs) {
@@ -408,7 +534,6 @@ export var schema;
408
534
  'blockNumber.to': Schema.blockNumberBound('swaps', 'to'),
409
535
  chainId: Schema.ChainIdQuery,
410
536
  cursor: Schema.Cursor,
411
- denomination: Schema.Denomination,
412
537
  include: getSwaps.includeQuery,
413
538
  limit: Schema.Limit,
414
539
  maker: z
@@ -426,6 +551,7 @@ export var schema;
426
551
  transactionHash: z
427
552
  .optional(Schema.Hash)
428
553
  .check(z.describe('Only include swaps included in this transaction hash.')),
554
+ 'valuation.currency': Schema.Denomination,
429
555
  })
430
556
  .check(z.describe('Query parameters for swap feed requests. Cursor-paginated only — a batched ' +
431
557
  'transaction expands one fill group into a variable number of swap rows, so a ' +
@@ -503,7 +629,7 @@ export var schema;
503
629
  /** Page-level resources: valuation rate provenance. */
504
630
  getSwaps.Meta = z
505
631
  .object({
506
- pricing: z
632
+ valuation: z
507
633
  .optional(Valuation.schema.Pricing)
508
634
  .check(z.describe('Rate provenance for amount valuations. Present when conversion rates were ' +
509
635
  'consulted; absent when every value was identity-valued or rates were unavailable.')),
@@ -953,19 +1079,19 @@ export function exchanges(options = {}) {
953
1079
  code: 'body_invalid',
954
1080
  message: 'Invalid request body',
955
1081
  }), OpenApi.describeRoute({
956
- description: 'Creates a priced exchange preview on Tempo’s native stablecoin DEX with unsigned approval and swap calls. This endpoint does not submit a transaction.',
1082
+ description: 'Attempts exchange providers in priority order and returns the first executable quote. This endpoint does not submit a transaction.',
957
1083
  operationId: 'createExchangeQuote',
958
1084
  responses: OpenApi.responses({
959
1085
  errors: {
960
1086
  400: { codes: ['body_invalid', 'query_invalid', 'quote_amount_out_of_range'] },
961
1087
  404: {
962
1088
  codes: ['quote_not_available'],
963
- description: 'The native DEX cannot price an executable exchange for these terms.',
1089
+ description: 'No configured provider can price an executable exchange for these terms.',
964
1090
  },
965
1091
  502: 'The Tempo RPC could not quote the swap or resolve token metadata.',
966
1092
  },
967
1093
  success: {
968
- description: 'A native DEX quote and the unsigned calls needed to execute it.',
1094
+ description: 'A provider-neutral quote and its next execution action.',
969
1095
  schema: schema.createQuote.Response,
970
1096
  },
971
1097
  }),
@@ -985,8 +1111,8 @@ export function exchanges(options = {}) {
985
1111
  message: 'Invalid request body',
986
1112
  });
987
1113
  const request = c.req.valid('json');
988
- const options = c.req.valid('query');
989
- const chainId = options.chainId ?? c.get('chainId');
1114
+ const query = c.req.valid('query');
1115
+ const chainId = query.chainId ?? c.get('chainId');
990
1116
  const client = c.get('getClient')(chainId);
991
1117
  const amount = BigInt(request.amount);
992
1118
  const slippageBps = BigInt(request.slippageBps);
@@ -994,7 +1120,7 @@ export function exchanges(options = {}) {
994
1120
  try {
995
1121
  // Value quoted amounts via their curated display currency; snapshot
996
1122
  // or rate failures degrade the values to `null`, never the quote.
997
- const denomination = options.denomination ?? 'USD';
1123
+ const denomination = query['valuation.currency'] ?? 'USD';
998
1124
  const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined);
999
1125
  const rates = await Valuation.ratesFor(c, {
1000
1126
  currencies: snapshot
@@ -1019,6 +1145,8 @@ export function exchanges(options = {}) {
1019
1145
  token: snapshot?.byAddress.get(address.toLowerCase()),
1020
1146
  }),
1021
1147
  });
1148
+ if (options.nativeDex === false || amount > maxSwapAmount)
1149
+ throw new ExchangeProvider.RouteUnavailableError();
1022
1150
  if (request.mode === 'exactSource') {
1023
1151
  const destinationAmount = await Actions.dex.getSellQuote(client, {
1024
1152
  amountIn: amount,
@@ -1026,7 +1154,7 @@ export function exchanges(options = {}) {
1026
1154
  tokenOut: request.destinationToken,
1027
1155
  });
1028
1156
  if (destinationAmount === 0n)
1029
- return quoteNotAvailable(c);
1157
+ throw new ExchangeProvider.RouteUnavailableError();
1030
1158
  const minimumAmount = (destinationAmount * (slippageDenominator - slippageBps) + slippageDenominator - 1n) /
1031
1159
  slippageDenominator;
1032
1160
  const approve = Actions.token.approve.call(client, {
@@ -1040,10 +1168,19 @@ export function exchanges(options = {}) {
1040
1168
  tokenIn: request.sourceToken,
1041
1169
  tokenOut: request.destinationToken,
1042
1170
  });
1043
- const tokensByAddress = await resolveTokensByAddress(c, {
1171
+ const calls = [
1172
+ { data: approve.data, to: approve.to, value: 0n },
1173
+ { data: swap.data, to: swap.to, value: 0n },
1174
+ ];
1175
+ const gasUnits = await client.estimateGas({
1176
+ ...(request.account ? { account: request.account } : {}),
1177
+ calls,
1178
+ });
1179
+ const gasPrice = await client.getGasPrice();
1180
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1044
1181
  addresses: [request.destinationToken, request.sourceToken],
1045
1182
  chainId,
1046
- include: options.include,
1183
+ include: query.include,
1047
1184
  });
1048
1185
  const destinationToken = tokensByAddress.get(request.destinationToken);
1049
1186
  const sourceToken = tokensByAddress.get(request.sourceToken);
@@ -1056,18 +1193,18 @@ export function exchanges(options = {}) {
1056
1193
  ...destinationToken,
1057
1194
  address: request.destinationToken,
1058
1195
  },
1059
- ...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
1196
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
1197
+ gasEstimate: gasCost({ gasPrice, gasUnits }),
1060
1198
  mode: request.mode,
1199
+ provider: 'nativeDex',
1061
1200
  sourceAmount: valued(request.amount, request.sourceToken, sourceToken),
1062
1201
  sourceToken: {
1063
1202
  ...sourceToken,
1064
1203
  address: request.sourceToken,
1065
1204
  },
1205
+ status: 'ready',
1066
1206
  transaction: {
1067
- calls: [
1068
- { data: approve.data, to: approve.to, value: '0x0' },
1069
- { data: swap.data, to: swap.to, value: '0x0' },
1070
- ],
1207
+ calls: calls.map((call) => ({ ...call, value: '0x0' })),
1071
1208
  chainId,
1072
1209
  },
1073
1210
  }), 200);
@@ -1078,14 +1215,11 @@ export function exchanges(options = {}) {
1078
1215
  tokenOut: request.destinationToken,
1079
1216
  });
1080
1217
  if (sourceAmount === 0n)
1081
- return quoteNotAvailable(c);
1082
- const maximumAmount = (sourceAmount * (slippageDenominator + slippageBps)) / slippageDenominator;
1218
+ throw new ExchangeProvider.RouteUnavailableError();
1219
+ const maximumAmount = (sourceAmount * (slippageDenominator + slippageBps) + slippageDenominator - 1n) /
1220
+ slippageDenominator;
1083
1221
  if (maximumAmount > maxSwapAmount)
1084
- return Response.error(c, {
1085
- code: 'quote_amount_out_of_range',
1086
- message: 'Slippage-adjusted source amount exceeds the native DEX limit',
1087
- status: 400,
1088
- });
1222
+ throw new NativeDexAmountOutOfRangeError();
1089
1223
  const approve = Actions.token.approve.call(client, {
1090
1224
  amount: maximumAmount,
1091
1225
  spender: Addresses.stablecoinDex,
@@ -1097,10 +1231,19 @@ export function exchanges(options = {}) {
1097
1231
  tokenIn: request.sourceToken,
1098
1232
  tokenOut: request.destinationToken,
1099
1233
  });
1100
- const tokensByAddress = await resolveTokensByAddress(c, {
1234
+ const calls = [
1235
+ { data: approve.data, to: approve.to, value: 0n },
1236
+ { data: swap.data, to: swap.to, value: 0n },
1237
+ ];
1238
+ const gasUnits = await client.estimateGas({
1239
+ ...(request.account ? { account: request.account } : {}),
1240
+ calls,
1241
+ });
1242
+ const gasPrice = await client.getGasPrice();
1243
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1101
1244
  addresses: [request.destinationToken, request.sourceToken],
1102
1245
  chainId,
1103
- include: options.include,
1246
+ include: query.include,
1104
1247
  });
1105
1248
  const destinationToken = tokensByAddress.get(request.destinationToken);
1106
1249
  const sourceToken = tokensByAddress.get(request.sourceToken);
@@ -1112,34 +1255,184 @@ export function exchanges(options = {}) {
1112
1255
  ...destinationToken,
1113
1256
  address: request.destinationToken,
1114
1257
  },
1115
- ...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
1258
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
1259
+ gasEstimate: gasCost({ gasPrice, gasUnits }),
1116
1260
  mode: request.mode,
1261
+ provider: 'nativeDex',
1117
1262
  sourceAmount: valued(sourceAmount, request.sourceToken, sourceToken),
1118
1263
  sourceAmountMax: valued(maximumAmount, request.sourceToken, sourceToken),
1119
1264
  sourceToken: {
1120
1265
  ...sourceToken,
1121
1266
  address: request.sourceToken,
1122
1267
  },
1268
+ status: 'ready',
1123
1269
  transaction: {
1124
- calls: [
1125
- { data: approve.data, to: approve.to, value: '0x0' },
1126
- { data: swap.data, to: swap.to, value: '0x0' },
1127
- ],
1270
+ calls: calls.map((call) => ({ ...call, value: '0x0' })),
1128
1271
  chainId,
1129
1272
  },
1130
1273
  }), 200);
1131
1274
  }
1132
1275
  catch (cause) {
1133
- if (request.mode === 'exactSource' && isQuoteAmountOutOfRange(cause))
1276
+ if (cause instanceof Valuation.UnsupportedDenominationError)
1277
+ return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
1278
+ const amountOutOfRange = cause instanceof NativeDexAmountOutOfRangeError ||
1279
+ (request.mode === 'exactSource' && isQuoteAmountOutOfRange(cause));
1280
+ const providers = c.get('providers').filter(ExchangeProvider.is);
1281
+ if (amountOutOfRange && providers.length === 0)
1134
1282
  return Response.error(c, {
1135
1283
  code: 'quote_amount_out_of_range',
1136
1284
  message: 'Quote amount exceeds the native DEX limit',
1137
1285
  status: 400,
1138
1286
  });
1139
- if (isQuoteUnavailable(cause))
1287
+ if (!(cause instanceof ExchangeProvider.RouteUnavailableError) &&
1288
+ !isQuoteUnavailable(cause) &&
1289
+ !amountOutOfRange)
1290
+ return Response.upstream(c, cause);
1291
+ if (!request.account)
1140
1292
  return quoteNotAvailable(c);
1141
- if (cause instanceof Valuation.UnsupportedDenominationError)
1142
- return Response.error(c, { code: 'query_invalid', message: cause.message, status: 400 });
1293
+ for (const provider of providers)
1294
+ try {
1295
+ const quote = await provider.quote({
1296
+ account: request.account,
1297
+ amount: request.amount,
1298
+ chainId,
1299
+ destinationToken: request.destinationToken,
1300
+ mode: request.mode,
1301
+ slippageBps: request.slippageBps,
1302
+ sourceToken: request.sourceToken,
1303
+ }, c.req.raw.signal);
1304
+ if (quote.status === 'ready')
1305
+ await validateProviderCalls(client, {
1306
+ account: request.account,
1307
+ calls: quote.transaction.calls,
1308
+ execution: providerExecution({ quote, request }),
1309
+ });
1310
+ const [gasPrice, gasUnits] = await Promise.all([
1311
+ client.getGasPrice(),
1312
+ quote.status === 'approvalRequired'
1313
+ ? client.estimateGas({
1314
+ account: request.account,
1315
+ calls: quote.approval.calls.map((call) => ({
1316
+ data: call.data,
1317
+ to: call.to,
1318
+ value: BigInt(call.value),
1319
+ })),
1320
+ })
1321
+ : Promise.resolve(BigInt(quote.gasUnits)),
1322
+ ]);
1323
+ return c.json(Response.validated(schema.createQuote.Response, await providerQuoteResponse(c, {
1324
+ chainId,
1325
+ gasPrice,
1326
+ gasUnits,
1327
+ include: query.include,
1328
+ oracle,
1329
+ query,
1330
+ quote,
1331
+ request,
1332
+ provider,
1333
+ })), 200);
1334
+ }
1335
+ catch (error) {
1336
+ if (error instanceof ExchangeProvider.RouteUnavailableError)
1337
+ continue;
1338
+ const failure = ExchangeProvider.failure(error, {
1339
+ chainId,
1340
+ operation: 'quote',
1341
+ provider,
1342
+ });
1343
+ if (failure)
1344
+ c.set('providerFailure', failure);
1345
+ return Response.upstream(c, error);
1346
+ }
1347
+ return quoteNotAvailable(c);
1348
+ }
1349
+ })
1350
+ .post('/v1/exchange/quotes/execute', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.createQuote.Query, {
1351
+ code: 'query_invalid',
1352
+ message: 'Invalid query parameters',
1353
+ }), OpenApi.validate('json', schema.executeQuote.Request, {
1354
+ code: 'body_invalid',
1355
+ message: 'Invalid request body',
1356
+ }), OpenApi.describeRoute({
1357
+ description: 'Finishes a provider quote after the wallet supplies the requested typed-data signature. This endpoint does not submit a transaction.',
1358
+ operationId: 'finalizeExchangeQuote',
1359
+ responses: OpenApi.responses({
1360
+ errors: {
1361
+ 400: {
1362
+ codes: [
1363
+ 'body_invalid',
1364
+ 'query_invalid',
1365
+ 'swap_continuation_invalid',
1366
+ 'swap_provider_invalid',
1367
+ ],
1368
+ },
1369
+ 502: 'The selected provider could not build the swap right now.',
1370
+ },
1371
+ success: {
1372
+ description: 'The final unsigned calls needed to execute the swap.',
1373
+ schema: schema.executeQuote.Response,
1374
+ },
1375
+ }),
1376
+ summary: 'Finalize quote',
1377
+ tags: ['Exchange'],
1378
+ }), async (c) => {
1379
+ if (Auth.narrowAccess)
1380
+ return Auth.paidAccessError(c);
1381
+ if (OpenApi.narrowValidation)
1382
+ return OpenApi.validationError(c, {
1383
+ code: 'query_invalid',
1384
+ message: 'Invalid query parameters',
1385
+ });
1386
+ if (OpenApi.narrowValidation)
1387
+ return OpenApi.validationError(c, {
1388
+ code: 'body_invalid',
1389
+ message: 'Invalid request body',
1390
+ });
1391
+ const request = c.req.valid('json');
1392
+ const chainId = c.req.valid('query').chainId ?? c.get('chainId');
1393
+ const provider = c
1394
+ .get('providers')
1395
+ .filter(ExchangeProvider.is)
1396
+ .find((candidate) => candidate.id === request.provider && candidate.finalizeQuote);
1397
+ if (!provider?.finalizeQuote)
1398
+ return Response.error(c, {
1399
+ code: 'swap_provider_invalid',
1400
+ message: 'The selected swap provider is not configured',
1401
+ status: 400,
1402
+ });
1403
+ c.header('Cache-Control', 'no-store');
1404
+ try {
1405
+ const client = c.get('getClient')(chainId);
1406
+ const result = await provider.finalizeQuote({
1407
+ account: request.account,
1408
+ chainId,
1409
+ continuation: request.continuation,
1410
+ signature: request.signature,
1411
+ }, c.req.raw.signal);
1412
+ await validateProviderCalls(client, {
1413
+ account: request.account,
1414
+ calls: result.calls,
1415
+ execution: result.execution,
1416
+ });
1417
+ return c.json(Response.validated(schema.executeQuote.Response, {
1418
+ provider: provider.id,
1419
+ transaction: { calls: result.calls, chainId },
1420
+ }), 200);
1421
+ }
1422
+ catch (cause) {
1423
+ if (cause instanceof ExchangeProvider.ProviderContinuationError)
1424
+ return Response.error(c, {
1425
+ code: 'swap_continuation_invalid',
1426
+ message: 'Invalid swap continuation',
1427
+ status: 400,
1428
+ });
1429
+ const failure = ExchangeProvider.failure(cause, {
1430
+ chainId,
1431
+ operation: 'finalize',
1432
+ provider,
1433
+ });
1434
+ if (failure)
1435
+ c.set('providerFailure', failure);
1143
1436
  return Response.upstream(c, cause);
1144
1437
  }
1145
1438
  })
@@ -1180,10 +1473,6 @@ export function exchanges(options = {}) {
1180
1473
  if (options.cursor !== undefined)
1181
1474
  Cache.setPolicy(c, Cache.policies.metadata);
1182
1475
  try {
1183
- // The pair index (base address → pair) resolves each fill's book
1184
- // orientation (the order events only carry the base-side `token`;
1185
- // the quote is intrinsic to it).
1186
- const pairIndex = await getPairIndex(c, { chainId });
1187
1476
  const page = await getSwaps(c, {
1188
1477
  chainId,
1189
1478
  cursor: options.cursor,
@@ -1192,7 +1481,6 @@ export function exchanges(options = {}) {
1192
1481
  limit: options.limit,
1193
1482
  maker: options.maker,
1194
1483
  order: options.order,
1195
- pairIndex,
1196
1484
  participant: options.participant,
1197
1485
  taker: options.taker,
1198
1486
  toBlock: options['blockNumber.to'],
@@ -1201,14 +1489,14 @@ export function exchanges(options = {}) {
1201
1489
  });
1202
1490
  // `route` spans every swap and fill side, so one lookup resolves each
1203
1491
  // token once for required RPC metadata and requested curated fields.
1204
- const tokensByAddress = await resolveTokensByAddress(c, {
1492
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1205
1493
  addresses: page.data.flatMap((swap) => swap.route),
1206
1494
  chainId,
1207
1495
  include: options.include,
1208
1496
  });
1209
1497
  // Value amounts via their curated display currency; snapshot or rate
1210
1498
  // failures degrade the values to `null`, never the feed.
1211
- const denomination = options.denomination ?? 'USD';
1499
+ const denomination = options['valuation.currency'] ?? 'USD';
1212
1500
  const snapshot = page.data.length > 0
1213
1501
  ? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
1214
1502
  : undefined;
@@ -1275,7 +1563,7 @@ export function exchanges(options = {}) {
1275
1563
  });
1276
1564
  return c.json(Response.validated(schema.getSwaps.Response, {
1277
1565
  data,
1278
- ...(rates ? { meta: { pricing: Valuation.pricing(rates, oracle) } } : {}),
1566
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
1279
1567
  nextCursor: page.nextCursor,
1280
1568
  }), 200);
1281
1569
  }
@@ -1352,7 +1640,7 @@ export function exchanges(options = {}) {
1352
1640
  transactionHash: pair.transactionHash,
1353
1641
  }));
1354
1642
  if (options.include.includes('tokens') && data.length > 0) {
1355
- const tokensByAddress = await resolveTokensByAddress(c, {
1643
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1356
1644
  addresses: data.flatMap((pair) => [pair.base.address, pair.quote.address]),
1357
1645
  chainId,
1358
1646
  include: tokenFields,
@@ -1437,7 +1725,7 @@ export function exchanges(options = {}) {
1437
1725
  let baseToken = { address: target.base };
1438
1726
  let quoteToken = { address: target.quote };
1439
1727
  if (options.include.includes('tokens')) {
1440
- const tokensByAddress = await resolveTokensByAddress(c, {
1728
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1441
1729
  addresses: [target.base, target.quote],
1442
1730
  chainId,
1443
1731
  include: tokenFields,
@@ -1503,18 +1791,19 @@ export function exchanges(options = {}) {
1503
1791
  const options = c.req.valid('query');
1504
1792
  const chainId = options.chainId ?? c.get('chainId');
1505
1793
  try {
1506
- // The pair index (base address → pair) resolves the `base` selector
1507
- // and each order's pair; the OrderPlaced scan only carries the
1508
- // base-side `token`.
1509
- const pairIndex = await getPairIndex(c, { chainId });
1510
1794
  // `base` selects the single pair it identifies — a pair's quote is
1511
1795
  // intrinsic to its base token on-chain, so the base address alone
1512
1796
  // is a complete selector.
1513
1797
  let pair;
1514
1798
  if (options.base !== undefined) {
1515
- const target = pairIndex.get(options.base);
1799
+ const target = (await getPairsByBase(c, { bases: [options.base], chainId })).get(options.base);
1800
+ // The 404's quote-token hint scans the full pair index; fetch it
1801
+ // only on this miss path so page requests never pay for it.
1516
1802
  if (!target)
1517
- return pairNotFoundError(c, { base: options.base, pairIndex });
1803
+ return pairNotFoundError(c, {
1804
+ base: options.base,
1805
+ pairIndex: await getPairIndex(c, { chainId }),
1806
+ });
1518
1807
  pair = target;
1519
1808
  }
1520
1809
  const page = await getOrders(c, {
@@ -1525,7 +1814,6 @@ export function exchanges(options = {}) {
1525
1814
  order: options.order,
1526
1815
  page: options.page,
1527
1816
  pair,
1528
- pairIndex,
1529
1817
  side: options.side,
1530
1818
  sort: options.sort,
1531
1819
  });
@@ -1535,7 +1823,7 @@ export function exchanges(options = {}) {
1535
1823
  // unavailable keeps just `address`.
1536
1824
  let data = page.data;
1537
1825
  if (options.include.includes('tokens') && data.length > 0) {
1538
- const tokensByAddress = await resolveTokensByAddress(c, {
1826
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1539
1827
  addresses: data.flatMap((o) => [o.pair.base.address, o.pair.quote.address]),
1540
1828
  chainId,
1541
1829
  include: tokenFields,
@@ -1815,7 +2103,7 @@ export function exchanges(options = {}) {
1815
2103
  let base = { address: target.base };
1816
2104
  let quote = { address: target.quote };
1817
2105
  if (options.include.includes('tokens')) {
1818
- const tokensByAddress = await resolveTokensByAddress(c, {
2106
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1819
2107
  addresses: [target.base, target.quote],
1820
2108
  chainId,
1821
2109
  include: tokenFields,
@@ -1906,7 +2194,7 @@ export function exchanges(options = {}) {
1906
2194
  let base = { address: target.base };
1907
2195
  let quote = { address: target.quote };
1908
2196
  if (options.include.includes('tokens')) {
1909
- const tokensByAddress = await resolveTokensByAddress(c, {
2197
+ const tokensByAddress = await Tokens.resolveTokens(c, {
1910
2198
  addresses: [target.base, target.quote],
1911
2199
  chainId,
1912
2200
  include: tokenFields,
@@ -1943,51 +2231,6 @@ function pairNotFoundError(c, options) {
1943
2231
  : 'Pair not found';
1944
2232
  return Response.error(c, { code: 'pair_not_found', message, status: 404 });
1945
2233
  }
1946
- /** Resolves RPC token metadata and explicitly requested enrichments. Unresolvable addresses are omitted. */
1947
- async function resolveTokensByAddress(c, options) {
1948
- const { addresses, chainId, include } = options;
1949
- const includeLogoUri = include.includes('token.logoUri');
1950
- const includeVerified = include.includes('token.verified');
1951
- const tokensByAddress = new Map();
1952
- const uniqueTokens = [...new Set(addresses)];
1953
- if (uniqueTokens.length === 0)
1954
- return tokensByAddress;
1955
- const snapshot = includeLogoUri || includeVerified
1956
- ? await VerifiedTokens.snapshot(c, chainId).catch(() => undefined)
1957
- : undefined;
1958
- const resolved = await Timing.time(c, 'tokens', () => Promise.all(uniqueTokens.map(async (token) => {
1959
- try {
1960
- const [logoUri, metadata] = await Promise.all([
1961
- includeLogoUri
1962
- ? Timing.time(c, 'token_logo', () => Tokens.getTokenLogo(c, { address: token, chainId })).catch(() => undefined)
1963
- : undefined,
1964
- Timing.time(c, 'token_metadata', () => Tokens.getTokenMetadata(c, { address: token, chainId })),
1965
- ]);
1966
- return [
1967
- token,
1968
- {
1969
- address: token,
1970
- currency: metadata.currency,
1971
- decimals: metadata.decimals,
1972
- id: token,
1973
- logoUri: includeLogoUri
1974
- ? (logoUri ?? snapshot?.byAddress.get(token)?.logoUri ?? metadata.logoUri)
1975
- : undefined,
1976
- name: metadata.name,
1977
- symbol: metadata.symbol,
1978
- verified: includeVerified ? snapshot?.byAddress.has(token) : undefined,
1979
- },
1980
- ];
1981
- }
1982
- catch {
1983
- return [token, undefined];
1984
- }
1985
- })));
1986
- for (const [token, metadata] of resolved)
1987
- if (metadata)
1988
- tokensByAddress.set(token, metadata);
1989
- return tokensByAddress;
1990
- }
1991
2234
  async function getPairs(c, options) {
1992
2235
  if (options.sort === 'liquidity')
1993
2236
  return getPairsByLiquidity(c, options);
@@ -2187,6 +2430,86 @@ async function getPairIndex(c, options) {
2187
2430
  ttl: Ttl.minutes(5),
2188
2431
  })).then((entries) => new Map(entries));
2189
2432
  }
2433
+ /**
2434
+ * Base-address chunk size for {@link getPairsByBase}. `tidx.fetch` transmits
2435
+ * queries as GET, so an unbounded `IN (...)` could overflow the request URI.
2436
+ */
2437
+ const pairLookupBatchSize = 200;
2438
+ /**
2439
+ * Resolves the pairs for a set of book base addresses with one targeted
2440
+ * `dex_pairs` lookup, avoiding the full pair-index fetch (1MB+ on large
2441
+ * chains).
2442
+ */
2443
+ async function getPairsByBase(c, options) {
2444
+ const { bases, chainId } = options;
2445
+ const pairs = new Map();
2446
+ if (bases.length === 0)
2447
+ return pairs;
2448
+ const tidx = c.get('getTidx')(chainId);
2449
+ return Timing.time(c, 'pair_lookup', async () => {
2450
+ for (let i = 0; i < bases.length; i += pairLookupBatchSize) {
2451
+ const list = bases
2452
+ .slice(i, i + pairLookupBatchSize)
2453
+ .map((base) => `'${base}'`)
2454
+ .join(', ');
2455
+ // `LIMIT 1 BY base` with the ascending sort picks each base's oldest
2456
+ // row, the row the pair index's last-entry-wins `Map` build selects.
2457
+ const result = await tidx.fetch({
2458
+ chainId,
2459
+ engine: 'clickhouse',
2460
+ query: `
2461
+ SELECT key, base, quote
2462
+ FROM dex_pairs
2463
+ WHERE address = '${stablecoinDex}' AND base IN (${list})
2464
+ ORDER BY block_num ASC, log_idx ASC
2465
+ LIMIT 1 BY base
2466
+ `,
2467
+ });
2468
+ // Drop malformed rows, mirroring `parsePairRow`.
2469
+ for (const row of result.rows) {
2470
+ const key = Schema.Hash.safeParse(row['key']);
2471
+ const base = Schema.TokenAddress.safeParse(row['base']);
2472
+ const quote = Schema.TokenAddress.safeParse(row['quote']);
2473
+ if (key.success && base.success && quote.success)
2474
+ pairs.set(base.data, { base: base.data, key: key.data, quote: quote.data });
2475
+ }
2476
+ }
2477
+ return pairs;
2478
+ });
2479
+ }
2480
+ /**
2481
+ * Resolves one pair by its book key with a targeted `dex_pairs` lookup,
2482
+ * covering books the bounded pair index ages out of its newest window.
2483
+ */
2484
+ async function getPairByKey(c, options) {
2485
+ const { chainId, key } = options;
2486
+ const tidx = c.get('getTidx')(chainId);
2487
+ return Timing.time(c, 'pair_lookup', async () => {
2488
+ // The ascending sort picks the key's oldest row, matching the pair
2489
+ // index's last-entry-wins `Map` build.
2490
+ const result = await tidx.fetch({
2491
+ chainId,
2492
+ engine: 'clickhouse',
2493
+ query: `
2494
+ SELECT key, base, quote
2495
+ FROM dex_pairs
2496
+ WHERE address = '${stablecoinDex}' AND key = '${key}'
2497
+ ORDER BY block_num ASC, log_idx ASC
2498
+ LIMIT 1
2499
+ `,
2500
+ });
2501
+ const row = result.rows[0];
2502
+ if (!row)
2503
+ return undefined;
2504
+ // Drop malformed rows, mirroring `parsePairRow`.
2505
+ const parsedKey = Schema.Hash.safeParse(row['key']);
2506
+ const base = Schema.TokenAddress.safeParse(row['base']);
2507
+ const quote = Schema.TokenAddress.safeParse(row['quote']);
2508
+ if (!parsedKey.success || !base.success || !quote.success)
2509
+ return undefined;
2510
+ return { base: base.data, key: parsedKey.data, quote: quote.data };
2511
+ });
2512
+ }
2190
2513
  /**
2191
2514
  * Validates and shapes one `PairCreated` row into the internal pair shape.
2192
2515
  * Returns `undefined` for malformed rows so the caller can drop them without
@@ -2248,7 +2571,7 @@ function parsePairRow(row) {
2248
2571
  * no candidate is discarded after the query runs.
2249
2572
  */
2250
2573
  async function getSwaps(c, options) {
2251
- const { chainId, cursor: cursorToken, fromBlock, fromTimestamp, limit, maker, order, pairIndex, participant, taker, toBlock, toTimestamp, transactionHash, } = options;
2574
+ const { chainId, cursor: cursorToken, fromBlock, fromTimestamp, limit, maker, order, participant, taker, toBlock, toTimestamp, transactionHash, } = options;
2252
2575
  const tidx = c.get('getTidx')(chainId);
2253
2576
  const direction = order === 'asc' ? 'ASC' : 'DESC';
2254
2577
  // Keyset cursor on `(block_num, group first_idx, row first log_idx)`: the
@@ -2370,16 +2693,17 @@ async function getSwaps(c, options) {
2370
2693
  ...new Set(groups.flatMap((group) => group.fills.map((fill) => fill.orderId))),
2371
2694
  ],
2372
2695
  }));
2373
- // Each fill's book quote: from the `dex_pairs` index when present, else
2374
- // the base token's on-chain `quoteToken()` — some books predate the
2375
- // indexer's `PairCreated` decode (genesis system books) and have no
2376
- // `dex_pairs` row.
2696
+ // Each fill's book quote: from a targeted `dex_pairs` lookup of this
2697
+ // batch's bases when indexed, else the base token's on-chain
2698
+ // `quoteToken()` some books predate the indexer's `PairCreated`
2699
+ // decode (genesis system books) and have no `dex_pairs` row.
2377
2700
  const bases = [
2378
2701
  ...new Set([...states.values()].flatMap((events) => events.map((event) => event.token))),
2379
2702
  ];
2703
+ const pairs = await getPairsByBase(c, { bases, chainId });
2380
2704
  const quoteByBase = new Map();
2381
2705
  for (const bookBase of bases) {
2382
- const indexed = pairIndex.get(bookBase);
2706
+ const indexed = pairs.get(bookBase);
2383
2707
  if (indexed)
2384
2708
  quoteByBase.set(bookBase, indexed.quote);
2385
2709
  }
@@ -3212,11 +3536,11 @@ const orderCursorTickBias = 32768;
3212
3536
  * `remaining = OrderPlaced.amount - sum(OrderFilled.amountFilled)`; orders
3213
3537
  * with an `OrderCancelled` event are excluded outright. Each row is annotated
3214
3538
  * with its pair: the scoped feed reuses the resolved `pair`, the unscoped
3215
- * feed resolves per row from the supplied pair index (rows whose pair is
3216
- * unknown are dropped).
3539
+ * feed resolves the page's base tokens with one targeted `dex_pairs` lookup
3540
+ * (rows whose pair is unknown are dropped).
3217
3541
  */
3218
3542
  async function getOrders(c, options) {
3219
- const { chainId, cursor, limit, maker, order, page, pair, pairIndex, side, sort } = options;
3543
+ const { chainId, cursor, limit, maker, order, page, pair, side, sort } = options;
3220
3544
  const store = c.get('store');
3221
3545
  return Timing.time(c, 'orders', async () => {
3222
3546
  // Snapshot is invariant in `(chainId, base?, maker?)`; sort/side/order are
@@ -3238,9 +3562,11 @@ async function getOrders(c, options) {
3238
3562
  side,
3239
3563
  sort,
3240
3564
  });
3565
+ const bases = pair ? [] : [...new Set(pageRows.map((row) => row.token))];
3566
+ const pairsByBase = await getPairsByBase(c, { bases, chainId });
3241
3567
  const data = [];
3242
3568
  for (const row of pageRows) {
3243
- const rowPair = pair ?? pairIndex.get(row.token);
3569
+ const rowPair = pair ?? pairsByBase.get(row.token);
3244
3570
  if (!rowPair)
3245
3571
  continue;
3246
3572
  const shaped = shapeRestingOrder(row);
@@ -3470,11 +3796,17 @@ async function loadRestingOrders(c, options) {
3470
3796
  });
3471
3797
  const truncated = result.rows.length > scanCap;
3472
3798
  const placedRows = result.rows.slice(0, scanCap);
3799
+ // `dex_orders` can carry duplicate rows per placement; keep the first
3800
+ // (newest) copy so pages emit each order once and a duplicate straddling an
3801
+ // IN-batch boundary can't double-count fills.
3473
3802
  const placed = [];
3803
+ const seen = new Set();
3474
3804
  for (const row of placedRows) {
3475
3805
  const parsed = parsePlacedRow(row);
3476
- if (parsed)
3477
- placed.push(parsed);
3806
+ if (!parsed || seen.has(parsed.orderId))
3807
+ continue;
3808
+ seen.add(parsed.orderId);
3809
+ placed.push(parsed);
3478
3810
  }
3479
3811
  if (placed.length === 0)
3480
3812
  return { orders: [], truncated };
@@ -3534,12 +3866,14 @@ export async function resolveBookReserves(c, options) {
3534
3866
  return { reserves, truncated: false };
3535
3867
  const tidx = c.get('getTidx')(chainId);
3536
3868
  // Scan the newest `scanCap` `OrderPlaced` rows per base. `LIMIT ... BY token`
3537
- // is the ClickHouse fair cap; the app-side `perToken` guard re-applies it
3538
- // across chunks (a base can't span chunks, but the guard also flips
3539
- // `truncated` consistently) and against the `scanCap + 1` probe row.
3869
+ // is the ClickHouse fair cap over raw rows; `rawPerToken` flips `truncated`
3870
+ // when a token's window overflows, since unfetched older rows may hold unique
3871
+ // placements even when duplicates keep the unique count under the cap.
3540
3872
  let truncated = false;
3541
3873
  const placed = [];
3542
3874
  const perToken = new Map();
3875
+ const rawPerToken = new Map();
3876
+ const seen = new Set();
3543
3877
  for (let i = 0; i < unique.length; i += reserveBaseInBatchSize) {
3544
3878
  const group = unique.slice(i, i + reserveBaseInBatchSize);
3545
3879
  const list = group.map((base) => `'${base}'`).join(', ');
@@ -3558,11 +3892,18 @@ export async function resolveBookReserves(c, options) {
3558
3892
  const parsed = parsePlacedRow(row);
3559
3893
  if (!parsed)
3560
3894
  continue;
3561
- const count = perToken.get(parsed.token) ?? 0;
3562
- if (count >= scanCap) {
3895
+ const raw = (rawPerToken.get(parsed.token) ?? 0) + 1;
3896
+ rawPerToken.set(parsed.token, raw);
3897
+ if (raw > scanCap)
3563
3898
  truncated = true;
3899
+ // Duplicate placement rows (see `loadRestingOrders`) can't add the same
3900
+ // order's remaining liquidity twice; the raw probe above still counts them.
3901
+ if (seen.has(parsed.orderId))
3564
3902
  continue;
3565
- }
3903
+ const count = perToken.get(parsed.token) ?? 0;
3904
+ if (count >= scanCap)
3905
+ continue;
3906
+ seen.add(parsed.orderId);
3566
3907
  perToken.set(parsed.token, count + 1);
3567
3908
  placed.push(parsed);
3568
3909
  }
@@ -3649,6 +3990,9 @@ async function fetchCancelledByIds(c, options) {
3649
3990
  if (orderIds.length === 0)
3650
3991
  return cancelled;
3651
3992
  const tidx = c.get('getTidx')(chainId);
3993
+ // Chunks resolve serially: the managed indexer rejects bursts of concurrent
3994
+ // chunk queries (~2-3 in flight), and the cancel/fill helpers already
3995
+ // overlap via `Promise.all`.
3652
3996
  for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
3653
3997
  const batch = orderIds.slice(i, i + orderInBatchSize);
3654
3998
  const result = await tidx.fetch({
@@ -3681,6 +4025,9 @@ async function fetchFillSumsByIds(c, options) {
3681
4025
  if (orderIds.length === 0)
3682
4026
  return sums;
3683
4027
  const tidx = c.get('getTidx')(chainId);
4028
+ // Chunks resolve serially: the managed indexer rejects bursts of concurrent
4029
+ // chunk queries (~2-3 in flight), and the cancel/fill helpers already
4030
+ // overlap via `Promise.all`.
3684
4031
  for (let i = 0; i < orderIds.length; i += orderInBatchSize) {
3685
4032
  const batch = orderIds.slice(i, i + orderInBatchSize);
3686
4033
  const result = await tidx.fetch({
@@ -3773,30 +4120,27 @@ async function getOrder(c, options) {
3773
4120
  const client = c.get('getClient')(chainId);
3774
4121
  return Timing.time(c, 'order', () => Store.memoize(async () => {
3775
4122
  // The on-chain DEX exposes the full order struct (placement params
3776
- // plus current `remaining`) in one view call. We resolve the pair
3777
- // off the returned `bookKey` concurrently with the RPC; on a warm
3778
- // pair-index cache that's effectively free.
3779
- const [chainOrder, pairsByKey] = await Promise.all([
3780
- Timing.time(c, 'order_dex_get', () =>
3781
- // The DEX reverts with `OrderDoesNotExist()` for ids it no longer
3782
- // holds (never placed, or filled/cancelled and cleared), rather
3783
- // than returning the zero struct. Map that revert to not-found so
3784
- // the route answers 404 instead of bubbling up as a 502.
3785
- client.dex.getOrder({ orderId: BigInt(orderId) }).catch((cause) => {
3786
- if (isOrderDoesNotExist(cause))
3787
- return undefined;
3788
- throw cause;
3789
- })),
3790
- getPairIndexByKey(c, { chainId }),
3791
- ]);
4123
+ // plus current `remaining`) in one view call.
4124
+ const chainOrder = await Timing.time(c, 'order_dex_get', () =>
4125
+ // The DEX reverts with `OrderDoesNotExist()` for ids it no longer
4126
+ // holds (never placed, or filled/cancelled and cleared), rather
4127
+ // than returning the zero struct. Map that revert to not-found so
4128
+ // the route answers 404 instead of bubbling up as a 502.
4129
+ client.dex.getOrder({ orderId: BigInt(orderId) }).catch((cause) => {
4130
+ if (isOrderDoesNotExist(cause))
4131
+ return undefined;
4132
+ throw cause;
4133
+ }));
3792
4134
  // The DEX returns the zero struct (or reverts, handled above) when an
3793
4135
  // order id is unknown.
3794
4136
  if (!chainOrder || chainOrder.orderId === 0n)
3795
4137
  return undefined;
3796
- // Pair index miss is a soft consistency floor (the index is bounded
3797
- // by `pairIndexLimit`); without `(base, quote)` we cannot frame the
3798
- // order, so surface as not-found.
3799
- const pair = pairsByKey.get(chainOrder.bookKey.toLowerCase());
4138
+ // Targeted lookup off the returned `bookKey`; the bounded pair index
4139
+ // misses books outside its newest window, 404ing live orders.
4140
+ const pair = await getPairByKey(c, {
4141
+ chainId,
4142
+ key: chainOrder.bookKey.toLowerCase(),
4143
+ });
3800
4144
  if (!pair)
3801
4145
  return undefined;
3802
4146
  const tick = chainOrder.tick;
@@ -3852,11 +4196,139 @@ function isOrderDoesNotExist(error) {
3852
4196
  return (revert instanceof ContractFunctionRevertedError &&
3853
4197
  revert.data?.errorName === 'OrderDoesNotExist');
3854
4198
  }
3855
- /** Returns the native DEX 404 used when no executable quote is available. */
4199
+ async function providerQuoteResponse(c, options) {
4200
+ const { chainId, gasPrice, gasUnits, oracle, provider, query, quote, request } = options;
4201
+ const tokensByAddress = await Tokens.resolveTokens(c, {
4202
+ addresses: [request.destinationToken, request.sourceToken],
4203
+ chainId,
4204
+ include: options.include,
4205
+ });
4206
+ const destinationToken = tokensByAddress.get(request.destinationToken);
4207
+ const sourceToken = tokensByAddress.get(request.sourceToken);
4208
+ if (!destinationToken || !sourceToken)
4209
+ throw new Error('Unable to resolve exchange quote token metadata');
4210
+ const denomination = query['valuation.currency'] ?? 'USD';
4211
+ const snapshot = await VerifiedTokens.snapshot(c, chainId).catch(() => undefined);
4212
+ const rates = await Valuation.ratesFor(c, {
4213
+ currencies: snapshot
4214
+ ? [request.destinationToken, request.sourceToken].flatMap((address) => {
4215
+ const held = snapshot.byAddress.get(address.toLowerCase())?.currency;
4216
+ return held === undefined ? [] : [held];
4217
+ })
4218
+ : [],
4219
+ denomination,
4220
+ oracle,
4221
+ });
4222
+ const valued = (baseUnits, address, token) => ({
4223
+ ...Value.tokenAmount({ baseUnits, currency: token.currency, decimals: token.decimals }),
4224
+ valuation: Valuation.valuationFor({
4225
+ amount: BigInt(baseUnits),
4226
+ denomination,
4227
+ rates,
4228
+ token: snapshot?.byAddress.get(address.toLowerCase()),
4229
+ }),
4230
+ });
4231
+ const execution = quote.status === 'ready'
4232
+ ? {
4233
+ status: quote.status,
4234
+ transaction: { calls: [...quote.transaction.calls], chainId },
4235
+ }
4236
+ : quote.status === 'approvalRequired'
4237
+ ? { approval: { calls: [...quote.approval.calls] }, status: quote.status }
4238
+ : {
4239
+ continuation: quote.continuation,
4240
+ status: quote.status,
4241
+ typedData: quote.typedData,
4242
+ };
4243
+ const common = {
4244
+ destinationToken: { ...destinationToken, address: request.destinationToken },
4245
+ ...execution,
4246
+ ...(rates ? { meta: { valuation: Valuation.pricing(rates, oracle) } } : {}),
4247
+ gasEstimate: gasCost({ gasPrice, gasUnits }),
4248
+ provider: provider.id,
4249
+ sourceToken: { ...sourceToken, address: request.sourceToken },
4250
+ };
4251
+ if (request.mode === 'exactSource') {
4252
+ if (!quote.minimumDestinationAmount)
4253
+ throw new ExchangeProvider.ProviderPayloadError();
4254
+ return {
4255
+ ...common,
4256
+ destinationAmount: valued(quote.destinationAmount, request.destinationToken, destinationToken),
4257
+ destinationAmountMin: valued(quote.minimumDestinationAmount, request.destinationToken, destinationToken),
4258
+ mode: request.mode,
4259
+ sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
4260
+ };
4261
+ }
4262
+ if (!quote.maximumSourceAmount)
4263
+ throw new ExchangeProvider.ProviderPayloadError();
4264
+ return {
4265
+ ...common,
4266
+ destinationAmount: valued(quote.destinationAmount, request.destinationToken, destinationToken),
4267
+ mode: request.mode,
4268
+ sourceAmount: valued(quote.sourceAmount, request.sourceToken, sourceToken),
4269
+ sourceAmountMax: valued(quote.maximumSourceAmount, request.sourceToken, sourceToken),
4270
+ };
4271
+ }
4272
+ function providerExecution(options) {
4273
+ const { quote, request } = options;
4274
+ return {
4275
+ destinationAmount: quote.destinationAmount,
4276
+ destinationToken: request.destinationToken,
4277
+ gasUnits: quote.gasUnits,
4278
+ ...(quote.maximumSourceAmount ? { maximumSourceAmount: quote.maximumSourceAmount } : {}),
4279
+ ...(quote.minimumDestinationAmount
4280
+ ? { minimumDestinationAmount: quote.minimumDestinationAmount }
4281
+ : {}),
4282
+ mode: request.mode,
4283
+ sourceAmount: quote.sourceAmount,
4284
+ sourceToken: request.sourceToken,
4285
+ };
4286
+ }
4287
+ async function validateProviderCalls(client, options) {
4288
+ try {
4289
+ const { results } = await Actions.simulate.simulateCalls(client, {
4290
+ account: options.account,
4291
+ calls: options.calls.map((call) => ({
4292
+ data: call.data,
4293
+ to: call.to,
4294
+ value: BigInt(call.value),
4295
+ })),
4296
+ traceTransfers: true,
4297
+ });
4298
+ if (results.some((result) => result.status !== 'success'))
4299
+ throw new ExchangeProvider.ProviderPayloadError();
4300
+ const logs = results.flatMap((result) => result.logs ?? []);
4301
+ const transfers = parseEventLogs({
4302
+ abi: [AbiEvent.fromAbi(Abis.tip20, 'Transfer')],
4303
+ eventName: 'Transfer',
4304
+ logs,
4305
+ }).map((log) => ({
4306
+ amount: log.args.amount,
4307
+ from: log.args.from,
4308
+ to: log.args.to,
4309
+ token: log.address,
4310
+ }));
4311
+ ExchangeProvider.validateExecution({
4312
+ account: options.account,
4313
+ execution: options.execution,
4314
+ transfers,
4315
+ });
4316
+ }
4317
+ catch (cause) {
4318
+ if (cause instanceof ExchangeProvider.ProviderPayloadError)
4319
+ throw cause;
4320
+ throw new ExchangeProvider.ProviderPayloadError();
4321
+ }
4322
+ }
4323
+ /** Converts estimated gas units to a native-token base-unit fee. */
4324
+ function gasCost(options) {
4325
+ return (options.gasPrice * options.gasUnits).toString();
4326
+ }
4327
+ /** Returns the 404 used when no executable quote is available. */
3856
4328
  function quoteNotAvailable(c) {
3857
4329
  return Response.error(c, {
3858
4330
  code: 'quote_not_available',
3859
- message: 'No executable quote is available on Tempo’s native DEX',
4331
+ message: 'No configured exchange provider has an executable quote',
3860
4332
  status: 404,
3861
4333
  });
3862
4334
  }
@@ -3964,18 +4436,6 @@ async function countOrderFills(c, options) {
3964
4436
  ttl: Ttl.seconds(10),
3965
4437
  }));
3966
4438
  }
3967
- /**
3968
- * Per-key pair index derived from the existing per-base index. Built once
3969
- * and memoized at the same cadence as the pair index itself so chained
3970
- * `getOrder` lookups stay an O(1) `Map.get`.
3971
- */
3972
- async function getPairIndexByKey(c, options) {
3973
- const pairsByBase = await getPairIndex(c, options);
3974
- const pairsByKey = new Map();
3975
- for (const pair of pairsByBase.values())
3976
- pairsByKey.set(pair.key.toLowerCase(), pair);
3977
- return pairsByKey;
3978
- }
3979
4439
  /**
3980
4440
  * Validates and shapes one `OrderFilled` row into the public `Fill` shape.
3981
4441
  * Drops the row when any required column is malformed so the caller can omit
@@ -4009,4 +4469,7 @@ function parseOrderFillRow(row) {
4009
4469
  transactionHash: transactionHash.data,
4010
4470
  };
4011
4471
  }
4472
+ class NativeDexAmountOutOfRangeError extends Error {
4473
+ name = 'Exchanges.NativeDexAmountOutOfRangeError';
4474
+ }
4012
4475
  //# sourceMappingURL=exchanges.js.map