tapimo 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist/App.d.ts +7222 -6316
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +4 -0
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +18 -1
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +24 -3
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/admin/apps/verified-tokens.d.ts +116 -116
  10. package/dist/apps/data/App.d.ts +2541 -2607
  11. package/dist/apps/data/App.d.ts.map +1 -1
  12. package/dist/apps/data/App.js +135 -44
  13. package/dist/apps/data/App.js.map +1 -1
  14. package/dist/apps/data/FundingQuoteProviders.d.ts +36 -0
  15. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -0
  16. package/dist/apps/data/FundingQuoteProviders.js +190 -0
  17. package/dist/apps/data/FundingQuoteProviders.js.map +1 -0
  18. package/dist/apps/data/index.d.ts +1 -1
  19. package/dist/apps/data/index.js +1 -1
  20. package/dist/apps/data/routes/activities.d.ts +242 -242
  21. package/dist/apps/data/routes/addresses.d.ts +227 -227
  22. package/dist/apps/data/routes/balances.d.ts +12 -12
  23. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  24. package/dist/apps/data/routes/balances.js +67 -149
  25. package/dist/apps/data/routes/balances.js.map +1 -1
  26. package/dist/apps/data/routes/blocks.d.ts +125 -126
  27. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  28. package/dist/apps/data/routes/blocks.js +3 -5
  29. package/dist/apps/data/routes/blocks.js.map +1 -1
  30. package/dist/apps/data/routes/coingecko.d.ts +55 -54
  31. package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
  32. package/dist/apps/data/routes/coingecko.js +3 -8
  33. package/dist/apps/data/routes/coingecko.js.map +1 -1
  34. package/dist/apps/data/routes/exchanges.d.ts +455 -455
  35. package/dist/apps/data/routes/fee-amm.d.ts +92 -92
  36. package/dist/apps/data/routes/funding.d.ts +91 -864
  37. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  38. package/dist/apps/data/routes/funding.js +138 -450
  39. package/dist/apps/data/routes/funding.js.map +1 -1
  40. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  41. package/dist/apps/data/routes/rpc.js +86 -16
  42. package/dist/apps/data/routes/rpc.js.map +1 -1
  43. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  44. package/dist/apps/data/routes/webhooks.d.ts +340 -0
  45. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  46. package/dist/apps/data/routes/webhooks.js +13 -1
  47. package/dist/apps/data/routes/webhooks.js.map +1 -1
  48. package/dist/apps/index.d.ts +1 -1
  49. package/dist/apps/index.js +1 -1
  50. package/dist/apps/management/App.d.ts +1843 -861
  51. package/dist/apps/management/App.d.ts.map +1 -1
  52. package/dist/apps/management/App.js +4 -0
  53. package/dist/apps/management/App.js.map +1 -1
  54. package/dist/apps/management/routes/api-keys.d.ts +121 -121
  55. package/dist/apps/management/routes/api-keys.js +2 -2
  56. package/dist/apps/management/routes/api-keys.js.map +1 -1
  57. package/dist/apps/management/routes/billing.d.ts +2 -2
  58. package/dist/apps/management/routes/invite-links.d.ts +1100 -0
  59. package/dist/apps/management/routes/invite-links.d.ts.map +1 -0
  60. package/dist/apps/management/routes/invite-links.js +411 -0
  61. package/dist/apps/management/routes/invite-links.js.map +1 -0
  62. package/dist/apps/management/routes/me.d.ts +13 -13
  63. package/dist/apps/management/routes/members.d.ts +77 -77
  64. package/dist/apps/management/routes/orgs.d.ts +96 -96
  65. package/dist/apps/management/routes/projects.d.ts +62 -62
  66. package/dist/apps/management/routes/scopes.d.ts +11 -11
  67. package/dist/apps/management/routes/scopes.d.ts.map +1 -1
  68. package/dist/apps/management/routes/scopes.js +2 -2
  69. package/dist/apps/management/routes/scopes.js.map +1 -1
  70. package/dist/apps/management/routes/usage.d.ts +79 -79
  71. package/dist/apps/mcp.d.ts.map +1 -1
  72. package/dist/apps/mcp.js +3 -1
  73. package/dist/apps/mcp.js.map +1 -1
  74. package/dist/apps/relay/App.d.ts.map +1 -1
  75. package/dist/apps/relay/App.js +42 -4
  76. package/dist/apps/relay/App.js.map +1 -1
  77. package/dist/cloudflare.d.ts +2 -0
  78. package/dist/cloudflare.d.ts.map +1 -1
  79. package/dist/cloudflare.js +4 -0
  80. package/dist/cloudflare.js.map +1 -1
  81. package/dist/db/Db.d.ts +3 -0
  82. package/dist/db/Db.d.ts.map +1 -1
  83. package/dist/db/Db.js +57 -0
  84. package/dist/db/Db.js.map +1 -1
  85. package/dist/db/Schema.d.ts +31 -0
  86. package/dist/db/Schema.d.ts.map +1 -1
  87. package/dist/db/Schema.js +31 -0
  88. package/dist/db/Schema.js.map +1 -1
  89. package/dist/db/tables/inviteLinks.d.ts +42 -0
  90. package/dist/db/tables/inviteLinks.d.ts.map +1 -0
  91. package/dist/db/tables/inviteLinks.js +148 -0
  92. package/dist/db/tables/inviteLinks.js.map +1 -0
  93. package/dist/db/tables/organizations.d.ts.map +1 -1
  94. package/dist/db/tables/organizations.js +2 -0
  95. package/dist/db/tables/organizations.js.map +1 -1
  96. package/dist/handlers/relay.d.ts.map +1 -1
  97. package/dist/handlers/relay.js +13 -3
  98. package/dist/handlers/relay.js.map +1 -1
  99. package/dist/internal/Auth.d.ts +42 -23
  100. package/dist/internal/Auth.d.ts.map +1 -1
  101. package/dist/internal/Auth.js +169 -20
  102. package/dist/internal/Auth.js.map +1 -1
  103. package/dist/internal/EdgeCache.d.ts +3 -1
  104. package/dist/internal/EdgeCache.d.ts.map +1 -1
  105. package/dist/internal/EdgeCache.js +17 -2
  106. package/dist/internal/EdgeCache.js.map +1 -1
  107. package/dist/internal/Errors.d.ts +6 -0
  108. package/dist/internal/Errors.d.ts.map +1 -0
  109. package/dist/internal/Errors.js +16 -0
  110. package/dist/internal/Errors.js.map +1 -0
  111. package/dist/internal/FundingQuotes.d.ts +644 -0
  112. package/dist/internal/FundingQuotes.d.ts.map +1 -0
  113. package/dist/internal/{FundingRoutes.js → FundingQuotes.js} +93 -289
  114. package/dist/internal/FundingQuotes.js.map +1 -0
  115. package/dist/internal/Store.d.ts +61 -16
  116. package/dist/internal/Store.d.ts.map +1 -1
  117. package/dist/internal/Store.js +72 -17
  118. package/dist/internal/Store.js.map +1 -1
  119. package/dist/internal/Viem.d.ts +2 -0
  120. package/dist/internal/Viem.d.ts.map +1 -1
  121. package/dist/internal/Viem.js +11 -2
  122. package/dist/internal/Viem.js.map +1 -1
  123. package/dist/internal/index.d.ts +27 -0
  124. package/dist/internal/index.d.ts.map +1 -0
  125. package/dist/internal/index.js +27 -0
  126. package/dist/internal/index.js.map +1 -0
  127. package/package.json +8 -3
  128. package/src/ApiKeys.test.ts +23 -0
  129. package/src/App.test-d.ts +2 -0
  130. package/src/App.test.ts +60 -4
  131. package/src/App.ts +6 -0
  132. package/src/Client.test-d.ts +16 -54
  133. package/src/Scope.test.ts +1 -0
  134. package/src/Scope.ts +30 -4
  135. package/src/apps/data/App.test.ts +354 -0
  136. package/src/apps/data/App.ts +159 -52
  137. package/src/apps/data/FundingQuoteProviders.test.ts +151 -0
  138. package/src/apps/data/FundingQuoteProviders.ts +251 -0
  139. package/src/apps/data/index.ts +1 -1
  140. package/src/apps/data/routes/balances.test.ts +64 -18
  141. package/src/apps/data/routes/balances.ts +76 -177
  142. package/src/apps/data/routes/blocks.ts +3 -5
  143. package/src/apps/data/routes/coingecko.ts +3 -8
  144. package/src/apps/data/routes/funding.test.ts +149 -306
  145. package/src/apps/data/routes/funding.ts +154 -604
  146. package/src/apps/data/routes/indexer.test.ts +99 -3
  147. package/src/apps/data/routes/rpc.test.ts +219 -0
  148. package/src/apps/data/routes/rpc.ts +92 -17
  149. package/src/apps/data/routes/webhooks.test.ts +23 -2
  150. package/src/apps/data/routes/webhooks.ts +13 -1
  151. package/src/apps/index.ts +1 -1
  152. package/src/apps/management/App.ts +4 -0
  153. package/src/apps/management/routes/api-keys.test.ts +47 -3
  154. package/src/apps/management/routes/api-keys.ts +2 -2
  155. package/src/apps/management/routes/invite-links.test.ts +385 -0
  156. package/src/apps/management/routes/invite-links.ts +570 -0
  157. package/src/apps/management/routes/scopes.test.ts +3 -2
  158. package/src/apps/management/routes/scopes.ts +4 -2
  159. package/src/apps/mcp.test.ts +55 -14
  160. package/src/apps/mcp.ts +3 -1
  161. package/src/apps/relay/App.test.ts +324 -4
  162. package/src/apps/relay/App.ts +40 -4
  163. package/src/cloudflare.ts +5 -0
  164. package/src/db/Db.ts +65 -0
  165. package/src/db/Schema.ts +39 -0
  166. package/src/db/tables/inviteLinks.ts +187 -0
  167. package/src/db/tables/organizations.ts +2 -0
  168. package/src/handlers/relay.ts +16 -4
  169. package/src/internal/Auth.test.ts +528 -37
  170. package/src/internal/Auth.ts +246 -45
  171. package/src/internal/EdgeCache.test.ts +24 -3
  172. package/src/internal/EdgeCache.ts +18 -2
  173. package/src/internal/FundingQuotes.test.ts +174 -0
  174. package/src/internal/FundingQuotes.ts +735 -0
  175. package/src/internal/Log.test.ts +4 -4
  176. package/src/internal/Store.test-d.ts +15 -0
  177. package/src/internal/Store.test.ts +153 -2
  178. package/src/internal/Store.ts +157 -41
  179. package/src/internal/Viem.ts +14 -5
  180. package/src/internal/index.test.ts +34 -0
  181. package/src/internal/index.ts +26 -0
  182. package/dist/apps/data/FundingRouteProviders.d.ts +0 -143
  183. package/dist/apps/data/FundingRouteProviders.d.ts.map +0 -1
  184. package/dist/apps/data/FundingRouteProviders.js +0 -546
  185. package/dist/apps/data/FundingRouteProviders.js.map +0 -1
  186. package/dist/internal/FundingRoutes.d.ts +0 -1085
  187. package/dist/internal/FundingRoutes.d.ts.map +0 -1
  188. package/dist/internal/FundingRoutes.js.map +0 -1
  189. package/src/apps/data/FundingRouteProviders.test.ts +0 -485
  190. package/src/apps/data/FundingRouteProviders.ts +0 -744
  191. package/src/internal/FundingRoutes.test.ts +0 -239
  192. package/src/internal/FundingRoutes.ts +0 -1067
@@ -4,19 +4,18 @@ import * as z from 'zod/mini'
4
4
  import type * as App from '../../../App.js'
5
5
  import * as Auth from '../../../internal/Auth.js'
6
6
  import * as Cache from '../../../internal/Cache.js'
7
- import * as FundingRoutes from '../../../internal/FundingRoutes.js'
7
+ import * as FundingQuotes from '../../../internal/FundingQuotes.js'
8
8
  import * as OpenApi from '../../../internal/OpenApi.js'
9
9
  import * as Response from '../../../internal/Response.js'
10
10
  import * as Schema from '../../../internal/Schema.js'
11
- import * as FundingRouteProviders from '../FundingRouteProviders.js'
12
11
 
13
- /** Zod schemas owned by the funding routes resource. */
12
+ /** Zod schemas owned by funding quote resources. */
14
13
  export namespace schema {
15
14
  /** Source or destination chain reference. */
16
15
  export const Chain = Schema.describe(
17
16
  z.object({
18
17
  addressFormat: z
19
- .enum(['evm', 'solana', 'tron'])
18
+ .literal('evm')
20
19
  .check(
21
20
  z.describe('Address family used by accounts and token identifiers on this chain.'),
22
21
  z.meta({ examples: ['evm'] }),
@@ -25,12 +24,12 @@ export namespace schema {
25
24
  .string()
26
25
  .check(
27
26
  z.describe(
28
- 'Stable chain id, preferably CAIP-2 when one exists. Funding spans non-EVM chains, so ids are strings, unlike numeric `chainId` params elsewhere.',
27
+ 'Stable CAIP-2 chain id, represented as a string instead of the numeric `chainId` used elsewhere.',
29
28
  ),
30
29
  z.meta({ examples: ['eip155:8453'] }),
31
30
  ),
32
31
  kind: z
33
- .enum(['evm', 'solana', 'tron'])
32
+ .literal('evm')
34
33
  .check(
35
34
  z.describe('Chain execution family used for provider routing.'),
36
35
  z.meta({ examples: ['evm'] }),
@@ -41,11 +40,11 @@ export namespace schema {
41
40
  providerIds: z
42
41
  .optional(z.record(z.string(), z.string()))
43
42
  .check(
44
- z.describe('Provider-specific chain ids Tempo uses when querying route providers.'),
45
- z.meta({ examples: [{ across: '8453', relay: '8453' }] }),
43
+ z.describe('Provider-specific chain ids Tempo uses when requesting quotes.'),
44
+ z.meta({ examples: [{ relay: '8453' }] }),
46
45
  ),
47
46
  }),
48
- 'A normalized chain reference for funding routes.',
47
+ 'A normalized chain reference for funding quotes.',
49
48
  )
50
49
 
51
50
  /** Source or destination token reference. */
@@ -89,14 +88,14 @@ export namespace schema {
89
88
  verified: z
90
89
  .boolean()
91
90
  .check(
92
- z.describe('Whether Tempo recognizes this token in its funding route inventory.'),
91
+ z.describe('Whether Tempo recognizes this token in its funding quote inventory.'),
93
92
  z.meta({ examples: [true] }),
94
93
  ),
95
94
  }),
96
- 'A normalized token reference for funding routes.',
95
+ 'A normalized token reference for funding quotes.',
97
96
  )
98
97
 
99
- /** Source amount echoed by a funding route response. */
98
+ /** Source amount echoed by a funding quote response. */
100
99
  export const TokenAmount = Schema.describe(
101
100
  z.object({
102
101
  amount: Schema.DecimalString.check(
@@ -110,151 +109,88 @@ export namespace schema {
110
109
  ),
111
110
  z.meta({ examples: ['1'] }),
112
111
  ),
113
- usd: z
114
- .nullable(z.string())
115
- .check(
116
- z.describe('USD estimate for the requested source amount, when available.'),
117
- z.meta({ examples: ['1.00'] }),
118
- ),
119
112
  }),
120
113
  'The requested source amount in provider-safe base units and display form.',
121
114
  )
122
115
 
123
- /** Provider summary embedded in a route candidate. */
116
+ /** Provider summary embedded in a funding quote. */
124
117
  export const ProviderRef = Schema.describe(
125
118
  z.object({
126
- id: z.string().check(z.describe('Stable provider id.'), z.meta({ examples: ['across'] })),
119
+ id: z
120
+ .literal('relay')
121
+ .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
127
122
  kind: z
128
123
  .string()
129
124
  .check(
130
- z.describe('Provider category, such as an intent bridge, solver network, or aggregator.'),
131
- z.meta({ examples: ['intentBridge'] }),
125
+ z.describe('Provider category, such as a solver network or aggregator.'),
126
+ z.meta({ examples: ['solverNetwork'] }),
132
127
  ),
133
128
  name: z
134
129
  .string()
135
- .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Across'] })),
130
+ .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Relay'] })),
136
131
  requiresApiKey: z
137
132
  .boolean()
138
133
  .check(
139
134
  z.describe('Whether Tempo needs provider credentials to query or use this provider.'),
140
- z.meta({ examples: [true] }),
135
+ z.meta({ examples: [false] }),
141
136
  ),
142
137
  }),
143
- 'Provider metadata embedded in a route candidate.',
138
+ 'Provider metadata embedded in a funding quote.',
144
139
  )
145
140
 
146
- /** Route quality signals exposed directly instead of implied by list order. */
141
+ /** Quote quality signals exposed directly instead of implied by list order. */
147
142
  export const Quality = Schema.describe(
148
143
  z.object({
149
- availableVolumeUsd: z
150
- .nullable(z.string())
151
- .check(
152
- z.describe('Available USD capacity, when available.'),
153
- z.meta({ examples: ['1114274.43'] }),
154
- ),
155
144
  estimatedSeconds: z
156
- .nullable(z.number().check(z.int(), z.nonnegative()))
145
+ .optional(z.number().check(z.int(), z.nonnegative()))
157
146
  .check(
158
147
  z.describe('Estimated settlement time in seconds, when known.'),
159
148
  z.meta({ examples: [2] }),
160
149
  ),
161
- feeBps: z
162
- .nullable(z.number().check(z.int(), z.nonnegative()))
163
- .check(
164
- z.describe('Estimated fee in basis points, when known.'),
165
- z.meta({ examples: [109] }),
166
- ),
167
- historicalVolumeUsd24h: z
168
- .nullable(z.string())
169
- .check(
170
- z.describe('24h routed volume in USD, when available.'),
171
- z.meta({ examples: ['250000.00'] }),
172
- ),
173
- instantVolumeUsd: z
174
- .nullable(z.string())
175
- .check(
176
- z.describe('Instant USD capacity, when available.'),
177
- z.meta({ examples: ['12453.94'] }),
178
- ),
179
150
  liquiditySource: z
180
151
  .string()
181
152
  .check(
182
- z.describe('Where the liquidity or support signal came from.'),
183
- z.meta({ examples: ['staticInventory'] }),
184
- ),
185
- score: z
186
- .nullable(z.number().check(z.int(), z.gte(0), z.lte(100)))
187
- .check(
188
- z.describe('Explainable route score from 0 to 100, when enough signals are available.'),
189
- z.meta({ examples: [91] }),
153
+ z.describe('Provider source for the live quote quality signal.'),
154
+ z.meta({ examples: ['providerQuote'] }),
190
155
  ),
191
156
  sourceDetail: z
192
- .nullable(z.string())
157
+ .optional(z.string())
193
158
  .check(
194
159
  z.describe('Provider-specific source or endpoint detail for the quality signal.'),
195
160
  z.meta({ examples: ['providerEndpoint'] }),
196
161
  ),
197
162
  tier: z
198
- .enum(['liquid', 'thin', 'unknown', 'unavailable', 'error'])
163
+ .enum(['liquid', 'thin'])
199
164
  .check(
200
- z.describe('Machine-readable route quality tier.'),
201
- z.meta({ examples: ['unknown'] }),
165
+ z.describe('Machine-readable quality tier for a successful quote.'),
166
+ z.meta({ examples: ['liquid'] }),
202
167
  ),
203
168
  }),
204
- 'Machine-readable liquidity, fee, and source signals for a route candidate.',
169
+ 'Machine-readable liquidity, fee, and source signals for a successful quote.',
205
170
  )
206
171
 
207
- /** Provider-derived quote data for a route candidate. */
208
- export const RouteQuote = Schema.describe(
172
+ /** Provider-derived output, limits, and freshness data. */
173
+ export const QuoteDetails = Schema.describe(
209
174
  z.object({
210
- expiresAt: z
211
- .nullable(z.iso.datetime())
212
- .check(
213
- z.describe('Provider quote expiry timestamp.'),
214
- z.meta({ examples: ['2026-01-01T00:00:30Z'] }),
215
- ),
216
175
  inputAmount: Schema.DecimalString.check(
217
176
  z.describe('Source amount sent to the provider in base units.'),
218
177
  z.meta({ examples: ['1000000'] }),
219
178
  ),
220
- limits: z
221
- .nullable(
222
- z.object({
223
- instantSourceAmount: z
224
- .nullable(Schema.DecimalString)
225
- .check(
226
- z.describe('Provider-reported instant source amount capacity.'),
227
- z.meta({ examples: ['12453940000'] }),
228
- ),
229
- maxSourceAmount: z
230
- .nullable(Schema.DecimalString)
231
- .check(
232
- z.describe('Provider-reported maximum source amount.'),
233
- z.meta({ examples: ['1114274433200'] }),
234
- ),
235
- minSourceAmount: z
236
- .nullable(Schema.DecimalString)
237
- .check(
238
- z.describe('Provider-reported minimum source amount.'),
239
- z.meta({ examples: ['500063'] }),
240
- ),
241
- }),
242
- )
243
- .check(z.describe('Provider limits expressed in source base units.')),
244
179
  minimumOutputAmount: z
245
- .nullable(Schema.DecimalString)
180
+ .optional(Schema.DecimalString)
246
181
  .check(
247
182
  z.describe('Slippage-adjusted minimum destination amount in base units.'),
248
183
  z.meta({ examples: ['988000'] }),
249
184
  ),
250
185
  outputAmount: z
251
- .nullable(Schema.DecimalString)
186
+ .string()
187
+ .check(z.regex(/^\d+$/))
252
188
  .check(
253
189
  z.describe('Expected destination amount in base units.'),
254
190
  z.meta({ examples: ['989102'] }),
255
191
  ),
256
192
  outputAmountFormatted: z
257
- .nullable(z.string())
193
+ .string()
258
194
  .check(
259
195
  z.describe('Expected destination amount rendered with destination token decimals.'),
260
196
  z.meta({ examples: ['0.989102'] }),
@@ -262,163 +198,40 @@ export namespace schema {
262
198
  sampledAt: z.iso
263
199
  .datetime()
264
200
  .check(
265
- z.describe('Timestamp for the live quote or route probe.'),
201
+ z.describe('Timestamp for the live quote probe.'),
266
202
  z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
267
203
  ),
268
204
  }),
269
- 'Provider-derived quote, limit, and freshness data for a route candidate.',
270
- )
271
-
272
- /** Token reference attached to a normalized quote fee. */
273
- export const QuoteFeeToken = Schema.describe(
274
- z.object({
275
- address: z
276
- .string()
277
- .check(
278
- z.describe('Contract address of the fee token.'),
279
- z.meta({ examples: ['0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] }),
280
- ),
281
- chainId: z
282
- .string()
283
- .check(z.describe('CAIP-2 chain id of the fee token.'), z.meta({ examples: ['eip155:8453'] })), // prettier-ignore
284
- decimals: z
285
- .number()
286
- .check(
287
- z.int(),
288
- z.nonnegative(),
289
- z.describe('Number of decimal places used by the fee token.'),
290
- z.meta({ examples: [6] }),
291
- ),
292
- symbol: z
293
- .string()
294
- .check(z.describe('Ticker symbol of the fee token.'), z.meta({ examples: ['USDC'] })),
295
- }),
296
- 'Token in which a normalized quote fee is denominated.',
297
- )
298
-
299
- /** Normalized fee summary for an explicit funding quote. */
300
- export const QuoteFee = Schema.describe(
301
- z.object({
302
- amount: Schema.DecimalString.check(
303
- z.describe("Fee amount in the fee token's smallest unit."),
304
- z.meta({ examples: ['1200'] }),
305
- ),
306
- amountUsd: z
307
- .nullable(z.string().check(z.regex(/^\d+(\.\d+)?$/)))
308
- .check(
309
- z.describe('Provider-estimated USD value of the fee.'),
310
- z.meta({ examples: ['0.0012'] }),
311
- ),
312
- bps: z
313
- .nullable(z.number().check(z.int(), z.nonnegative()))
314
- .check(z.describe('Fee as basis points of the quoted input.'), z.meta({ examples: [12] })),
315
- token: QuoteFeeToken,
316
- }),
317
- 'Provider-neutral fee amount and denomination.',
205
+ 'Provider-derived output, limits, and freshness data for a funding quote.',
318
206
  )
319
207
 
320
- /** Explicit depositor-specific quote for one curated funding route. */
208
+ /** Successful live funding quote. */
321
209
  export const FundingQuote = Schema.describe(
322
- z.object({
323
- destinationChain: Chain.check(z.describe('Destination chain for the quoted route.')),
324
- destinationToken: Token.check(z.describe('Token received on the destination chain.')),
325
- estimatedSeconds: z
326
- .nullable(z.number().check(z.int(), z.nonnegative()))
327
- .check(z.describe('Estimated settlement time in seconds.'), z.meta({ examples: [2] })),
328
- expiresAt: z.iso
329
- .datetime()
330
- .check(
331
- z.describe('Timestamp after which the quote must not be used.'),
332
- z.meta({ examples: ['2026-01-01T00:01:00Z'] }),
333
- ),
334
- fees: z
335
- .object({
336
- total: QuoteFee.check(z.describe('Current estimated total fee.')),
337
- totalMax: QuoteFee.check(z.describe('Maximum total fee allowed by the quote.')),
338
- })
339
- .check(z.describe('Current and maximum provider fee summaries.')),
340
- inputAmount: Schema.DecimalString.check(
341
- z.describe('Exact source amount quoted in base units.'),
342
- z.meta({ examples: ['1000000'] }),
343
- ),
344
- minimumOutputAmount: Schema.DecimalString.check(
345
- z.describe('Slippage-adjusted minimum destination amount in base units.'),
346
- z.meta({ examples: ['988000'] }),
347
- ),
348
- outputAmount: Schema.DecimalString.check(
349
- z.describe('Expected destination amount in base units.'),
350
- z.meta({ examples: ['990000'] }),
351
- ),
352
- outputAmountFormatted: z
353
- .string()
354
- .check(
355
- z.describe('Expected destination amount rendered with token decimals.'),
356
- z.meta({ examples: ['0.99'] }),
357
- ),
358
- provider: ProviderRef.check(z.describe('Provider that produced the quote.')),
359
- routeId: z
360
- .string()
361
- .check(
362
- z.describe('Stable id of the curated route that was quoted.'),
363
- z.meta({ examples: ['base-usdc-tempo-usdce-across'] }),
364
- ),
365
- sampledAt: z.iso
366
- .datetime()
367
- .check(
368
- z.describe('Timestamp when Tempo sampled the provider quote.'),
369
- z.meta({ examples: ['2026-01-01T00:00:00Z'] }),
370
- ),
371
- sourceChain: Chain.check(z.describe('Source chain for the quoted route.')),
372
- sourceToken: Token.check(z.describe('Token spent on the source chain.')),
373
- }),
374
- 'Normalized quote information without provider execution payloads.',
375
- )
376
-
377
- /** Static or live funding route candidate. */
378
- export const RouteCandidate = Schema.describe(
379
210
  z.object({
380
211
  destinationChain: Chain.check(z.describe('Destination chain, always Tempo mainnet in V1.')),
381
- destinationToken: Token.check(z.describe('Tempo token expected from this route.')),
382
- errorCode: z
383
- .nullable(z.string())
384
- .check(
385
- z.describe('Stable route error code, when status is `error`.'),
386
- z.meta({ examples: ['provider_timeout'] }),
387
- ),
212
+ destinationToken: Token.check(z.describe('Tempo token expected from this quote.')),
388
213
  id: z
389
214
  .string()
390
215
  .check(
391
- z.describe('Stable deterministic route candidate id.'),
392
- z.meta({ examples: ['base-usdc-tempo-usdce-across'] }),
216
+ z.describe('Stable deterministic funding quote id.'),
217
+ z.meta({ examples: ['base-usdc-tempo-usdce-relay'] }),
393
218
  ),
394
219
  provider: ProviderRef,
395
220
  quality: Quality,
396
- quote: z
397
- .nullable(RouteQuote)
398
- .check(z.describe('Provider-derived quote data, when a live route probe succeeds.')),
221
+ quote: QuoteDetails,
399
222
  sourceAmount: TokenAmount,
400
223
  sourceChain: Chain.check(z.describe('Chain where the caller currently holds funds.')),
401
224
  sourceToken: Token.check(z.describe('Token the caller currently holds.')),
402
- status: z
403
- .enum(['available', 'thin', 'unknown', 'unavailable', 'error'])
404
- .check(
405
- z.describe('Provider-specific route status for the requested amount.'),
406
- z.meta({ examples: ['unknown'] }),
407
- ),
408
225
  }),
409
- 'One provider-specific funding route candidate.',
226
+ 'One successful provider-specific funding quote.',
410
227
  )
411
228
 
412
- /** Generic provider catalog entry. */
229
+ /** Funding quote provider catalog entry. */
413
230
  export const Provider = Schema.describe(
414
231
  z.object({
415
- capabilities: z
416
- .array(z.enum(['fundingRoutes']))
417
- .check(
418
- z.describe('Provider capabilities Tempo exposes through public APIs.'),
419
- z.meta({ examples: [['fundingRoutes']] }),
420
- ),
421
- id: z.string().check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
232
+ id: z
233
+ .literal('relay')
234
+ .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
422
235
  kind: z
423
236
  .string()
424
237
  .check(z.describe('Provider category.'), z.meta({ examples: ['solverNetwork'] })),
@@ -432,15 +245,15 @@ export namespace schema {
432
245
  z.meta({ examples: [false] }),
433
246
  ),
434
247
  status: z
435
- .enum(['configured', 'inventoryOnly', 'planned'])
248
+ .enum(['configured', 'unconfigured'])
436
249
  .check(
437
250
  z.describe(
438
- '`inventoryOnly` means Tempo exposes static route support but does not query live quotes yet. `planned` means the provider is listed for future support and may not return route candidates.',
251
+ '`configured` means live quotes are enabled for this deployment. `unconfigured` means the provider is supported but unavailable here.',
439
252
  ),
440
- z.meta({ examples: ['inventoryOnly'] }),
253
+ z.meta({ examples: ['configured', 'unconfigured'] }),
441
254
  ),
442
255
  }),
443
- 'One provider in the generic provider catalog.',
256
+ 'One funding quote provider.',
444
257
  )
445
258
 
446
259
  /** Chain inventory entry returned by the funding chains endpoint. */
@@ -451,9 +264,9 @@ export namespace schema {
451
264
  'One source chain and its known stablecoin inventory.',
452
265
  )
453
266
 
454
- /** Schemas for the listFundingRoutes operation. */
455
- export namespace listFundingRoutes {
456
- /** Query parameters for funding route discovery. */
267
+ /** Schemas for the quoteFunding operation. */
268
+ export namespace quoteFunding {
269
+ /** Query parameters for live funding quotes. */
457
270
  export const Query = z
458
271
  .strictObject({
459
272
  destinationToken: z
@@ -464,26 +277,21 @@ export namespace schema {
464
277
  ),
465
278
  z.meta({ examples: ['USDC.e'] }),
466
279
  ),
467
- include: z
468
- .optional(z.string())
469
- .check(
470
- z.describe('Comma-separated response expansions. V1 accepts `quotes`.'),
471
- z.meta({ examples: ['quotes'] }),
472
- ),
473
- limit: Schema.Limit,
474
280
  provider: z
475
- .optional(z.string())
281
+ .optional(z.literal('relay'))
476
282
  .check(
477
283
  z.describe(
478
- 'Only return candidates from this provider id, such as `across`, `relay`, or `bridge`. Planned providers can return an empty list.',
284
+ 'Only request a quote from this provider. The supported id is `relay`; omit it to query every configured provider.',
479
285
  ),
480
- z.meta({ examples: ['across', 'bridge'] }),
286
+ z.meta({ examples: ['relay'] }),
481
287
  ),
482
288
  sourceAmount: z
483
289
  .string()
484
290
  .check(
485
- z.minLength(1),
486
- z.describe('Source token amount. Base units by default, so 1 USDC is `1000000`.'),
291
+ z.regex(/^(?=.*[1-9])\d+(\.\d+)?$/),
292
+ z.describe(
293
+ 'Positive source token amount. Base units by default, so 1 USDC is `1000000`.',
294
+ ),
487
295
  z.meta({ examples: ['1000000'] }),
488
296
  ),
489
297
  sourceAmountUnits: z
@@ -493,98 +301,33 @@ export namespace schema {
493
301
  z.meta({ examples: ['baseUnits', 'decimal'] }),
494
302
  ),
495
303
  sourceChain: z
304
+ .string()
305
+ .check(
306
+ z.minLength(1),
307
+ z.describe('Source chain alias or CAIP-2 id, such as `base` or `eip155:8453`.'),
308
+ z.meta({ examples: ['base', 'eip155:8453'] }),
309
+ ),
310
+ sourceToken: z
496
311
  .string()
497
312
  .check(
498
313
  z.minLength(1),
499
314
  z.describe(
500
- 'Source chain alias or CAIP-2 id, such as `base`, `solana`, `tron`, or `eip155:8453`.',
315
+ 'Source token symbol, contract address, or Tempo token key. Symbol and address lookup is scoped to `sourceChain` and case-insensitive. An unknown token returns an empty list.',
501
316
  ),
502
- z.meta({ examples: ['base', 'solana', 'tron'] }),
503
- ),
504
- sourceToken: z.string().check(
505
- z.minLength(1),
506
- z.describe(
507
- 'Source token symbol, contract address, mint, or Tempo token key. Symbol lookup is scoped to `sourceChain`; EVM identifiers are case-insensitive, while Solana and Tron identifiers must match exactly. An unknown token returns an empty list, not an error.',
317
+ z.meta({ examples: ['USDC', '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] }),
508
318
  ),
509
- z.meta({
510
- examples: [
511
- 'USDC',
512
- 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
513
- 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
514
- ],
515
- }),
516
- ),
517
319
  })
518
- .check(z.describe('Query parameters for discovering funding routes into Tempo.'))
320
+ .check(z.describe('Query parameters for live funding quotes into Tempo.'))
519
321
 
520
- /** Non-paginated list of funding route candidates. */
322
+ /** Non-paginated list of successful funding quotes. */
521
323
  export const Response = Schema.describe(
522
324
  z.object({
523
- data: z
524
- .array(RouteCandidate)
525
- .check(z.describe('Funding route candidates matching the request.')),
325
+ data: z.array(FundingQuote).check(z.describe('Successful live funding quotes.')),
526
326
  }),
527
- 'A non-paginated list of funding route candidates.',
327
+ 'A non-paginated list of successful live funding quotes.',
528
328
  )
529
329
  }
530
330
 
531
- /** Schemas for the quoteFundingRoute operation. */
532
- export namespace quoteFundingRoute {
533
- /** JSON body for an explicit funding route quote. */
534
- export const Body = z
535
- .strictObject({
536
- depositor: Schema.Address.check(
537
- z.describe('Address that would submit the funding transaction.'),
538
- ),
539
- destinationToken: z
540
- .optional(z.string())
541
- .check(
542
- z.describe('Tempo destination token symbol, address, or token key.'),
543
- z.meta({ examples: ['USDC.e'] }),
544
- ),
545
- provider: z
546
- .literal('across')
547
- .check(
548
- z.describe('Provider id selected from funding route discovery.'),
549
- z.meta({ examples: ['across'] }),
550
- ),
551
- recipient: z
552
- .optional(Schema.Address)
553
- .check(z.describe('Optional destination recipient; defaults to the depositor.')),
554
- sourceAmount: z
555
- .string()
556
- .check(
557
- z.minLength(1),
558
- z.describe('Exact source amount to quote.'),
559
- z.meta({ examples: ['1000000'] }),
560
- ),
561
- sourceAmountUnits: z
562
- ._default(z.enum(['baseUnits', 'decimal']), 'baseUnits')
563
- .check(
564
- z.describe('Whether `sourceAmount` uses base units or decimal notation.'),
565
- z.meta({ examples: ['baseUnits'] }),
566
- ),
567
- sourceChain: z
568
- .string()
569
- .check(
570
- z.minLength(1),
571
- z.describe('Source chain alias or CAIP-2 id.'),
572
- z.meta({ examples: ['base'] }),
573
- ),
574
- sourceToken: z
575
- .string()
576
- .check(
577
- z.minLength(1),
578
- z.describe('Source token symbol, address, mint, or token key.'),
579
- z.meta({ examples: ['USDC'] }),
580
- ),
581
- })
582
- .check(z.describe('Parameters for a depositor-specific exact-input funding quote.'))
583
-
584
- /** Normalized funding quote without provider execution payloads. */
585
- export const Response = FundingQuote
586
- }
587
-
588
331
  /** Schemas for the listFundingChains operation. */
589
332
  export namespace listFundingChains {
590
333
  /** Non-paginated source-chain inventory. */
@@ -592,7 +335,7 @@ export namespace schema {
592
335
  z.object({
593
336
  data: z
594
337
  .array(ChainInventory)
595
- .check(z.describe('Source chains and stablecoins known to the funding route API.')),
338
+ .check(z.describe('Source chains and stablecoins supported by funding quotes.')),
596
339
  }),
597
340
  'A non-paginated list of source chains and stablecoin inventory.',
598
341
  )
@@ -600,168 +343,89 @@ export namespace schema {
600
343
 
601
344
  /** Schemas for the listProviders operation. */
602
345
  export namespace listProviders {
603
- /** Query parameters for the generic provider catalog. */
604
- export const Query = z
605
- .strictObject({
606
- capability: z
607
- .optional(z.enum(['fundingRoutes']))
608
- .check(
609
- z.describe('Optional provider capability filter.'),
610
- z.meta({ examples: ['fundingRoutes'] }),
611
- ),
612
- })
613
- .check(z.describe('Query parameters for listing providers.'))
614
-
615
- /** Non-paginated generic provider catalog. */
346
+ /** Non-paginated funding quote provider catalog. */
616
347
  export const Response = Schema.describe(
617
348
  z.object({
618
- data: z.array(Provider).check(z.describe("Providers in Tempo's generic provider catalog.")),
349
+ data: z.array(Provider).check(z.describe("Providers in Tempo's funding quote catalog.")),
619
350
  }),
620
- 'A non-paginated list of providers.',
351
+ 'A non-paginated list of funding quote providers.',
621
352
  )
622
353
  }
623
354
  }
624
355
 
625
- // Examples derive from the static inventory so they never drift from real responses.
626
- const fundingRouteResponseExamples = {
627
- baseUsdc: {
628
- description:
629
- '`GET /v1/funding/routes?sourceChain=base&sourceToken=USDC&sourceAmount=1000000&provider=across`',
630
- summary: 'Base USDC',
631
- value: {
632
- data: FundingRoutes.listStaticRoutes({
633
- limit: 10,
634
- provider: 'across',
635
- sourceAmount: '1000000',
636
- sourceAmountUnits: 'baseUnits',
637
- sourceChain: 'base',
638
- sourceToken: 'USDC',
639
- }),
640
- } satisfies z.output<typeof schema.listFundingRoutes.Response>,
641
- },
642
- solanaUsdc: {
643
- description:
644
- '`GET /v1/funding/routes?sourceChain=solana&sourceToken=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&sourceAmount=1000000&provider=bridge`',
645
- summary: 'Solana USDC',
646
- value: {
647
- data: FundingRoutes.listStaticRoutes({
648
- limit: 10,
649
- provider: 'bridge',
650
- sourceAmount: '1000000',
651
- sourceAmountUnits: 'baseUnits',
652
- sourceChain: 'solana',
653
- sourceToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
654
- }),
655
- } satisfies z.output<typeof schema.listFundingRoutes.Response>,
656
- },
657
- tronUsdt: {
658
- description:
659
- '`GET /v1/funding/routes?sourceChain=tron&sourceToken=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&sourceAmount=1000000&provider=bridge`',
660
- summary: 'Tron USDT',
661
- value: {
662
- data: FundingRoutes.listStaticRoutes({
663
- limit: 10,
664
- provider: 'bridge',
665
- sourceAmount: '1000000',
666
- sourceAmountUnits: 'baseUnits',
667
- sourceChain: 'tron',
668
- sourceToken: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
669
- }),
670
- } satisfies z.output<typeof schema.listFundingRoutes.Response>,
671
- },
672
- } satisfies OpenApi.responses.Options<
673
- typeof schema.listFundingRoutes.Response
674
- >['success']['examples']
356
+ const fundingQuoteResponseExample = (() => {
357
+ const [candidate] = FundingQuotes.listQuoteCandidates({
358
+ provider: 'relay',
359
+ sourceAmount: '1000000',
360
+ sourceAmountUnits: 'baseUnits',
361
+ sourceChain: 'base',
362
+ sourceToken: 'USDC',
363
+ })
364
+ if (!candidate) throw new Error('Missing Relay funding quote example candidate')
365
+ return {
366
+ data: [
367
+ {
368
+ ...candidate,
369
+ quality: {
370
+ estimatedSeconds: 1,
371
+ liquiditySource: 'providerQuote',
372
+ sourceDetail: 'relay:quote-v2',
373
+ tier: 'liquid',
374
+ },
375
+ quote: {
376
+ inputAmount: '1000000',
377
+ minimumOutputAmount: '939242',
378
+ outputAmount: '979295',
379
+ outputAmountFormatted: '0.979295',
380
+ sampledAt: '2026-01-01T00:00:00.000Z',
381
+ },
382
+ },
383
+ ],
384
+ }
385
+ })() satisfies z.output<typeof schema.quoteFunding.Response>
675
386
 
676
387
  const fundingChainsResponseExample = {
677
- data: FundingRoutes.listChains(),
388
+ data: FundingQuotes.listChains(),
678
389
  } satisfies z.output<typeof schema.listFundingChains.Response>
679
390
 
680
391
  const providersResponseExample = {
681
- data: FundingRoutes.listProviders(),
392
+ data: FundingQuotes.listProviders().map((provider) => ({
393
+ ...provider,
394
+ status: 'configured' as const,
395
+ })),
682
396
  } satisfies z.output<typeof schema.listProviders.Response>
683
397
 
684
- const [fundingQuoteRouteExample] = FundingRoutes.listStaticRoutes({
685
- destinationToken: 'USDC.e',
686
- limit: 1,
687
- provider: 'across',
688
- sourceAmount: '1000000',
689
- sourceAmountUnits: 'baseUnits',
690
- sourceChain: 'base',
691
- sourceToken: 'USDC',
692
- })
693
-
694
- const fundingQuoteResponseExample = {
695
- destinationChain: fundingQuoteRouteExample!.destinationChain,
696
- destinationToken: fundingQuoteRouteExample!.destinationToken,
697
- estimatedSeconds: 2,
698
- expiresAt: '2026-01-01T00:01:00Z',
699
- fees: {
700
- total: {
701
- amount: '1200',
702
- amountUsd: '0.0012',
703
- bps: 12,
704
- token: {
705
- address: fundingQuoteRouteExample!.sourceToken.address,
706
- chainId: fundingQuoteRouteExample!.sourceChain.id,
707
- decimals: fundingQuoteRouteExample!.sourceToken.decimals,
708
- symbol: fundingQuoteRouteExample!.sourceToken.symbol,
709
- },
710
- },
711
- totalMax: {
712
- amount: '1800',
713
- amountUsd: '0.0018',
714
- bps: 18,
715
- token: {
716
- address: fundingQuoteRouteExample!.sourceToken.address,
717
- chainId: fundingQuoteRouteExample!.sourceChain.id,
718
- decimals: fundingQuoteRouteExample!.sourceToken.decimals,
719
- symbol: fundingQuoteRouteExample!.sourceToken.symbol,
720
- },
721
- },
722
- },
723
- inputAmount: '1000000',
724
- minimumOutputAmount: '988000',
725
- outputAmount: '990000',
726
- outputAmountFormatted: '0.99',
727
- provider: fundingQuoteRouteExample!.provider,
728
- routeId: fundingQuoteRouteExample!.id,
729
- sampledAt: '2026-01-01T00:00:00Z',
730
- sourceChain: fundingQuoteRouteExample!.sourceChain,
731
- sourceToken: fundingQuoteRouteExample!.sourceToken,
732
- } satisfies z.output<typeof schema.quoteFundingRoute.Response>
733
-
734
- /** Mounts funding route discovery and generic provider inventory endpoints. */
398
+ /** Mounts live funding quotes and their supporting inventory endpoints. */
735
399
  export function funding(options: funding.Options = {}) {
736
400
  return new Hono<App.Environment>()
737
401
  .get(
738
- '/v1/funding/routes',
402
+ '/v1/funding/quotes',
739
403
  Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
740
- OpenApi.validate('query', schema.listFundingRoutes.Query, {
404
+ OpenApi.validate('query', schema.quoteFunding.Query, {
741
405
  code: 'query_invalid',
742
406
  message: 'Invalid query parameters',
743
407
  }),
744
408
  OpenApi.describeRoute({
745
409
  description:
746
- 'Lists provider-specific route candidates for moving a source stablecoin amount into Tempo. This endpoint is discovery-only: it does not execute a bridge, reserve liquidity, or guarantee settlement. Static inventory candidates use `status: unknown`; provider adapters may add best-effort live quote fields.',
747
- operationId: 'listFundingRoutes',
410
+ 'Returns live quotes for funding Tempo with a stablecoin. Omit `provider` to query all configured providers. This endpoint does not execute a transfer.',
411
+ operationId: 'quoteFunding',
748
412
  responses: OpenApi.responses({
749
- errors: { 400: { codes: ['query_invalid'] } },
413
+ errors: {
414
+ 400: { codes: ['query_invalid'] },
415
+ 502: {
416
+ codes: ['upstream_error'],
417
+ description: 'Every matching quote provider failed unexpectedly.',
418
+ },
419
+ },
750
420
  success: {
751
- description:
752
- 'Discovery-only funding route candidates for the requested source chain and token.',
753
- examples: fundingRouteResponseExamples,
754
- schema: schema.listFundingRoutes.Response,
421
+ description: 'Live funding quotes. An empty list means no provider returned a quote.',
422
+ example: fundingQuoteResponseExample,
423
+ schema: schema.quoteFunding.Response,
755
424
  },
756
425
  }),
757
- summary: 'List funding routes',
426
+ summary: 'Get funding quotes',
758
427
  tags: ['Funding'],
759
428
  }),
760
- Cache.response<App.Environment>({
761
- cacheControl: Cache.policies.noStore,
762
- name: 'tempo-api:funding-routes:v1',
763
- key: (c) => Cache.urlKey(c, schema.listFundingRoutes.Query),
764
- }),
765
429
  async (c) => {
766
430
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
767
431
  if (OpenApi.narrowValidation)
@@ -772,16 +436,14 @@ export function funding(options: funding.Options = {}) {
772
436
 
773
437
  const query = c.req.valid('query')
774
438
  try {
775
- const include = FundingRoutes.parseInclude(query.include)
439
+ c.header('Cache-Control', 'no-store')
776
440
  return c.json(
777
- Response.validated(schema.listFundingRoutes.Response, {
778
- data: await FundingRoutes.listRoutes({
441
+ Response.validated(schema.quoteFunding.Response, {
442
+ data: await FundingQuotes.listQuotes({
779
443
  adapters: options.adapters,
780
444
  adapterTimeoutMs: options.adapterTimeoutMs,
781
445
  cache: { bypass: cacheBypass(c.req.raw) },
782
446
  destinationToken: query.destinationToken,
783
- include,
784
- limit: query.limit,
785
447
  provider: query.provider,
786
448
  sourceAmount: query.sourceAmount,
787
449
  sourceAmountUnits: query.sourceAmountUnits,
@@ -794,103 +456,12 @@ export function funding(options: funding.Options = {}) {
794
456
  } catch (cause) {
795
457
  const message = requestErrorMessage(cause)
796
458
  if (message) return Response.error(c, { code: 'query_invalid', message, status: 400 })
797
- throw cause
798
- }
799
- },
800
- )
801
- .post(
802
- '/v1/funding/routes/quote',
803
- Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
804
- OpenApi.validate('json', schema.quoteFundingRoute.Body, {
805
- code: 'body_invalid',
806
- message: 'Invalid quote parameters',
807
- }),
808
- OpenApi.describeRoute({
809
- description:
810
- 'Gets a depositor-specific exact-input quote for one curated funding route. The response excludes provider transaction calldata, approvals, and wallet balance details.',
811
- operationId: 'quoteFundingRoute',
812
- responses: OpenApi.responses({
813
- errors: {
814
- 400: { codes: ['body_invalid'] },
815
- 404: { codes: ['route_not_found', 'quote_unavailable'] },
816
- 501: { codes: ['provider_unconfigured'] },
817
- 502: { codes: ['provider_error', 'provider_rate_limited', 'provider_timeout'] },
818
- },
819
- success: {
820
- description: 'Normalized route quote without provider execution payloads.',
821
- example: fundingQuoteResponseExample,
822
- schema: schema.quoteFundingRoute.Response,
823
- },
824
- }),
825
- summary: 'Quote funding route',
826
- tags: ['Funding'],
827
- }),
828
- async (c) => {
829
- if (Auth.narrowAccess) return Auth.paidAccessError(c)
830
- if (OpenApi.narrowValidation)
831
- return OpenApi.validationError(c, {
832
- code: 'body_invalid',
833
- message: 'Invalid quote parameters',
834
- })
835
-
836
- const body = c.req.valid('json')
837
- try {
838
- const quote = await FundingRoutes.quoteRoute({
839
- depositor: body.depositor,
840
- destinationToken: body.destinationToken,
841
- provider: body.provider,
842
- quote: options.acrossQuote,
843
- quoteTimeoutMs: options.quoteTimeoutMs,
844
- recipient: body.recipient,
845
- sourceAmount: body.sourceAmount,
846
- sourceAmountUnits: body.sourceAmountUnits,
847
- sourceChain: body.sourceChain,
848
- sourceToken: body.sourceToken,
849
- })
850
- c.header('Cache-Control', 'no-store')
851
- return c.json(Response.validated(schema.quoteFundingRoute.Response, quote), 200)
852
- } catch (cause) {
853
- const message = requestErrorMessage(cause)
854
- if (message) return Response.error(c, { code: 'body_invalid', message, status: 400 })
855
- if (cause instanceof FundingRoutes.FundingRouteNotFoundError)
459
+ if (cause instanceof FundingQuotes.ProviderQuoteError)
856
460
  return Response.error(c, {
857
- code: 'route_not_found',
858
- message: 'No curated funding route matches the request.',
859
- status: 404,
860
- })
861
- if (cause instanceof FundingRoutes.ProviderQuoteUnavailableError)
862
- return Response.error(c, {
863
- code: 'quote_unavailable',
864
- message: 'The provider cannot quote this route.',
865
- status: 404,
866
- })
867
- if (cause instanceof FundingRoutes.ProviderNotConfiguredError)
868
- return Response.error(c, {
869
- code: 'provider_unconfigured',
870
- message: 'The provider quote integration is not configured.',
871
- status: 501,
872
- })
873
- if (cause instanceof FundingRoutes.ProviderRateLimitError)
874
- return Response.error(c, {
875
- code: 'provider_rate_limited',
876
- message: 'The provider temporarily rate-limited this quote.',
461
+ code: 'upstream_error',
462
+ message: 'Quote providers could not complete the request.',
877
463
  status: 502,
878
464
  })
879
- if (cause instanceof FundingRoutes.ProviderAdapterTimeoutError)
880
- return Response.error(c, {
881
- code: 'provider_timeout',
882
- message: 'The provider quote timed out.',
883
- status: 502,
884
- })
885
- if (cause instanceof Error) {
886
- const providerFailure = FundingRouteProviders.acrossQuoteFailure({ cause })
887
- if (providerFailure) c.set('providerFailure', providerFailure)
888
- return Response.error(c, {
889
- code: 'provider_error',
890
- message: 'The provider could not complete the quote.',
891
- status: 502,
892
- })
893
- }
894
465
  throw cause
895
466
  }
896
467
  },
@@ -900,11 +471,11 @@ export function funding(options: funding.Options = {}) {
900
471
  Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
901
472
  OpenApi.describeRoute({
902
473
  description:
903
- 'Lists source chains and stablecoins understood by the funding route API, including provider-specific ids useful when comparing provider docs. This is static inventory metadata, not a live liquidity check.',
474
+ 'Lists the source chains and stablecoins you can use when requesting a funding quote.',
904
475
  operationId: 'listFundingChains',
905
476
  responses: OpenApi.responses({
906
477
  success: {
907
- description: 'Source-chain and stablecoin inventory for funding route discovery.',
478
+ description: 'Supported source chains and stablecoins.',
908
479
  example: fundingChainsResponseExample,
909
480
  schema: schema.listFundingChains.Response,
910
481
  },
@@ -921,55 +492,39 @@ export function funding(options: funding.Options = {}) {
921
492
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
922
493
  return c.json(
923
494
  Response.validated(schema.listFundingChains.Response, {
924
- data: FundingRoutes.listChains(),
495
+ data: FundingQuotes.listChains(),
925
496
  }),
926
497
  200,
927
498
  )
928
499
  },
929
500
  )
930
501
  .get(
931
- '/v1/providers',
502
+ '/v1/funding/providers',
932
503
  Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
933
- OpenApi.validate('query', schema.listProviders.Query, {
934
- code: 'query_invalid',
935
- message: 'Invalid query parameters',
936
- }),
937
504
  OpenApi.describeRoute({
938
505
  description:
939
- 'Lists provider metadata, capability flags, auth requirements, and integration status across provider domains. `inventoryOnly` providers can appear in static route candidates; `planned` providers are visible for roadmap transparency and may not return candidates.',
940
- operationId: 'listProviders',
506
+ 'Lists funding quote providers and whether live quoting is configured for this deployment.',
507
+ operationId: 'listFundingProviders',
941
508
  responses: OpenApi.responses({
942
- errors: { 400: { codes: ['query_invalid'] } },
943
509
  success: {
944
- description: 'Providers known to Tempo.',
510
+ description: 'Funding quote providers supported by Tempo.',
945
511
  example: providersResponseExample,
946
512
  schema: schema.listProviders.Response,
947
513
  },
948
514
  }),
949
- summary: 'List providers',
950
- tags: ['Providers'],
515
+ summary: 'List funding providers',
516
+ tags: ['Funding'],
951
517
  }),
952
518
  Cache.response<App.Environment>({
953
519
  cacheControl: Cache.policies.stable,
954
- name: 'tempo-api:providers:v1',
955
- key: (c) => Cache.urlKey(c, schema.listProviders.Query),
520
+ name: 'tempo-api:funding-providers:v1',
521
+ key: (c) => c.req.url,
956
522
  }),
957
523
  (c) => {
958
524
  if (Auth.narrowAccess) return Auth.paidAccessError(c)
959
- if (OpenApi.narrowValidation)
960
- return OpenApi.validationError(c, {
961
- code: 'query_invalid',
962
- message: 'Invalid query parameters',
963
- })
964
-
965
- const query = c.req.valid('query')
966
525
  return c.json(
967
526
  Response.validated(schema.listProviders.Response, {
968
- data: FundingRoutes.listProviders({
969
- adapters: options.adapters,
970
- capability: query.capability,
971
- configuredProviders: options.acrossQuote ? ['across'] : [],
972
- }),
527
+ data: FundingQuotes.listProviders({ adapters: options.adapters }),
973
528
  }),
974
529
  200,
975
530
  )
@@ -978,27 +533,22 @@ export function funding(options: funding.Options = {}) {
978
533
  }
979
534
 
980
535
  export declare namespace funding {
981
- /** Options for funding route discovery. */
536
+ /** Options for live funding quotes. */
982
537
  type Options = {
983
- /** Across explicit quote capability. */
984
- acrossQuote?: FundingRoutes.ProviderQuote | undefined
985
- /** Provider adapters used to enrich static inventory with live data. */
986
- adapters?: FundingRoutes.ProviderAdapters | undefined
538
+ /** Provider adapters used to request live quotes. */
539
+ adapters?: FundingQuotes.ProviderAdapters | undefined
987
540
  /** Per-provider quote timeout in milliseconds. */
988
541
  adapterTimeoutMs?: number | undefined
989
- /** Timeout for depositor-specific provider quotes. */
990
- quoteTimeoutMs?: number | undefined
991
542
  }
992
543
  }
993
544
 
994
545
  // Maps caller-input errors to a specific 400 message; anything else rethrows.
995
546
  function requestErrorMessage(cause: unknown) {
996
- if (cause instanceof FundingRoutes.InvalidAmountError) return 'Invalid `sourceAmount`.'
997
- if (cause instanceof FundingRoutes.UnsupportedIncludeError) return 'Unsupported `include`.'
998
- if (cause instanceof FundingRoutes.UnsupportedDestinationTokenError)
547
+ if (cause instanceof FundingQuotes.InvalidAmountError) return 'Invalid `sourceAmount`.'
548
+ if (cause instanceof FundingQuotes.UnsupportedDestinationTokenError)
999
549
  return 'Unsupported `destinationToken`.'
1000
- if (cause instanceof FundingRoutes.UnsupportedProviderError) return 'Unsupported `provider`.'
1001
- if (cause instanceof FundingRoutes.UnsupportedSourceChainError)
550
+ if (cause instanceof FundingQuotes.UnsupportedProviderError) return 'Unsupported `provider`.'
551
+ if (cause instanceof FundingQuotes.UnsupportedSourceChainError)
1002
552
  return 'Unsupported `sourceChain`.'
1003
553
  return undefined
1004
554
  }