tapimo 0.2.0 → 0.3.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 (313) hide show
  1. package/README.md +31 -3
  2. package/dist/ApiKey.d.ts +1 -0
  3. package/dist/ApiKey.d.ts.map +1 -1
  4. package/dist/ApiKey.js +5 -2
  5. package/dist/ApiKey.js.map +1 -1
  6. package/dist/ApiKeys.d.ts +28 -1
  7. package/dist/ApiKeys.d.ts.map +1 -1
  8. package/dist/ApiKeys.js +34 -1
  9. package/dist/ApiKeys.js.map +1 -1
  10. package/dist/App.d.ts +7167 -4507
  11. package/dist/App.d.ts.map +1 -1
  12. package/dist/App.js +8 -0
  13. package/dist/App.js.map +1 -1
  14. package/dist/Scope.d.ts +11 -2
  15. package/dist/Scope.d.ts.map +1 -1
  16. package/dist/Scope.js +14 -3
  17. package/dist/Scope.js.map +1 -1
  18. package/dist/admin/App.d.ts +128 -118
  19. package/dist/admin/App.d.ts.map +1 -1
  20. package/dist/admin/apps/api-keys.d.ts +7 -0
  21. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  22. package/dist/admin/apps/scopes.d.ts +8 -0
  23. package/dist/admin/apps/scopes.d.ts.map +1 -1
  24. package/dist/admin/apps/scopes.js +3 -0
  25. package/dist/admin/apps/scopes.js.map +1 -1
  26. package/dist/admin/apps/verified-tokens.d.ts +57 -57
  27. package/dist/admin/ui.generated.d.ts +1 -1
  28. package/dist/admin/ui.generated.js +13 -13
  29. package/dist/admin/ui.generated.js.map +1 -1
  30. package/dist/analytics/Analytics.d.ts +151 -0
  31. package/dist/analytics/Analytics.d.ts.map +1 -0
  32. package/dist/analytics/Analytics.js +212 -0
  33. package/dist/analytics/Analytics.js.map +1 -0
  34. package/dist/analytics/tables/requestEvents.d.ts +215 -0
  35. package/dist/analytics/tables/requestEvents.d.ts.map +1 -0
  36. package/dist/analytics/tables/requestEvents.js +264 -0
  37. package/dist/analytics/tables/requestEvents.js.map +1 -0
  38. package/dist/apps/data/App.d.ts +1024 -624
  39. package/dist/apps/data/App.d.ts.map +1 -1
  40. package/dist/apps/data/App.js +36 -0
  41. package/dist/apps/data/App.js.map +1 -1
  42. package/dist/apps/data/routes/balances.d.ts +45 -45
  43. package/dist/apps/data/routes/coingecko.d.ts +176 -176
  44. package/dist/apps/data/routes/exchanges.d.ts +455 -455
  45. package/dist/apps/data/routes/fee-amm.d.ts +101 -101
  46. package/dist/apps/data/routes/funding.d.ts +765 -0
  47. package/dist/apps/data/routes/funding.d.ts.map +1 -0
  48. package/dist/apps/data/routes/funding.js +383 -0
  49. package/dist/apps/data/routes/funding.js.map +1 -0
  50. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  51. package/dist/apps/data/routes/receipts.js +2 -8
  52. package/dist/apps/data/routes/receipts.js.map +1 -1
  53. package/dist/apps/data/routes/rpc.d.ts +29 -36
  54. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  55. package/dist/apps/data/routes/rpc.js +29 -1
  56. package/dist/apps/data/routes/rpc.js.map +1 -1
  57. package/dist/apps/data/routes/tokenlist.d.ts +36 -36
  58. package/dist/apps/data/routes/transfers.d.ts +56 -56
  59. package/dist/apps/data/routes/verified-tokens.d.ts +36 -36
  60. package/dist/apps/data/routes/webhooks.d.ts +45 -45
  61. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  62. package/dist/apps/data/routes/webhooks.js +8 -8
  63. package/dist/apps/data/routes/webhooks.js.map +1 -1
  64. package/dist/apps/docs/App.d.ts +4 -2
  65. package/dist/apps/docs/App.d.ts.map +1 -1
  66. package/dist/apps/docs/App.js +27 -95
  67. package/dist/apps/docs/App.js.map +1 -1
  68. package/dist/apps/docs/reference.d.ts +21 -0
  69. package/dist/apps/docs/reference.d.ts.map +1 -0
  70. package/dist/apps/docs/reference.js +112 -0
  71. package/dist/apps/docs/reference.js.map +1 -0
  72. package/dist/apps/index.d.ts +1 -0
  73. package/dist/apps/index.d.ts.map +1 -1
  74. package/dist/apps/index.js +1 -0
  75. package/dist/apps/index.js.map +1 -1
  76. package/dist/apps/mcp.d.ts +76 -0
  77. package/dist/apps/mcp.d.ts.map +1 -0
  78. package/dist/apps/mcp.js +188 -0
  79. package/dist/apps/mcp.js.map +1 -0
  80. package/dist/apps/platform/App.d.ts +3005 -728
  81. package/dist/apps/platform/App.d.ts.map +1 -1
  82. package/dist/apps/platform/App.js +13 -3
  83. package/dist/apps/platform/App.js.map +1 -1
  84. package/dist/apps/platform/Billing.d.ts +279 -0
  85. package/dist/apps/platform/Billing.d.ts.map +1 -0
  86. package/dist/apps/platform/Billing.js +477 -0
  87. package/dist/apps/platform/Billing.js.map +1 -0
  88. package/dist/apps/platform/index.d.ts +1 -0
  89. package/dist/apps/platform/index.d.ts.map +1 -1
  90. package/dist/apps/platform/index.js +1 -0
  91. package/dist/apps/platform/index.js.map +1 -1
  92. package/dist/apps/platform/routes/api-keys.d.ts +341 -49
  93. package/dist/apps/platform/routes/api-keys.d.ts.map +1 -1
  94. package/dist/apps/platform/routes/api-keys.js +115 -13
  95. package/dist/apps/platform/routes/api-keys.js.map +1 -1
  96. package/dist/apps/platform/routes/billing.d.ts +1520 -0
  97. package/dist/apps/platform/routes/billing.d.ts.map +1 -0
  98. package/dist/apps/platform/routes/billing.js +795 -0
  99. package/dist/apps/platform/routes/billing.js.map +1 -0
  100. package/dist/apps/platform/routes/invitations.d.ts +201 -83
  101. package/dist/apps/platform/routes/invitations.d.ts.map +1 -1
  102. package/dist/apps/platform/routes/invitations.js +58 -0
  103. package/dist/apps/platform/routes/invitations.js.map +1 -1
  104. package/dist/apps/platform/routes/me.d.ts +17 -17
  105. package/dist/apps/platform/routes/orgs.d.ts +50 -36
  106. package/dist/apps/platform/routes/orgs.d.ts.map +1 -1
  107. package/dist/apps/platform/routes/orgs.js +14 -3
  108. package/dist/apps/platform/routes/orgs.js.map +1 -1
  109. package/dist/apps/platform/routes/projects.d.ts +97 -97
  110. package/dist/apps/platform/routes/scopes.d.ts +107 -0
  111. package/dist/apps/platform/routes/scopes.d.ts.map +1 -0
  112. package/dist/apps/platform/routes/scopes.js +66 -0
  113. package/dist/apps/platform/routes/scopes.js.map +1 -0
  114. package/dist/apps/platform/routes/usage.d.ts +588 -0
  115. package/dist/apps/platform/routes/usage.d.ts.map +1 -0
  116. package/dist/apps/platform/routes/usage.js +391 -0
  117. package/dist/apps/platform/routes/usage.js.map +1 -0
  118. package/dist/apps/relay/App.d.ts +4 -1
  119. package/dist/apps/relay/App.d.ts.map +1 -1
  120. package/dist/apps/relay/App.js +118 -10
  121. package/dist/apps/relay/App.js.map +1 -1
  122. package/dist/apps/relay/Sponsorships.d.ts.map +1 -1
  123. package/dist/apps/relay/Sponsorships.js +2 -1
  124. package/dist/apps/relay/Sponsorships.js.map +1 -1
  125. package/dist/cli/Cli.d.ts +8 -1
  126. package/dist/cli/Cli.d.ts.map +1 -1
  127. package/dist/cli/Cli.js +11 -3
  128. package/dist/cli/Cli.js.map +1 -1
  129. package/dist/cli/commands/admin.d.ts +4 -0
  130. package/dist/cli/commands/admin.d.ts.map +1 -1
  131. package/dist/cli/commands/admin.js +80 -1
  132. package/dist/cli/commands/admin.js.map +1 -1
  133. package/dist/db/Db.d.ts +7 -0
  134. package/dist/db/Db.d.ts.map +1 -1
  135. package/dist/db/Db.js +126 -0
  136. package/dist/db/Db.js.map +1 -1
  137. package/dist/db/Schema.d.ts +79 -0
  138. package/dist/db/Schema.d.ts.map +1 -1
  139. package/dist/db/Schema.js +88 -2
  140. package/dist/db/Schema.js.map +1 -1
  141. package/dist/db/tables/billingSettings.d.ts +55 -0
  142. package/dist/db/tables/billingSettings.d.ts.map +1 -0
  143. package/dist/db/tables/billingSettings.js +70 -0
  144. package/dist/db/tables/billingSettings.js.map +1 -0
  145. package/dist/db/tables/invitations.js +2 -2
  146. package/dist/db/tables/invitations.js.map +1 -1
  147. package/dist/db/tables/organizations.d.ts +6 -2
  148. package/dist/db/tables/organizations.d.ts.map +1 -1
  149. package/dist/db/tables/organizations.js +10 -4
  150. package/dist/db/tables/organizations.js.map +1 -1
  151. package/dist/db/tables/projects.js +2 -2
  152. package/dist/db/tables/projects.js.map +1 -1
  153. package/dist/db/tables/requestUsage.d.ts +121 -0
  154. package/dist/db/tables/requestUsage.d.ts.map +1 -0
  155. package/dist/db/tables/requestUsage.js +150 -0
  156. package/dist/db/tables/requestUsage.js.map +1 -0
  157. package/dist/db/tables/sponsoredTransactions.d.ts +119 -0
  158. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  159. package/dist/db/tables/sponsoredTransactions.js +155 -2
  160. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  161. package/dist/db/tables/stripeCustomers.d.ts +81 -0
  162. package/dist/db/tables/stripeCustomers.d.ts.map +1 -0
  163. package/dist/db/tables/stripeCustomers.js +120 -0
  164. package/dist/db/tables/stripeCustomers.js.map +1 -0
  165. package/dist/db/tables/users.js +2 -2
  166. package/dist/db/tables/users.js.map +1 -1
  167. package/dist/handlers/internal/sponsorship.d.ts +5 -2
  168. package/dist/handlers/internal/sponsorship.d.ts.map +1 -1
  169. package/dist/handlers/internal/sponsorship.js +19 -5
  170. package/dist/handlers/internal/sponsorship.js.map +1 -1
  171. package/dist/handlers/internal/utils.d.ts +10 -3
  172. package/dist/handlers/internal/utils.d.ts.map +1 -1
  173. package/dist/handlers/internal/utils.js +14 -6
  174. package/dist/handlers/internal/utils.js.map +1 -1
  175. package/dist/index.d.ts +1 -0
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +1 -0
  178. package/dist/index.js.map +1 -1
  179. package/dist/internal/Auth.d.ts +18 -4
  180. package/dist/internal/Auth.d.ts.map +1 -1
  181. package/dist/internal/Auth.js +148 -76
  182. package/dist/internal/Auth.js.map +1 -1
  183. package/dist/internal/Cache.d.ts.map +1 -1
  184. package/dist/internal/Cache.js +4 -1
  185. package/dist/internal/Cache.js.map +1 -1
  186. package/dist/internal/EdgeCache.d.ts +10 -0
  187. package/dist/internal/EdgeCache.d.ts.map +1 -1
  188. package/dist/internal/EdgeCache.js +39 -8
  189. package/dist/internal/EdgeCache.js.map +1 -1
  190. package/dist/internal/Fees.d.ts +27 -0
  191. package/dist/internal/Fees.d.ts.map +1 -0
  192. package/dist/internal/Fees.js +48 -0
  193. package/dist/internal/Fees.js.map +1 -0
  194. package/dist/internal/FundingRoutes.d.ts +183 -0
  195. package/dist/internal/FundingRoutes.d.ts.map +1 -0
  196. package/dist/internal/FundingRoutes.js +490 -0
  197. package/dist/internal/FundingRoutes.js.map +1 -0
  198. package/dist/internal/Id.d.ts +15 -0
  199. package/dist/internal/Id.d.ts.map +1 -0
  200. package/dist/internal/Id.js +22 -0
  201. package/dist/internal/Id.js.map +1 -0
  202. package/dist/internal/Log.d.ts +2 -0
  203. package/dist/internal/Log.d.ts.map +1 -1
  204. package/dist/internal/Log.js +3 -0
  205. package/dist/internal/Log.js.map +1 -1
  206. package/dist/internal/OpenApi.d.ts +10 -1
  207. package/dist/internal/OpenApi.d.ts.map +1 -1
  208. package/dist/internal/OpenApi.js +8 -1
  209. package/dist/internal/OpenApi.js.map +1 -1
  210. package/dist/internal/RateLimit.d.ts +25 -0
  211. package/dist/internal/RateLimit.d.ts.map +1 -1
  212. package/dist/internal/RateLimit.js +51 -0
  213. package/dist/internal/RateLimit.js.map +1 -1
  214. package/dist/internal/Response.d.ts +1 -1
  215. package/dist/internal/Response.d.ts.map +1 -1
  216. package/dist/internal/Schema.d.ts +8 -0
  217. package/dist/internal/Schema.d.ts.map +1 -1
  218. package/dist/internal/Schema.js +7 -0
  219. package/dist/internal/Schema.js.map +1 -1
  220. package/dist/internal/Webhooks.d.ts.map +1 -1
  221. package/dist/internal/Webhooks.js +3 -3
  222. package/dist/internal/Webhooks.js.map +1 -1
  223. package/package.json +4 -3
  224. package/src/ApiKey.ts +9 -2
  225. package/src/ApiKeys.test.ts +51 -0
  226. package/src/ApiKeys.ts +50 -1
  227. package/src/App.test.ts +33 -86718
  228. package/src/App.ts +18 -0
  229. package/src/Client.test-d.ts +351 -0
  230. package/src/Scope.ts +16 -3
  231. package/src/admin/apps/scopes.test.ts +6 -0
  232. package/src/admin/apps/scopes.ts +3 -0
  233. package/src/admin/ui/src/components/Page.tsx +2 -3
  234. package/src/admin/ui/src/routes/__root.tsx +2 -2
  235. package/src/admin/ui/src/routes/api-keys.tsx +2 -2
  236. package/src/admin/ui.generated.ts +13 -13
  237. package/src/analytics/Analytics.test.ts +527 -0
  238. package/src/analytics/Analytics.ts +318 -0
  239. package/src/analytics/tables/requestEvents.ts +523 -0
  240. package/src/apps/data/App.test.ts +72 -0
  241. package/src/apps/data/App.ts +35 -0
  242. package/src/apps/data/routes/funding.test.ts +214 -0
  243. package/src/apps/data/routes/funding.ts +584 -0
  244. package/src/apps/data/routes/receipts.ts +2 -9
  245. package/src/apps/data/routes/rpc.test.ts +78 -2
  246. package/src/apps/data/routes/rpc.ts +31 -1
  247. package/src/apps/data/routes/webhooks.test.ts +1 -1
  248. package/src/apps/data/routes/webhooks.ts +11 -8
  249. package/src/apps/docs/App.ts +29 -100
  250. package/src/apps/docs/reference.ts +132 -0
  251. package/src/apps/index.ts +1 -0
  252. package/src/apps/mcp.test.ts +206 -0
  253. package/src/apps/mcp.ts +250 -0
  254. package/src/apps/platform/App.ts +43 -4
  255. package/src/apps/platform/Billing.test.ts +530 -0
  256. package/src/apps/platform/Billing.ts +682 -0
  257. package/src/apps/platform/index.ts +1 -0
  258. package/src/apps/platform/routes/api-keys.test.ts +172 -9
  259. package/src/apps/platform/routes/api-keys.ts +136 -20
  260. package/src/apps/platform/routes/billing.test.ts +1100 -0
  261. package/src/apps/platform/routes/billing.ts +966 -0
  262. package/src/apps/platform/routes/invitations.test.ts +55 -7
  263. package/src/apps/platform/routes/invitations.ts +68 -0
  264. package/src/apps/platform/routes/me.test.ts +230 -0
  265. package/src/apps/platform/routes/orgs.ts +26 -4
  266. package/src/apps/platform/routes/scopes.test.ts +29 -0
  267. package/src/apps/platform/routes/scopes.ts +85 -0
  268. package/src/apps/platform/routes/usage.test.ts +422 -0
  269. package/src/apps/platform/routes/usage.ts +527 -0
  270. package/src/apps/relay/App.test.ts +457 -8
  271. package/src/apps/relay/App.ts +120 -12
  272. package/src/apps/relay/Sponsorships.test.ts +1 -1
  273. package/src/apps/relay/Sponsorships.ts +2 -1
  274. package/src/cli/Cli.test.ts +25 -2
  275. package/src/cli/Cli.ts +17 -2
  276. package/src/cli/commands/admin.test.ts +83 -0
  277. package/src/cli/commands/admin.ts +89 -1
  278. package/src/db/Db.ts +137 -0
  279. package/src/db/Schema.ts +104 -2
  280. package/src/db/tables/billingSettings.test.ts +87 -0
  281. package/src/db/tables/billingSettings.ts +108 -0
  282. package/src/db/tables/invitations.ts +2 -2
  283. package/src/db/tables/organizations.test.ts +1 -1
  284. package/src/db/tables/organizations.ts +15 -5
  285. package/src/db/tables/projects.ts +2 -2
  286. package/src/db/tables/requestUsage.ts +231 -0
  287. package/src/db/tables/sponsoredTransactions.test.ts +108 -1
  288. package/src/db/tables/sponsoredTransactions.ts +230 -2
  289. package/src/db/tables/stripeCustomers.test.ts +109 -0
  290. package/src/db/tables/stripeCustomers.ts +162 -0
  291. package/src/db/tables/users.ts +2 -2
  292. package/src/handlers/internal/sponsorship.ts +34 -7
  293. package/src/handlers/internal/utils.ts +19 -7
  294. package/src/index.ts +1 -0
  295. package/src/internal/Auth.test.ts +175 -25
  296. package/src/internal/Auth.ts +175 -86
  297. package/src/internal/Cache.ts +5 -1
  298. package/src/internal/EdgeCache.test.ts +27 -4
  299. package/src/internal/EdgeCache.ts +47 -9
  300. package/src/internal/Fees.test.ts +32 -0
  301. package/src/internal/Fees.ts +51 -0
  302. package/src/internal/FundingRoutes.ts +583 -0
  303. package/src/internal/Id.test.ts +17 -0
  304. package/src/internal/Id.ts +24 -0
  305. package/src/internal/Log.test.ts +1 -0
  306. package/src/internal/Log.ts +5 -0
  307. package/src/internal/OpenApi.ts +12 -1
  308. package/src/internal/RateLimit.test.ts +84 -0
  309. package/src/internal/RateLimit.ts +70 -0
  310. package/src/internal/Response.ts +1 -1
  311. package/src/internal/Schema.ts +8 -0
  312. package/src/internal/Webhooks.test.ts +3 -3
  313. package/src/internal/Webhooks.ts +3 -3
@@ -0,0 +1,51 @@
1
+ import { Hex } from 'ox'
2
+
3
+ // Tempo gas prices (`maxFeePerGas`, `effectiveGasPrice`, block base fee) are
4
+ // denominated in attodollars (10^-18 USD) per gas, while fee-token balances
5
+ // use 6 decimals (microdollars, 10^-6 USD). The charged fee is
6
+ // `ceil(gas × gasPrice / 10^12)`, mirroring `calc_gas_balance_spending` in
7
+ // tempoxyz/tempo.
8
+
9
+ /** Attodollar exponent gas prices use (10^-18 USD per gas), fixed by the fee spec. */
10
+ const attoDecimals = 18
11
+
12
+ /** Fee-token decimals: TIP-20 fixes 6 (1 token unit = 1 microdollar). */
13
+ export const tokenDecimals = 6
14
+
15
+ /** Scaling between attodollar gas math and fee-token units, derived from the exponents. */
16
+ export const scalingFactor = 10n ** BigInt(attoDecimals - tokenDecimals)
17
+
18
+ /**
19
+ * Fee in fee-token base units for a gas amount priced in attodollars per gas
20
+ * (ceiling division). Works for actual fees (`gasUsed × effectiveGasPrice`)
21
+ * and signed caps (`gas × maxFeePerGas`) alike.
22
+ *
23
+ * @param gas - Gas amount.
24
+ * @param gasPrice - Price in attodollars per gas.
25
+ * @returns The fee in fee-token base units.
26
+ */
27
+ export function fromGas(gas: bigint, gasPrice: bigint): bigint {
28
+ return (gas * gasPrice + scalingFactor - 1n) / scalingFactor
29
+ }
30
+
31
+ /**
32
+ * Signed fee cap of a candidate transaction in fee-token base units:
33
+ * `gas × maxFeePerGas` (attodollars) scaled through {@link fromGas}. Undefined
34
+ * when either field is missing or unparseable, so callers can fail closed.
35
+ *
36
+ * @param request - Transaction-shaped fee fields.
37
+ * @returns The cap in base units, or undefined.
38
+ */
39
+ export function maxOf(request: { gas?: unknown; maxFeePerGas?: unknown }): bigint | undefined {
40
+ const gas = toBigInt(request.gas)
41
+ const maxFeePerGas = toBigInt(request.maxFeePerGas)
42
+ if (gas === undefined || maxFeePerGas === undefined) return undefined
43
+ return fromGas(gas, maxFeePerGas)
44
+ }
45
+
46
+ /** Fee fields arrive as bigints (raw envelopes) or hex quantities (fills). */
47
+ function toBigInt(value: unknown): bigint | undefined {
48
+ if (typeof value === 'bigint') return value
49
+ if (typeof value === 'string' && Hex.validate(value)) return Hex.toBigInt(value)
50
+ return undefined
51
+ }
@@ -0,0 +1,583 @@
1
+ /** Tempo mainnet as a CAIP-2 chain reference. */
2
+ const destinationChain = {
3
+ addressFormat: 'evm',
4
+ id: 'eip155:4217',
5
+ kind: 'evm',
6
+ name: 'Tempo',
7
+ } as const
8
+
9
+ /** Tempo token used when the caller omits `destinationToken`. */
10
+ const defaultDestinationToken = 'usdce'
11
+
12
+ /** Source chains accepted by the funding route inventory. */
13
+ const sourceChains = [
14
+ {
15
+ addressFormat: 'evm',
16
+ aliases: ['ethereum', 'eth', 'eip155:1'],
17
+ id: 'eip155:1',
18
+ kind: 'evm',
19
+ name: 'Ethereum',
20
+ providerIds: {
21
+ across: '1',
22
+ bridge: 'ethereum',
23
+ bungee: '1',
24
+ lifi: '1',
25
+ relay: '1',
26
+ },
27
+ slug: 'ethereum',
28
+ tokens: [
29
+ {
30
+ address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48',
31
+ coingeckoId: 'usd-coin',
32
+ decimals: 6,
33
+ name: 'USD Coin',
34
+ standard: 'ERC-20',
35
+ symbol: 'USDC',
36
+ },
37
+ {
38
+ address: '0xdac17f958d2ee523a2206206994597c13d831ec7',
39
+ coingeckoId: 'tether',
40
+ decimals: 6,
41
+ name: 'Tether USD',
42
+ standard: 'ERC-20',
43
+ symbol: 'USDT',
44
+ },
45
+ {
46
+ address: '0x6c3ea9036406852006290770bedfcaba0e23a0e8',
47
+ coingeckoId: 'paypal-usd',
48
+ decimals: 6,
49
+ name: 'PayPal USD',
50
+ standard: 'ERC-20',
51
+ symbol: 'PYUSD',
52
+ },
53
+ {
54
+ address: '0x1abaea1f7c830bd89acc67ec4af516284b1bc33c',
55
+ coingeckoId: 'euro-coin',
56
+ decimals: 6,
57
+ name: 'Euro Coin',
58
+ standard: 'ERC-20',
59
+ symbol: 'EURC',
60
+ },
61
+ {
62
+ address: '0x6b175474e89094c44da98b954eedeac495271d0f',
63
+ coingeckoId: 'dai',
64
+ decimals: 18,
65
+ name: 'Dai Stablecoin',
66
+ standard: 'ERC-20',
67
+ symbol: 'DAI',
68
+ },
69
+ ],
70
+ },
71
+ {
72
+ addressFormat: 'evm',
73
+ aliases: ['base', 'eip155:8453'],
74
+ id: 'eip155:8453',
75
+ kind: 'evm',
76
+ name: 'Base',
77
+ providerIds: {
78
+ across: '8453',
79
+ bridge: 'base',
80
+ bungee: '8453',
81
+ lifi: '8453',
82
+ relay: '8453',
83
+ },
84
+ slug: 'base',
85
+ tokens: [
86
+ {
87
+ address: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
88
+ coingeckoId: 'usd-coin',
89
+ decimals: 6,
90
+ name: 'USD Coin',
91
+ standard: 'ERC-20',
92
+ symbol: 'USDC',
93
+ },
94
+ {
95
+ address: '0xfde4c96c8593536e31f229ea8f37b2ada2699bb2',
96
+ coingeckoId: 'tether',
97
+ decimals: 6,
98
+ name: 'Tether USD',
99
+ standard: 'ERC-20',
100
+ symbol: 'USDT',
101
+ },
102
+ {
103
+ address: '0x60a3e35cc302bfa44cb288bc5a4f316fdb1adb42',
104
+ coingeckoId: 'euro-coin',
105
+ decimals: 6,
106
+ name: 'Euro Coin',
107
+ standard: 'ERC-20',
108
+ symbol: 'EURC',
109
+ },
110
+ ],
111
+ },
112
+ {
113
+ addressFormat: 'evm',
114
+ aliases: ['bnb', 'bsc', 'eip155:56'],
115
+ id: 'eip155:56',
116
+ kind: 'evm',
117
+ name: 'BNB Smart Chain',
118
+ providerIds: {
119
+ across: '56',
120
+ bungee: '56',
121
+ lifi: '56',
122
+ relay: '56',
123
+ },
124
+ slug: 'bnb',
125
+ tokens: [
126
+ {
127
+ address: '0x8ac76a51cc950d9822d68b83fe1ad97b32cd580d',
128
+ coingeckoId: 'usd-coin',
129
+ decimals: 18,
130
+ name: 'Binance-Peg USD Coin',
131
+ standard: 'BEP-20',
132
+ symbol: 'USDC',
133
+ },
134
+ {
135
+ address: '0x55d398326f99059ff775485246999027b3197955',
136
+ coingeckoId: 'tether',
137
+ decimals: 18,
138
+ name: 'Tether USD',
139
+ standard: 'BEP-20',
140
+ symbol: 'USDT',
141
+ },
142
+ ],
143
+ },
144
+ {
145
+ addressFormat: 'solana',
146
+ aliases: ['solana', 'solana:mainnet'],
147
+ id: 'solana:mainnet',
148
+ kind: 'solana',
149
+ name: 'Solana',
150
+ providerIds: {
151
+ bridge: 'solana',
152
+ relay: 'solana',
153
+ },
154
+ slug: 'solana',
155
+ tokens: [
156
+ {
157
+ address: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
158
+ coingeckoId: 'usd-coin',
159
+ decimals: 6,
160
+ name: 'USD Coin',
161
+ standard: 'SPL',
162
+ symbol: 'USDC',
163
+ },
164
+ {
165
+ address: 'Es9vMFrzaCERmJfrF4H2FYD4KCo3LwC1uix9YEaQ8t1v',
166
+ coingeckoId: 'tether',
167
+ decimals: 6,
168
+ name: 'Tether USD',
169
+ standard: 'SPL',
170
+ symbol: 'USDT',
171
+ },
172
+ ],
173
+ },
174
+ {
175
+ addressFormat: 'tron',
176
+ aliases: ['tron', 'tron:mainnet'],
177
+ id: 'tron:mainnet',
178
+ kind: 'tron',
179
+ name: 'Tron',
180
+ providerIds: {
181
+ bridge: 'tron',
182
+ relay: 'tron',
183
+ },
184
+ slug: 'tron',
185
+ tokens: [
186
+ {
187
+ address: 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t',
188
+ coingeckoId: 'tether',
189
+ decimals: 6,
190
+ name: 'Tether USD',
191
+ standard: 'TRC-20',
192
+ symbol: 'USDT',
193
+ },
194
+ ],
195
+ },
196
+ ] as const
197
+
198
+ /** Tempo destination tokens supported by the initial funding route inventory. */
199
+ const destinationTokens = [
200
+ {
201
+ address: '0x20c0000000000000000000000000000000000000',
202
+ decimals: 6,
203
+ name: 'pathUSD',
204
+ slug: 'pathusd',
205
+ standard: 'TIP-20',
206
+ symbol: 'pathUSD',
207
+ },
208
+ {
209
+ address: '0x20c000000000000000000000b9537d11c60e8b50',
210
+ decimals: 6,
211
+ name: 'Bridged USDC (Stargate)',
212
+ slug: 'usdce',
213
+ standard: 'TIP-20',
214
+ symbol: 'USDC.e',
215
+ },
216
+ {
217
+ address: '0x20c0000000000000000000001621e21f71cf12fb',
218
+ decimals: 6,
219
+ name: 'Bridged EURC',
220
+ slug: 'eurce',
221
+ standard: 'TIP-20',
222
+ symbol: 'EURC.e',
223
+ },
224
+ {
225
+ address: '0x20c00000000000000000000014f22ca97301eb73',
226
+ decimals: 6,
227
+ name: 'USDT0',
228
+ slug: 'usdt0',
229
+ standard: 'TIP-20',
230
+ symbol: 'USDT0',
231
+ },
232
+ {
233
+ address: '0x20c0000000000000000000003554d28269e0f3c2',
234
+ decimals: 6,
235
+ name: 'frxUSD',
236
+ slug: 'frxusd',
237
+ standard: 'TIP-20',
238
+ symbol: 'frxUSD',
239
+ },
240
+ ] as const
241
+
242
+ /** Providers exposed by the generic provider catalog. */
243
+ const providers = [
244
+ {
245
+ capabilities: ['fundingRoutes'],
246
+ id: 'across',
247
+ kind: 'intentBridge',
248
+ name: 'Across',
249
+ requiresApiKey: true,
250
+ status: 'inventoryOnly',
251
+ },
252
+ {
253
+ capabilities: ['fundingRoutes'],
254
+ id: 'relay',
255
+ kind: 'solverNetwork',
256
+ name: 'Relay',
257
+ requiresApiKey: false,
258
+ status: 'inventoryOnly',
259
+ },
260
+ {
261
+ capabilities: ['fundingRoutes'],
262
+ id: 'bridge',
263
+ kind: 'enterpriseTransfer',
264
+ name: 'Bridge.xyz',
265
+ requiresApiKey: true,
266
+ status: 'inventoryOnly',
267
+ },
268
+ {
269
+ capabilities: ['fundingRoutes'],
270
+ id: 'bungee',
271
+ kind: 'aggregator',
272
+ name: 'Bungee',
273
+ requiresApiKey: false,
274
+ status: 'inventoryOnly',
275
+ },
276
+ {
277
+ capabilities: ['fundingRoutes'],
278
+ id: 'lifi',
279
+ kind: 'aggregator',
280
+ name: 'LI.FI',
281
+ requiresApiKey: true,
282
+ status: 'planned',
283
+ },
284
+ ] as const
285
+
286
+ type TokenInput = (typeof sourceChains)[number]['tokens'][number]
287
+ type DestinationTokenInput = (typeof destinationTokens)[number]
288
+ type ProviderInput = (typeof providers)[number]
289
+ type SourceChainInput = (typeof sourceChains)[number]
290
+
291
+ /** Static provider support rows used until live quote adapters are configured. */
292
+ const inventory: readonly InventoryEntry[] = [
293
+ { destinationToken: 'usdce', provider: 'across', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC'] }, // prettier-ignore
294
+ { destinationToken: 'usdce', provider: 'relay', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC', 'USDT'] }, // prettier-ignore
295
+ { destinationToken: 'usdce', provider: 'bridge', sourceChains: ['ethereum', 'base', 'solana'], sourceTokens: ['USDC'] }, // prettier-ignore
296
+ { destinationToken: 'usdce', provider: 'bridge', sourceChains: ['ethereum', 'solana', 'tron'], sourceTokens: ['USDT'] }, // prettier-ignore
297
+ { destinationToken: 'usdce', provider: 'bungee', sourceChains: ['ethereum', 'base', 'bnb'], sourceTokens: ['USDC'] }, // prettier-ignore
298
+ ]
299
+
300
+ type InventoryEntry = {
301
+ destinationToken: string
302
+ provider: ProviderInput['id']
303
+ sourceChains: readonly string[]
304
+ sourceTokens: readonly string[]
305
+ }
306
+
307
+ /** Lists normalized chains and source tokens that can fund Tempo. */
308
+ export function listChains() {
309
+ return sourceChains.map((chain) => ({
310
+ ...formatChain(chain),
311
+ tokens: chain.tokens.map((token) => formatSourceToken(chain, token)),
312
+ }))
313
+ }
314
+
315
+ /** Lists providers, optionally filtered by one provider capability. */
316
+ export function listProviders(options: listProviders.Options = {}) {
317
+ return providers
318
+ .filter((provider) =>
319
+ options.capability === undefined ? true : provider.capabilities.includes(options.capability),
320
+ )
321
+ .map(formatProvider)
322
+ }
323
+
324
+ export declare namespace listProviders {
325
+ /** Options for listing providers. */
326
+ type Options = {
327
+ /** Provider capability to require. */
328
+ capability?: Capability | undefined
329
+ }
330
+ }
331
+
332
+ /** Lists static funding route candidates for a normalized caller request. */
333
+ export function listRoutes(options: listRoutes.Options) {
334
+ const sourceChain = resolveSourceChain(options.sourceChain)
335
+ const sourceToken = resolveSourceToken(sourceChain, options.sourceToken)
336
+ const destinationToken = resolveDestinationToken(options.destinationToken)
337
+ const provider = options.provider ? resolveProvider(options.provider) : undefined
338
+
339
+ if (!sourceToken) {
340
+ validateSourceAmountSyntax(options.sourceAmount, options.sourceAmountUnits)
341
+ return []
342
+ }
343
+
344
+ const sourceAmount = resolveSourceAmount({
345
+ amount: options.sourceAmount,
346
+ token: sourceToken,
347
+ units: options.sourceAmountUnits,
348
+ })
349
+
350
+ return inventory
351
+ .filter((entry) => entry.sourceChains.includes(sourceChain.slug))
352
+ .filter((entry) => entry.sourceTokens.includes(sourceToken.symbol))
353
+ .filter((entry) => entry.destinationToken === destinationToken.slug)
354
+ .filter((entry) => provider === undefined || entry.provider === provider.id)
355
+ .slice(0, options.limit)
356
+ .map((entry) => {
357
+ const entryProvider = providers.find((candidate) => candidate.id === entry.provider)!
358
+ return {
359
+ destinationChain,
360
+ destinationToken: formatDestinationToken(destinationToken),
361
+ id: [
362
+ sourceChain.slug,
363
+ sourceToken.symbol.toLowerCase(),
364
+ 'tempo',
365
+ destinationToken.slug,
366
+ entryProvider.id,
367
+ ].join('-'),
368
+ provider: formatProviderRef(entryProvider),
369
+ quality: {
370
+ availableVolumeUsd: null,
371
+ estimatedSeconds: null,
372
+ feeBps: null,
373
+ historicalVolumeUsd24h: null,
374
+ instantVolumeUsd: null,
375
+ liquiditySource: 'staticInventory',
376
+ score: null,
377
+ tier: 'unknown' as const,
378
+ },
379
+ sourceAmount,
380
+ sourceChain: formatChain(sourceChain),
381
+ sourceToken: formatSourceToken(sourceChain, sourceToken),
382
+ status: 'unknown' as const,
383
+ }
384
+ })
385
+ }
386
+
387
+ export declare namespace listRoutes {
388
+ /** Options for listing funding routes. */
389
+ type Options = {
390
+ /** Optional Tempo destination token symbol, address, or token key. */
391
+ destinationToken?: string | undefined
392
+ /** Maximum number of route candidates to return. */
393
+ limit: number
394
+ /** Optional provider id filter. */
395
+ provider?: string | undefined
396
+ /** Source amount as supplied by the caller. */
397
+ sourceAmount: string
398
+ /** Unit used by {@link sourceAmount}. */
399
+ sourceAmountUnits: SourceAmountUnits
400
+ /** Chain alias or CAIP-2 source chain id. */
401
+ sourceChain: string
402
+ /** Source token symbol, contract address, mint, or Tempo token key. */
403
+ sourceToken: string
404
+ }
405
+ }
406
+
407
+ /** Provider capability identifiers accepted by the generic provider catalog. */
408
+ export type Capability = 'fundingRoutes'
409
+
410
+ /** Source amount unit accepted by the funding route request. */
411
+ export type SourceAmountUnits = 'baseUnits' | 'decimal'
412
+
413
+ function tokenKey(chain: { id: string }, token: TokenInput | DestinationTokenInput) {
414
+ const standard =
415
+ token.standard === 'SPL' ? 'spl' : token.standard === 'TRC-20' ? 'trc20' : 'erc20'
416
+ return `${chain.id}/${standard}:${token.address}`
417
+ }
418
+
419
+ function decimalFromBaseUnits(baseUnits: string, decimals: number) {
420
+ const padded = baseUnits.padStart(decimals + 1, '0')
421
+ const whole = decimals === 0 ? padded : padded.slice(0, -decimals)
422
+ const fraction = decimals === 0 ? '' : padded.slice(-decimals).replace(/0+$/, '')
423
+ return fraction ? `${whole}.${fraction}` : whole
424
+ }
425
+
426
+ function formatChain(chain: SourceChainInput) {
427
+ const { addressFormat, id, kind, name, providerIds } = chain
428
+ return { addressFormat, id, kind, name, providerIds }
429
+ }
430
+
431
+ function formatDestinationToken(token: DestinationTokenInput) {
432
+ return {
433
+ address: token.address,
434
+ decimals: token.decimals,
435
+ metadata: {},
436
+ name: token.name,
437
+ standard: token.standard,
438
+ symbol: token.symbol,
439
+ tokenKey: tokenKey(destinationChain, token),
440
+ verified: true,
441
+ }
442
+ }
443
+
444
+ function formatProvider(provider: ProviderInput) {
445
+ const { id, kind, name, requiresApiKey, status } = provider
446
+ return { capabilities: [...provider.capabilities], id, kind, name, requiresApiKey, status }
447
+ }
448
+
449
+ function formatProviderRef(provider: ProviderInput) {
450
+ const { id, kind, name, requiresApiKey } = provider
451
+ return { id, kind, name, requiresApiKey }
452
+ }
453
+
454
+ function formatSourceToken(chain: SourceChainInput, token: TokenInput) {
455
+ return {
456
+ address: token.address,
457
+ decimals: token.decimals,
458
+ metadata: { coingeckoId: token.coingeckoId },
459
+ name: token.name,
460
+ standard: token.standard,
461
+ symbol: token.symbol,
462
+ tokenKey: tokenKey(chain, token),
463
+ verified: true,
464
+ }
465
+ }
466
+
467
+ function normalizeInput(value: string) {
468
+ return value.trim().toLowerCase()
469
+ }
470
+
471
+ function parseBaseUnits(value: string) {
472
+ if (!/^\d+$/.test(value) || BigInt(value) <= 0n) throw new InvalidAmountError()
473
+ return BigInt(value).toString()
474
+ }
475
+
476
+ function parseDecimalUnits(value: string, decimals: number) {
477
+ if (!/^\d+(\.\d+)?$/.test(value)) throw new InvalidAmountError()
478
+ const [whole, fraction = ''] = value.split('.')
479
+ if (fraction.length > decimals) throw new InvalidAmountError()
480
+ const baseUnits = BigInt(`${whole}${fraction.padEnd(decimals, '0')}`)
481
+ if (baseUnits <= 0n) throw new InvalidAmountError()
482
+ return baseUnits.toString()
483
+ }
484
+
485
+ function resolveDestinationToken(input: string | undefined) {
486
+ if (input === undefined) return destinationTokens.find((token) => token.slug === defaultDestinationToken)! // prettier-ignore
487
+ const normalized = normalizeInput(input)
488
+ const token = destinationTokens.find(
489
+ (candidate) =>
490
+ candidate.slug === normalized ||
491
+ candidate.symbol.toLowerCase() === normalized ||
492
+ candidate.address === normalized ||
493
+ tokenKey(destinationChain, candidate).toLowerCase() === normalized,
494
+ )
495
+ if (!token) throw new UnsupportedDestinationTokenError()
496
+ return token
497
+ }
498
+
499
+ function resolveProvider(input: string) {
500
+ const provider = providers.find((candidate) => candidate.id === normalizeInput(input))
501
+ if (!provider) throw new UnsupportedProviderError()
502
+ return provider
503
+ }
504
+
505
+ function resolveSourceAmount(options: resolveSourceAmount.Options) {
506
+ const amount =
507
+ options.units === 'baseUnits'
508
+ ? parseBaseUnits(options.amount)
509
+ : parseDecimalUnits(options.amount, options.token.decimals)
510
+ return {
511
+ amount,
512
+ formatted: decimalFromBaseUnits(amount, options.token.decimals),
513
+ usd: null,
514
+ }
515
+ }
516
+
517
+ declare namespace resolveSourceAmount {
518
+ type Options = {
519
+ amount: string
520
+ token: TokenInput
521
+ units: SourceAmountUnits
522
+ }
523
+ }
524
+
525
+ function resolveSourceToken(chain: SourceChainInput, input: string) {
526
+ const trimmed = input.trim()
527
+ const normalized = trimmed.toLowerCase()
528
+ return chain.tokens.find(
529
+ (token) =>
530
+ token.symbol.toLowerCase() === normalized ||
531
+ matchesTokenIdentifier(chain, token.address, trimmed, normalized) ||
532
+ matchesTokenIdentifier(chain, tokenKey(chain, token), trimmed, normalized),
533
+ )
534
+ }
535
+
536
+ function matchesTokenIdentifier(
537
+ chain: SourceChainInput,
538
+ candidate: string,
539
+ trimmed: string,
540
+ normalized: string,
541
+ ) {
542
+ return chain.kind === 'evm' ? candidate.toLowerCase() === normalized : candidate === trimmed
543
+ }
544
+
545
+ function resolveSourceChain(input: string) {
546
+ const normalized = normalizeInput(input)
547
+ const chain = sourceChains.find(
548
+ (candidate) =>
549
+ candidate.id === normalized || (candidate.aliases as readonly string[]).includes(normalized),
550
+ )
551
+ if (!chain) throw new UnsupportedSourceChainError()
552
+ return chain
553
+ }
554
+
555
+ function validateSourceAmountSyntax(value: string, units: SourceAmountUnits) {
556
+ if (units === 'baseUnits') {
557
+ parseBaseUnits(value)
558
+ return
559
+ }
560
+ if (!/^\d+(\.\d+)?$/.test(value)) throw new InvalidAmountError()
561
+ const [whole, fraction = ''] = value.split('.')
562
+ if (BigInt(`${whole}${fraction}`) <= 0n) throw new InvalidAmountError()
563
+ }
564
+
565
+ /** Error thrown when the caller supplies an unsupported destination token. */
566
+ export class UnsupportedDestinationTokenError extends Error {
567
+ override name = 'FundingRoutes.UnsupportedDestinationTokenError'
568
+ }
569
+
570
+ /** Error thrown when the caller supplies an invalid source amount. */
571
+ export class InvalidAmountError extends Error {
572
+ override name = 'FundingRoutes.InvalidAmountError'
573
+ }
574
+
575
+ /** Error thrown when the caller filters to an unknown provider. */
576
+ export class UnsupportedProviderError extends Error {
577
+ override name = 'FundingRoutes.UnsupportedProviderError'
578
+ }
579
+
580
+ /** Error thrown when the caller supplies an unsupported source chain. */
581
+ export class UnsupportedSourceChainError extends Error {
582
+ override name = 'FundingRoutes.UnsupportedSourceChainError'
583
+ }
@@ -0,0 +1,17 @@
1
+ import * as Id from './Id.js'
2
+
3
+ describe('generate', () => {
4
+ test('produces a prefixed 24-char base62 id', () => {
5
+ expect(Id.generate('usr')).toMatch(/^usr_[0-9A-Za-z]{24}$/)
6
+ })
7
+
8
+ test('never emits `_` or `-` in the random segment', () => {
9
+ for (let i = 0; i < 100; i++) expect(Id.generate('org').slice(4)).toMatch(/^[0-9A-Za-z]{24}$/)
10
+ })
11
+ })
12
+
13
+ describe('random', () => {
14
+ test('produces a 24-char base62 segment', () => {
15
+ expect(Id.random()).toMatch(/^[0-9A-Za-z]{24}$/)
16
+ })
17
+ })
@@ -0,0 +1,24 @@
1
+ import { customAlphabet } from 'nanoid'
2
+
3
+ /** Base62 alphabet: `_` and `-` excluded so the prefix separator stays unambiguous. */
4
+ const segment = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 24)
5
+
6
+ /**
7
+ * Generates a prefixed resource id (`{prefix}_{24 base62 chars}`, ~143 bits).
8
+ *
9
+ * @param prefix - The resource-type prefix (e.g. `usr`, `org`).
10
+ * @returns The generated id.
11
+ */
12
+ export function generate(prefix: string): string {
13
+ return `${prefix}_${random()}`
14
+ }
15
+
16
+ /**
17
+ * Generates the random segment of an id (24 base62 chars) without a prefix,
18
+ * for ids composing extra parts (e.g. `wh_{timestamp}_{random}`).
19
+ *
20
+ * @returns The generated segment.
21
+ */
22
+ export function random(): string {
23
+ return segment()
24
+ }
@@ -74,6 +74,7 @@ describe('middleware', () => {
74
74
  "method": "GET",
75
75
  "path": "/secure",
76
76
  "principal": {
77
+ "billingActive": false,
77
78
  "environment": "production",
78
79
  "id": "key_1",
79
80
  "orgId": "org_1",
@@ -47,6 +47,8 @@ export type Entry = {
47
47
  | {
48
48
  /** Attributed super admin identity for super admin callers. */
49
49
  actor?: string | undefined
50
+ /** Whether the owning org's billing was active for API-key callers; drives request-metered billing. */
51
+ billingActive?: boolean | undefined
50
52
  /** Key environment for API-key callers. */
51
53
  environment?: ApiKey.ApiKey['environment'] | undefined
52
54
  /** Principal id: the API key id, the public quota identity, the user id, or `super_admin`. */
@@ -151,6 +153,9 @@ export function middleware<environment extends Environment = Environment>(
151
153
  : {
152
154
  principal: {
153
155
  ...(principal.type === 'super_admin' ? { actor: principal.actor } : {}),
156
+ ...(principal.type === 'api_key'
157
+ ? { billingActive: principal.apiKey.billingActive === true }
158
+ : {}),
154
159
  ...(principal.type === 'api_key' ? { environment: principal.environment } : {}),
155
160
  id: principal.id,
156
161
  ...(principal.type === 'api_key' ? { orgId: principal.orgId } : {}),