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
@@ -2,32 +2,31 @@ import { Hono } from 'hono';
2
2
  import * as z from 'zod/mini';
3
3
  import * as Auth from '../../../internal/Auth.js';
4
4
  import * as Cache from '../../../internal/Cache.js';
5
- import * as FundingRoutes from '../../../internal/FundingRoutes.js';
5
+ import * as FundingQuotes from '../../../internal/FundingQuotes.js';
6
6
  import * as OpenApi from '../../../internal/OpenApi.js';
7
7
  import * as Response from '../../../internal/Response.js';
8
8
  import * as Schema from '../../../internal/Schema.js';
9
- import * as FundingRouteProviders from '../FundingRouteProviders.js';
10
- /** Zod schemas owned by the funding routes resource. */
9
+ /** Zod schemas owned by funding quote resources. */
11
10
  export var schema;
12
11
  (function (schema) {
13
12
  /** Source or destination chain reference. */
14
13
  schema.Chain = Schema.describe(z.object({
15
14
  addressFormat: z
16
- .enum(['evm', 'solana', 'tron'])
15
+ .literal('evm')
17
16
  .check(z.describe('Address family used by accounts and token identifiers on this chain.'), z.meta({ examples: ['evm'] })),
18
17
  id: z
19
18
  .string()
20
- .check(z.describe('Stable chain id, preferably CAIP-2 when one exists. Funding spans non-EVM chains, so ids are strings, unlike numeric `chainId` params elsewhere.'), z.meta({ examples: ['eip155:8453'] })),
19
+ .check(z.describe('Stable CAIP-2 chain id, represented as a string instead of the numeric `chainId` used elsewhere.'), z.meta({ examples: ['eip155:8453'] })),
21
20
  kind: z
22
- .enum(['evm', 'solana', 'tron'])
21
+ .literal('evm')
23
22
  .check(z.describe('Chain execution family used for provider routing.'), z.meta({ examples: ['evm'] })),
24
23
  name: z
25
24
  .string()
26
25
  .check(z.describe('Human-readable chain name.'), z.meta({ examples: ['Base'] })),
27
26
  providerIds: z
28
27
  .optional(z.record(z.string(), z.string()))
29
- .check(z.describe('Provider-specific chain ids Tempo uses when querying route providers.'), z.meta({ examples: [{ across: '8453', relay: '8453' }] })),
30
- }), 'A normalized chain reference for funding routes.');
28
+ .check(z.describe('Provider-specific chain ids Tempo uses when requesting quotes.'), z.meta({ examples: [{ relay: '8453' }] })),
29
+ }), 'A normalized chain reference for funding quotes.');
31
30
  /** Source or destination token reference. */
32
31
  schema.Token = Schema.describe(z.object({
33
32
  address: z
@@ -53,179 +52,81 @@ export var schema;
53
52
  })),
54
53
  verified: z
55
54
  .boolean()
56
- .check(z.describe('Whether Tempo recognizes this token in its funding route inventory.'), z.meta({ examples: [true] })),
57
- }), 'A normalized token reference for funding routes.');
58
- /** Source amount echoed by a funding route response. */
55
+ .check(z.describe('Whether Tempo recognizes this token in its funding quote inventory.'), z.meta({ examples: [true] })),
56
+ }), 'A normalized token reference for funding quotes.');
57
+ /** Source amount echoed by a funding quote response. */
59
58
  schema.TokenAmount = Schema.describe(z.object({
60
59
  amount: Schema.DecimalString.check(z.describe("The requested source amount in the token's smallest unit.")),
61
60
  formatted: z
62
61
  .string()
63
62
  .check(z.describe('The same amount in human-readable decimal form, using the source token’s `decimals`.'), z.meta({ examples: ['1'] })),
64
- usd: z
65
- .nullable(z.string())
66
- .check(z.describe('USD estimate for the requested source amount, when available.'), z.meta({ examples: ['1.00'] })),
67
63
  }), 'The requested source amount in provider-safe base units and display form.');
68
- /** Provider summary embedded in a route candidate. */
64
+ /** Provider summary embedded in a funding quote. */
69
65
  schema.ProviderRef = Schema.describe(z.object({
70
- id: z.string().check(z.describe('Stable provider id.'), z.meta({ examples: ['across'] })),
66
+ id: z
67
+ .literal('relay')
68
+ .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
71
69
  kind: z
72
70
  .string()
73
- .check(z.describe('Provider category, such as an intent bridge, solver network, or aggregator.'), z.meta({ examples: ['intentBridge'] })),
71
+ .check(z.describe('Provider category, such as a solver network or aggregator.'), z.meta({ examples: ['solverNetwork'] })),
74
72
  name: z
75
73
  .string()
76
- .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Across'] })),
74
+ .check(z.describe('Human-readable provider name.'), z.meta({ examples: ['Relay'] })),
77
75
  requiresApiKey: z
78
76
  .boolean()
79
- .check(z.describe('Whether Tempo needs provider credentials to query or use this provider.'), z.meta({ examples: [true] })),
80
- }), 'Provider metadata embedded in a route candidate.');
81
- /** Route quality signals exposed directly instead of implied by list order. */
77
+ .check(z.describe('Whether Tempo needs provider credentials to query or use this provider.'), z.meta({ examples: [false] })),
78
+ }), 'Provider metadata embedded in a funding quote.');
79
+ /** Quote quality signals exposed directly instead of implied by list order. */
82
80
  schema.Quality = Schema.describe(z.object({
83
- availableVolumeUsd: z
84
- .nullable(z.string())
85
- .check(z.describe('Available USD capacity, when available.'), z.meta({ examples: ['1114274.43'] })),
86
81
  estimatedSeconds: z
87
- .nullable(z.number().check(z.int(), z.nonnegative()))
82
+ .optional(z.number().check(z.int(), z.nonnegative()))
88
83
  .check(z.describe('Estimated settlement time in seconds, when known.'), z.meta({ examples: [2] })),
89
- feeBps: z
90
- .nullable(z.number().check(z.int(), z.nonnegative()))
91
- .check(z.describe('Estimated fee in basis points, when known.'), z.meta({ examples: [109] })),
92
- historicalVolumeUsd24h: z
93
- .nullable(z.string())
94
- .check(z.describe('24h routed volume in USD, when available.'), z.meta({ examples: ['250000.00'] })),
95
- instantVolumeUsd: z
96
- .nullable(z.string())
97
- .check(z.describe('Instant USD capacity, when available.'), z.meta({ examples: ['12453.94'] })),
98
84
  liquiditySource: z
99
85
  .string()
100
- .check(z.describe('Where the liquidity or support signal came from.'), z.meta({ examples: ['staticInventory'] })),
101
- score: z
102
- .nullable(z.number().check(z.int(), z.gte(0), z.lte(100)))
103
- .check(z.describe('Explainable route score from 0 to 100, when enough signals are available.'), z.meta({ examples: [91] })),
86
+ .check(z.describe('Provider source for the live quote quality signal.'), z.meta({ examples: ['providerQuote'] })),
104
87
  sourceDetail: z
105
- .nullable(z.string())
88
+ .optional(z.string())
106
89
  .check(z.describe('Provider-specific source or endpoint detail for the quality signal.'), z.meta({ examples: ['providerEndpoint'] })),
107
90
  tier: z
108
- .enum(['liquid', 'thin', 'unknown', 'unavailable', 'error'])
109
- .check(z.describe('Machine-readable route quality tier.'), z.meta({ examples: ['unknown'] })),
110
- }), 'Machine-readable liquidity, fee, and source signals for a route candidate.');
111
- /** Provider-derived quote data for a route candidate. */
112
- schema.RouteQuote = Schema.describe(z.object({
113
- expiresAt: z
114
- .nullable(z.iso.datetime())
115
- .check(z.describe('Provider quote expiry timestamp.'), z.meta({ examples: ['2026-01-01T00:00:30Z'] })),
91
+ .enum(['liquid', 'thin'])
92
+ .check(z.describe('Machine-readable quality tier for a successful quote.'), z.meta({ examples: ['liquid'] })),
93
+ }), 'Machine-readable liquidity, fee, and source signals for a successful quote.');
94
+ /** Provider-derived output, limits, and freshness data. */
95
+ schema.QuoteDetails = Schema.describe(z.object({
116
96
  inputAmount: Schema.DecimalString.check(z.describe('Source amount sent to the provider in base units.'), z.meta({ examples: ['1000000'] })),
117
- limits: z
118
- .nullable(z.object({
119
- instantSourceAmount: z
120
- .nullable(Schema.DecimalString)
121
- .check(z.describe('Provider-reported instant source amount capacity.'), z.meta({ examples: ['12453940000'] })),
122
- maxSourceAmount: z
123
- .nullable(Schema.DecimalString)
124
- .check(z.describe('Provider-reported maximum source amount.'), z.meta({ examples: ['1114274433200'] })),
125
- minSourceAmount: z
126
- .nullable(Schema.DecimalString)
127
- .check(z.describe('Provider-reported minimum source amount.'), z.meta({ examples: ['500063'] })),
128
- }))
129
- .check(z.describe('Provider limits expressed in source base units.')),
130
97
  minimumOutputAmount: z
131
- .nullable(Schema.DecimalString)
98
+ .optional(Schema.DecimalString)
132
99
  .check(z.describe('Slippage-adjusted minimum destination amount in base units.'), z.meta({ examples: ['988000'] })),
133
100
  outputAmount: z
134
- .nullable(Schema.DecimalString)
101
+ .string()
102
+ .check(z.regex(/^\d+$/))
135
103
  .check(z.describe('Expected destination amount in base units.'), z.meta({ examples: ['989102'] })),
136
104
  outputAmountFormatted: z
137
- .nullable(z.string())
105
+ .string()
138
106
  .check(z.describe('Expected destination amount rendered with destination token decimals.'), z.meta({ examples: ['0.989102'] })),
139
107
  sampledAt: z.iso
140
108
  .datetime()
141
- .check(z.describe('Timestamp for the live quote or route probe.'), z.meta({ examples: ['2026-01-01T00:00:00Z'] })),
142
- }), 'Provider-derived quote, limit, and freshness data for a route candidate.');
143
- /** Token reference attached to a normalized quote fee. */
144
- schema.QuoteFeeToken = Schema.describe(z.object({
145
- address: z
146
- .string()
147
- .check(z.describe('Contract address of the fee token.'), z.meta({ examples: ['0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] })),
148
- chainId: z
149
- .string()
150
- .check(z.describe('CAIP-2 chain id of the fee token.'), z.meta({ examples: ['eip155:8453'] })), // prettier-ignore
151
- decimals: z
152
- .number()
153
- .check(z.int(), z.nonnegative(), z.describe('Number of decimal places used by the fee token.'), z.meta({ examples: [6] })),
154
- symbol: z
155
- .string()
156
- .check(z.describe('Ticker symbol of the fee token.'), z.meta({ examples: ['USDC'] })),
157
- }), 'Token in which a normalized quote fee is denominated.');
158
- /** Normalized fee summary for an explicit funding quote. */
159
- schema.QuoteFee = Schema.describe(z.object({
160
- amount: Schema.DecimalString.check(z.describe("Fee amount in the fee token's smallest unit."), z.meta({ examples: ['1200'] })),
161
- amountUsd: z
162
- .nullable(z.string().check(z.regex(/^\d+(\.\d+)?$/)))
163
- .check(z.describe('Provider-estimated USD value of the fee.'), z.meta({ examples: ['0.0012'] })),
164
- bps: z
165
- .nullable(z.number().check(z.int(), z.nonnegative()))
166
- .check(z.describe('Fee as basis points of the quoted input.'), z.meta({ examples: [12] })),
167
- token: schema.QuoteFeeToken,
168
- }), 'Provider-neutral fee amount and denomination.');
169
- /** Explicit depositor-specific quote for one curated funding route. */
109
+ .check(z.describe('Timestamp for the live quote probe.'), z.meta({ examples: ['2026-01-01T00:00:00Z'] })),
110
+ }), 'Provider-derived output, limits, and freshness data for a funding quote.');
111
+ /** Successful live funding quote. */
170
112
  schema.FundingQuote = Schema.describe(z.object({
171
- destinationChain: schema.Chain.check(z.describe('Destination chain for the quoted route.')),
172
- destinationToken: schema.Token.check(z.describe('Token received on the destination chain.')),
173
- estimatedSeconds: z
174
- .nullable(z.number().check(z.int(), z.nonnegative()))
175
- .check(z.describe('Estimated settlement time in seconds.'), z.meta({ examples: [2] })),
176
- expiresAt: z.iso
177
- .datetime()
178
- .check(z.describe('Timestamp after which the quote must not be used.'), z.meta({ examples: ['2026-01-01T00:01:00Z'] })),
179
- fees: z
180
- .object({
181
- total: schema.QuoteFee.check(z.describe('Current estimated total fee.')),
182
- totalMax: schema.QuoteFee.check(z.describe('Maximum total fee allowed by the quote.')),
183
- })
184
- .check(z.describe('Current and maximum provider fee summaries.')),
185
- inputAmount: Schema.DecimalString.check(z.describe('Exact source amount quoted in base units.'), z.meta({ examples: ['1000000'] })),
186
- minimumOutputAmount: Schema.DecimalString.check(z.describe('Slippage-adjusted minimum destination amount in base units.'), z.meta({ examples: ['988000'] })),
187
- outputAmount: Schema.DecimalString.check(z.describe('Expected destination amount in base units.'), z.meta({ examples: ['990000'] })),
188
- outputAmountFormatted: z
189
- .string()
190
- .check(z.describe('Expected destination amount rendered with token decimals.'), z.meta({ examples: ['0.99'] })),
191
- provider: schema.ProviderRef.check(z.describe('Provider that produced the quote.')),
192
- routeId: z
193
- .string()
194
- .check(z.describe('Stable id of the curated route that was quoted.'), z.meta({ examples: ['base-usdc-tempo-usdce-across'] })),
195
- sampledAt: z.iso
196
- .datetime()
197
- .check(z.describe('Timestamp when Tempo sampled the provider quote.'), z.meta({ examples: ['2026-01-01T00:00:00Z'] })),
198
- sourceChain: schema.Chain.check(z.describe('Source chain for the quoted route.')),
199
- sourceToken: schema.Token.check(z.describe('Token spent on the source chain.')),
200
- }), 'Normalized quote information without provider execution payloads.');
201
- /** Static or live funding route candidate. */
202
- schema.RouteCandidate = Schema.describe(z.object({
203
113
  destinationChain: schema.Chain.check(z.describe('Destination chain, always Tempo mainnet in V1.')),
204
- destinationToken: schema.Token.check(z.describe('Tempo token expected from this route.')),
205
- errorCode: z
206
- .nullable(z.string())
207
- .check(z.describe('Stable route error code, when status is `error`.'), z.meta({ examples: ['provider_timeout'] })),
114
+ destinationToken: schema.Token.check(z.describe('Tempo token expected from this quote.')),
208
115
  id: z
209
116
  .string()
210
- .check(z.describe('Stable deterministic route candidate id.'), z.meta({ examples: ['base-usdc-tempo-usdce-across'] })),
117
+ .check(z.describe('Stable deterministic funding quote id.'), z.meta({ examples: ['base-usdc-tempo-usdce-relay'] })),
211
118
  provider: schema.ProviderRef,
212
119
  quality: schema.Quality,
213
- quote: z
214
- .nullable(schema.RouteQuote)
215
- .check(z.describe('Provider-derived quote data, when a live route probe succeeds.')),
120
+ quote: schema.QuoteDetails,
216
121
  sourceAmount: schema.TokenAmount,
217
122
  sourceChain: schema.Chain.check(z.describe('Chain where the caller currently holds funds.')),
218
123
  sourceToken: schema.Token.check(z.describe('Token the caller currently holds.')),
219
- status: z
220
- .enum(['available', 'thin', 'unknown', 'unavailable', 'error'])
221
- .check(z.describe('Provider-specific route status for the requested amount.'), z.meta({ examples: ['unknown'] })),
222
- }), 'One provider-specific funding route candidate.');
223
- /** Generic provider catalog entry. */
124
+ }), 'One successful provider-specific funding quote.');
125
+ /** Funding quote provider catalog entry. */
224
126
  schema.Provider = Schema.describe(z.object({
225
- capabilities: z
226
- .array(z.enum(['fundingRoutes']))
227
- .check(z.describe('Provider capabilities Tempo exposes through public APIs.'), z.meta({ examples: [['fundingRoutes']] })),
228
- id: z.string().check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
127
+ id: z
128
+ .literal('relay')
129
+ .check(z.describe('Stable provider id.'), z.meta({ examples: ['relay'] })),
229
130
  kind: z
230
131
  .string()
231
132
  .check(z.describe('Provider category.'), z.meta({ examples: ['solverNetwork'] })),
@@ -236,87 +137,44 @@ export var schema;
236
137
  .boolean()
237
138
  .check(z.describe('Whether Tempo needs provider credentials to query or use this provider.'), z.meta({ examples: [false] })),
238
139
  status: z
239
- .enum(['configured', 'inventoryOnly', 'planned'])
240
- .check(z.describe('`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.'), z.meta({ examples: ['inventoryOnly'] })),
241
- }), 'One provider in the generic provider catalog.');
140
+ .enum(['configured', 'unconfigured'])
141
+ .check(z.describe('`configured` means live quotes are enabled for this deployment. `unconfigured` means the provider is supported but unavailable here.'), z.meta({ examples: ['configured', 'unconfigured'] })),
142
+ }), 'One funding quote provider.');
242
143
  /** Chain inventory entry returned by the funding chains endpoint. */
243
144
  schema.ChainInventory = Schema.describe(z.extend(schema.Chain, {
244
145
  tokens: z.array(schema.Token).check(z.describe('Stablecoins known on this source chain.')),
245
146
  }), 'One source chain and its known stablecoin inventory.');
246
- /** Schemas for the listFundingRoutes operation. */
247
- let listFundingRoutes;
248
- (function (listFundingRoutes) {
249
- /** Query parameters for funding route discovery. */
250
- listFundingRoutes.Query = z
147
+ /** Schemas for the quoteFunding operation. */
148
+ let quoteFunding;
149
+ (function (quoteFunding) {
150
+ /** Query parameters for live funding quotes. */
151
+ quoteFunding.Query = z
251
152
  .strictObject({
252
153
  destinationToken: z
253
154
  .optional(z.string())
254
155
  .check(z.describe('Tempo destination token symbol, address, or token key. Defaults to USDC.e.'), z.meta({ examples: ['USDC.e'] })),
255
- include: z
256
- .optional(z.string())
257
- .check(z.describe('Comma-separated response expansions. V1 accepts `quotes`.'), z.meta({ examples: ['quotes'] })),
258
- limit: Schema.Limit,
259
156
  provider: z
260
- .optional(z.string())
261
- .check(z.describe('Only return candidates from this provider id, such as `across`, `relay`, or `bridge`. Planned providers can return an empty list.'), z.meta({ examples: ['across', 'bridge'] })),
157
+ .optional(z.literal('relay'))
158
+ .check(z.describe('Only request a quote from this provider. The supported id is `relay`; omit it to query every configured provider.'), z.meta({ examples: ['relay'] })),
262
159
  sourceAmount: z
263
160
  .string()
264
- .check(z.minLength(1), z.describe('Source token amount. Base units by default, so 1 USDC is `1000000`.'), z.meta({ examples: ['1000000'] })),
161
+ .check(z.regex(/^(?=.*[1-9])\d+(\.\d+)?$/), z.describe('Positive source token amount. Base units by default, so 1 USDC is `1000000`.'), z.meta({ examples: ['1000000'] })),
265
162
  sourceAmountUnits: z
266
163
  ._default(z.enum(['baseUnits', 'decimal']), 'baseUnits')
267
164
  .check(z.describe('Whether `sourceAmount` is base units or a human-readable decimal.'), z.meta({ examples: ['baseUnits', 'decimal'] })),
268
165
  sourceChain: z
269
166
  .string()
270
- .check(z.minLength(1), z.describe('Source chain alias or CAIP-2 id, such as `base`, `solana`, `tron`, or `eip155:8453`.'), z.meta({ examples: ['base', 'solana', 'tron'] })),
271
- sourceToken: z.string().check(z.minLength(1), z.describe('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.'), z.meta({
272
- examples: [
273
- 'USDC',
274
- 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
275
- 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
276
- ],
277
- })),
278
- })
279
- .check(z.describe('Query parameters for discovering funding routes into Tempo.'));
280
- /** Non-paginated list of funding route candidates. */
281
- listFundingRoutes.Response = Schema.describe(z.object({
282
- data: z
283
- .array(schema.RouteCandidate)
284
- .check(z.describe('Funding route candidates matching the request.')),
285
- }), 'A non-paginated list of funding route candidates.');
286
- })(listFundingRoutes = schema.listFundingRoutes || (schema.listFundingRoutes = {}));
287
- /** Schemas for the quoteFundingRoute operation. */
288
- let quoteFundingRoute;
289
- (function (quoteFundingRoute) {
290
- /** JSON body for an explicit funding route quote. */
291
- quoteFundingRoute.Body = z
292
- .strictObject({
293
- depositor: Schema.Address.check(z.describe('Address that would submit the funding transaction.')),
294
- destinationToken: z
295
- .optional(z.string())
296
- .check(z.describe('Tempo destination token symbol, address, or token key.'), z.meta({ examples: ['USDC.e'] })),
297
- provider: z
298
- .literal('across')
299
- .check(z.describe('Provider id selected from funding route discovery.'), z.meta({ examples: ['across'] })),
300
- recipient: z
301
- .optional(Schema.Address)
302
- .check(z.describe('Optional destination recipient; defaults to the depositor.')),
303
- sourceAmount: z
304
- .string()
305
- .check(z.minLength(1), z.describe('Exact source amount to quote.'), z.meta({ examples: ['1000000'] })),
306
- sourceAmountUnits: z
307
- ._default(z.enum(['baseUnits', 'decimal']), 'baseUnits')
308
- .check(z.describe('Whether `sourceAmount` uses base units or decimal notation.'), z.meta({ examples: ['baseUnits'] })),
309
- sourceChain: z
310
- .string()
311
- .check(z.minLength(1), z.describe('Source chain alias or CAIP-2 id.'), z.meta({ examples: ['base'] })),
167
+ .check(z.minLength(1), z.describe('Source chain alias or CAIP-2 id, such as `base` or `eip155:8453`.'), z.meta({ examples: ['base', 'eip155:8453'] })),
312
168
  sourceToken: z
313
169
  .string()
314
- .check(z.minLength(1), z.describe('Source token symbol, address, mint, or token key.'), z.meta({ examples: ['USDC'] })),
170
+ .check(z.minLength(1), z.describe('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.'), z.meta({ examples: ['USDC', '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'] })),
315
171
  })
316
- .check(z.describe('Parameters for a depositor-specific exact-input funding quote.'));
317
- /** Normalized funding quote without provider execution payloads. */
318
- quoteFundingRoute.Response = schema.FundingQuote;
319
- })(quoteFundingRoute = schema.quoteFundingRoute || (schema.quoteFundingRoute = {}));
172
+ .check(z.describe('Query parameters for live funding quotes into Tempo.'));
173
+ /** Non-paginated list of successful funding quotes. */
174
+ quoteFunding.Response = Schema.describe(z.object({
175
+ data: z.array(schema.FundingQuote).check(z.describe('Successful live funding quotes.')),
176
+ }), 'A non-paginated list of successful live funding quotes.');
177
+ })(quoteFunding = schema.quoteFunding || (schema.quoteFunding = {}));
320
178
  /** Schemas for the listFundingChains operation. */
321
179
  let listFundingChains;
322
180
  (function (listFundingChains) {
@@ -324,148 +182,83 @@ export var schema;
324
182
  listFundingChains.Response = Schema.describe(z.object({
325
183
  data: z
326
184
  .array(schema.ChainInventory)
327
- .check(z.describe('Source chains and stablecoins known to the funding route API.')),
185
+ .check(z.describe('Source chains and stablecoins supported by funding quotes.')),
328
186
  }), 'A non-paginated list of source chains and stablecoin inventory.');
329
187
  })(listFundingChains = schema.listFundingChains || (schema.listFundingChains = {}));
330
188
  /** Schemas for the listProviders operation. */
331
189
  let listProviders;
332
190
  (function (listProviders) {
333
- /** Query parameters for the generic provider catalog. */
334
- listProviders.Query = z
335
- .strictObject({
336
- capability: z
337
- .optional(z.enum(['fundingRoutes']))
338
- .check(z.describe('Optional provider capability filter.'), z.meta({ examples: ['fundingRoutes'] })),
339
- })
340
- .check(z.describe('Query parameters for listing providers.'));
341
- /** Non-paginated generic provider catalog. */
191
+ /** Non-paginated funding quote provider catalog. */
342
192
  listProviders.Response = Schema.describe(z.object({
343
- data: z.array(schema.Provider).check(z.describe("Providers in Tempo's generic provider catalog.")),
344
- }), 'A non-paginated list of providers.');
193
+ data: z.array(schema.Provider).check(z.describe("Providers in Tempo's funding quote catalog.")),
194
+ }), 'A non-paginated list of funding quote providers.');
345
195
  })(listProviders = schema.listProviders || (schema.listProviders = {}));
346
196
  })(schema || (schema = {}));
347
- // Examples derive from the static inventory so they never drift from real responses.
348
- const fundingRouteResponseExamples = {
349
- baseUsdc: {
350
- description: '`GET /v1/funding/routes?sourceChain=base&sourceToken=USDC&sourceAmount=1000000&provider=across`',
351
- summary: 'Base USDC',
352
- value: {
353
- data: FundingRoutes.listStaticRoutes({
354
- limit: 10,
355
- provider: 'across',
356
- sourceAmount: '1000000',
357
- sourceAmountUnits: 'baseUnits',
358
- sourceChain: 'base',
359
- sourceToken: 'USDC',
360
- }),
361
- },
362
- },
363
- solanaUsdc: {
364
- description: '`GET /v1/funding/routes?sourceChain=solana&sourceToken=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v&sourceAmount=1000000&provider=bridge`',
365
- summary: 'Solana USDC',
366
- value: {
367
- data: FundingRoutes.listStaticRoutes({
368
- limit: 10,
369
- provider: 'bridge',
370
- sourceAmount: '1000000',
371
- sourceAmountUnits: 'baseUnits',
372
- sourceChain: 'solana',
373
- sourceToken: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
374
- }),
375
- },
376
- },
377
- tronUsdt: {
378
- description: '`GET /v1/funding/routes?sourceChain=tron&sourceToken=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t&sourceAmount=1000000&provider=bridge`',
379
- summary: 'Tron USDT',
380
- value: {
381
- data: FundingRoutes.listStaticRoutes({
382
- limit: 10,
383
- provider: 'bridge',
384
- sourceAmount: '1000000',
385
- sourceAmountUnits: 'baseUnits',
386
- sourceChain: 'tron',
387
- sourceToken: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
388
- }),
389
- },
390
- },
391
- };
197
+ const fundingQuoteResponseExample = (() => {
198
+ const [candidate] = FundingQuotes.listQuoteCandidates({
199
+ provider: 'relay',
200
+ sourceAmount: '1000000',
201
+ sourceAmountUnits: 'baseUnits',
202
+ sourceChain: 'base',
203
+ sourceToken: 'USDC',
204
+ });
205
+ if (!candidate)
206
+ throw new Error('Missing Relay funding quote example candidate');
207
+ return {
208
+ data: [
209
+ {
210
+ ...candidate,
211
+ quality: {
212
+ estimatedSeconds: 1,
213
+ liquiditySource: 'providerQuote',
214
+ sourceDetail: 'relay:quote-v2',
215
+ tier: 'liquid',
216
+ },
217
+ quote: {
218
+ inputAmount: '1000000',
219
+ minimumOutputAmount: '939242',
220
+ outputAmount: '979295',
221
+ outputAmountFormatted: '0.979295',
222
+ sampledAt: '2026-01-01T00:00:00.000Z',
223
+ },
224
+ },
225
+ ],
226
+ };
227
+ })();
392
228
  const fundingChainsResponseExample = {
393
- data: FundingRoutes.listChains(),
229
+ data: FundingQuotes.listChains(),
394
230
  };
395
231
  const providersResponseExample = {
396
- data: FundingRoutes.listProviders(),
397
- };
398
- const [fundingQuoteRouteExample] = FundingRoutes.listStaticRoutes({
399
- destinationToken: 'USDC.e',
400
- limit: 1,
401
- provider: 'across',
402
- sourceAmount: '1000000',
403
- sourceAmountUnits: 'baseUnits',
404
- sourceChain: 'base',
405
- sourceToken: 'USDC',
406
- });
407
- const fundingQuoteResponseExample = {
408
- destinationChain: fundingQuoteRouteExample.destinationChain,
409
- destinationToken: fundingQuoteRouteExample.destinationToken,
410
- estimatedSeconds: 2,
411
- expiresAt: '2026-01-01T00:01:00Z',
412
- fees: {
413
- total: {
414
- amount: '1200',
415
- amountUsd: '0.0012',
416
- bps: 12,
417
- token: {
418
- address: fundingQuoteRouteExample.sourceToken.address,
419
- chainId: fundingQuoteRouteExample.sourceChain.id,
420
- decimals: fundingQuoteRouteExample.sourceToken.decimals,
421
- symbol: fundingQuoteRouteExample.sourceToken.symbol,
422
- },
423
- },
424
- totalMax: {
425
- amount: '1800',
426
- amountUsd: '0.0018',
427
- bps: 18,
428
- token: {
429
- address: fundingQuoteRouteExample.sourceToken.address,
430
- chainId: fundingQuoteRouteExample.sourceChain.id,
431
- decimals: fundingQuoteRouteExample.sourceToken.decimals,
432
- symbol: fundingQuoteRouteExample.sourceToken.symbol,
433
- },
434
- },
435
- },
436
- inputAmount: '1000000',
437
- minimumOutputAmount: '988000',
438
- outputAmount: '990000',
439
- outputAmountFormatted: '0.99',
440
- provider: fundingQuoteRouteExample.provider,
441
- routeId: fundingQuoteRouteExample.id,
442
- sampledAt: '2026-01-01T00:00:00Z',
443
- sourceChain: fundingQuoteRouteExample.sourceChain,
444
- sourceToken: fundingQuoteRouteExample.sourceToken,
232
+ data: FundingQuotes.listProviders().map((provider) => ({
233
+ ...provider,
234
+ status: 'configured',
235
+ })),
445
236
  };
446
- /** Mounts funding route discovery and generic provider inventory endpoints. */
237
+ /** Mounts live funding quotes and their supporting inventory endpoints. */
447
238
  export function funding(options = {}) {
448
239
  return new Hono()
449
- .get('/v1/funding/routes', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.listFundingRoutes.Query, {
240
+ .get('/v1/funding/quotes', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.quoteFunding.Query, {
450
241
  code: 'query_invalid',
451
242
  message: 'Invalid query parameters',
452
243
  }), OpenApi.describeRoute({
453
- description: '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.',
454
- operationId: 'listFundingRoutes',
244
+ description: 'Returns live quotes for funding Tempo with a stablecoin. Omit `provider` to query all configured providers. This endpoint does not execute a transfer.',
245
+ operationId: 'quoteFunding',
455
246
  responses: OpenApi.responses({
456
- errors: { 400: { codes: ['query_invalid'] } },
247
+ errors: {
248
+ 400: { codes: ['query_invalid'] },
249
+ 502: {
250
+ codes: ['upstream_error'],
251
+ description: 'Every matching quote provider failed unexpectedly.',
252
+ },
253
+ },
457
254
  success: {
458
- description: 'Discovery-only funding route candidates for the requested source chain and token.',
459
- examples: fundingRouteResponseExamples,
460
- schema: schema.listFundingRoutes.Response,
255
+ description: 'Live funding quotes. An empty list means no provider returned a quote.',
256
+ example: fundingQuoteResponseExample,
257
+ schema: schema.quoteFunding.Response,
461
258
  },
462
259
  }),
463
- summary: 'List funding routes',
260
+ summary: 'Get funding quotes',
464
261
  tags: ['Funding'],
465
- }), Cache.response({
466
- cacheControl: Cache.policies.noStore,
467
- name: 'tempo-api:funding-routes:v1',
468
- key: (c) => Cache.urlKey(c, schema.listFundingRoutes.Query),
469
262
  }), async (c) => {
470
263
  if (Auth.narrowAccess)
471
264
  return Auth.paidAccessError(c);
@@ -476,15 +269,13 @@ export function funding(options = {}) {
476
269
  });
477
270
  const query = c.req.valid('query');
478
271
  try {
479
- const include = FundingRoutes.parseInclude(query.include);
480
- return c.json(Response.validated(schema.listFundingRoutes.Response, {
481
- data: await FundingRoutes.listRoutes({
272
+ c.header('Cache-Control', 'no-store');
273
+ return c.json(Response.validated(schema.quoteFunding.Response, {
274
+ data: await FundingQuotes.listQuotes({
482
275
  adapters: options.adapters,
483
276
  adapterTimeoutMs: options.adapterTimeoutMs,
484
277
  cache: { bypass: cacheBypass(c.req.raw) },
485
278
  destinationToken: query.destinationToken,
486
- include,
487
- limit: query.limit,
488
279
  provider: query.provider,
489
280
  sourceAmount: query.sourceAmount,
490
281
  sourceAmountUnits: query.sourceAmountUnits,
@@ -497,108 +288,21 @@ export function funding(options = {}) {
497
288
  const message = requestErrorMessage(cause);
498
289
  if (message)
499
290
  return Response.error(c, { code: 'query_invalid', message, status: 400 });
500
- throw cause;
501
- }
502
- })
503
- .post('/v1/funding/routes/quote', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('json', schema.quoteFundingRoute.Body, {
504
- code: 'body_invalid',
505
- message: 'Invalid quote parameters',
506
- }), OpenApi.describeRoute({
507
- description: 'Gets a depositor-specific exact-input quote for one curated funding route. The response excludes provider transaction calldata, approvals, and wallet balance details.',
508
- operationId: 'quoteFundingRoute',
509
- responses: OpenApi.responses({
510
- errors: {
511
- 400: { codes: ['body_invalid'] },
512
- 404: { codes: ['route_not_found', 'quote_unavailable'] },
513
- 501: { codes: ['provider_unconfigured'] },
514
- 502: { codes: ['provider_error', 'provider_rate_limited', 'provider_timeout'] },
515
- },
516
- success: {
517
- description: 'Normalized route quote without provider execution payloads.',
518
- example: fundingQuoteResponseExample,
519
- schema: schema.quoteFundingRoute.Response,
520
- },
521
- }),
522
- summary: 'Quote funding route',
523
- tags: ['Funding'],
524
- }), async (c) => {
525
- if (Auth.narrowAccess)
526
- return Auth.paidAccessError(c);
527
- if (OpenApi.narrowValidation)
528
- return OpenApi.validationError(c, {
529
- code: 'body_invalid',
530
- message: 'Invalid quote parameters',
531
- });
532
- const body = c.req.valid('json');
533
- try {
534
- const quote = await FundingRoutes.quoteRoute({
535
- depositor: body.depositor,
536
- destinationToken: body.destinationToken,
537
- provider: body.provider,
538
- quote: options.acrossQuote,
539
- quoteTimeoutMs: options.quoteTimeoutMs,
540
- recipient: body.recipient,
541
- sourceAmount: body.sourceAmount,
542
- sourceAmountUnits: body.sourceAmountUnits,
543
- sourceChain: body.sourceChain,
544
- sourceToken: body.sourceToken,
545
- });
546
- c.header('Cache-Control', 'no-store');
547
- return c.json(Response.validated(schema.quoteFundingRoute.Response, quote), 200);
548
- }
549
- catch (cause) {
550
- const message = requestErrorMessage(cause);
551
- if (message)
552
- return Response.error(c, { code: 'body_invalid', message, status: 400 });
553
- if (cause instanceof FundingRoutes.FundingRouteNotFoundError)
554
- return Response.error(c, {
555
- code: 'route_not_found',
556
- message: 'No curated funding route matches the request.',
557
- status: 404,
558
- });
559
- if (cause instanceof FundingRoutes.ProviderQuoteUnavailableError)
560
- return Response.error(c, {
561
- code: 'quote_unavailable',
562
- message: 'The provider cannot quote this route.',
563
- status: 404,
564
- });
565
- if (cause instanceof FundingRoutes.ProviderNotConfiguredError)
566
- return Response.error(c, {
567
- code: 'provider_unconfigured',
568
- message: 'The provider quote integration is not configured.',
569
- status: 501,
570
- });
571
- if (cause instanceof FundingRoutes.ProviderRateLimitError)
572
- return Response.error(c, {
573
- code: 'provider_rate_limited',
574
- message: 'The provider temporarily rate-limited this quote.',
575
- status: 502,
576
- });
577
- if (cause instanceof FundingRoutes.ProviderAdapterTimeoutError)
578
- return Response.error(c, {
579
- code: 'provider_timeout',
580
- message: 'The provider quote timed out.',
581
- status: 502,
582
- });
583
- if (cause instanceof Error) {
584
- const providerFailure = FundingRouteProviders.acrossQuoteFailure({ cause });
585
- if (providerFailure)
586
- c.set('providerFailure', providerFailure);
291
+ if (cause instanceof FundingQuotes.ProviderQuoteError)
587
292
  return Response.error(c, {
588
- code: 'provider_error',
589
- message: 'The provider could not complete the quote.',
293
+ code: 'upstream_error',
294
+ message: 'Quote providers could not complete the request.',
590
295
  status: 502,
591
296
  });
592
- }
593
297
  throw cause;
594
298
  }
595
299
  })
596
300
  .get('/v1/funding/chains', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.describeRoute({
597
- description: '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.',
301
+ description: 'Lists the source chains and stablecoins you can use when requesting a funding quote.',
598
302
  operationId: 'listFundingChains',
599
303
  responses: OpenApi.responses({
600
304
  success: {
601
- description: 'Source-chain and stablecoin inventory for funding route discovery.',
305
+ description: 'Supported source chains and stablecoins.',
602
306
  example: fundingChainsResponseExample,
603
307
  schema: schema.listFundingChains.Response,
604
308
  },
@@ -613,58 +317,42 @@ export function funding(options = {}) {
613
317
  if (Auth.narrowAccess)
614
318
  return Auth.paidAccessError(c);
615
319
  return c.json(Response.validated(schema.listFundingChains.Response, {
616
- data: FundingRoutes.listChains(),
320
+ data: FundingQuotes.listChains(),
617
321
  }), 200);
618
322
  })
619
- .get('/v1/providers', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.validate('query', schema.listProviders.Query, {
620
- code: 'query_invalid',
621
- message: 'Invalid query parameters',
622
- }), OpenApi.describeRoute({
623
- description: '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.',
624
- operationId: 'listProviders',
323
+ .get('/v1/funding/providers', Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }), OpenApi.describeRoute({
324
+ description: 'Lists funding quote providers and whether live quoting is configured for this deployment.',
325
+ operationId: 'listFundingProviders',
625
326
  responses: OpenApi.responses({
626
- errors: { 400: { codes: ['query_invalid'] } },
627
327
  success: {
628
- description: 'Providers known to Tempo.',
328
+ description: 'Funding quote providers supported by Tempo.',
629
329
  example: providersResponseExample,
630
330
  schema: schema.listProviders.Response,
631
331
  },
632
332
  }),
633
- summary: 'List providers',
634
- tags: ['Providers'],
333
+ summary: 'List funding providers',
334
+ tags: ['Funding'],
635
335
  }), Cache.response({
636
336
  cacheControl: Cache.policies.stable,
637
- name: 'tempo-api:providers:v1',
638
- key: (c) => Cache.urlKey(c, schema.listProviders.Query),
337
+ name: 'tempo-api:funding-providers:v1',
338
+ key: (c) => c.req.url,
639
339
  }), (c) => {
640
340
  if (Auth.narrowAccess)
641
341
  return Auth.paidAccessError(c);
642
- if (OpenApi.narrowValidation)
643
- return OpenApi.validationError(c, {
644
- code: 'query_invalid',
645
- message: 'Invalid query parameters',
646
- });
647
- const query = c.req.valid('query');
648
342
  return c.json(Response.validated(schema.listProviders.Response, {
649
- data: FundingRoutes.listProviders({
650
- adapters: options.adapters,
651
- capability: query.capability,
652
- configuredProviders: options.acrossQuote ? ['across'] : [],
653
- }),
343
+ data: FundingQuotes.listProviders({ adapters: options.adapters }),
654
344
  }), 200);
655
345
  });
656
346
  }
657
347
  // Maps caller-input errors to a specific 400 message; anything else rethrows.
658
348
  function requestErrorMessage(cause) {
659
- if (cause instanceof FundingRoutes.InvalidAmountError)
349
+ if (cause instanceof FundingQuotes.InvalidAmountError)
660
350
  return 'Invalid `sourceAmount`.';
661
- if (cause instanceof FundingRoutes.UnsupportedIncludeError)
662
- return 'Unsupported `include`.';
663
- if (cause instanceof FundingRoutes.UnsupportedDestinationTokenError)
351
+ if (cause instanceof FundingQuotes.UnsupportedDestinationTokenError)
664
352
  return 'Unsupported `destinationToken`.';
665
- if (cause instanceof FundingRoutes.UnsupportedProviderError)
353
+ if (cause instanceof FundingQuotes.UnsupportedProviderError)
666
354
  return 'Unsupported `provider`.';
667
- if (cause instanceof FundingRoutes.UnsupportedSourceChainError)
355
+ if (cause instanceof FundingQuotes.UnsupportedSourceChainError)
668
356
  return 'Unsupported `sourceChain`.';
669
357
  return undefined;
670
358
  }