tapimo 0.5.2 → 0.6.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 (299) hide show
  1. package/dist/App.d.ts +13987 -5755
  2. package/dist/App.d.ts.map +1 -1
  3. package/dist/App.js.map +1 -1
  4. package/dist/admin/App.d.ts +910 -412
  5. package/dist/admin/App.d.ts.map +1 -1
  6. package/dist/admin/App.js +4 -0
  7. package/dist/admin/App.js.map +1 -1
  8. package/dist/admin/apps/early-access.d.ts +148 -0
  9. package/dist/admin/apps/early-access.d.ts.map +1 -0
  10. package/dist/admin/apps/early-access.js +133 -0
  11. package/dist/admin/apps/early-access.js.map +1 -0
  12. package/dist/admin/apps/verified-tokens.d.ts +643 -118
  13. package/dist/admin/apps/verified-tokens.d.ts.map +1 -1
  14. package/dist/admin/apps/verified-tokens.js +214 -1
  15. package/dist/admin/apps/verified-tokens.js.map +1 -1
  16. package/dist/admin/ui.generated.d.ts +1 -1
  17. package/dist/admin/ui.generated.d.ts.map +1 -1
  18. package/dist/admin/ui.generated.js +45 -33
  19. package/dist/admin/ui.generated.js.map +1 -1
  20. package/dist/apps/data/App.d.ts +3733 -2428
  21. package/dist/apps/data/App.d.ts.map +1 -1
  22. package/dist/apps/data/App.js +11 -6
  23. package/dist/apps/data/App.js.map +1 -1
  24. package/dist/apps/data/FundingQuoteProviders.d.ts +34 -1
  25. package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -1
  26. package/dist/apps/data/FundingQuoteProviders.js +193 -2
  27. package/dist/apps/data/FundingQuoteProviders.js.map +1 -1
  28. package/dist/apps/data/FxOracle.d.ts +71 -0
  29. package/dist/apps/data/FxOracle.d.ts.map +1 -0
  30. package/dist/apps/data/FxOracle.js +97 -0
  31. package/dist/apps/data/FxOracle.js.map +1 -0
  32. package/dist/apps/data/index.d.ts +1 -0
  33. package/dist/apps/data/index.d.ts.map +1 -1
  34. package/dist/apps/data/index.js +1 -0
  35. package/dist/apps/data/index.js.map +1 -1
  36. package/dist/apps/data/routes/activities.d.ts +3575 -1358
  37. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  38. package/dist/apps/data/routes/activities.js +230 -88
  39. package/dist/apps/data/routes/activities.js.map +1 -1
  40. package/dist/apps/data/routes/addresses.d.ts +963 -342
  41. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  42. package/dist/apps/data/routes/addresses.js +11 -9
  43. package/dist/apps/data/routes/addresses.js.map +1 -1
  44. package/dist/apps/data/routes/balances.d.ts +108 -57
  45. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  46. package/dist/apps/data/routes/balances.js +88 -45
  47. package/dist/apps/data/routes/balances.js.map +1 -1
  48. package/dist/apps/data/routes/coingecko.d.ts +169 -169
  49. package/dist/apps/data/routes/exchanges.d.ts +952 -201
  50. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  51. package/dist/apps/data/routes/exchanges.js +518 -76
  52. package/dist/apps/data/routes/exchanges.js.map +1 -1
  53. package/dist/apps/data/routes/fee-amm.d.ts +24 -24
  54. package/dist/apps/data/routes/funding.d.ts +8 -2
  55. package/dist/apps/data/routes/funding.d.ts.map +1 -1
  56. package/dist/apps/data/routes/funding.js +32 -6
  57. package/dist/apps/data/routes/funding.js.map +1 -1
  58. package/dist/apps/data/routes/indexer.d.ts +5 -5
  59. package/dist/apps/data/routes/receipts.d.ts +392 -315
  60. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  61. package/dist/apps/data/routes/receipts.js +152 -77
  62. package/dist/apps/data/routes/receipts.js.map +1 -1
  63. package/dist/apps/data/routes/tokens.d.ts +166 -173
  64. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  65. package/dist/apps/data/routes/tokens.js +14 -12
  66. package/dist/apps/data/routes/tokens.js.map +1 -1
  67. package/dist/apps/data/routes/transactions.d.ts +277 -536
  68. package/dist/apps/data/routes/transactions.d.ts.map +1 -1
  69. package/dist/apps/data/routes/transactions.js +96 -77
  70. package/dist/apps/data/routes/transactions.js.map +1 -1
  71. package/dist/apps/data/routes/transfers.d.ts +82 -17
  72. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  73. package/dist/apps/data/routes/transfers.js +70 -13
  74. package/dist/apps/data/routes/transfers.js.map +1 -1
  75. package/dist/apps/data/routes/valuation.d.ts +307 -0
  76. package/dist/apps/data/routes/valuation.d.ts.map +1 -0
  77. package/dist/apps/data/routes/valuation.js +292 -0
  78. package/dist/apps/data/routes/valuation.js.map +1 -0
  79. package/dist/apps/data/routes/verified-tokens.d.ts.map +1 -1
  80. package/dist/apps/data/routes/verified-tokens.js +7 -5
  81. package/dist/apps/data/routes/verified-tokens.js.map +1 -1
  82. package/dist/apps/data/routes/webhooks.d.ts +459 -479
  83. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  84. package/dist/apps/data/routes/webhooks.js +124 -25
  85. package/dist/apps/data/routes/webhooks.js.map +1 -1
  86. package/dist/apps/index.d.ts +1 -1
  87. package/dist/apps/index.d.ts.map +1 -1
  88. package/dist/apps/index.js +1 -1
  89. package/dist/apps/index.js.map +1 -1
  90. package/dist/apps/management/App.d.ts +8606 -1681
  91. package/dist/apps/management/App.d.ts.map +1 -1
  92. package/dist/apps/management/App.js +12 -1
  93. package/dist/apps/management/App.js.map +1 -1
  94. package/dist/apps/management/routes/api-keys.d.ts +23 -0
  95. package/dist/apps/management/routes/api-keys.d.ts.map +1 -1
  96. package/dist/apps/management/routes/api-keys.js +5 -3
  97. package/dist/apps/management/routes/api-keys.js.map +1 -1
  98. package/dist/apps/management/routes/billing.d.ts +88 -48
  99. package/dist/apps/management/routes/billing.d.ts.map +1 -1
  100. package/dist/apps/management/routes/billing.js +10 -2
  101. package/dist/apps/management/routes/billing.js.map +1 -1
  102. package/dist/apps/management/routes/faucet.d.ts +218 -0
  103. package/dist/apps/management/routes/faucet.d.ts.map +1 -0
  104. package/dist/apps/management/routes/faucet.js +139 -0
  105. package/dist/apps/management/routes/faucet.js.map +1 -0
  106. package/dist/apps/management/routes/invitations.d.ts +121 -121
  107. package/dist/apps/management/routes/invitations.d.ts.map +1 -1
  108. package/dist/apps/management/routes/invitations.js +3 -0
  109. package/dist/apps/management/routes/invitations.js.map +1 -1
  110. package/dist/apps/management/routes/invite-links.d.ts +197 -168
  111. package/dist/apps/management/routes/invite-links.d.ts.map +1 -1
  112. package/dist/apps/management/routes/invite-links.js +26 -1
  113. package/dist/apps/management/routes/invite-links.js.map +1 -1
  114. package/dist/apps/management/routes/me.d.ts +2 -0
  115. package/dist/apps/management/routes/me.d.ts.map +1 -1
  116. package/dist/apps/management/routes/me.js +4 -0
  117. package/dist/apps/management/routes/me.js.map +1 -1
  118. package/dist/apps/management/routes/members.d.ts +49 -49
  119. package/dist/apps/management/routes/orgs.d.ts +91 -91
  120. package/dist/apps/management/routes/projects.d.ts +115 -115
  121. package/dist/apps/management/routes/usage.d.ts +35 -32
  122. package/dist/apps/management/routes/usage.d.ts.map +1 -1
  123. package/dist/apps/management/routes/usage.js +4 -0
  124. package/dist/apps/management/routes/usage.js.map +1 -1
  125. package/dist/apps/management/routes/verified-token-requests.d.ts +697 -0
  126. package/dist/apps/management/routes/verified-token-requests.d.ts.map +1 -0
  127. package/dist/apps/management/routes/verified-token-requests.js +271 -0
  128. package/dist/apps/management/routes/verified-token-requests.js.map +1 -0
  129. package/dist/apps/management/routes/webhooks.d.ts +6977 -0
  130. package/dist/apps/management/routes/webhooks.d.ts.map +1 -0
  131. package/dist/apps/management/routes/webhooks.js +573 -0
  132. package/dist/apps/management/routes/webhooks.js.map +1 -0
  133. package/dist/apps/mcp.d.ts +9 -2
  134. package/dist/apps/mcp.d.ts.map +1 -1
  135. package/dist/apps/mcp.js +9 -4
  136. package/dist/apps/mcp.js.map +1 -1
  137. package/dist/cli/Cli.d.ts.map +1 -1
  138. package/dist/cli/Cli.js +7 -2
  139. package/dist/cli/Cli.js.map +1 -1
  140. package/dist/db/Db.d.ts +4 -0
  141. package/dist/db/Db.d.ts.map +1 -1
  142. package/dist/db/Db.js +83 -0
  143. package/dist/db/Db.js.map +1 -1
  144. package/dist/db/Schema.d.ts +41 -0
  145. package/dist/db/Schema.d.ts.map +1 -1
  146. package/dist/db/Schema.js +45 -0
  147. package/dist/db/Schema.js.map +1 -1
  148. package/dist/db/tables/earlyAccess.d.ts +50 -0
  149. package/dist/db/tables/earlyAccess.d.ts.map +1 -0
  150. package/dist/db/tables/earlyAccess.js +63 -0
  151. package/dist/db/tables/earlyAccess.js.map +1 -0
  152. package/dist/db/tables/invitations.d.ts +12 -1
  153. package/dist/db/tables/invitations.d.ts.map +1 -1
  154. package/dist/db/tables/invitations.js +23 -0
  155. package/dist/db/tables/invitations.js.map +1 -1
  156. package/dist/db/tables/inviteLinks.d.ts +10 -2
  157. package/dist/db/tables/inviteLinks.d.ts.map +1 -1
  158. package/dist/db/tables/inviteLinks.js +10 -1
  159. package/dist/db/tables/inviteLinks.js.map +1 -1
  160. package/dist/db/tables/sponsoredTransactions.d.ts +2 -0
  161. package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
  162. package/dist/db/tables/sponsoredTransactions.js +2 -0
  163. package/dist/db/tables/sponsoredTransactions.js.map +1 -1
  164. package/dist/db/tables/verifiedTokenRequests.d.ts +94 -0
  165. package/dist/db/tables/verifiedTokenRequests.d.ts.map +1 -0
  166. package/dist/db/tables/verifiedTokenRequests.js +120 -0
  167. package/dist/db/tables/verifiedTokenRequests.js.map +1 -0
  168. package/dist/db/tables/webhookSubscriptions.d.ts +14 -0
  169. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  170. package/dist/db/tables/webhookSubscriptions.js +16 -0
  171. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  172. package/dist/internal/Auth.d.ts +43 -2
  173. package/dist/internal/Auth.d.ts.map +1 -1
  174. package/dist/internal/Auth.js +60 -45
  175. package/dist/internal/Auth.js.map +1 -1
  176. package/dist/internal/FundingQuotes.d.ts +69 -15
  177. package/dist/internal/FundingQuotes.d.ts.map +1 -1
  178. package/dist/internal/FundingQuotes.js +74 -25
  179. package/dist/internal/FundingQuotes.js.map +1 -1
  180. package/dist/internal/Log.d.ts +19 -1
  181. package/dist/internal/Log.d.ts.map +1 -1
  182. package/dist/internal/Log.js +2 -0
  183. package/dist/internal/Log.js.map +1 -1
  184. package/dist/internal/MetricSink.d.ts.map +1 -1
  185. package/dist/internal/MetricSink.js +9 -0
  186. package/dist/internal/MetricSink.js.map +1 -1
  187. package/dist/internal/OpenApi.d.ts +2 -2
  188. package/dist/internal/OpenApi.d.ts.map +1 -1
  189. package/dist/internal/OpenApi.js +3 -0
  190. package/dist/internal/OpenApi.js.map +1 -1
  191. package/dist/internal/Schema.d.ts +14 -5
  192. package/dist/internal/Schema.d.ts.map +1 -1
  193. package/dist/internal/Schema.js +23 -5
  194. package/dist/internal/Schema.js.map +1 -1
  195. package/dist/internal/Value.d.ts +18 -0
  196. package/dist/internal/Value.d.ts.map +1 -1
  197. package/dist/internal/Value.js +11 -1
  198. package/dist/internal/Value.js.map +1 -1
  199. package/dist/internal/VerifiedTokens.d.ts.map +1 -1
  200. package/dist/internal/VerifiedTokens.js +10 -1
  201. package/dist/internal/VerifiedTokens.js.map +1 -1
  202. package/dist/internal/Viem.d.ts +1 -1
  203. package/dist/internal/Webhooks.d.ts +24 -3
  204. package/dist/internal/Webhooks.d.ts.map +1 -1
  205. package/dist/internal/Webhooks.js +34 -8
  206. package/dist/internal/Webhooks.js.map +1 -1
  207. package/package.json +2 -2
  208. package/src/App.ts +9 -1
  209. package/src/Client.test-d.ts +638 -6
  210. package/src/admin/App.ts +4 -0
  211. package/src/admin/apps/early-access.test.ts +125 -0
  212. package/src/admin/apps/early-access.ts +175 -0
  213. package/src/admin/apps/verified-tokens.test.ts +201 -0
  214. package/src/admin/apps/verified-tokens.ts +532 -286
  215. package/src/admin/ui/plugin.ts +2 -1
  216. package/src/admin/ui/src/lib/early-access.ts +63 -0
  217. package/src/admin/ui/src/lib/verified-tokens.ts +79 -0
  218. package/src/admin/ui/src/routeTree.gen.ts +33 -2
  219. package/src/admin/ui/src/routes/__root.tsx +2 -1
  220. package/src/admin/ui/src/routes/early-access.tsx +157 -0
  221. package/src/admin/ui/src/routes/verified-tokens.tsx +230 -19
  222. package/src/admin/ui.generated.ts +48 -33
  223. package/src/apps/data/App.ts +22 -14
  224. package/src/apps/data/FundingQuoteProviders.test.ts +298 -0
  225. package/src/apps/data/FundingQuoteProviders.ts +257 -4
  226. package/src/apps/data/FxOracle.test.ts +118 -0
  227. package/src/apps/data/FxOracle.ts +153 -0
  228. package/src/apps/data/index.ts +1 -0
  229. package/src/apps/data/routes/activities.test.ts +173 -3
  230. package/src/apps/data/routes/activities.ts +403 -132
  231. package/src/apps/data/routes/addresses.ts +19 -9
  232. package/src/apps/data/routes/balances.test.ts +144 -11
  233. package/src/apps/data/routes/balances.ts +140 -51
  234. package/src/apps/data/routes/exchanges.test.ts +540 -9
  235. package/src/apps/data/routes/exchanges.ts +690 -103
  236. package/src/apps/data/routes/funding.test.ts +84 -0
  237. package/src/apps/data/routes/funding.ts +38 -6
  238. package/src/apps/data/routes/receipts.test.ts +125 -23
  239. package/src/apps/data/routes/receipts.ts +205 -100
  240. package/src/apps/data/routes/tokens.test.ts +43 -0
  241. package/src/apps/data/routes/tokens.ts +27 -12
  242. package/src/apps/data/routes/transactions.test.ts +72 -19
  243. package/src/apps/data/routes/transactions.ts +162 -92
  244. package/src/apps/data/routes/transfers.test.ts +146 -4
  245. package/src/apps/data/routes/transfers.ts +91 -13
  246. package/src/apps/data/routes/valuation.test.ts +422 -0
  247. package/src/apps/data/routes/valuation.ts +423 -0
  248. package/src/apps/data/routes/verified-tokens.ts +14 -2
  249. package/src/apps/data/routes/webhooks.test.ts +56 -8
  250. package/src/apps/data/routes/webhooks.ts +144 -27
  251. package/src/apps/index.ts +1 -1
  252. package/src/apps/management/App.ts +13 -0
  253. package/src/apps/management/routes/api-keys.test.ts +87 -0
  254. package/src/apps/management/routes/api-keys.ts +4 -3
  255. package/src/apps/management/routes/billing.test.ts +112 -1
  256. package/src/apps/management/routes/billing.ts +7 -2
  257. package/src/apps/management/routes/faucet.test.ts +79 -0
  258. package/src/apps/management/routes/faucet.ts +185 -0
  259. package/src/apps/management/routes/invitations.test.ts +172 -0
  260. package/src/apps/management/routes/invitations.ts +3 -0
  261. package/src/apps/management/routes/invite-links.test.ts +117 -0
  262. package/src/apps/management/routes/invite-links.ts +43 -1
  263. package/src/apps/management/routes/me.test.ts +140 -88
  264. package/src/apps/management/routes/me.ts +6 -0
  265. package/src/apps/management/routes/usage.test.ts +6 -0
  266. package/src/apps/management/routes/usage.ts +7 -0
  267. package/src/apps/management/routes/verified-token-requests.test.ts +377 -0
  268. package/src/apps/management/routes/verified-token-requests.ts +397 -0
  269. package/src/apps/management/routes/webhooks.test.ts +426 -0
  270. package/src/apps/management/routes/webhooks.ts +672 -0
  271. package/src/apps/mcp.test.ts +13 -0
  272. package/src/apps/mcp.ts +18 -5
  273. package/src/cli/Cli.test.ts +36 -0
  274. package/src/cli/Cli.ts +7 -2
  275. package/src/db/Db.test.ts +19 -0
  276. package/src/db/Db.ts +95 -0
  277. package/src/db/Schema.ts +53 -0
  278. package/src/db/tables/earlyAccess.ts +86 -0
  279. package/src/db/tables/invitations.ts +26 -1
  280. package/src/db/tables/inviteLinks.ts +22 -3
  281. package/src/db/tables/sponsoredTransactions.ts +4 -0
  282. package/src/db/tables/verifiedTokenRequests.test.ts +200 -0
  283. package/src/db/tables/verifiedTokenRequests.ts +182 -0
  284. package/src/db/tables/webhookSubscriptions.ts +31 -0
  285. package/src/internal/Auth.ts +73 -45
  286. package/src/internal/FundingQuotes.test.ts +143 -1
  287. package/src/internal/FundingQuotes.ts +95 -28
  288. package/src/internal/Log.test-d.ts +21 -0
  289. package/src/internal/Log.test.ts +50 -0
  290. package/src/internal/Log.ts +24 -1
  291. package/src/internal/MetricSink.test.ts +160 -0
  292. package/src/internal/MetricSink.ts +10 -0
  293. package/src/internal/OpenApi.ts +3 -0
  294. package/src/internal/Schema.ts +50 -5
  295. package/src/internal/Value.test.ts +20 -0
  296. package/src/internal/Value.ts +24 -1
  297. package/src/internal/VerifiedTokens.ts +9 -1
  298. package/src/internal/Webhooks.test.ts +140 -0
  299. package/src/internal/Webhooks.ts +53 -9
@@ -0,0 +1,397 @@
1
+ import { type Context, Hono } from 'hono'
2
+ import * as z from 'zod/mini'
3
+
4
+ import * as Db from '../../../db/Db.js'
5
+ import * as VerifiedTokenRequests from '../../../db/tables/verifiedTokenRequests.js'
6
+ import * as Auth from '../../../internal/Auth.js'
7
+ import * as OpenApi from '../../../internal/OpenApi.js'
8
+ import * as Response from '../../../internal/Response.js'
9
+ import * as Schema from '../../../internal/Schema.js'
10
+ import * as VerifiedTokens from '../../../internal/VerifiedTokens.js'
11
+ import { schema as tokenSchema } from '../../data/routes/verified-tokens.js'
12
+ import type { Environment } from '../App.js'
13
+
14
+ /** Largest accepted inline SVG logo (matches the admin upload limit). */
15
+ const maxLogoBytes = 256 * 1024
16
+
17
+ /** OpenAPI schemas owned by verified-token requests. */
18
+ export namespace schema {
19
+ const chainId = z
20
+ .number()
21
+ .check(
22
+ z.int(),
23
+ z.describe('The Tempo chain id the token belongs to.'),
24
+ z.meta({ examples: [4217] }),
25
+ )
26
+
27
+ /**
28
+ * An organization's verification request (response shape). `reviewedBy` is
29
+ * deliberately absent: reviewer identity stays on the admin surface.
30
+ */
31
+ export const VerifiedTokenRequest = Schema.describe(
32
+ z.extend(tokenSchema.Input, {
33
+ chainId,
34
+ createdAt: z
35
+ .string()
36
+ .check(
37
+ z.describe('When the request was created (ISO 8601).'),
38
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
39
+ ),
40
+ id: z
41
+ .string()
42
+ .check(
43
+ z.describe('Opaque request resource id (`vtr_…`).'),
44
+ z.meta({ examples: ['vtr_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
45
+ ),
46
+ logo: z.optional(
47
+ z
48
+ .string()
49
+ .check(
50
+ z.describe('Inline SVG logo markup uploaded with the request, when present.'),
51
+ z.meta({ examples: ['<svg xmlns="http://www.w3.org/2000/svg"/>'] }),
52
+ ),
53
+ ),
54
+ note: z
55
+ .nullable(z.string())
56
+ .check(
57
+ z.describe('Requester note to the reviewers, or null.'),
58
+ z.meta({ examples: ['We are the token issuer.', null] }),
59
+ ),
60
+ orgId: z
61
+ .string()
62
+ .check(
63
+ z.describe('Requesting organization id (`org_…`).'),
64
+ z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
65
+ ),
66
+ requestedBy: z
67
+ .string()
68
+ .check(
69
+ z.describe('User id that submitted the request.'),
70
+ z.meta({ examples: ['usr_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
71
+ ),
72
+ reviewNote: z
73
+ .nullable(z.string())
74
+ .check(
75
+ z.describe('Reviewer note shown when the request was denied, or null.'),
76
+ z.meta({ examples: ['Logo URL is unreachable.', null] }),
77
+ ),
78
+ reviewedAt: z
79
+ .nullable(z.string())
80
+ .check(
81
+ z.describe('When the request was reviewed (ISO 8601), or null while pending.'),
82
+ z.meta({ examples: ['2026-01-02T00:00:00.000Z', null] }),
83
+ ),
84
+ status: z
85
+ .enum(['approved', 'denied', 'pending'])
86
+ .check(z.describe('Review status of the request.'), z.meta({ examples: ['pending'] })),
87
+ updatedAt: z
88
+ .string()
89
+ .check(
90
+ z.describe('When the request was last changed (ISO 8601).'),
91
+ z.meta({ examples: ['2026-01-01T00:00:00.000Z'] }),
92
+ ),
93
+ }),
94
+ "An organization's request to add a token to the curated verified list.",
95
+ )
96
+
97
+ /**
98
+ * Create body. The shared token fields trust admin curation, so the
99
+ * member-facing surface re-declares them with length caps.
100
+ */
101
+ export const CreateBody = Schema.describe(
102
+ z.extend(tokenSchema.Input, {
103
+ chainId: Schema.ChainId,
104
+ currency: z
105
+ .string()
106
+ .check(
107
+ z.minLength(1),
108
+ z.maxLength(10),
109
+ z.describe('The currency label for this token, such as `USD`.'),
110
+ z.meta({ examples: ['USD'] }),
111
+ ),
112
+ logo: z.optional(
113
+ z.string().check(
114
+ z.refine(
115
+ (value) => /^<(\?xml|svg)[\s/>]/i.test(value.trimStart()),
116
+ 'Logo must be SVG markup.',
117
+ ),
118
+ z.refine(
119
+ (value) => new TextEncoder().encode(value).byteLength <= maxLogoBytes,
120
+ `Logo exceeds the ${maxLogoBytes / 1024} KiB limit.`,
121
+ ),
122
+ z.describe('Inline SVG logo markup, published to the asset store on approval.'),
123
+ z.meta({ examples: ['<svg xmlns="http://www.w3.org/2000/svg"/>'] }),
124
+ ),
125
+ ),
126
+ logoUri: z.optional(
127
+ z
128
+ .url({ protocol: /^https$/ })
129
+ .check(
130
+ z.maxLength(2048),
131
+ z.describe('The HTTPS URL for this token’s logo image, when one is set.'),
132
+ z.meta({ examples: ['https://assets.tempo.xyz/icons/usdc.svg'] }),
133
+ ),
134
+ ),
135
+ name: z
136
+ .string()
137
+ .check(
138
+ z.minLength(1),
139
+ z.maxLength(100),
140
+ z.describe('The token’s human-readable name.'),
141
+ z.meta({ examples: ['USD Coin'] }),
142
+ ),
143
+ note: z.optional(
144
+ z
145
+ .string()
146
+ .check(
147
+ z.trim(),
148
+ z.maxLength(500),
149
+ z.describe('Optional note to the reviewers.'),
150
+ z.meta({ examples: ['We are the token issuer.'] }),
151
+ ),
152
+ ),
153
+ symbol: z
154
+ .string()
155
+ .check(
156
+ z.minLength(1),
157
+ z.maxLength(20),
158
+ z.describe('The short ticker symbol wallets and apps show for this token.'),
159
+ z.meta({ examples: ['USDC'] }),
160
+ ),
161
+ }),
162
+ 'Fields for requesting verification of a token.',
163
+ )
164
+
165
+ /** Non-paginated list of an organization's requests. */
166
+ export const ListResponse = Schema.describe(
167
+ z.object({
168
+ data: z
169
+ .array(VerifiedTokenRequest)
170
+ .check(z.describe("The organization's verification requests, newest first.")),
171
+ }),
172
+ "A non-paginated list of an organization's verified-token requests.",
173
+ )
174
+
175
+ /** Path parameters addressing an organization's requests. */
176
+ export const Params = z
177
+ .object({
178
+ orgId: z
179
+ .string()
180
+ .check(
181
+ z.describe('Organization id (`org_…`).'),
182
+ z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
183
+ ),
184
+ })
185
+ .check(z.describe("Path parameters for an organization's verified-token requests."))
186
+
187
+ /** Path parameters addressing one verification request. */
188
+ export const RequestParams = z
189
+ .object({
190
+ orgId: z
191
+ .string()
192
+ .check(
193
+ z.describe('Organization id (`org_…`).'),
194
+ z.meta({ examples: ['org_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
195
+ ),
196
+ requestId: z
197
+ .string()
198
+ .check(
199
+ z.describe('Request resource id (`vtr_…`).'),
200
+ z.meta({ examples: ['vtr_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
201
+ ),
202
+ })
203
+ .check(z.describe('Path parameters for one verified-token request.'))
204
+
205
+ /** Cancel confirmation. */
206
+ export const DeleteResponse = z
207
+ .object({
208
+ id: z
209
+ .string()
210
+ .check(
211
+ z.describe('Canceled request resource id.'),
212
+ z.meta({ examples: ['vtr_1a2b3c4d5e6f7g8h9j0k1m2n'] }),
213
+ ),
214
+ })
215
+ .check(z.describe('Confirmation that a verified-token request was canceled.'))
216
+ }
217
+
218
+ const bodyValidation = {
219
+ code: 'body_invalid',
220
+ message: 'Check the request body and try again.',
221
+ } as const
222
+ const paramValidation = {
223
+ code: 'param_invalid',
224
+ message: 'Check the path parameters and try again.',
225
+ } as const
226
+
227
+ /** Maximum open (pending) requests per organization. */
228
+ const maxPending = 10
229
+
230
+ /** Mounts organization verified-token request operations. */
231
+ export function verifiedTokenRequests() {
232
+ return new Hono<Environment>()
233
+ .post(
234
+ '/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/verified-token-requests',
235
+ Auth.policy({ session: true }),
236
+ Auth.ensureOrg(),
237
+ OpenApi.validate('param', schema.Params, paramValidation),
238
+ OpenApi.validate('json', schema.CreateBody, bodyValidation),
239
+ OpenApi.describeRoute({
240
+ operationId: 'createVerifiedTokenRequest',
241
+ responses: OpenApi.responses({
242
+ errors: {
243
+ 404: 'No accessible organization was found.',
244
+ 409: {
245
+ codes: ['request_limit_reached', 'request_pending_exists', 'verified_symbol_exists', 'verified_token_exists'], // prettier-ignore
246
+ description: 'The token is already verified or requested, or the organization is at its pending-request limit.', // prettier-ignore
247
+ },
248
+ },
249
+ success: { description: 'Created request.', schema: schema.VerifiedTokenRequest },
250
+ }),
251
+ summary: 'Create token request',
252
+ tags: ['Verified Token Requests'],
253
+ }),
254
+ async (c) => {
255
+ if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
256
+ if (Auth.narrowScope) return Auth.ensureOrgError(c)
257
+ if (OpenApi.narrowValidation) return OpenApi.validationError(c, bodyValidation)
258
+ const body = c.req.valid('json')
259
+ try {
260
+ const db = Db.get(c.get('db'))
261
+ const orgId = Auth.org(c).id
262
+ // Reject requests that could never be approved: the verified list
263
+ // enforces address and case-insensitive symbol uniqueness per chain.
264
+ const snapshot = await VerifiedTokens.read(db, body.chainId)
265
+ if (snapshot?.byAddress.has(body.address))
266
+ return Response.error(c, {
267
+ code: 'verified_token_exists',
268
+ message: 'Token is already verified',
269
+ status: 409,
270
+ })
271
+ if (snapshot?.bySymbol.has(body.symbol.toLowerCase()))
272
+ return Response.error(c, {
273
+ code: 'verified_symbol_exists',
274
+ message: 'A verified token already uses this symbol',
275
+ status: 409,
276
+ })
277
+ if ((await VerifiedTokenRequests.countPending(db, orgId)) >= maxPending)
278
+ return Response.error(c, {
279
+ code: 'request_limit_reached',
280
+ message: `Organizations may have at most ${maxPending} pending requests`,
281
+ status: 409,
282
+ })
283
+ const record = await VerifiedTokenRequests.create(db, {
284
+ address: body.address,
285
+ chainId: body.chainId,
286
+ currency: body.currency,
287
+ decimals: body.decimals,
288
+ ...(body.logo === undefined ? {} : { logo: body.logo }),
289
+ ...(body.logoUri === undefined ? {} : { logoUri: body.logoUri }),
290
+ name: body.name,
291
+ ...(body.note ? { note: body.note } : {}),
292
+ orgId,
293
+ requestedBy: Auth.membership(c)?.userId ?? 'super_admin',
294
+ symbol: body.symbol,
295
+ })
296
+ if (!record)
297
+ return Response.error(c, {
298
+ code: 'request_pending_exists',
299
+ message: 'Token already has a pending verification request',
300
+ status: 409,
301
+ })
302
+ return c.json(
303
+ Response.validated(
304
+ schema.VerifiedTokenRequest,
305
+ VerifiedTokenRequests.toRequest(record),
306
+ ),
307
+ 200,
308
+ )
309
+ } catch (cause) {
310
+ return Response.upstream(c, cause)
311
+ }
312
+ },
313
+ )
314
+ .get(
315
+ '/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/verified-token-requests',
316
+ Auth.policy({ session: true }),
317
+ Auth.ensureOrg(),
318
+ OpenApi.validate('param', schema.Params, paramValidation),
319
+ OpenApi.describeRoute({
320
+ operationId: 'listVerifiedTokenRequests',
321
+ responses: OpenApi.responses({
322
+ errors: { 404: 'No accessible organization was found.' },
323
+ success: { description: 'Verification requests.', schema: schema.ListResponse },
324
+ }),
325
+ summary: 'List token requests',
326
+ tags: ['Verified Token Requests'],
327
+ }),
328
+ async (c) => {
329
+ if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
330
+ if (Auth.narrowScope) return Auth.ensureOrgError(c)
331
+ if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
332
+ try {
333
+ const records = await VerifiedTokenRequests.list(Db.get(c.get('db')), Auth.org(c).id)
334
+ return c.json(
335
+ Response.validated(schema.ListResponse, {
336
+ data: records.map(VerifiedTokenRequests.toRequest),
337
+ }),
338
+ 200,
339
+ )
340
+ } catch (cause) {
341
+ return Response.upstream(c, cause)
342
+ }
343
+ },
344
+ )
345
+ .delete(
346
+ '/v1/orgs/:orgId{org_[A-Za-z0-9_-]+}/verified-token-requests/:requestId{vtr_[A-Za-z0-9_-]+}',
347
+ Auth.policy({ session: true }),
348
+ Auth.ensureOrg(),
349
+ OpenApi.validate('param', schema.RequestParams, paramValidation),
350
+ OpenApi.describeRoute({
351
+ operationId: 'cancelVerifiedTokenRequest',
352
+ responses: OpenApi.responses({
353
+ errors: {
354
+ 404: 'No accessible verification request was found.',
355
+ 409: {
356
+ codes: ['request_not_pending'],
357
+ description: 'Only pending requests can be canceled.',
358
+ },
359
+ },
360
+ success: { description: 'Canceled request.', schema: schema.DeleteResponse },
361
+ }),
362
+ summary: 'Cancel token request',
363
+ tags: ['Verified Token Requests'],
364
+ }),
365
+ async (c) => {
366
+ if (Auth.narrowAccess) return Auth.superAdminAccessError(c)
367
+ if (Auth.narrowScope) return Auth.ensureOrgError(c)
368
+ if (OpenApi.narrowValidation) return OpenApi.validationError(c, paramValidation)
369
+ try {
370
+ const db = Db.get(c.get('db'))
371
+ const orgId = Auth.org(c).id
372
+ const id = c.req.valid('param').requestId
373
+ if (!(await VerifiedTokenRequests.remove(db, orgId, id))) {
374
+ const existing = await VerifiedTokenRequests.get(db, id)
375
+ if (existing && existing.orgId === orgId)
376
+ return Response.error(c, {
377
+ code: 'request_not_pending',
378
+ message: 'Only pending requests can be canceled',
379
+ status: 409,
380
+ })
381
+ return notFound(c)
382
+ }
383
+ return c.json({ id }, 200)
384
+ } catch (cause) {
385
+ return Response.upstream(c, cause)
386
+ }
387
+ },
388
+ )
389
+ }
390
+
391
+ function notFound(c: Context<Environment>) {
392
+ return Response.error(c, {
393
+ code: 'verified_token_request_not_found',
394
+ message: 'Verification request not found',
395
+ status: 404,
396
+ })
397
+ }