tapimo 0.7.2 → 0.9.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 (300) hide show
  1. package/README.md +10 -7
  2. package/dist/ApiKey.d.ts +3 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +10 -0
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +7 -3
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +9 -2
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +20117 -19183
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +61 -4
  13. package/dist/App.js.map +1 -1
  14. package/dist/admin/App.d.ts +84 -74
  15. package/dist/admin/App.d.ts.map +1 -1
  16. package/dist/admin/apps/api-keys.d.ts +14 -1
  17. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  18. package/dist/admin/apps/api-keys.js +6 -2
  19. package/dist/admin/apps/api-keys.js.map +1 -1
  20. package/dist/admin/apps/organizations.d.ts +2 -0
  21. package/dist/admin/apps/organizations.d.ts.map +1 -1
  22. package/dist/admin/apps/verified-tokens.d.ts +11 -11
  23. package/dist/admin/ui.generated.d.ts +1 -1
  24. package/dist/admin/ui.generated.js +67 -67
  25. package/dist/admin/ui.generated.js.map +1 -1
  26. package/dist/analytics/Analytics.d.ts +2 -0
  27. package/dist/analytics/Analytics.d.ts.map +1 -1
  28. package/dist/analytics/Analytics.js +3 -0
  29. package/dist/analytics/Analytics.js.map +1 -1
  30. package/dist/apps/data/App.d.ts +11696 -13937
  31. package/dist/apps/data/App.d.ts.map +1 -1
  32. package/dist/apps/data/App.js +4 -8
  33. package/dist/apps/data/App.js.map +1 -1
  34. package/dist/apps/data/routes/activities.d.ts +271 -271
  35. package/dist/apps/data/routes/addresses.d.ts +398 -167
  36. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  37. package/dist/apps/data/routes/balances.d.ts +278 -8
  38. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  39. package/dist/apps/data/routes/balances.js +114 -2
  40. package/dist/apps/data/routes/balances.js.map +1 -1
  41. package/dist/apps/data/routes/blocks.d.ts +123 -123
  42. package/dist/apps/data/routes/coingecko.d.ts +170 -170
  43. package/dist/apps/data/routes/earn.d.ts +498 -6
  44. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  45. package/dist/apps/data/routes/earn.js +876 -4
  46. package/dist/apps/data/routes/earn.js.map +1 -1
  47. package/dist/apps/data/routes/exchanges.d.ts +10 -10
  48. package/dist/apps/data/routes/fee-amm.d.ts +2 -2
  49. package/dist/apps/data/routes/indexer.d.ts +6 -6
  50. package/dist/apps/data/routes/indexer.js +4 -1
  51. package/dist/apps/data/routes/indexer.js.map +1 -1
  52. package/dist/apps/data/routes/receipts.d.ts +235 -235
  53. package/dist/apps/data/routes/rpc.d.ts +31 -31
  54. package/dist/apps/data/routes/rpc.js +4 -1
  55. package/dist/apps/data/routes/rpc.js.map +1 -1
  56. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  57. package/dist/apps/data/routes/tokens.d.ts +449 -449
  58. package/dist/apps/data/routes/transactions.d.ts +2 -2
  59. package/dist/apps/data/routes/transfers.d.ts +81 -81
  60. package/dist/apps/data/routes/valuation.d.ts +1 -1
  61. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  62. package/dist/apps/data/routes/webhooks.d.ts +9 -9
  63. package/dist/apps/data/routes/zones.d.ts +14 -14
  64. package/dist/apps/funding/Access.d.ts +16 -0
  65. package/dist/apps/funding/Access.d.ts.map +1 -0
  66. package/dist/apps/funding/Access.js +22 -0
  67. package/dist/apps/funding/Access.js.map +1 -0
  68. package/dist/apps/{data/routes/funding.d.ts → funding/App.d.ts} +1640 -3217
  69. package/dist/apps/funding/App.d.ts.map +1 -0
  70. package/dist/apps/funding/App.js +61 -0
  71. package/dist/apps/funding/App.js.map +1 -0
  72. package/dist/apps/funding/Inventory.d.ts +5 -0
  73. package/dist/apps/funding/Inventory.d.ts.map +1 -0
  74. package/dist/apps/funding/Inventory.js +25 -0
  75. package/dist/apps/funding/Inventory.js.map +1 -0
  76. package/dist/apps/funding/ProviderAttempts.d.ts +5 -0
  77. package/dist/apps/funding/ProviderAttempts.d.ts.map +1 -0
  78. package/dist/apps/funding/ProviderAttempts.js +24 -0
  79. package/dist/apps/funding/ProviderAttempts.js.map +1 -0
  80. package/dist/apps/funding/index.d.ts +2 -0
  81. package/dist/apps/funding/index.d.ts.map +1 -0
  82. package/dist/apps/funding/index.js +2 -0
  83. package/dist/apps/funding/index.js.map +1 -0
  84. package/dist/apps/funding/routes/chains.d.ts +169 -0
  85. package/dist/apps/funding/routes/chains.d.ts.map +1 -0
  86. package/dist/apps/funding/routes/chains.js +80 -0
  87. package/dist/apps/funding/routes/chains.js.map +1 -0
  88. package/dist/apps/funding/routes/deposit-addresses.d.ts +1997 -0
  89. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -0
  90. package/dist/apps/funding/routes/deposit-addresses.js +778 -0
  91. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -0
  92. package/dist/apps/funding/routes/providers.d.ts +91 -0
  93. package/dist/apps/funding/routes/providers.d.ts.map +1 -0
  94. package/dist/apps/funding/routes/providers.js +56 -0
  95. package/dist/apps/funding/routes/providers.js.map +1 -0
  96. package/dist/apps/funding/routes/quotes.d.ts +426 -0
  97. package/dist/apps/funding/routes/quotes.d.ts.map +1 -0
  98. package/dist/apps/funding/routes/quotes.js +188 -0
  99. package/dist/apps/funding/routes/quotes.js.map +1 -0
  100. package/dist/apps/funding/routes/transfers.d.ts +1999 -0
  101. package/dist/apps/funding/routes/transfers.d.ts.map +1 -0
  102. package/dist/apps/funding/routes/transfers.js +614 -0
  103. package/dist/apps/funding/routes/transfers.js.map +1 -0
  104. package/dist/apps/index.d.ts +1 -0
  105. package/dist/apps/index.d.ts.map +1 -1
  106. package/dist/apps/index.js +1 -0
  107. package/dist/apps/index.js.map +1 -1
  108. package/dist/apps/management/App.d.ts +430 -165
  109. package/dist/apps/management/App.d.ts.map +1 -1
  110. package/dist/apps/management/routes/api-keys.d.ts +298 -21
  111. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  112. package/dist/apps/management/routes/api-keys.js +75 -1
  113. package/dist/apps/management/routes/api-keys.js.map +1 -1
  114. package/dist/apps/management/routes/billing.d.ts +6 -6
  115. package/dist/apps/management/routes/faucet.d.ts +35 -35
  116. package/dist/apps/management/routes/invitations.d.ts +122 -122
  117. package/dist/apps/management/routes/invite-links.d.ts +38 -38
  118. package/dist/apps/management/routes/members.d.ts +69 -69
  119. package/dist/apps/management/routes/orgs.d.ts +99 -99
  120. package/dist/apps/management/routes/projects.d.ts +25 -25
  121. package/dist/apps/management/routes/scopes.d.ts +1 -1
  122. package/dist/apps/management/routes/usage.d.ts +72 -72
  123. package/dist/apps/management/routes/verified-token-requests.d.ts +77 -77
  124. package/dist/apps/management/routes/webhooks.d.ts +128 -128
  125. package/dist/apps/mcp.d.ts +2 -3
  126. package/dist/apps/mcp.d.ts.map +1 -1
  127. package/dist/apps/mcp.js +16 -14
  128. package/dist/apps/mcp.js.map +1 -1
  129. package/dist/apps/metadata.d.ts +4 -0
  130. package/dist/apps/metadata.d.ts.map +1 -1
  131. package/dist/apps/metadata.js +10 -0
  132. package/dist/apps/metadata.js.map +1 -1
  133. package/dist/apps/mpp/App.d.ts +44 -44
  134. package/dist/cloudflare.d.ts +50 -0
  135. package/dist/cloudflare.d.ts.map +1 -1
  136. package/dist/cloudflare.js +178 -0
  137. package/dist/cloudflare.js.map +1 -1
  138. package/dist/db/Db.d.ts +2 -0
  139. package/dist/db/Db.d.ts.map +1 -1
  140. package/dist/db/Db.js +45 -0
  141. package/dist/db/Db.js.map +1 -1
  142. package/dist/db/Schema.d.ts +12 -0
  143. package/dist/db/Schema.d.ts.map +1 -1
  144. package/dist/db/Schema.js +20 -0
  145. package/dist/db/Schema.js.map +1 -1
  146. package/dist/db/tables/fundingDepositAddresses.d.ts +13 -0
  147. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
  148. package/dist/db/tables/fundingDepositAddresses.js +12 -0
  149. package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
  150. package/dist/db/tables/fundingDepositRequestObservations.d.ts +45 -0
  151. package/dist/db/tables/fundingDepositRequestObservations.d.ts.map +1 -0
  152. package/dist/db/tables/fundingDepositRequestObservations.js +46 -0
  153. package/dist/db/tables/fundingDepositRequestObservations.js.map +1 -0
  154. package/dist/db/tables/fundingDeposits.d.ts +74 -1
  155. package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
  156. package/dist/db/tables/fundingDeposits.js +126 -0
  157. package/dist/db/tables/fundingDeposits.js.map +1 -1
  158. package/dist/internal/Auth.d.ts +15 -11
  159. package/dist/internal/Auth.d.ts.map +1 -1
  160. package/dist/internal/Auth.js +52 -17
  161. package/dist/internal/Auth.js.map +1 -1
  162. package/dist/internal/Cache.js +1 -1
  163. package/dist/internal/Cache.js.map +1 -1
  164. package/dist/internal/EdgeCache.d.ts +2 -2
  165. package/dist/internal/EdgeCache.d.ts.map +1 -1
  166. package/dist/internal/EdgeCache.js +10 -4
  167. package/dist/internal/EdgeCache.js.map +1 -1
  168. package/dist/internal/IpAllowlist.d.ts +15 -0
  169. package/dist/internal/IpAllowlist.d.ts.map +1 -0
  170. package/dist/internal/IpAllowlist.js +27 -0
  171. package/dist/internal/IpAllowlist.js.map +1 -0
  172. package/dist/internal/OpenApi.d.ts +1 -1
  173. package/dist/internal/OpenApi.js +1 -1
  174. package/dist/internal/OpenApi.js.map +1 -1
  175. package/dist/internal/Tidx.d.ts +6 -0
  176. package/dist/internal/Tidx.d.ts.map +1 -1
  177. package/dist/internal/Tidx.js +13 -3
  178. package/dist/internal/Tidx.js.map +1 -1
  179. package/dist/internal/Viem.d.ts +8 -0
  180. package/dist/internal/Viem.d.ts.map +1 -1
  181. package/dist/internal/Viem.js +12 -5
  182. package/dist/internal/Viem.js.map +1 -1
  183. package/dist/internal/funding/Deposit.d.ts +42 -0
  184. package/dist/internal/funding/Deposit.d.ts.map +1 -1
  185. package/dist/internal/funding/Deposit.js +37 -5
  186. package/dist/internal/funding/Deposit.js.map +1 -1
  187. package/dist/internal/funding/Evidence.d.ts +1 -5
  188. package/dist/internal/funding/Evidence.d.ts.map +1 -1
  189. package/dist/internal/funding/Evidence.js +4 -3
  190. package/dist/internal/funding/Evidence.js.map +1 -1
  191. package/dist/internal/funding/Provider.d.ts +102 -0
  192. package/dist/internal/funding/Provider.d.ts.map +1 -1
  193. package/dist/internal/funding/Provider.js +5 -0
  194. package/dist/internal/funding/Provider.js.map +1 -1
  195. package/dist/internal/funding/Reconciliation.d.ts +16 -2
  196. package/dist/internal/funding/Reconciliation.d.ts.map +1 -1
  197. package/dist/internal/funding/Reconciliation.js +348 -54
  198. package/dist/internal/funding/Reconciliation.js.map +1 -1
  199. package/dist/internal/funding/SourceObservation.d.ts +108 -0
  200. package/dist/internal/funding/SourceObservation.d.ts.map +1 -0
  201. package/dist/internal/funding/SourceObservation.js +143 -0
  202. package/dist/internal/funding/SourceObservation.js.map +1 -0
  203. package/dist/internal/funding/Subsidy.d.ts +2 -2
  204. package/dist/internal/funding/Subsidy.d.ts.map +1 -1
  205. package/dist/internal/funding/Subsidy.js +1 -1
  206. package/dist/internal/funding/Subsidy.js.map +1 -1
  207. package/dist/internal/funding/index.d.ts +1 -0
  208. package/dist/internal/funding/index.d.ts.map +1 -1
  209. package/dist/internal/funding/index.js +1 -0
  210. package/dist/internal/funding/index.js.map +1 -1
  211. package/dist/internal/funding/providers/relay.d.ts +43 -1
  212. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  213. package/dist/internal/funding/providers/relay.js +438 -27
  214. package/dist/internal/funding/providers/relay.js.map +1 -1
  215. package/package.json +3 -3
  216. package/src/ApiKey.test.ts +35 -0
  217. package/src/ApiKey.ts +27 -0
  218. package/src/ApiKeys.test.ts +29 -0
  219. package/src/ApiKeys.ts +11 -3
  220. package/src/App.test.ts +55 -5
  221. package/src/App.ts +79 -5
  222. package/src/Client.test-d.ts +203 -28
  223. package/src/admin/apps/api-keys.test.ts +25 -1
  224. package/src/admin/apps/api-keys.ts +6 -2
  225. package/src/admin/ui.generated.ts +67 -67
  226. package/src/analytics/Analytics.ts +4 -0
  227. package/src/apps/composition.test.ts +130 -3
  228. package/src/apps/data/App.test.ts +0 -12
  229. package/src/apps/data/App.ts +4 -8
  230. package/src/apps/data/routes/balances.test.ts +42 -0
  231. package/src/apps/data/routes/balances.ts +218 -85
  232. package/src/apps/data/routes/earn.test.ts +363 -0
  233. package/src/apps/data/routes/earn.ts +1141 -3
  234. package/src/apps/data/routes/indexer.ts +2 -1
  235. package/src/apps/data/routes/rpc.ts +2 -0
  236. package/src/apps/data/routes/tokens.test.ts +6 -8
  237. package/src/apps/funding/Access.ts +26 -0
  238. package/src/apps/funding/App.test.ts +78 -0
  239. package/src/apps/funding/App.ts +78 -0
  240. package/src/apps/funding/Inventory.ts +30 -0
  241. package/src/apps/funding/ProviderAttempts.ts +26 -0
  242. package/src/apps/funding/index.ts +1 -0
  243. package/src/apps/funding/routes/chains.test.ts +78 -0
  244. package/src/apps/funding/routes/chains.ts +101 -0
  245. package/src/apps/funding/routes/deposit-addresses.test.ts +1649 -0
  246. package/src/apps/funding/routes/deposit-addresses.ts +932 -0
  247. package/src/apps/funding/routes/providers.test.ts +165 -0
  248. package/src/apps/funding/routes/providers.ts +73 -0
  249. package/src/apps/funding/routes/quotes.test.ts +511 -0
  250. package/src/apps/funding/routes/quotes.ts +205 -0
  251. package/src/apps/funding/routes/transfers.test.ts +1236 -0
  252. package/src/apps/funding/routes/transfers.ts +704 -0
  253. package/src/apps/index.ts +1 -0
  254. package/src/apps/management/routes/api-keys.test.ts +98 -0
  255. package/src/apps/management/routes/api-keys.ts +96 -1
  256. package/src/apps/mcp.test.ts +17 -2
  257. package/src/apps/mcp.ts +18 -13
  258. package/src/apps/metadata.ts +12 -0
  259. package/src/apps/mpp/internal/Policy.test.ts +7 -1
  260. package/src/cloudflare.ts +279 -0
  261. package/src/db/Db.ts +71 -0
  262. package/src/db/Schema.ts +24 -0
  263. package/src/db/tables/fundingDepositAddresses.ts +28 -0
  264. package/src/db/tables/fundingDepositRequestObservations.test.ts +106 -0
  265. package/src/db/tables/fundingDepositRequestObservations.ts +99 -0
  266. package/src/db/tables/fundingDeposits.test.ts +239 -0
  267. package/src/db/tables/fundingDeposits.ts +214 -1
  268. package/src/internal/Auth.test.ts +205 -5
  269. package/src/internal/Auth.ts +63 -19
  270. package/src/internal/Cache.test.ts +37 -3
  271. package/src/internal/Cache.ts +1 -1
  272. package/src/internal/EdgeCache.test.ts +7 -7
  273. package/src/internal/EdgeCache.ts +13 -4
  274. package/src/internal/IpAllowlist.test.ts +52 -0
  275. package/src/internal/IpAllowlist.ts +39 -0
  276. package/src/internal/Log.test.ts +7 -1
  277. package/src/internal/OpenApi.ts +1 -1
  278. package/src/internal/Tidx.test.ts +28 -0
  279. package/src/internal/Tidx.ts +19 -3
  280. package/src/internal/Viem.test.ts +28 -0
  281. package/src/internal/Viem.ts +21 -5
  282. package/src/internal/funding/Deposit.ts +74 -5
  283. package/src/internal/funding/Evidence.test.ts +2 -2
  284. package/src/internal/funding/Evidence.ts +4 -9
  285. package/src/internal/funding/Provider.ts +115 -0
  286. package/src/internal/funding/Reconciliation.local.test.ts +7 -0
  287. package/src/internal/funding/Reconciliation.test.ts +1364 -109
  288. package/src/internal/funding/Reconciliation.ts +467 -88
  289. package/src/internal/funding/SourceObservation.test.ts +301 -0
  290. package/src/internal/funding/SourceObservation.ts +267 -0
  291. package/src/internal/funding/Subsidy.ts +2 -2
  292. package/src/internal/funding/index.test.ts +1 -0
  293. package/src/internal/funding/index.ts +1 -0
  294. package/src/internal/funding/providers/relay.test.ts +94 -4
  295. package/src/internal/funding/providers/relay.ts +533 -27
  296. package/dist/apps/data/routes/funding.d.ts.map +0 -1
  297. package/dist/apps/data/routes/funding.js +0 -1557
  298. package/dist/apps/data/routes/funding.js.map +0 -1
  299. package/src/apps/data/routes/funding.test.ts +0 -2994
  300. package/src/apps/data/routes/funding.ts +0 -1821
@@ -259,7 +259,7 @@ async function passthrough(
259
259
  // Resolve the upstream for this caller. A resolver `tidx` can route by
260
260
  // principal (e.g. anonymous `type: 'public'` callers to a public, no-auth
261
261
  // indexer); a static config ignores the principal.
262
- const { baseUrl, basicAuth, bearerAuth } = Tidx.resolve(tidx, {
262
+ const { baseUrl, basicAuth, bearerAuth, zoneHeaders } = Tidx.resolve(tidx, {
263
263
  chainId,
264
264
  principal: Auth.getPrincipal(c),
265
265
  zone: c.get('zones').get(chainId),
@@ -296,6 +296,7 @@ async function passthrough(
296
296
  const headers = new Headers()
297
297
  for (const [name, value] of c.req.raw.headers)
298
298
  if (!strippedHeaders.has(name.toLowerCase())) headers.set(name, value)
299
+ if (zoneHeaders) for (const [name, value] of new Headers(zoneHeaders)) headers.set(name, value)
299
300
  if (basicAuth) headers.set('authorization', `Basic ${btoa(basicAuth)}`)
300
301
  else if (bearerAuth) headers.set('authorization', `Bearer ${bearerAuth}`)
301
302
 
@@ -368,6 +368,7 @@ async function passthrough(
368
368
  basicAuth,
369
369
  bearerAuth,
370
370
  publicZoneUrl,
371
+ zoneHeaders,
371
372
  url: resolvedUrl,
372
373
  } = Viem.resolveRpc(upstream_rpc, { chainId, principal, zone })
373
374
  const usePublicZoneUrl = Boolean(zone && zoneToken)
@@ -385,6 +386,7 @@ async function passthrough(
385
386
  const headers = new Headers()
386
387
  for (const [name, value] of c.req.raw.headers)
387
388
  if (!strippedHeaders.has(name.toLowerCase())) headers.set(name, value)
389
+ if (zoneHeaders) for (const [name, value] of new Headers(zoneHeaders)) headers.set(name, value)
388
390
  // Public Zone endpoints authenticate with the caller's token, never internal RPC credentials.
389
391
  if (!usePublicZoneUrl && basicAuth) headers.set('authorization', `Basic ${btoa(basicAuth)}`)
390
392
  else if (!usePublicZoneUrl && bearerAuth) headers.set('authorization', `Bearer ${bearerAuth}`)
@@ -274,7 +274,6 @@ describe('GET /tokens?verified=true', () => {
274
274
  describe('GET /tokens?addresses=', () => {
275
275
  test('separates repeated addresses in the response cache', async () => {
276
276
  const routed = TestApp.create({ db })
277
- const headers = { authorization: `Bearer ${TestApp.key.token}` }
278
277
  const repeated = new URLSearchParams()
279
278
  repeated.append('addresses', TestApp.token)
280
279
  repeated.append('addresses', TestApp.tokenWithHolders)
@@ -282,9 +281,9 @@ describe('GET /tokens?addresses=', () => {
282
281
  addresses: TestApp.tokenWithHolders,
283
282
  })
284
283
 
285
- const primed = await routed.request(`/v1/tokens?${repeated}`, { headers })
286
- const miss = await routed.request(`/v1/tokens?${single}`, { headers })
287
- const hit = await routed.request(`/v1/tokens?${single}`, { headers })
284
+ const primed = await routed.request(`/v1/tokens?${repeated}`)
285
+ const miss = await routed.request(`/v1/tokens?${single}`)
286
+ const hit = await routed.request(`/v1/tokens?${single}`)
288
287
  const primedBody = await TestApp.json(primed, Tokens.schema.getTokens.Response)
289
288
  const body = await TestApp.json(hit, Tokens.schema.getTokens.Response)
290
289
 
@@ -302,7 +301,6 @@ describe('GET /tokens?addresses=', () => {
302
301
 
303
302
  test('separates repeated includes in the response cache', async () => {
304
303
  const routed = TestApp.create({ db })
305
- const headers = { authorization: `Bearer ${TestApp.key.token}` }
306
304
  const repeated = new URLSearchParams({ limit: '5' })
307
305
  repeated.append('include', 'createdAt')
308
306
  repeated.append('include', 'holderCount')
@@ -311,9 +309,9 @@ describe('GET /tokens?addresses=', () => {
311
309
  limit: '5',
312
310
  })
313
311
 
314
- const primed = await routed.request(`/v1/tokens?${repeated}`, { headers })
315
- const miss = await routed.request(`/v1/tokens?${single}`, { headers })
316
- const hit = await routed.request(`/v1/tokens?${single}`, { headers })
312
+ const primed = await routed.request(`/v1/tokens?${repeated}`)
313
+ const miss = await routed.request(`/v1/tokens?${single}`)
314
+ const hit = await routed.request(`/v1/tokens?${single}`)
317
315
  const primedBody = await TestApp.json(primed, Tokens.schema.getTokens.Response)
318
316
  const body = await TestApp.json(hit, Tokens.schema.getTokens.Response)
319
317
 
@@ -0,0 +1,26 @@
1
+ import type { Context } from 'hono'
2
+
3
+ import type * as App from '../../App.js'
4
+ import type * as FundingTransfers from '../../db/tables/fundingTransfers.js'
5
+ import * as Auth from '../../internal/Auth.js'
6
+ import * as Response from '../../internal/Response.js'
7
+
8
+ /** Returns the funding owner encoded by an API-key principal. */
9
+ export function owner(c: Context<App.Environment>): FundingTransfers.Owner | null {
10
+ const principal = Auth.getPrincipal(c)
11
+ if (principal?.type !== 'api_key') return null
12
+ return {
13
+ environment: principal.environment,
14
+ orgId: principal.orgId,
15
+ projectId: principal.projectId,
16
+ }
17
+ }
18
+
19
+ /** Returns the error used when a funding resource has no API-key owner. */
20
+ export function unauthorized(c: Context<App.Environment>) {
21
+ return Response.error(c, {
22
+ code: 'unauthorized',
23
+ message: 'Tempo could not determine which organization owns this funding resource.',
24
+ status: 401,
25
+ })
26
+ }
@@ -0,0 +1,78 @@
1
+ import { App } from 'tapimo'
2
+
3
+ import * as Store from '../../internal/Store.js'
4
+ import * as Viem from '../../internal/Viem.js'
5
+ import * as TestApp from '../../../test/App.js'
6
+ import { funding } from './App.js'
7
+
8
+ const sandbox = {
9
+ environment: 'sandbox',
10
+ id: 'key_sandbox_funding',
11
+ orgId: 'org_test',
12
+ scopes: ['data:read'],
13
+ token: 'secret_sandbox_funding',
14
+ } satisfies TestApp.kvStore.Key
15
+
16
+ function as(key: { token: string }) {
17
+ return { headers: { authorization: `Bearer ${key.token}` } } as const
18
+ }
19
+
20
+ describe('funding access', () => {
21
+ test('rejects sandbox keys on a mainnet-default deployment', async () => {
22
+ const app = App.create({
23
+ auth: {},
24
+ db: TestApp.database(),
25
+ defaultChainId: Viem.chainId.mainnet,
26
+ kv: { store: TestApp.kvStore({ keys: [sandbox] }) },
27
+ }).route('/', funding())
28
+
29
+ const response = await app.request('/v1/funding/chains', as(sandbox))
30
+
31
+ expect(response.status).toBe(403)
32
+ expect(((await response.json()) as { error: { code: string } }).error.code).toBe(
33
+ 'api_key_forbidden',
34
+ )
35
+ })
36
+
37
+ test('requires a matching Zone scope and bypasses the edge cache', async () => {
38
+ const chainId = 421_700_001
39
+ const reader = {
40
+ id: 'key_zone_funding',
41
+ orgId: 'org_test',
42
+ scopes: ['data:read', `zone:${chainId}:read`],
43
+ token: 'secret_zone_funding',
44
+ } satisfies TestApp.kvStore.Key
45
+ const app = App.create({
46
+ auth: {},
47
+ cache: { store: Store.memory() },
48
+ db: TestApp.database(),
49
+ defaultChainId: chainId,
50
+ kv: { store: TestApp.kvStore({ keys: [reader] }) },
51
+ zones: [TestApp.zone({ chainId, rpcUrl: `https://${chainId}.rpc.test` })],
52
+ }).route('/', funding())
53
+
54
+ const allowed = await app.request('/v1/funding/chains', as(reader))
55
+ const anonymous = await app.request('/v1/funding/chains')
56
+
57
+ expect(allowed.status).toBe(200)
58
+ expect(allowed.headers.get('cache-control')).toContain('private')
59
+ expect(anonymous.status).toBe(403)
60
+ })
61
+
62
+ test('keeps public-chain inventory edge-cacheable on a Zone deployment', async () => {
63
+ const chainId = 421_700_001
64
+ const app = App.create({
65
+ auth: false,
66
+ cache: { store: Store.memory() },
67
+ db: TestApp.database(),
68
+ zones: [TestApp.zone({ chainId, rpcUrl: `https://${chainId}.rpc.test` })],
69
+ }).route('/', funding())
70
+
71
+ const first = await app.request('/v1/funding/chains')
72
+ const second = await app.request('/v1/funding/chains')
73
+
74
+ expect(first.status).toBe(200)
75
+ expect(second.status).toBe(200)
76
+ expect(second.headers.get('cache-control')).toContain('public')
77
+ })
78
+ })
@@ -0,0 +1,78 @@
1
+ import { Hono } from 'hono'
2
+
3
+ import type * as App from '../../App.js'
4
+ import type * as FundingDepositAddress from '../../internal/funding/DepositAddress.js'
5
+ import type * as FundingProvider from '../../internal/funding/Provider.js'
6
+ import * as Metadata from '../metadata.js'
7
+ import { chains } from './routes/chains.js'
8
+ import { depositAddresses } from './routes/deposit-addresses.js'
9
+ import { providers } from './routes/providers.js'
10
+ import { quotes } from './routes/quotes.js'
11
+ import { transfers } from './routes/transfers.js'
12
+
13
+ /**
14
+ * Mounts the Funding & Bridge API, including quotes, inventory, reusable
15
+ * deposit addresses, detected deposits, and transfers.
16
+ *
17
+ * ```ts
18
+ * App.create(options).route('/', data()).route('/', funding())
19
+ * ```
20
+ */
21
+ export function funding(options: funding.Options = {}) {
22
+ const app = new Hono<App.Environment>()
23
+ .route('/', quotes())
24
+ .route('/', chains())
25
+ .route('/', providers())
26
+ .route('/', depositAddresses(options))
27
+ .route('/', transfers())
28
+ return Metadata.defaultChain(Metadata.attach(app, openapi))
29
+ }
30
+
31
+ export declare namespace funding {
32
+ /** Inbound funding route configuration. */
33
+ type Options = {
34
+ /** Enqueues one deposit address for asynchronous reconciliation. */
35
+ dispatchReconciliation?:
36
+ | ((message: FundingProvider.Webhook.receive.Dispatchable) => Promise<void>)
37
+ | undefined
38
+ /** Registers a created address with a source-chain observer. */
39
+ registerDepositAddress?: ((address: FundingDepositAddress.Public) => Promise<void>) | undefined
40
+ }
41
+ }
42
+
43
+ const openapi = {
44
+ tags: [
45
+ {
46
+ name: 'Chains',
47
+ description: 'Source chains and stablecoins supported for funding.',
48
+ 'x-pagePath': 'funding/chains',
49
+ },
50
+ {
51
+ name: 'Deposit Addresses',
52
+ description: 'Reusable funding addresses and deposits detected at those addresses.',
53
+ 'x-pagePath': 'funding/deposit-addresses',
54
+ },
55
+ {
56
+ name: 'Providers',
57
+ description: 'Providers available for inbound funding.',
58
+ 'x-pagePath': 'funding/providers',
59
+ },
60
+ {
61
+ name: 'Quotes',
62
+ description: 'Live quotes for funding Tempo from other chains.',
63
+ 'x-pagePath': 'funding/quotes',
64
+ },
65
+ {
66
+ name: 'Funding Transfers',
67
+ description: 'Inbound funding transfers.',
68
+ 'x-displayName': 'Transfers',
69
+ 'x-pagePath': 'funding/transfers',
70
+ },
71
+ ],
72
+ 'x-tagGroups': [
73
+ {
74
+ name: 'Funding & Bridge API',
75
+ tags: ['Chains', 'Deposit Addresses', 'Providers', 'Quotes', 'Funding Transfers'],
76
+ },
77
+ ],
78
+ } satisfies App.create.Metadata
@@ -0,0 +1,30 @@
1
+ import type { Context } from 'hono'
2
+
3
+ import type * as App from '../../App.js'
4
+ import type * as Db from '../../db/Db.js'
5
+ import * as FundingProvider from '../../internal/funding/Provider.js'
6
+
7
+ const sourceScopes = new WeakMap<Db.Source, number>()
8
+ let nextSourceScope = 0
9
+
10
+ /** Returns an inventory cache key scoped by request URL, providers, and database source. */
11
+ export function key(c: Context<App.Environment>) {
12
+ const url = new URL(c.req.url)
13
+ const providers = c
14
+ .get('providers')
15
+ .filter(FundingProvider.is)
16
+ .map((provider) => provider.id)
17
+ .sort()
18
+ url.searchParams.set('__tempo_database', String(sourceScope(c.get('dbCached'))))
19
+ url.searchParams.set('__tempo_providers', providers.join(','))
20
+ return url.toString()
21
+ }
22
+
23
+ function sourceScope(source: Db.Source) {
24
+ const current = sourceScopes.get(source)
25
+ if (current !== undefined) return current
26
+ // A production isolate has one source, while multi-app runtimes receive distinct scopes.
27
+ const scope = nextSourceScope++
28
+ sourceScopes.set(source, scope)
29
+ return scope
30
+ }
@@ -0,0 +1,26 @@
1
+ import * as FundingProvider from '../../internal/funding/Provider.js'
2
+ import type * as Log from '../../internal/Log.js'
3
+
4
+ /** Formats one provider attempt for the canonical request log. */
5
+ export function format(attempt: FundingProvider.ProviderAttempt): Log.FundingProviderAttempt {
6
+ const { id } = attempt.provider
7
+ if (attempt.outcome !== 'failed')
8
+ return {
9
+ durationMs: attempt.durationMs,
10
+ id,
11
+ operation: attempt.operation,
12
+ outcome: attempt.outcome,
13
+ }
14
+
15
+ return {
16
+ durationMs: attempt.durationMs,
17
+ failure: FundingProvider.failure({
18
+ cause: attempt.cause,
19
+ operation: attempt.operation,
20
+ provider: attempt.provider,
21
+ }).failure,
22
+ id,
23
+ operation: attempt.operation,
24
+ outcome: attempt.outcome,
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ export { funding } from './App.js'
@@ -0,0 +1,78 @@
1
+ import * as Across from '../../../internal/funding/providers/across.js'
2
+
3
+ import * as Relay from '../../../internal/funding/providers/relay.js'
4
+
5
+ import * as Rhino from '../../../internal/funding/providers/rhino.js'
6
+
7
+ import * as Squid from '../../../internal/funding/providers/squid.js'
8
+
9
+ import * as Symbiosis from '../../../internal/funding/providers/symbiosis.js'
10
+
11
+ import * as TestApp from '../../../../test/App.js'
12
+
13
+ import * as TestFunding from '../../../../test/Funding.js'
14
+
15
+ import * as Funding from './chains.js'
16
+
17
+ const db = TestApp.database()
18
+
19
+ const providers = [
20
+ Across.across({
21
+ apiKey: 'across-api-key',
22
+ integratorId: '0xdead',
23
+ userAddress: '0x1111111111111111111111111111111111111111',
24
+ }),
25
+ Relay.relay({ userAddress: '0x1111111111111111111111111111111111111111' }),
26
+ Rhino.rhino(),
27
+ Squid.squid({
28
+ integratorId: 'squid-integrator-id',
29
+ userAddress: '0x1111111111111111111111111111111111111111',
30
+ }),
31
+ Symbiosis.symbiosis({ userAddress: '0x1111111111111111111111111111111111111111' }),
32
+ ] as const
33
+
34
+ beforeAll(() => TestFunding.publish(db))
35
+
36
+ function create(options: TestApp.create.Options = {}) {
37
+ return TestApp.create({ ...options, db })
38
+ }
39
+
40
+ describe('funding OpenAPI', () => {
41
+ test('publishes get operation ids for funding inventory', async () => {
42
+ const app = create({ auth: false })
43
+ const spec = await (await app.request('/openapi.json')).json()
44
+
45
+ expect({
46
+ chains: spec.paths['/v1/funding/chains'].get.operationId,
47
+ providers: spec.paths['/v1/funding/providers'].get.operationId,
48
+ }).toEqual({
49
+ chains: 'getFundingChains',
50
+ providers: 'getFundingProviders',
51
+ })
52
+ })
53
+ })
54
+
55
+ describe('GET /funding/chains', () => {
56
+ test('lists only inputs supported by quote providers', async () => {
57
+ const response = await create({ providers }).request('/v1/funding/chains', {
58
+ headers: TestApp.auth.headers,
59
+ })
60
+ expect(response.status).toBe(200)
61
+ const body = await TestApp.json(response, Funding.schema.getFundingChains.Response)
62
+
63
+ expect(body.data.map((chain) => chain.id)).toEqual([
64
+ 'eip155:1',
65
+ 'eip155:56',
66
+ 'eip155:8453',
67
+ 'eip155:137',
68
+ 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp',
69
+ 'tron:0x2b6653dc',
70
+ ])
71
+ expect(body.data.flatMap((chain) => chain.tokens.map((token) => token.symbol))).toEqual(
72
+ expect.arrayContaining(['USDC', 'USDT']),
73
+ )
74
+ expect(
75
+ body.data.flatMap((chain) => chain.tokens).every((token) => token.currency === 'USD'),
76
+ ).toBe(true)
77
+ })
78
+ })
@@ -0,0 +1,101 @@
1
+ import { Hono } from 'hono'
2
+ import * as z from 'zod/mini'
3
+
4
+ import type * as App from '../../../App.js'
5
+ import * as Auth from '../../../internal/Auth.js'
6
+ import * as Cache from '../../../internal/Cache.js'
7
+ import * as FundingCatalog from '../../../internal/funding/Catalog.js'
8
+ import * as FundingProvider from '../../../internal/funding/Provider.js'
9
+ import * as OpenApi from '../../../internal/OpenApi.js'
10
+ import * as Response from '../../../internal/Response.js'
11
+ import * as Schema from '../../../internal/Schema.js'
12
+ import * as Inventory from '../Inventory.js'
13
+
14
+ /** Zod schemas owned by funding chain resources. */
15
+ export namespace schema {
16
+ /** Source chain reference. */
17
+ export const Chain = FundingProvider.schema.ChainRef
18
+
19
+ /** Source token reference. */
20
+ export const Token = FundingProvider.schema.TokenRef
21
+
22
+ /** Chain inventory entry returned by the funding chains endpoint. */
23
+ export const ChainInventory = Schema.describe(
24
+ z.extend(Chain, {
25
+ tokens: z.array(Token).check(z.describe('Stablecoins known on this source chain.')),
26
+ }),
27
+ 'One source chain and its known stablecoin inventory.',
28
+ )
29
+
30
+ /** Schemas for the getFundingChains operation. */
31
+ export namespace getFundingChains {
32
+ /** Non-paginated source-chain inventory. */
33
+ export const Response = Schema.describe(
34
+ z.object({
35
+ data: z
36
+ .array(ChainInventory)
37
+ .check(z.describe('Source chains and stablecoins supported by funding quotes.')),
38
+ }),
39
+ 'A non-paginated list of source chains and stablecoin inventory.',
40
+ )
41
+ }
42
+ }
43
+
44
+ const baseChainExample = {
45
+ addressFormat: 'hex',
46
+ id: 'eip155:8453',
47
+ kind: 'evm',
48
+ name: 'Base',
49
+ } as const
50
+
51
+ const baseUsdcExample = {
52
+ address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
53
+ currency: 'USD',
54
+ decimals: 6,
55
+ name: 'USD Coin',
56
+ standard: 'ERC-20',
57
+ symbol: 'USDC',
58
+ tokenKey: 'eip155:8453/erc20:0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
59
+ verified: true,
60
+ } as const
61
+
62
+ const fundingChainsResponseExample = {
63
+ data: [{ ...baseChainExample, tokens: [baseUsdcExample] }],
64
+ } satisfies z.output<typeof schema.getFundingChains.Response>
65
+
66
+ /** Mounts funding chain inventory routes. */
67
+ export function chains() {
68
+ return new Hono<App.Environment>().get(
69
+ '/v1/funding/chains',
70
+ Auth.policy({ apiKey: { scopes: ['data:read'] }, mpp: true, public: true }),
71
+ OpenApi.describeRoute({
72
+ description: 'Lists supported source chains and tokens.',
73
+ operationId: 'getFundingChains',
74
+ responses: OpenApi.responses({
75
+ success: {
76
+ description: 'Supported source chains and stablecoins.',
77
+ example: fundingChainsResponseExample,
78
+ schema: schema.getFundingChains.Response,
79
+ },
80
+ }),
81
+ summary: 'Get chains',
82
+ tags: ['Chains'],
83
+ }),
84
+ Cache.response<App.Environment>({
85
+ cacheControl: Cache.policies.stable,
86
+ key: Inventory.key,
87
+ name: 'tempo-api:funding-chains:v5',
88
+ }),
89
+ async (c) => {
90
+ if (Auth.narrowAccess) return Auth.paidAccessError(c)
91
+ const catalog = await FundingCatalog.snapshot(c)
92
+ const providers = c.get('providers').filter(FundingProvider.is)
93
+ return c.json(
94
+ Response.validated(schema.getFundingChains.Response, {
95
+ data: FundingProvider.getChains({ catalog, providers }),
96
+ }),
97
+ 200,
98
+ )
99
+ },
100
+ )
101
+ }