tapimo 0.12.0 → 0.13.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 (257) hide show
  1. package/dist/App.d.ts +5561 -5026
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js +38 -3
  4. package/dist/App.js.map +1 -1
  5. package/dist/Scope.d.ts +2 -0
  6. package/dist/Scope.d.ts.map +1 -1
  7. package/dist/Scope.js +17 -0
  8. package/dist/Scope.js.map +1 -1
  9. package/dist/admin/App.d.ts +123 -74
  10. package/dist/admin/App.d.ts.map +1 -1
  11. package/dist/admin/apps/api-keys.d.ts +80 -0
  12. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  13. package/dist/admin/apps/api-keys.js +54 -0
  14. package/dist/admin/apps/api-keys.js.map +1 -1
  15. package/dist/admin/apps/earn-vaults.d.ts +15 -15
  16. package/dist/admin/apps/earn-vaults.js +1 -1
  17. package/dist/admin/apps/verified-tokens.d.ts +81 -81
  18. package/dist/admin/ui.generated.d.ts +1 -1
  19. package/dist/admin/ui.generated.d.ts.map +1 -1
  20. package/dist/admin/ui.generated.js +151 -151
  21. package/dist/admin/ui.generated.js.map +1 -1
  22. package/dist/apps/Zones.d.ts +16 -16
  23. package/dist/apps/Zones.js +4 -4
  24. package/dist/apps/data/App.js +18 -18
  25. package/dist/apps/data/App.js.map +1 -1
  26. package/dist/apps/data/ZoneSelection.d.ts +8 -8
  27. package/dist/apps/data/ZoneSelection.d.ts.map +1 -1
  28. package/dist/apps/data/ZoneSelection.js +1 -1
  29. package/dist/apps/data/ZoneSelection.js.map +1 -1
  30. package/dist/apps/data/routes/activities.d.ts +588 -584
  31. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  32. package/dist/apps/data/routes/activities.js +1561 -1239
  33. package/dist/apps/data/routes/activities.js.map +1 -1
  34. package/dist/apps/data/routes/balances.d.ts +26 -26
  35. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  36. package/dist/apps/data/routes/balances.js +43 -16
  37. package/dist/apps/data/routes/balances.js.map +1 -1
  38. package/dist/apps/data/routes/blocks.d.ts +44 -44
  39. package/dist/apps/data/routes/blocks.d.ts.map +1 -1
  40. package/dist/apps/data/routes/blocks.js +21 -11
  41. package/dist/apps/data/routes/blocks.js.map +1 -1
  42. package/dist/apps/data/routes/coingecko.d.ts +3 -3
  43. package/dist/apps/data/routes/earn.d.ts +18 -18
  44. package/dist/apps/data/routes/earn.js +13 -13
  45. package/dist/apps/data/routes/exchanges.d.ts +145 -145
  46. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  47. package/dist/apps/data/routes/receipts.d.ts +155 -55
  48. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  49. package/dist/apps/data/routes/receipts.js +28 -10
  50. package/dist/apps/data/routes/receipts.js.map +1 -1
  51. package/dist/apps/data/routes/tokenlist.d.ts +13 -13
  52. package/dist/apps/data/routes/tokens.d.ts +98 -98
  53. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  54. package/dist/apps/data/routes/tokens.js +51 -20
  55. package/dist/apps/data/routes/tokens.js.map +1 -1
  56. package/dist/apps/data/routes/transactions.d.ts +7 -2
  57. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  58. package/dist/apps/data/routes/transactions.js +37 -17
  59. package/dist/apps/data/routes/transactions.js.map +1 -1
  60. package/dist/apps/data/routes/transfers.d.ts +1 -1
  61. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  62. package/dist/apps/data/routes/transfers.js +18 -12
  63. package/dist/apps/data/routes/transfers.js.map +1 -1
  64. package/dist/apps/data/routes/valuation.d.ts +1 -1
  65. package/dist/apps/data/routes/valuation.d.ts.map +1 -1
  66. package/dist/apps/data/routes/valuation.js +12 -7
  67. package/dist/apps/data/routes/valuation.js.map +1 -1
  68. package/dist/apps/data/routes/verified-tokens.d.ts +3 -3
  69. package/dist/apps/data/routes/webhooks.d.ts +11 -11
  70. package/dist/apps/data/routes/zones.d.ts +14 -14
  71. package/dist/apps/data/routes/zones.js +1 -1
  72. package/dist/apps/funding/App.d.ts +11 -0
  73. package/dist/apps/funding/App.d.ts.map +1 -1
  74. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  75. package/dist/apps/funding/routes/deposit-addresses.js +16 -11
  76. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  77. package/dist/apps/funding/routes/transfers.d.ts +60 -48
  78. package/dist/apps/funding/routes/transfers.d.ts.map +1 -1
  79. package/dist/apps/funding/routes/transfers.js +27 -19
  80. package/dist/apps/funding/routes/transfers.js.map +1 -1
  81. package/dist/apps/management/App.d.ts +4487 -3963
  82. package/dist/apps/management/App.d.ts.map +1 -1
  83. package/dist/apps/management/routes/api-keys.d.ts +710 -159
  84. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  85. package/dist/apps/management/routes/api-keys.js +236 -4
  86. package/dist/apps/management/routes/api-keys.js.map +1 -1
  87. package/dist/apps/management/routes/faucet.d.ts +6 -6
  88. package/dist/apps/management/routes/invite-links.d.ts +42 -42
  89. package/dist/apps/management/routes/members.d.ts +30 -30
  90. package/dist/apps/management/routes/projects.d.ts +40 -40
  91. package/dist/apps/management/routes/usage.d.ts +24 -24
  92. package/dist/apps/management/routes/verified-token-requests.d.ts +1 -1
  93. package/dist/apps/management/routes/webhooks.d.ts +55 -55
  94. package/dist/db/Db.d.ts.map +1 -1
  95. package/dist/db/Db.js +12 -1
  96. package/dist/db/Db.js.map +1 -1
  97. package/dist/db/Schema.d.ts +3 -2
  98. package/dist/db/Schema.d.ts.map +1 -1
  99. package/dist/db/Schema.js +5 -2
  100. package/dist/db/Schema.js.map +1 -1
  101. package/dist/db/tables/fundingCatalog.d.ts +4 -2
  102. package/dist/db/tables/fundingCatalog.d.ts.map +1 -1
  103. package/dist/db/tables/fundingCatalog.js +5 -1
  104. package/dist/db/tables/fundingCatalog.js.map +1 -1
  105. package/dist/handlers/internal/utils.d.ts.map +1 -1
  106. package/dist/handlers/internal/utils.js +9 -0
  107. package/dist/handlers/internal/utils.js.map +1 -1
  108. package/dist/internal/Auth.d.ts +3 -1
  109. package/dist/internal/Auth.d.ts.map +1 -1
  110. package/dist/internal/Auth.js +6 -3
  111. package/dist/internal/Auth.js.map +1 -1
  112. package/dist/internal/EarnVaults.d.ts +3 -3
  113. package/dist/internal/EarnVaults.js +3 -3
  114. package/dist/internal/Fetch.d.ts +23 -0
  115. package/dist/internal/Fetch.d.ts.map +1 -0
  116. package/dist/internal/Fetch.js +26 -0
  117. package/dist/internal/Fetch.js.map +1 -0
  118. package/dist/internal/Log.d.ts +3 -1
  119. package/dist/internal/Log.d.ts.map +1 -1
  120. package/dist/internal/Log.js +16 -3
  121. package/dist/internal/Log.js.map +1 -1
  122. package/dist/internal/OpenApi.d.ts +5 -3
  123. package/dist/internal/OpenApi.d.ts.map +1 -1
  124. package/dist/internal/OpenApi.js +13 -3
  125. package/dist/internal/OpenApi.js.map +1 -1
  126. package/dist/internal/Response.d.ts +1 -1
  127. package/dist/internal/Response.d.ts.map +1 -1
  128. package/dist/internal/Schema.d.ts +6 -3
  129. package/dist/internal/Schema.d.ts.map +1 -1
  130. package/dist/internal/Schema.js +8 -2
  131. package/dist/internal/Schema.js.map +1 -1
  132. package/dist/internal/Store.d.ts +16 -3
  133. package/dist/internal/Store.d.ts.map +1 -1
  134. package/dist/internal/Store.js +82 -16
  135. package/dist/internal/Store.js.map +1 -1
  136. package/dist/internal/Tidx.d.ts.map +1 -1
  137. package/dist/internal/Tidx.js +7 -2
  138. package/dist/internal/Tidx.js.map +1 -1
  139. package/dist/internal/Timeout.d.ts +36 -0
  140. package/dist/internal/Timeout.d.ts.map +1 -0
  141. package/dist/internal/Timeout.js +37 -0
  142. package/dist/internal/Timeout.js.map +1 -0
  143. package/dist/internal/Timing.d.ts +9 -0
  144. package/dist/internal/Timing.d.ts.map +1 -1
  145. package/dist/internal/Timing.js +7 -0
  146. package/dist/internal/Timing.js.map +1 -1
  147. package/dist/internal/WebhookDestination.d.ts.map +1 -1
  148. package/dist/internal/WebhookDestination.js +3 -0
  149. package/dist/internal/WebhookDestination.js.map +1 -1
  150. package/dist/internal/funding/Action.d.ts +9 -0
  151. package/dist/internal/funding/Action.d.ts.map +1 -1
  152. package/dist/internal/funding/Action.js +16 -8
  153. package/dist/internal/funding/Action.js.map +1 -1
  154. package/dist/internal/funding/Catalog.d.ts +9 -2
  155. package/dist/internal/funding/Catalog.d.ts.map +1 -1
  156. package/dist/internal/funding/Catalog.js +19 -8
  157. package/dist/internal/funding/Catalog.js.map +1 -1
  158. package/dist/internal/funding/Provider.d.ts +68 -13
  159. package/dist/internal/funding/Provider.d.ts.map +1 -1
  160. package/dist/internal/funding/Provider.js +29 -8
  161. package/dist/internal/funding/Provider.js.map +1 -1
  162. package/dist/internal/funding/Transfer.d.ts +13 -12
  163. package/dist/internal/funding/Transfer.d.ts.map +1 -1
  164. package/dist/internal/funding/Transfer.js +23 -21
  165. package/dist/internal/funding/Transfer.js.map +1 -1
  166. package/dist/internal/funding/providers/stargate.d.ts +28 -9
  167. package/dist/internal/funding/providers/stargate.d.ts.map +1 -1
  168. package/dist/internal/funding/providers/stargate.js +251 -117
  169. package/dist/internal/funding/providers/stargate.js.map +1 -1
  170. package/dist/internal/index.d.ts +1 -0
  171. package/dist/internal/index.d.ts.map +1 -1
  172. package/dist/internal/index.js +1 -0
  173. package/dist/internal/index.js.map +1 -1
  174. package/package.json +2 -2
  175. package/src/App.test.ts +100 -0
  176. package/src/App.ts +42 -3
  177. package/src/Client.test-d.ts +46 -0
  178. package/src/Scope.test.ts +20 -0
  179. package/src/Scope.ts +16 -0
  180. package/src/admin/apps/api-keys.test.ts +75 -0
  181. package/src/admin/apps/api-keys.ts +64 -0
  182. package/src/admin/apps/earn-vaults.test.ts +1 -1
  183. package/src/admin/apps/earn-vaults.ts +1 -1
  184. package/src/admin/ui/src/lib/api-keys.ts +19 -0
  185. package/src/admin/ui/src/routes/api-keys.tsx +89 -2
  186. package/src/admin/ui.generated.ts +189 -151
  187. package/src/apps/Zones.test.ts +4 -4
  188. package/src/apps/Zones.ts +4 -4
  189. package/src/apps/composition.test.ts +1 -1
  190. package/src/apps/data/App.test.ts +41 -0
  191. package/src/apps/data/App.ts +18 -18
  192. package/src/apps/data/ZoneSelection.test.ts +2 -2
  193. package/src/apps/data/ZoneSelection.ts +8 -8
  194. package/src/apps/data/routes/activities.test.ts +1526 -12
  195. package/src/apps/data/routes/activities.ts +1774 -1356
  196. package/src/apps/data/routes/balances.ts +133 -97
  197. package/src/apps/data/routes/blocks.test.ts +533 -0
  198. package/src/apps/data/routes/blocks.ts +35 -16
  199. package/src/apps/data/routes/earn.test.ts +4 -2
  200. package/src/apps/data/routes/earn.ts +13 -13
  201. package/src/apps/data/routes/earn.zone-access.test.ts +6 -6
  202. package/src/apps/data/routes/receipts.ts +47 -16
  203. package/src/apps/data/routes/tokens.test.ts +578 -0
  204. package/src/apps/data/routes/tokens.ts +283 -225
  205. package/src/apps/data/routes/transactions.ts +68 -29
  206. package/src/apps/data/routes/transfers.test.ts +421 -0
  207. package/src/apps/data/routes/transfers.ts +45 -27
  208. package/src/apps/data/routes/valuation.ts +94 -78
  209. package/src/apps/data/routes/zones.test.ts +2 -2
  210. package/src/apps/data/routes/zones.ts +1 -1
  211. package/src/apps/funding/routes/deposit-addresses.test.ts +25 -3
  212. package/src/apps/funding/routes/deposit-addresses.ts +17 -12
  213. package/src/apps/funding/routes/quotes.test.ts +5 -9
  214. package/src/apps/funding/routes/transfers.test.ts +395 -8
  215. package/src/apps/funding/routes/transfers.ts +76 -59
  216. package/src/apps/management/routes/api-keys.test.ts +220 -0
  217. package/src/apps/management/routes/api-keys.ts +280 -3
  218. package/src/db/Db.ts +13 -1
  219. package/src/db/Schema.ts +5 -2
  220. package/src/db/tables/earnVaults.test.ts +9 -9
  221. package/src/db/tables/fundingCatalog.test.ts +16 -2
  222. package/src/db/tables/fundingCatalog.ts +9 -3
  223. package/src/handlers/internal/utils.test.ts +53 -0
  224. package/src/handlers/internal/utils.ts +15 -0
  225. package/src/internal/Auth.ts +12 -4
  226. package/src/internal/EarnVaults.capabilities.test.ts +2 -2
  227. package/src/internal/EarnVaults.test.ts +1 -1
  228. package/src/internal/EarnVaults.ts +3 -3
  229. package/src/internal/Fetch.test.ts +46 -0
  230. package/src/internal/Fetch.ts +56 -0
  231. package/src/internal/Log.test.ts +21 -0
  232. package/src/internal/Log.ts +20 -5
  233. package/src/internal/OpenApi.ts +14 -4
  234. package/src/internal/Response.ts +1 -1
  235. package/src/internal/Schema.test.ts +2 -0
  236. package/src/internal/Schema.ts +12 -2
  237. package/src/internal/Store.test.ts +178 -0
  238. package/src/internal/Store.ts +104 -18
  239. package/src/internal/Tidx.test.ts +2 -1
  240. package/src/internal/Tidx.ts +7 -2
  241. package/src/internal/Timeout.test.ts +35 -0
  242. package/src/internal/Timeout.ts +73 -0
  243. package/src/internal/Timing.ts +16 -0
  244. package/src/internal/WebhookDestination.ts +3 -0
  245. package/src/internal/funding/Action.test.ts +41 -1
  246. package/src/internal/funding/Action.ts +69 -41
  247. package/src/internal/funding/Catalog.test.ts +34 -0
  248. package/src/internal/funding/Catalog.ts +28 -11
  249. package/src/internal/funding/Provider.test.ts +73 -0
  250. package/src/internal/funding/Provider.ts +82 -28
  251. package/src/internal/funding/Transfer.ts +133 -110
  252. package/src/internal/funding/providers/index.test.ts +4 -167
  253. package/src/internal/funding/providers/relay.test.ts +2 -2
  254. package/src/internal/funding/providers/stargate.test.ts +163 -0
  255. package/src/internal/funding/providers/stargate.ts +359 -134
  256. package/src/internal/index.test.ts +1 -0
  257. package/src/internal/index.ts +1 -0
@@ -4,6 +4,7 @@ import type * as Db from '../../db/Db.js'
4
4
  import * as FundingTransferEvents from '../../db/tables/fundingTransferEvents.js'
5
5
  import * as FundingTransfers from '../../db/tables/fundingTransfers.js'
6
6
  import * as Id from '../Id.js'
7
+ import * as OpenApi from '../OpenApi.js'
7
8
  import * as Schema from '../Schema.js'
8
9
  import * as Action from './Action.js'
9
10
  import * as Provider from './Provider.js'
@@ -91,22 +92,25 @@ export namespace schema {
91
92
  )
92
93
 
93
94
  /** Customer-safe explanation of a status that needs context. */
94
- export const StatusReason = z
95
- .object({
96
- code: z
97
- .enum(statusReasonCodes)
98
- .check(
99
- z.describe('Stable machine-readable reason code.'),
100
- z.meta({ examples: ['destination_amount_below_minimum'] }),
95
+ export const StatusReason = OpenApi.component(
96
+ z
97
+ .object({
98
+ code: z
99
+ .enum(statusReasonCodes)
100
+ .check(
101
+ z.describe('Stable machine-readable reason code.'),
102
+ z.meta({ examples: ['destination_amount_below_minimum'] }),
103
+ ),
104
+ message: z.string().check(
105
+ z.describe('Human-readable explanation of the reason.'),
106
+ z.meta({
107
+ examples: ['The verified destination amount did not satisfy the quoted minimum.'],
108
+ }),
101
109
  ),
102
- message: z.string().check(
103
- z.describe('Human-readable explanation of the reason.'),
104
- z.meta({
105
- examples: ['The verified destination amount did not satisfy the quoted minimum.'],
106
- }),
107
- ),
108
- })
109
- .check(z.describe('Why the transfer is in its current status, when context is needed.'))
110
+ })
111
+ .check(z.describe('Why the transfer is in its current status, when context is needed.')),
112
+ 'FundingTransferStatusReason',
113
+ )
110
114
 
111
115
  /** Funding method selected at creation. */
112
116
  export const Method = z
@@ -122,39 +126,45 @@ export namespace schema {
122
126
  )
123
127
 
124
128
  /** One fee applied to the transfer. */
125
- export const Fee = z
126
- .object({
127
- amount: Schema.TokenAmount,
128
- side: z
129
- .enum(['destination', 'source'])
130
- .check(
131
- z.describe('Which side of the transfer the fee is taken from.'),
132
- z.meta({ examples: ['destination'] }),
133
- ),
134
- token: Provider.schema.TokenRef,
135
- type: z
136
- .enum(['provider'])
137
- .check(z.describe('What the fee pays for.'), z.meta({ examples: ['provider'] })),
138
- })
139
- .check(z.describe('One fee applied to the transfer.'))
129
+ export const Fee = OpenApi.component(
130
+ z
131
+ .object({
132
+ amount: Schema.TokenAmount,
133
+ side: z
134
+ .enum(['destination', 'source'])
135
+ .check(
136
+ z.describe('Which side of the transfer the fee is taken from.'),
137
+ z.meta({ examples: ['destination'] }),
138
+ ),
139
+ token: Provider.schema.TokenRef,
140
+ type: z
141
+ .enum(['provider'])
142
+ .check(z.describe('What the fee pays for.'), z.meta({ examples: ['provider'] })),
143
+ })
144
+ .check(z.describe('One fee applied to the transfer.')),
145
+ 'FundingTransferFee',
146
+ )
140
147
 
141
148
  /** Freshness and validity window of the selected quote. */
142
- export const Quote = z
143
- .object({
144
- expiresAt: z
145
- .string()
146
- .check(
147
- z.describe('When the quoted terms stop being executable (ISO 8601).'),
148
- z.meta({ examples: ['2026-07-30T04:01:00.000Z'] }),
149
- ),
150
- sampledAt: z
151
- .string()
152
- .check(
153
- z.describe('When the provider produced the quote (ISO 8601).'),
154
- z.meta({ examples: ['2026-07-30T04:00:00.000Z'] }),
155
- ),
156
- })
157
- .check(z.describe('Freshness and validity window of the selected quote.'))
149
+ export const Quote = OpenApi.component(
150
+ z
151
+ .object({
152
+ expiresAt: z.iso
153
+ .datetime()
154
+ .check(
155
+ z.describe('When the quoted terms stop being executable (ISO 8601).'),
156
+ z.meta({ examples: ['2026-07-30T04:01:00.000Z'] }),
157
+ ),
158
+ sampledAt: z.iso
159
+ .datetime()
160
+ .check(
161
+ z.describe('When the provider produced the quote (ISO 8601).'),
162
+ z.meta({ examples: ['2026-07-30T04:00:00.000Z'] }),
163
+ ),
164
+ })
165
+ .check(z.describe('Freshness and validity window of the selected quote.')),
166
+ 'FundingTransferQuote',
167
+ )
158
168
 
159
169
  const hashesCheck = (description: string) => [
160
170
  z.describe(description),
@@ -219,8 +229,8 @@ export namespace schema {
219
229
  .check(z.describe('Quote terms and reconciled public fields of a funding transfer.'))
220
230
 
221
231
  const fundingTransferFields = {
222
- createdAt: z
223
- .string()
232
+ createdAt: z.iso
233
+ .datetime()
224
234
  .check(
225
235
  z.describe('When the transfer was created (ISO 8601).'),
226
236
  z.meta({ examples: ['2026-07-30T04:00:00.000Z'] }),
@@ -253,8 +263,8 @@ export namespace schema {
253
263
  sourceTransactionHashes: snapshotFields.sourceTransactionHashes,
254
264
  status: Status,
255
265
  statusReason: z.optional(StatusReason),
256
- updatedAt: z
257
- .string()
266
+ updatedAt: z.iso
267
+ .datetime()
258
268
  .check(
259
269
  z.describe('When the transfer last materially changed (ISO 8601).'),
260
270
  z.meta({ examples: ['2026-07-30T04:00:20.000Z'] }),
@@ -270,73 +280,86 @@ export namespace schema {
270
280
  }
271
281
 
272
282
  /** A funding transfer as returned by reads. Reads never include `action`. */
273
- export const FundingTransfer = z
274
- .object(fundingTransferFields)
275
- .check(z.describe('One durable funding transfer.'))
283
+ export const FundingTransfer = OpenApi.component(
284
+ z.object(fundingTransferFields).check(z.describe('One durable funding transfer.')),
285
+ 'FundingTransfer',
286
+ )
276
287
 
277
288
  /** A created funding transfer: the read shape plus the executable action. */
278
- export const CreatedFundingTransfer = z
279
- .object({ action: Action.schema.Action, ...fundingTransferFields })
280
- .check(z.describe('The created funding transfer, including its one-time executable action.'))
289
+ export const CreatedFundingTransfer = OpenApi.component(
290
+ z
291
+ .object({ action: Action.schema.Action, ...fundingTransferFields })
292
+ .check(z.describe('The created funding transfer, including its one-time executable action.')),
293
+ 'CreatedFundingTransfer',
294
+ )
281
295
 
282
296
  /** Request body accepted by funding transfer creation. */
283
- export const CreateRequest = z
284
- .strictObject({
285
- amount: z
286
- .string()
287
- .check(
288
- z.regex(/^[1-9]\d*$/),
289
- z.describe('Amount in base units of the token the mode fixes.'),
290
- z.meta({ examples: ['1000000'] }),
291
- ),
292
- destinationToken: z
293
- .string()
294
- .check(
295
- z.minLength(1),
296
- z.describe('Tempo destination token symbol, contract address, or token key.'),
297
- z.meta({ examples: ['pathusd'] }),
298
- ),
299
- mode: Mode,
300
- recipient: z
301
- .string()
302
- .check(
303
- z.regex(/^0x[0-9a-fA-F]{40}$/),
304
- z.describe('Final beneficiary of the transfer.'),
305
- z.meta({ examples: [`0x${'11'.repeat(20)}`] }),
306
- ),
307
- sender: z
308
- .string()
309
- .check(
310
- z.regex(/^0x[0-9a-fA-F]{40}$/),
311
- z.describe('Source-chain account that signs the funding action.'),
312
- z.meta({ examples: [`0x${'22'.repeat(20)}`] }),
313
- ),
314
- slippageBps: z.optional(
315
- z
316
- .number()
297
+ export const CreateRequest = OpenApi.component(
298
+ z
299
+ .strictObject({
300
+ amount: z
301
+ .string()
317
302
  .check(
318
- z.int(),
319
- z.gte(0),
320
- z.lte(10_000),
321
- z.describe('Maximum acceptable slippage in basis points.'),
322
- z.meta({ examples: [50] }),
303
+ z.regex(/^[1-9]\d*$/),
304
+ z.describe('Amount in base units of the token the mode fixes.'),
305
+ z.meta({ examples: ['1000000'] }),
323
306
  ),
324
- ),
325
- sourceChain: z
326
- .string()
327
- .check(
328
- z.describe('Source chain CAIP-2 id, slug, or alias.'),
329
- z.meta({ examples: ['base', 'eip155:8453'] }),
330
- ),
331
- sourceToken: z
332
- .string()
333
- .check(
334
- z.minLength(1),
335
- z.describe('Source token symbol, contract address, or token key.'),
336
- z.meta({ examples: ['usdc'] }),
307
+ destinationToken: z
308
+ .string()
309
+ .check(
310
+ z.minLength(1),
311
+ z.describe('Tempo destination token symbol, contract address, or token key.'),
312
+ z.meta({ examples: ['pathusd'] }),
313
+ ),
314
+ mode: Mode,
315
+ provider: z
316
+ .optional(z.string().check(z.minLength(1)))
317
+ .check(
318
+ z.describe('Funding provider ID. Omit to select the best available provider.'),
319
+ z.meta({ examples: ['relay'] }),
320
+ ),
321
+ recipient: z
322
+ .string()
323
+ .check(
324
+ z.regex(/^0x[0-9a-fA-F]{40}$/),
325
+ z.describe('Final beneficiary of the transfer.'),
326
+ z.meta({ examples: [`0x${'11'.repeat(20)}`] }),
327
+ ),
328
+ sender: z
329
+ .string()
330
+ .check(
331
+ z.regex(/^0x[0-9a-fA-F]{40}$/),
332
+ z.describe('Source-chain account that signs the funding action.'),
333
+ z.meta({ examples: [`0x${'22'.repeat(20)}`] }),
334
+ ),
335
+ slippageBps: z.optional(
336
+ z
337
+ .number()
338
+ .check(
339
+ z.int(),
340
+ z.gte(0),
341
+ z.lte(10_000),
342
+ z.describe('Maximum acceptable slippage in basis points.'),
343
+ z.meta({ examples: [50] }),
344
+ ),
337
345
  ),
338
- })
339
- .check(z.describe('Funding transfer creation request.'))
346
+ sourceChain: z
347
+ .string()
348
+ .check(
349
+ z.describe('Source chain CAIP-2 id, slug, or alias.'),
350
+ z.meta({ examples: ['base', 'eip155:8453'] }),
351
+ ),
352
+ sourceToken: z
353
+ .string()
354
+ .check(
355
+ z.minLength(1),
356
+ z.describe('Source token symbol, contract address, or token key.'),
357
+ z.meta({ examples: ['usdc'] }),
358
+ ),
359
+ })
360
+ .check(z.describe('Funding transfer creation request.')),
361
+ 'CreateFundingTransferRequest',
362
+ )
340
363
  }
341
364
 
342
365
  /** Stored public snapshot of a funding transfer (see {@link schema.Snapshot}). */
@@ -22,10 +22,7 @@ const providers = [
22
22
  integratorId: 'squid-integrator-id',
23
23
  userAddress: '0x1111111111111111111111111111111111111111',
24
24
  }),
25
- Stargate.stargate({
26
- apiKey: 'layerzero-api-key',
27
- userAddress: '0x1111111111111111111111111111111111111111',
28
- }),
25
+ Stargate.stargate(),
29
26
  Symbiosis.symbiosis({ userAddress: '0x1111111111111111111111111111111111111111' }),
30
27
  ] as const
31
28
 
@@ -340,126 +337,12 @@ describe('funding providers', () => {
340
337
  })
341
338
  })
342
339
 
343
- test('maps the best Stargate quote to an available quote result', async () => {
344
- const requests: RecordedRequest[] = []
345
- const candidate = quoteCandidate('stargate')
346
- const fetch = recordingFetch(requests, async () => jsonResponse(stargateQuotes(candidate)))
347
- const provider = Stargate.stargate({
348
- apiKey: 'layerzero-api-key',
349
- baseUrl: 'https://layerzero.test/v1/',
350
- fetch,
351
- now,
352
- userAddress: '0x1111111111111111111111111111111111111111',
353
- })
354
-
355
- const result = await provider.getQuote(getQuoteInput(candidate), new AbortController().signal)
356
-
357
- expect(requests).toHaveLength(1)
358
- expect(requests[0]?.url.pathname).toBe('/v1/quotes')
359
- expect(new Headers(requests[0]?.init?.headers).get('user-agent')).toBe('tempo-api')
360
- expect(new Headers(requests[0]?.init?.headers).get('x-api-key')).toBe('layerzero-api-key')
361
- expect(jsonRequestBody(requests[0])).toEqual({
362
- amount: '1000000',
363
- dstChainKey: 'tempo',
364
- dstTokenAddress: candidate.destinationToken.address,
365
- dstWalletAddress: '0x1111111111111111111111111111111111111111',
366
- options: { amountType: 'EXACT_SRC_AMOUNT' },
367
- srcChainKey: 'base',
368
- srcTokenAddress: candidate.sourceToken.address,
369
- srcWalletAddress: '0x1111111111111111111111111111111111111111',
370
- })
371
- expect(result).toEqual({
372
- expiresAt: '2026-01-01T00:01:00.000Z',
373
- destinationAmountMin: '999100',
374
- destinationAmount: '999600',
375
- quality: {
376
- estimatedSeconds: 259,
377
- liquiditySource: 'providerQuote',
378
- sourceDetail: 'stargate:value-transfer-v1:bus',
379
- tier: 'liquid',
380
- },
381
- sampledAt: '2026-01-01T00:00:00.000Z',
382
- status: 'available',
383
- })
384
- })
385
-
386
- test('skips expired Stargate alternatives', async () => {
387
- const candidate = quoteCandidate('stargate')
388
- const response = stargateQuotes(candidate)
389
- response.quotes[2]!.expiresAt = '2026-01-01T00:00:00.000Z'
390
- const provider = Stargate.stargate({
391
- apiKey: 'layerzero-api-key',
392
- fetch: recordingFetch([], async () => jsonResponse(response)),
393
- now,
394
- userAddress: '0x1111111111111111111111111111111111111111',
395
- })
396
-
397
- await expect(
398
- provider.getQuote(getQuoteInput(candidate), new AbortController().signal),
399
- ).resolves.toMatchObject({
400
- destinationAmountMin: '999000',
401
- destinationAmount: '999500',
402
- quality: {
403
- sourceDetail: 'stargate:value-transfer-v1:taxi',
404
- tier: 'liquid',
405
- },
406
- status: 'available',
407
- })
408
- })
409
-
410
340
  test('exposes Base and Ethereum Stargate quote candidates', () => {
411
341
  expect(
412
342
  ['base', 'ethereum'].map((sourceChain) => quoteCandidate('stargate', { sourceChain }).id),
413
343
  ).toEqual(['base-usdc-tempo-usdce-stargate', 'ethereum-usdc-tempo-usdce-stargate'])
414
344
  })
415
345
 
416
- test('maps responses without Stargate routes to unavailable quote results', async () => {
417
- const candidate = quoteCandidate('stargate')
418
- const response = stargateQuotes(candidate)
419
- response.quotes = response.quotes.filter((quote) => quote.routeSteps[0]?.type === 'CCTP')
420
- const provider = Stargate.stargate({
421
- apiKey: 'layerzero-api-key',
422
- fetch: recordingFetch([], async () => jsonResponse(response)),
423
- now,
424
- userAddress: '0x1111111111111111111111111111111111111111',
425
- })
426
-
427
- await expect(
428
- provider.getQuote(getQuoteInput(candidate), new AbortController().signal),
429
- ).resolves.toMatchObject({
430
- quality: {
431
- sourceDetail: 'stargate:value-transfer-v1:NO_STARGATE_ROUTE',
432
- tier: 'unavailable',
433
- },
434
- status: 'unavailable',
435
- })
436
- })
437
-
438
- test('rejects malformed Stargate quotes', async () => {
439
- const candidate = quoteCandidate('stargate')
440
- const response = stargateQuotes(candidate)
441
- response.quotes[2]!.srcAmount = '1'
442
- const provider = Stargate.stargate({
443
- apiKey: 'layerzero-api-key',
444
- fetch: recordingFetch([], async () => jsonResponse(response)),
445
- now,
446
- userAddress: '0x1111111111111111111111111111111111111111',
447
- })
448
-
449
- await expect(
450
- provider.getQuote(getQuoteInput(candidate), new AbortController().signal),
451
- ).rejects.toThrowErrorMatchingInlineSnapshot(`[FundingProvider.ProviderPayloadError]`)
452
- })
453
-
454
- test('rejects invalid Stargate configuration', () => {
455
- expect(() =>
456
- Stargate.stargate({
457
- apiKey: '',
458
- userAddress: '0x1111111111111111111111111111111111111111',
459
- }),
460
- ).toThrowErrorMatchingInlineSnapshot(`[FundingProvider.ProviderConfigurationError]`)
461
- })
462
-
463
346
  test('maps successful Symbiosis quotes to available quote results', async () => {
464
347
  const requests: RecordedRequest[] = []
465
348
  const candidate = quoteCandidate('symbiosis')
@@ -1086,29 +969,17 @@ describe('funding providers', () => {
1086
969
  })
1087
970
  })
1088
971
 
1089
- test('returns bounded Stargate failure diagnostics', async () => {
1090
- const candidate = quoteCandidate('stargate')
1091
- const provider = Stargate.stargate({
1092
- apiKey: 'layerzero-api-key',
1093
- fetch: recordingFetch([], async () => jsonResponse({ message: 'Unauthorized' }, 401)),
1094
- now,
1095
- userAddress: '0x1111111111111111111111111111111111111111',
1096
- })
1097
- const cause = await provider
1098
- .getQuote(getQuoteInput(candidate), new AbortController().signal)
1099
- .catch((error: unknown) => error)
1100
-
972
+ test('returns bounded Stargate failure diagnostics', () => {
1101
973
  expect(
1102
974
  FundingProvider.failure({
1103
- cause,
975
+ cause: new TypeError('network failure'),
1104
976
  operation: 'getQuote',
1105
977
  provider: getProvider('stargate'),
1106
978
  }),
1107
979
  ).toEqual({
1108
- failure: 'http',
980
+ failure: 'network',
1109
981
  id: 'stargate',
1110
982
  operation: 'getQuote',
1111
- status: 401,
1112
983
  })
1113
984
  })
1114
985
 
@@ -1210,40 +1081,6 @@ function squidQuote(candidate: FundingProvider.getQuote.Parameters['candidate'])
1210
1081
  }
1211
1082
  }
1212
1083
 
1213
- function stargateQuotes(candidate: FundingProvider.getQuote.Parameters['candidate']) {
1214
- return {
1215
- error: null,
1216
- quotes: [
1217
- {
1218
- dstAmount: '999900',
1219
- dstAmountMin: '999800',
1220
- duration: { estimated: '10000' },
1221
- id: 'quote-cctp',
1222
- routeSteps: [{ srcChainKey: 'base', type: 'CCTP' }],
1223
- srcAmount: candidate.sourceAmount.amount,
1224
- },
1225
- {
1226
- dstAmount: '999500',
1227
- dstAmountMin: '999000',
1228
- duration: { estimated: '27600' },
1229
- expiresAt: '2026-01-01T00:01:00.000Z',
1230
- id: 'quote-stargate-taxi',
1231
- routeSteps: [{ srcChainKey: 'base', type: 'STARGATE_V2_TAXI' }],
1232
- srcAmount: candidate.sourceAmount.amount,
1233
- },
1234
- {
1235
- dstAmount: '999600',
1236
- dstAmountMin: '999100',
1237
- duration: { estimated: '258899.99999999997' },
1238
- expiresAt: '2026-01-01T00:01:00.000Z',
1239
- id: 'quote-stargate-bus',
1240
- routeSteps: [{ srcChainKey: 'base', type: 'STARGATE_V2_BUS' }],
1241
- srcAmount: candidate.sourceAmount.amount,
1242
- },
1243
- ],
1244
- }
1245
- }
1246
-
1247
1084
  function symbiosisQuote(candidate: FundingProvider.getQuote.Parameters['candidate']) {
1248
1085
  const source =
1249
1086
  candidate.sourceChain.kind === 'tron'
@@ -147,8 +147,8 @@ describe.skipIf(!apiKey)('relay.prepareTransfer (live)', () => {
147
147
  expect(call.data).toMatch(/^0x[0-9a-fA-F]*$/)
148
148
  expect(call.value).toBe('0x0')
149
149
  }
150
- expect(result.correlation.requestId).toMatch(/^0x[0-9a-f]{64}$/)
151
- expect(result.correlation.checkEndpoint).toContain('/intents/status/v3')
150
+ expect(result.correlation?.requestId).toMatch(/^0x[0-9a-f]{64}$/)
151
+ expect(result.correlation?.checkEndpoint).toContain('/intents/status/v3')
152
152
  expect(BigInt(result.destinationAmount) > 0n).toBe(true)
153
153
  expect(BigInt(result.destinationAmountMin) > 0n).toBe(true)
154
154
  expect(BigInt(result.destinationAmountMin) <= BigInt(result.destinationAmount)).toBe(true)
@@ -0,0 +1,163 @@
1
+ import { AbiFunction, Hex } from 'ox'
2
+
3
+ import type * as Action from '../Action.js'
4
+ import type * as Catalog from '../Catalog.js'
5
+ import * as FundingProvider from '../Provider.js'
6
+ import * as Stargate from './stargate.js'
7
+
8
+ const amount = 1_000_000n
9
+ const destinationToken = '0x20C000000000000000000000b9537d11c60E8b50'
10
+ const nativeFee = 10_000n
11
+ const otherAddress = '0x9999999999999999999999999999999999999999'
12
+ const pool = '0x27a16dc786820B16E5c9028b75B99F6f604b5d26'
13
+ const recipient = '0x1111111111111111111111111111111111111111'
14
+ const sender = '0x2222222222222222222222222222222222222222'
15
+ const sourceToken = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
16
+
17
+ const approve = AbiFunction.from('function approve(address spender, uint256 amount)')
18
+ const sendToken = AbiFunction.from(
19
+ 'function sendToken((uint32 dstEid, bytes32 to, uint256 amountLD, uint256 minAmountLD, bytes extraOptions, bytes composeMsg, bytes oftCmd) sendParam, (uint256 nativeFee, uint256 lzTokenFee) fee, address refundAddress) payable returns ((bytes32 guid, uint64 nonce, (uint256 nativeFee, uint256 lzTokenFee) fee) msgReceipt, (uint256 amountSentLD, uint256 amountReceivedLD) oftReceipt, (uint72 ticketId, bytes passengerBytes) ticket)',
20
+ )
21
+
22
+ describe('stargate', () => {
23
+ test('creates a credential-free quote and transfer provider', () => {
24
+ expect(Stargate.stargate()).toMatchObject({
25
+ getQuote: expect.any(Function),
26
+ id: 'stargate',
27
+ name: 'Stargate',
28
+ prepareTransfer: expect.any(Function),
29
+ })
30
+ })
31
+ })
32
+
33
+ describe('validateAction', () => {
34
+ test('accepts the exact approval and Taxi send calls', () => {
35
+ expect(validate(action())).toEqual([{ to: pool, value: Hex.fromNumber(nativeFee) }])
36
+ })
37
+
38
+ test('rejects calls outside the curated Stargate route', () => {
39
+ const invalid = [
40
+ action({ approvalAmount: amount + 1n }),
41
+ action({ approvalSpender: otherAddress }),
42
+ action({ composeMsg: '0x01' }),
43
+ action({ destinationEid: 1 }),
44
+ action({ executionTarget: otherAddress }),
45
+ action({ extraOptions: '0x01' }),
46
+ action({ lzTokenFee: 1n }),
47
+ action({ minimumAmount: amount - 1n }),
48
+ action({ oftCmd: '0x01' }),
49
+ action({ recipient: otherAddress }),
50
+ action({ refundAddress: otherAddress }),
51
+ action({ sourceAmount: amount + 1n }),
52
+ ]
53
+ for (const candidate of invalid)
54
+ expect(() => validate(candidate)).toThrowError(FundingProvider.ProviderPayloadError)
55
+ expect(() => validate(action(), { sourceTokenAddress: otherAddress })).toThrowError(
56
+ FundingProvider.ProviderPayloadError,
57
+ )
58
+ expect(() => validate(action(), { destinationTokenAddress: otherAddress })).toThrowError(
59
+ FundingProvider.ProviderPayloadError,
60
+ )
61
+ })
62
+
63
+ test('rejects malformed selectors and mismatched native value', () => {
64
+ const malformed = action()
65
+ malformed.calls[1]!.data = '0xdeadbeef'
66
+ expect(() => validate(malformed)).toThrowError(FundingProvider.ProviderPayloadError)
67
+
68
+ const mismatched = action()
69
+ mismatched.calls[1]!.value = Hex.fromNumber(nativeFee + 1n)
70
+ expect(() => validate(mismatched)).toThrowError(FundingProvider.ProviderPayloadError)
71
+ })
72
+
73
+ test('rejects missing or mismatched route configuration', () => {
74
+ expect(() =>
75
+ Stargate.validateAction({
76
+ action: action(),
77
+ destinationTokenAddress: destinationToken,
78
+ recipient,
79
+ sender,
80
+ sourceAmount: amount.toString(),
81
+ sourceChainId: 'eip155:8453',
82
+ sourceTokenAddress: sourceToken,
83
+ }),
84
+ ).toThrowError(FundingProvider.ProviderPayloadError)
85
+ expect(() => validate(action(), { configuration: { poolAddress: otherAddress } })).toThrowError(
86
+ FundingProvider.ProviderPayloadError,
87
+ )
88
+ })
89
+ })
90
+
91
+ function action(options: action.Options = {}): Action.EvmCalls {
92
+ const executionFee = options.nativeFee ?? nativeFee
93
+ const sendParam = {
94
+ amountLD: options.sourceAmount ?? amount,
95
+ composeMsg: options.composeMsg ?? '0x',
96
+ dstEid: options.destinationEid ?? 30_410,
97
+ extraOptions: options.extraOptions ?? '0x',
98
+ minAmountLD: options.minimumAmount ?? amount,
99
+ oftCmd: options.oftCmd ?? '0x',
100
+ to: Hex.padLeft(options.recipient ?? recipient, 32),
101
+ } as const
102
+ return {
103
+ calls: [
104
+ {
105
+ data: AbiFunction.encodeData(approve, [
106
+ options.approvalSpender ?? pool,
107
+ options.approvalAmount ?? amount,
108
+ ]),
109
+ to: sourceToken,
110
+ value: '0x0',
111
+ },
112
+ {
113
+ data: AbiFunction.encodeData(sendToken, [
114
+ sendParam,
115
+ { lzTokenFee: options.lzTokenFee ?? 0n, nativeFee: executionFee },
116
+ options.refundAddress ?? sender,
117
+ ]),
118
+ to: options.executionTarget ?? pool,
119
+ value: Hex.fromNumber(executionFee),
120
+ },
121
+ ],
122
+ type: 'evm:calls',
123
+ }
124
+ }
125
+
126
+ declare namespace action {
127
+ type Options = {
128
+ approvalAmount?: bigint | undefined
129
+ approvalSpender?: `0x${string}` | undefined
130
+ composeMsg?: Hex.Hex | undefined
131
+ destinationEid?: number | undefined
132
+ executionTarget?: `0x${string}` | undefined
133
+ extraOptions?: Hex.Hex | undefined
134
+ lzTokenFee?: bigint | undefined
135
+ minimumAmount?: bigint | undefined
136
+ nativeFee?: bigint | undefined
137
+ oftCmd?: Hex.Hex | undefined
138
+ recipient?: Hex.Hex | undefined
139
+ refundAddress?: `0x${string}` | undefined
140
+ sourceAmount?: bigint | undefined
141
+ }
142
+ }
143
+
144
+ function validate(candidate: Action.EvmCalls, options: validate.Options = {}) {
145
+ return Stargate.validateAction({
146
+ action: candidate,
147
+ configuration: options.configuration ?? { poolAddress: pool },
148
+ destinationTokenAddress: options.destinationTokenAddress ?? destinationToken,
149
+ recipient,
150
+ sender,
151
+ sourceAmount: amount.toString(),
152
+ sourceChainId: 'eip155:8453',
153
+ sourceTokenAddress: options.sourceTokenAddress ?? sourceToken,
154
+ })
155
+ }
156
+
157
+ declare namespace validate {
158
+ type Options = {
159
+ configuration?: Catalog.Configuration | undefined
160
+ destinationTokenAddress?: string | undefined
161
+ sourceTokenAddress?: string | undefined
162
+ }
163
+ }