tapimo 0.10.0 → 0.10.2

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 (295) hide show
  1. package/dist/ApiKey.d.ts +2 -1
  2. package/dist/ApiKey.d.ts.map +1 -1
  3. package/dist/ApiKeys.d.ts +4 -2
  4. package/dist/ApiKeys.d.ts.map +1 -1
  5. package/dist/ApiKeys.js +26 -1
  6. package/dist/ApiKeys.js.map +1 -1
  7. package/dist/App.d.ts +6007 -5003
  8. package/dist/App.d.ts.map +1 -1
  9. package/dist/App.js +1 -0
  10. package/dist/App.js.map +1 -1
  11. package/dist/Webhooks.d.ts +1 -1
  12. package/dist/Webhooks.d.ts.map +1 -1
  13. package/dist/Webhooks.js +6 -6
  14. package/dist/Webhooks.js.map +1 -1
  15. package/dist/admin/App.d.ts +91 -84
  16. package/dist/admin/App.d.ts.map +1 -1
  17. package/dist/admin/apps/api-keys.d.ts +22 -13
  18. package/dist/admin/apps/api-keys.d.ts.map +1 -1
  19. package/dist/admin/apps/api-keys.js +6 -0
  20. package/dist/admin/apps/api-keys.js.map +1 -1
  21. package/dist/admin/apps/organizations.d.ts +4 -2
  22. package/dist/admin/apps/organizations.d.ts.map +1 -1
  23. package/dist/admin/ui.generated.d.ts +1 -1
  24. package/dist/admin/ui.generated.js +69 -69
  25. package/dist/admin/ui.generated.js.map +1 -1
  26. package/dist/analytics/Analytics.d.ts.map +1 -1
  27. package/dist/analytics/Analytics.js +232 -0
  28. package/dist/analytics/Analytics.js.map +1 -1
  29. package/dist/analytics/tables/requestEvents.d.ts +4 -0
  30. package/dist/analytics/tables/requestEvents.d.ts.map +1 -1
  31. package/dist/analytics/tables/requestEvents.js +2 -0
  32. package/dist/analytics/tables/requestEvents.js.map +1 -1
  33. package/dist/apps/Zones.d.ts +4266 -82
  34. package/dist/apps/Zones.d.ts.map +1 -1
  35. package/dist/apps/Zones.js +27 -8
  36. package/dist/apps/Zones.js.map +1 -1
  37. package/dist/apps/data/App.d.ts +3467 -2696
  38. package/dist/apps/data/App.d.ts.map +1 -1
  39. package/dist/apps/data/App.js +2 -0
  40. package/dist/apps/data/App.js.map +1 -1
  41. package/dist/apps/data/routes/activities.d.ts +2999 -100
  42. package/dist/apps/data/routes/activities.d.ts.map +1 -1
  43. package/dist/apps/data/routes/activities.js +340 -2
  44. package/dist/apps/data/routes/activities.js.map +1 -1
  45. package/dist/apps/data/routes/addresses.d.ts +514 -0
  46. package/dist/apps/data/routes/addresses.d.ts.map +1 -1
  47. package/dist/apps/data/routes/balances.d.ts +26 -26
  48. package/dist/apps/data/routes/balances.d.ts.map +1 -1
  49. package/dist/apps/data/routes/balances.js +7 -3
  50. package/dist/apps/data/routes/balances.js.map +1 -1
  51. package/dist/apps/data/routes/blocks.d.ts +4 -4
  52. package/dist/apps/data/routes/earn.d.ts +75 -75
  53. package/dist/apps/data/routes/earn.d.ts.map +1 -1
  54. package/dist/apps/data/routes/earn.js +65 -36
  55. package/dist/apps/data/routes/earn.js.map +1 -1
  56. package/dist/apps/data/routes/exchanges.d.ts +124 -120
  57. package/dist/apps/data/routes/exchanges.d.ts.map +1 -1
  58. package/dist/apps/data/routes/exchanges.js +115 -77
  59. package/dist/apps/data/routes/exchanges.js.map +1 -1
  60. package/dist/apps/data/routes/fee-amm.d.ts +24 -24
  61. package/dist/apps/data/routes/indexer.d.ts +2 -1
  62. package/dist/apps/data/routes/indexer.d.ts.map +1 -1
  63. package/dist/apps/data/routes/indexer.js +3 -2
  64. package/dist/apps/data/routes/indexer.js.map +1 -1
  65. package/dist/apps/data/routes/receipts.d.ts +4 -3
  66. package/dist/apps/data/routes/receipts.d.ts.map +1 -1
  67. package/dist/apps/data/routes/receipts.js +15 -14
  68. package/dist/apps/data/routes/receipts.js.map +1 -1
  69. package/dist/apps/data/routes/rpc.d.ts.map +1 -1
  70. package/dist/apps/data/routes/rpc.js +5 -1
  71. package/dist/apps/data/routes/rpc.js.map +1 -1
  72. package/dist/apps/data/routes/tokenlist.d.ts +12 -12
  73. package/dist/apps/data/routes/tokens.d.ts +1 -1
  74. package/dist/apps/data/routes/tokens.d.ts.map +1 -1
  75. package/dist/apps/data/routes/tokens.js +4 -3
  76. package/dist/apps/data/routes/tokens.js.map +1 -1
  77. package/dist/apps/data/routes/transfers.d.ts.map +1 -1
  78. package/dist/apps/data/routes/transfers.js +25 -7
  79. package/dist/apps/data/routes/transfers.js.map +1 -1
  80. package/dist/apps/data/routes/verified-tokens.d.ts +37 -37
  81. package/dist/apps/data/routes/webhooks.d.ts +71 -1
  82. package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
  83. package/dist/apps/data/routes/webhooks.js +177 -23
  84. package/dist/apps/data/routes/webhooks.js.map +1 -1
  85. package/dist/apps/data/routes/zones.js +1 -1
  86. package/dist/apps/data/routes/zones.js.map +1 -1
  87. package/dist/apps/funding/App.d.ts +322 -89
  88. package/dist/apps/funding/App.d.ts.map +1 -1
  89. package/dist/apps/funding/routes/deposit-addresses.d.ts +375 -45
  90. package/dist/apps/funding/routes/deposit-addresses.d.ts.map +1 -1
  91. package/dist/apps/funding/routes/deposit-addresses.js +208 -12
  92. package/dist/apps/funding/routes/deposit-addresses.js.map +1 -1
  93. package/dist/apps/funding/routes/transfers.d.ts +32 -32
  94. package/dist/apps/funding/routes/transfers.js +1 -1
  95. package/dist/apps/funding/routes/transfers.js.map +1 -1
  96. package/dist/apps/management/App.d.ts +418 -418
  97. package/dist/apps/management/routes/api-keys.d.ts +50 -50
  98. package/dist/apps/management/routes/billing.d.ts +72 -72
  99. package/dist/apps/management/routes/billing.js +1 -1
  100. package/dist/apps/management/routes/billing.js.map +1 -1
  101. package/dist/apps/management/routes/faucet.d.ts +8 -8
  102. package/dist/apps/management/routes/faucet.js +2 -2
  103. package/dist/apps/management/routes/faucet.js.map +1 -1
  104. package/dist/apps/management/routes/invite-links.d.ts +42 -42
  105. package/dist/apps/management/routes/me.d.ts +6 -6
  106. package/dist/apps/management/routes/members.d.ts +14 -14
  107. package/dist/apps/management/routes/projects.d.ts +40 -40
  108. package/dist/apps/management/routes/usage.d.ts +8 -8
  109. package/dist/apps/management/routes/webhooks.d.ts +49 -49
  110. package/dist/apps/mcp.d.ts.map +1 -1
  111. package/dist/apps/mcp.js +4 -1
  112. package/dist/apps/mcp.js.map +1 -1
  113. package/dist/db/Db.d.ts +2 -0
  114. package/dist/db/Db.d.ts.map +1 -1
  115. package/dist/db/Db.js +90 -0
  116. package/dist/db/Db.js.map +1 -1
  117. package/dist/db/Schema.d.ts +19 -0
  118. package/dist/db/Schema.d.ts.map +1 -1
  119. package/dist/db/Schema.js +24 -0
  120. package/dist/db/Schema.js.map +1 -1
  121. package/dist/db/tables/fundingDepositAddresses.d.ts +20 -0
  122. package/dist/db/tables/fundingDepositAddresses.d.ts.map +1 -1
  123. package/dist/db/tables/fundingDepositAddresses.js +17 -0
  124. package/dist/db/tables/fundingDepositAddresses.js.map +1 -1
  125. package/dist/db/tables/fundingDeposits.d.ts +41 -0
  126. package/dist/db/tables/fundingDeposits.d.ts.map +1 -1
  127. package/dist/db/tables/fundingDeposits.js +69 -0
  128. package/dist/db/tables/fundingDeposits.js.map +1 -1
  129. package/dist/db/tables/webhookQueueEvents.d.ts +122 -0
  130. package/dist/db/tables/webhookQueueEvents.d.ts.map +1 -0
  131. package/dist/db/tables/webhookQueueEvents.js +160 -0
  132. package/dist/db/tables/webhookQueueEvents.js.map +1 -0
  133. package/dist/db/tables/webhookSubscriptions.d.ts +2 -0
  134. package/dist/db/tables/webhookSubscriptions.d.ts.map +1 -1
  135. package/dist/db/tables/webhookSubscriptions.js +10 -0
  136. package/dist/db/tables/webhookSubscriptions.js.map +1 -1
  137. package/dist/internal/Auth.d.ts +3 -26
  138. package/dist/internal/Auth.d.ts.map +1 -1
  139. package/dist/internal/Auth.js +6 -37
  140. package/dist/internal/Auth.js.map +1 -1
  141. package/dist/internal/Credential.d.ts +27 -0
  142. package/dist/internal/Credential.d.ts.map +1 -0
  143. package/dist/internal/Credential.js +34 -0
  144. package/dist/internal/Credential.js.map +1 -0
  145. package/dist/internal/EarnRates.js +11 -7
  146. package/dist/internal/EarnRates.js.map +1 -1
  147. package/dist/internal/Log.d.ts +8 -0
  148. package/dist/internal/Log.d.ts.map +1 -1
  149. package/dist/internal/Log.js +4 -0
  150. package/dist/internal/Log.js.map +1 -1
  151. package/dist/internal/MetricSink.d.ts +51 -0
  152. package/dist/internal/MetricSink.d.ts.map +1 -1
  153. package/dist/internal/MetricSink.js +54 -2
  154. package/dist/internal/MetricSink.js.map +1 -1
  155. package/dist/internal/RateLimit.d.ts +4 -6
  156. package/dist/internal/RateLimit.d.ts.map +1 -1
  157. package/dist/internal/RateLimit.js +15 -14
  158. package/dist/internal/RateLimit.js.map +1 -1
  159. package/dist/internal/Store.d.ts +2 -1
  160. package/dist/internal/Store.d.ts.map +1 -1
  161. package/dist/internal/Store.js +57 -18
  162. package/dist/internal/Store.js.map +1 -1
  163. package/dist/internal/Tidx.d.ts +4 -3
  164. package/dist/internal/Tidx.d.ts.map +1 -1
  165. package/dist/internal/Tidx.js +2 -2
  166. package/dist/internal/Tidx.js.map +1 -1
  167. package/dist/internal/Value.d.ts +2 -0
  168. package/dist/internal/Value.d.ts.map +1 -1
  169. package/dist/internal/Value.js +25 -0
  170. package/dist/internal/Value.js.map +1 -1
  171. package/dist/internal/Viem.d.ts +4 -3
  172. package/dist/internal/Viem.d.ts.map +1 -1
  173. package/dist/internal/Viem.js +3 -2
  174. package/dist/internal/Viem.js.map +1 -1
  175. package/dist/internal/WebhookTransfer.d.ts +20 -0
  176. package/dist/internal/WebhookTransfer.d.ts.map +1 -1
  177. package/dist/internal/WebhookTransfer.js +7 -4
  178. package/dist/internal/WebhookTransfer.js.map +1 -1
  179. package/dist/internal/Webhooks.d.ts +141 -0
  180. package/dist/internal/Webhooks.d.ts.map +1 -1
  181. package/dist/internal/Webhooks.js +139 -10
  182. package/dist/internal/Webhooks.js.map +1 -1
  183. package/dist/internal/funding/providers/relay.d.ts +3 -4
  184. package/dist/internal/funding/providers/relay.d.ts.map +1 -1
  185. package/dist/internal/funding/providers/relay.js +59 -8
  186. package/dist/internal/funding/providers/relay.js.map +1 -1
  187. package/dist/internal/index.d.ts +1 -0
  188. package/dist/internal/index.d.ts.map +1 -1
  189. package/dist/internal/index.js +1 -0
  190. package/dist/internal/index.js.map +1 -1
  191. package/package.json +3 -3
  192. package/src/ApiKeys.test.ts +20 -0
  193. package/src/ApiKeys.ts +28 -1
  194. package/src/App.test.ts +40 -8
  195. package/src/App.ts +1 -0
  196. package/src/Client.test-d.ts +34 -1
  197. package/src/Webhooks.ts +20 -18
  198. package/src/admin/apps/api-keys.test.ts +9 -0
  199. package/src/admin/apps/api-keys.ts +15 -0
  200. package/src/admin/ui/src/lib/query-client.ts +3 -2
  201. package/src/admin/ui/src/routes/api-keys.tsx +31 -9
  202. package/src/admin/ui.generated.ts +69 -69
  203. package/src/analytics/Analytics.test.ts +42 -0
  204. package/src/analytics/Analytics.ts +232 -0
  205. package/src/analytics/tables/requestEvents.ts +6 -0
  206. package/src/apps/Zones.test.ts +20 -3
  207. package/src/apps/Zones.ts +28 -8
  208. package/src/apps/composition.test.ts +2 -0
  209. package/src/apps/data/App.test.ts +2 -2
  210. package/src/apps/data/App.ts +2 -0
  211. package/src/apps/data/routes/activities.bench.ts +41 -0
  212. package/src/apps/data/routes/activities.test.ts +103 -2
  213. package/src/apps/data/routes/activities.ts +401 -2
  214. package/src/apps/data/routes/balances.bench.ts +21 -0
  215. package/src/apps/data/routes/balances.ts +7 -3
  216. package/src/apps/data/routes/blocks.bench.ts +34 -0
  217. package/src/apps/data/routes/coingecko.bench.ts +53 -0
  218. package/src/apps/data/routes/earn.bench.ts +71 -0
  219. package/src/apps/data/routes/earn.ts +66 -36
  220. package/src/apps/data/routes/exchanges.bench.ts +85 -0
  221. package/src/apps/data/routes/exchanges.test.ts +8 -3
  222. package/src/apps/data/routes/exchanges.ts +134 -82
  223. package/src/apps/data/routes/fee-amm.bench.ts +13 -0
  224. package/src/apps/data/routes/indexer.bench.ts +8 -0
  225. package/src/apps/data/routes/indexer.test.ts +2 -1
  226. package/src/apps/data/routes/indexer.ts +3 -2
  227. package/src/apps/data/routes/receipts.bench.ts +39 -0
  228. package/src/apps/data/routes/receipts.ts +16 -14
  229. package/src/apps/data/routes/rpc.bench.ts +14 -0
  230. package/src/apps/data/routes/rpc.test.ts +27 -0
  231. package/src/apps/data/routes/rpc.ts +5 -1
  232. package/src/apps/data/routes/tokenlist.bench.ts +3 -0
  233. package/src/apps/data/routes/tokens.bench.ts +76 -0
  234. package/src/apps/data/routes/tokens.ts +3 -2
  235. package/src/apps/data/routes/transactions.bench.ts +48 -0
  236. package/src/apps/data/routes/transfers.bench.ts +28 -0
  237. package/src/apps/data/routes/transfers.ts +36 -10
  238. package/src/apps/data/routes/valuation.bench.ts +14 -0
  239. package/src/apps/data/routes/verified-tokens.bench.ts +8 -0
  240. package/src/apps/data/routes/webhooks.bench.ts +26 -0
  241. package/src/apps/data/routes/webhooks.scan.test.ts +326 -0
  242. package/src/apps/data/routes/webhooks.test.ts +53 -6
  243. package/src/apps/data/routes/webhooks.ts +252 -24
  244. package/src/apps/data/routes/zones.bench.ts +32 -0
  245. package/src/apps/data/routes/zones.test.ts +1 -1
  246. package/src/apps/data/routes/zones.ts +1 -1
  247. package/src/apps/funding/routes/chains.test.ts +1 -1
  248. package/src/apps/funding/routes/deposit-addresses.test.ts +217 -3
  249. package/src/apps/funding/routes/deposit-addresses.ts +255 -19
  250. package/src/apps/funding/routes/providers.test.ts +1 -1
  251. package/src/apps/funding/routes/quotes.test.ts +1 -1
  252. package/src/apps/funding/routes/transfers.test.ts +20 -8
  253. package/src/apps/funding/routes/transfers.ts +1 -1
  254. package/src/apps/management/routes/billing.ts +1 -1
  255. package/src/apps/management/routes/faucet.ts +2 -2
  256. package/src/apps/management/routes/me.test.ts +31 -0
  257. package/src/apps/mcp.ts +4 -1
  258. package/src/db/Db.ts +117 -0
  259. package/src/db/Schema.ts +32 -0
  260. package/src/db/tables/fundingDepositAddresses.test.ts +28 -0
  261. package/src/db/tables/fundingDepositAddresses.ts +39 -0
  262. package/src/db/tables/fundingDeposits.test.ts +82 -0
  263. package/src/db/tables/fundingDeposits.ts +130 -0
  264. package/src/db/tables/webhookQueueEvents.ts +285 -0
  265. package/src/db/tables/webhookSubscriptions.ts +15 -0
  266. package/src/internal/Auth.test.ts +61 -98
  267. package/src/internal/Auth.ts +9 -63
  268. package/src/internal/Credential.test.ts +51 -0
  269. package/src/internal/Credential.ts +58 -0
  270. package/src/internal/EarnRates.ts +13 -7
  271. package/src/internal/EarnVaults.test.ts +2 -2
  272. package/src/internal/Log.test.ts +3 -1
  273. package/src/internal/Log.ts +14 -0
  274. package/src/internal/MetricSink.test.ts +108 -2
  275. package/src/internal/MetricSink.ts +112 -2
  276. package/src/internal/RateLimit.test.ts +23 -18
  277. package/src/internal/RateLimit.ts +23 -15
  278. package/src/internal/Store.test.ts +99 -13
  279. package/src/internal/Store.ts +52 -17
  280. package/src/internal/Tidx.test.ts +4 -4
  281. package/src/internal/Tidx.ts +5 -4
  282. package/src/internal/Value.test.ts +25 -0
  283. package/src/internal/Value.ts +29 -0
  284. package/src/internal/Viem.test.ts +4 -0
  285. package/src/internal/Viem.ts +6 -4
  286. package/src/internal/WebhookTransfer.test.ts +89 -0
  287. package/src/internal/WebhookTransfer.ts +11 -7
  288. package/src/internal/Webhooks.test.ts +488 -0
  289. package/src/internal/Webhooks.ts +291 -10
  290. package/src/internal/funding/Provider.test.ts +1 -1
  291. package/src/internal/funding/providers/index.test.ts +73 -3
  292. package/src/internal/funding/providers/relay.test.ts +1 -5
  293. package/src/internal/funding/providers/relay.ts +56 -12
  294. package/src/internal/index.test.ts +1 -0
  295. package/src/internal/index.ts +1 -0
@@ -5,10 +5,12 @@ import * as RequestEvents from './tables/requestEvents.js'
5
5
  const context = { enabled: true, environment: 'test', service: 'api' }
6
6
 
7
7
  const entry = {
8
+ chainId: 4217,
8
9
  duration: 12.3,
9
10
  level: 'info',
10
11
  method: 'GET',
11
12
  path: '/v1/transactions',
13
+ query: 'include=receipt&limit=10',
12
14
  requestId: 'req-1',
13
15
  route: '/v1/transactions',
14
16
  status: 200,
@@ -25,6 +27,7 @@ const clickHouse = {
25
27
  /** Baseline stored row for insert/queue tests. */
26
28
  const row = {
27
29
  billing_active: null,
30
+ chain_id: 4217,
28
31
  duration_ms: 12.3,
29
32
  environment: 'test',
30
33
  error_code: null,
@@ -34,6 +37,7 @@ const row = {
34
37
  org_id: null,
35
38
  project_id: null,
36
39
  principal_type: 'unknown',
40
+ query: 'include=receipt&limit=10',
37
41
  rate_limit_scope: null,
38
42
  request_id: 'req-1',
39
43
  route: '/v1/transactions',
@@ -183,6 +187,31 @@ describe('migrations', () => {
183
187
  const sql = Analytics.migrations.map((migration) => migration.sql).join('\n')
184
188
  for (const column of Object.keys(row)) expect(sql).toContain(column)
185
189
  expect(sql).toContain('timings Map(String, Float64)')
190
+ expect(sql).toContain('query String')
191
+ })
192
+
193
+ test('the migrations declare query benchmark history', () => {
194
+ const sql = Analytics.migrations.map((migration) => migration.sql).join('\n')
195
+ expect(sql).toContain('CREATE TABLE IF NOT EXISTS query_benchmark_results')
196
+ expect(sql).toContain('ORDER BY (chain_id, query, metric, timestamp, run_id)')
197
+ expect(sql).toContain('rpc_url String')
198
+ expect(sql).toContain('tidx_url String')
199
+ })
200
+
201
+ test('the migrations declare the endpoint latency view', () => {
202
+ const sql = Analytics.migrations.map((migration) => migration.sql).join('\n')
203
+ const latest = Analytics.migrations[Analytics.migrations.length - 1]!
204
+ expect(sql).toContain('CREATE OR REPLACE VIEW endpoint_latency_results')
205
+ expect(sql).toContain("'production' AS source")
206
+ expect(sql).toContain("'benchmark' AS source")
207
+ expect(sql).toContain("if(result.metric = 'benchmark', 'request', result.metric) AS metric")
208
+ expect(sql).toContain("if(status >= 200 AND status < 300, 'success', 'error') AS outcome")
209
+ expect(sql).toContain("WHERE result.metric != 'request'")
210
+ expect(sql).toContain('arrayZip(mapKeys(timings), mapValues(timings))')
211
+ expect(latest.name).toBe('0011_endpoint_latency_query')
212
+ expect(latest.sql).toContain("environment = 'production' AND service = 'cadent-api'")
213
+ expect(latest.sql).toContain("coalesce(request_id, '') AS request_id")
214
+ expect(latest.sql).toContain('query AS variant')
186
215
  })
187
216
  })
188
217
 
@@ -205,6 +234,7 @@ describe('createQueueSink', () => {
205
234
  const row = send.mock.calls[0]![0]
206
235
  expect({
207
236
  billing_active: row.billing_active,
237
+ chain_id: row.chain_id,
208
238
  duration_ms: row.duration_ms,
209
239
  environment: row.environment,
210
240
  error_code: row.error_code,
@@ -214,6 +244,7 @@ describe('createQueueSink', () => {
214
244
  org_id: row.org_id,
215
245
  principal_type: row.principal_type,
216
246
  project_id: row.project_id,
247
+ query: row.query,
217
248
  rate_limit_scope: row.rate_limit_scope,
218
249
  request_id: row.request_id,
219
250
  route: row.route,
@@ -227,6 +258,7 @@ describe('createQueueSink', () => {
227
258
  }).toMatchInlineSnapshot(`
228
259
  {
229
260
  "billing_active": null,
261
+ "chain_id": 4217,
230
262
  "duration_ms": 12.3,
231
263
  "environment": "test",
232
264
  "error_code": null,
@@ -236,6 +268,7 @@ describe('createQueueSink', () => {
236
268
  "org_id": null,
237
269
  "principal_type": "unknown",
238
270
  "project_id": null,
271
+ "query": "include=receipt&limit=10",
239
272
  "rate_limit_scope": null,
240
273
  "request_id": "req-1",
241
274
  "route": "/v1/transactions",
@@ -262,6 +295,15 @@ describe('createQueueSink', () => {
262
295
  expect(send.mock.calls[0]![0].timings).toMatchInlineSnapshot(`{}`)
263
296
  })
264
297
 
298
+ test('stores an empty query when the request has no query string', async () => {
299
+ const send = vi.fn<(message: Analytics.Event) => Promise<void>>().mockResolvedValue(undefined)
300
+ const sink = Analytics.createQueueSink({ send })(context)
301
+
302
+ await sink({ ...entry, query: undefined })
303
+
304
+ expect(send.mock.calls[0]![0].query).toMatchInlineSnapshot(`""`)
305
+ })
306
+
265
307
  test('retries a failed send once with the same row', async () => {
266
308
  const send = vi
267
309
  .fn<(message: Analytics.Event) => Promise<void>>()
@@ -120,6 +120,7 @@ export const migrations: readonly Migration[] = [
120
120
  timestamp DateTime64(3, 'UTC'),
121
121
  service LowCardinality(String),
122
122
  environment LowCardinality(String),
123
+ chain_id Nullable(UInt32),
123
124
  method LowCardinality(String),
124
125
  route LowCardinality(String),
125
126
  status UInt16,
@@ -129,6 +130,7 @@ export const migrations: readonly Migration[] = [
129
130
  key_environment Nullable(String),
130
131
  org_id Nullable(String),
131
132
  project_id Nullable(String),
133
+ query String,
132
134
  rate_limit_scope Nullable(String),
133
135
  error_code Nullable(String),
134
136
  rpc_error_code Nullable(Int32),
@@ -192,6 +194,236 @@ export const migrations: readonly Migration[] = [
192
194
  ADD COLUMN IF NOT EXISTS timings Map(String, Float64)
193
195
  `,
194
196
  },
197
+ {
198
+ name: '0005_query_benchmark_results',
199
+ sql: `
200
+ CREATE TABLE IF NOT EXISTS query_benchmark_results (
201
+ timestamp DateTime64(3, 'UTC'),
202
+ run_id String,
203
+ repository LowCardinality(String),
204
+ git_sha String,
205
+ git_ref LowCardinality(String),
206
+ chain_id UInt32,
207
+ chain LowCardinality(String),
208
+ method LowCardinality(String),
209
+ route LowCardinality(String),
210
+ query String,
211
+ metric LowCardinality(String),
212
+ mean_ms Float64,
213
+ min_ms Float64,
214
+ max_ms Float64,
215
+ samples UInt16,
216
+ tidx_queries Array(String),
217
+ rpc_url String,
218
+ tidx_url String
219
+ )
220
+ ENGINE = ReplacingMergeTree
221
+ PARTITION BY toYYYYMM(timestamp)
222
+ ORDER BY (chain_id, query, metric, timestamp, run_id)
223
+ `,
224
+ },
225
+ {
226
+ name: '0006_endpoint_latency_dimensions',
227
+ // Patches production while fresh preview tables skip the unavailable ALTER.
228
+ guard: `
229
+ SELECT toUInt8(count() = 1) FROM system.columns
230
+ WHERE database = currentDatabase()
231
+ AND table = 'request_events'
232
+ AND name = 'chain_id'
233
+ `,
234
+ sql: `
235
+ ALTER TABLE request_events
236
+ ADD COLUMN IF NOT EXISTS chain_id Nullable(UInt32) AFTER environment
237
+ `,
238
+ },
239
+ {
240
+ name: '0007_query_benchmark_dimensions',
241
+ // Patches production while fresh preview tables skip the unavailable ALTER.
242
+ guard: `
243
+ SELECT toUInt8(count() = 2) FROM system.columns
244
+ WHERE database = currentDatabase()
245
+ AND table = 'query_benchmark_results'
246
+ AND name IN ('method', 'route')
247
+ `,
248
+ sql: `
249
+ ALTER TABLE query_benchmark_results
250
+ ADD COLUMN IF NOT EXISTS method LowCardinality(String) AFTER chain,
251
+ ADD COLUMN IF NOT EXISTS route LowCardinality(String) AFTER method
252
+ `,
253
+ },
254
+ {
255
+ name: '0008_endpoint_latency_results',
256
+ sql: `
257
+ CREATE OR REPLACE VIEW endpoint_latency_results AS
258
+ SELECT
259
+ timestamp,
260
+ 'production' AS source,
261
+ chain_id,
262
+ method,
263
+ route AS endpoint,
264
+ '' AS variant,
265
+ toNullable(status) AS status,
266
+ if(status >= 200 AND status < 300, 'success', 'error') AS outcome,
267
+ measurement.1 AS metric,
268
+ measurement.2 AS mean_ms,
269
+ measurement.2 AS min_ms,
270
+ measurement.2 AS max_ms,
271
+ toUInt64(1) AS samples,
272
+ '' AS run_id,
273
+ '' AS git_sha
274
+ FROM request_events
275
+ ARRAY JOIN arrayConcat(
276
+ [('request', duration_ms)],
277
+ arrayFilter(
278
+ measurement -> measurement.1 != 'request',
279
+ arrayZip(mapKeys(timings), mapValues(timings))
280
+ )
281
+ ) AS measurement
282
+ WHERE environment = 'production' AND service = 'api'
283
+
284
+ UNION ALL
285
+
286
+ SELECT
287
+ timestamp,
288
+ 'benchmark' AS source,
289
+ toNullable(chain_id) AS chain_id,
290
+ method,
291
+ if(route = '', query, route) AS endpoint,
292
+ query AS variant,
293
+ CAST(NULL, 'Nullable(UInt16)') AS status,
294
+ 'success' AS outcome,
295
+ if(result.metric = 'benchmark', 'request', result.metric) AS metric,
296
+ mean_ms,
297
+ min_ms,
298
+ max_ms,
299
+ toUInt64(samples) AS samples,
300
+ run_id,
301
+ git_sha
302
+ FROM query_benchmark_results AS result
303
+ WHERE result.metric != 'request'
304
+ `,
305
+ },
306
+ {
307
+ name: '0009_endpoint_latency_production_service',
308
+ sql: `
309
+ CREATE OR REPLACE VIEW endpoint_latency_results AS
310
+ SELECT
311
+ timestamp,
312
+ 'production' AS source,
313
+ chain_id,
314
+ method,
315
+ route AS endpoint,
316
+ '' AS variant,
317
+ toNullable(status) AS status,
318
+ if(status >= 200 AND status < 300, 'success', 'error') AS outcome,
319
+ measurement.1 AS metric,
320
+ measurement.2 AS mean_ms,
321
+ measurement.2 AS min_ms,
322
+ measurement.2 AS max_ms,
323
+ toUInt64(1) AS samples,
324
+ '' AS run_id,
325
+ '' AS git_sha
326
+ FROM request_events
327
+ ARRAY JOIN arrayConcat(
328
+ [('request', duration_ms)],
329
+ arrayFilter(
330
+ measurement -> measurement.1 != 'request',
331
+ arrayZip(mapKeys(timings), mapValues(timings))
332
+ )
333
+ ) AS measurement
334
+ WHERE environment = 'production' AND service = 'cadent-api'
335
+
336
+ UNION ALL
337
+
338
+ SELECT
339
+ timestamp,
340
+ 'benchmark' AS source,
341
+ toNullable(chain_id) AS chain_id,
342
+ method,
343
+ if(route = '', query, route) AS endpoint,
344
+ query AS variant,
345
+ CAST(NULL, 'Nullable(UInt16)') AS status,
346
+ 'success' AS outcome,
347
+ if(result.metric = 'benchmark', 'request', result.metric) AS metric,
348
+ mean_ms,
349
+ min_ms,
350
+ max_ms,
351
+ toUInt64(samples) AS samples,
352
+ run_id,
353
+ git_sha
354
+ FROM query_benchmark_results AS result
355
+ WHERE result.metric != 'request'
356
+ `,
357
+ },
358
+ {
359
+ name: '0010_request_events_query',
360
+ // Patches tables created before redacted request queries entered the baseline.
361
+ // Fresh tables skip this ALTER, allowing scoped preview users to migrate.
362
+ guard: `
363
+ SELECT toUInt8(count() = 1) FROM system.columns
364
+ WHERE database = currentDatabase()
365
+ AND table = 'request_events'
366
+ AND name = 'query'
367
+ `,
368
+ sql: `
369
+ ALTER TABLE request_events
370
+ ADD COLUMN IF NOT EXISTS query String AFTER project_id
371
+ `,
372
+ },
373
+ {
374
+ name: '0011_endpoint_latency_query',
375
+ sql: `
376
+ CREATE OR REPLACE VIEW endpoint_latency_results AS
377
+ SELECT
378
+ timestamp,
379
+ 'production' AS source,
380
+ chain_id,
381
+ method,
382
+ route AS endpoint,
383
+ query AS variant,
384
+ toNullable(status) AS status,
385
+ if(status >= 200 AND status < 300, 'success', 'error') AS outcome,
386
+ measurement.1 AS metric,
387
+ measurement.2 AS mean_ms,
388
+ measurement.2 AS min_ms,
389
+ measurement.2 AS max_ms,
390
+ toUInt64(1) AS samples,
391
+ coalesce(request_id, '') AS request_id,
392
+ '' AS run_id,
393
+ '' AS git_sha
394
+ FROM request_events
395
+ ARRAY JOIN arrayConcat(
396
+ [('request', duration_ms)],
397
+ arrayFilter(
398
+ measurement -> measurement.1 != 'request',
399
+ arrayZip(mapKeys(timings), mapValues(timings))
400
+ )
401
+ ) AS measurement
402
+ WHERE environment = 'production' AND service = 'cadent-api'
403
+
404
+ UNION ALL
405
+
406
+ SELECT
407
+ timestamp,
408
+ 'benchmark' AS source,
409
+ toNullable(chain_id) AS chain_id,
410
+ method,
411
+ if(route = '', query, route) AS endpoint,
412
+ query AS variant,
413
+ CAST(NULL, 'Nullable(UInt16)') AS status,
414
+ 'success' AS outcome,
415
+ if(result.metric = 'benchmark', 'request', result.metric) AS metric,
416
+ mean_ms,
417
+ min_ms,
418
+ max_ms,
419
+ toUInt64(samples) AS samples,
420
+ '' AS request_id,
421
+ run_id,
422
+ git_sha
423
+ FROM query_benchmark_results AS result
424
+ WHERE result.metric != 'request'
425
+ `,
426
+ },
195
427
  ]
196
428
 
197
429
  /**
@@ -10,6 +10,8 @@ export type Table = {
10
10
  * billing gate for sandbox: only `1` rows bill.
11
11
  */
12
12
  billing_active: number | null
13
+ /** Tempo chain selected for the request. */
14
+ chain_id: number | null
13
15
  /** Total request duration in milliseconds. */
14
16
  duration_ms: number
15
17
  /** Deployment environment that served the request. */
@@ -28,6 +30,8 @@ export type Table = {
28
30
  project_id: string | null
29
31
  /** Caller principal kind. */
30
32
  principal_type: 'api_key' | 'public' | 'session' | 'super_admin' | 'unknown'
33
+ /** Redacted request query string, without a leading `?`. */
34
+ query: string
31
35
  /** Rate-limit bucket scope, when a rate limit was applied. */
32
36
  rate_limit_scope: string | null
33
37
  /** Numeric JSON-RPC error code when every failed response shares one code. */
@@ -557,6 +561,7 @@ function event(entry: Log.Entry, context: Metrics.cloudflare.Context): Table {
557
561
  const principal = entry.principal
558
562
  return {
559
563
  billing_active: principal?.type === 'api_key' ? Number(principal.billingActive === true) : null,
564
+ chain_id: entry.chainId ?? null,
560
565
  duration_ms: entry.duration,
561
566
  environment: context.environment ?? 'unknown',
562
567
  error_code: entry.errorCode ?? null,
@@ -566,6 +571,7 @@ function event(entry: Log.Entry, context: Metrics.cloudflare.Context): Table {
566
571
  org_id: principal?.type === 'api_key' ? (principal.orgId ?? null) : null,
567
572
  project_id: principal?.type === 'api_key' ? (principal.projectId ?? null) : null,
568
573
  principal_type: principal?.type ?? 'unknown',
574
+ query: entry.query ?? '',
569
575
  rate_limit_scope: entry.rateLimit?.scope ?? null,
570
576
  request_id: entry.requestId ?? null,
571
577
  route: entry.route,
@@ -5,10 +5,12 @@ describe('chains', () => {
5
5
  expect(Zones.chains).toMatchObject([
6
6
  {
7
7
  contracts: {
8
- messenger: { address: '0xc9C88278eA934A03CE8c90793F0B903e1C63B735' },
9
- portal: { address: '0xd8fDA2e3f421F272C56752cBCf5Ae0782c8B9ed2' },
8
+ messenger: { address: '0x2fB7Aba18510622cd88F5f45B3AC0E7Dd70606a5' },
9
+ portal: { address: '0x5765e8B9003054e479df44D12D3dEeaADEfa8b7c' },
10
+ verifier: { address: '0xfa16b9C6A356a096F0e7ceF0135C393A81d4a355' },
10
11
  },
11
- id: 421_700_001,
12
+ id: 1_424_310_001,
13
+ name: 'zone-moderato-internal',
12
14
  rpcUrls: {
13
15
  default: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
14
16
  internal: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
@@ -16,6 +18,21 @@ describe('chains', () => {
16
18
  },
17
19
  sourceId: 42_431,
18
20
  },
21
+ {
22
+ contracts: {
23
+ messenger: { address: '0x171699d2B5211414C23E5Cd306d05046b78FdD16' },
24
+ portal: { address: '0xe5208b9604972CA6a2E1EF656a9d2bDF2e530B9A' },
25
+ verifier: { address: '0x3E7C1cC9C049052eb061116A4Ee7a7C281fa1F30' },
26
+ },
27
+ id: 421_700_001,
28
+ name: 'zone-mainnet-internal',
29
+ rpcUrls: {
30
+ default: { http: ['https://zone-internal-rpc.tempo.xyz'] },
31
+ internal: { http: ['https://zone-internal-rpc.tempo.xyz'] },
32
+ tidx: { http: ['https://indexer-zone-internal.tempo.xyz'] },
33
+ },
34
+ sourceId: 4_217,
35
+ },
19
36
  {
20
37
  contracts: {
21
38
  messenger: { address: '0x5A4d000000000000000000000000000000000000' },
package/src/apps/Zones.ts CHANGED
@@ -1,16 +1,17 @@
1
1
  import { defineChain } from 'viem'
2
- import { tempoDevnet, tempoTestnet } from 'viem/tempo/chains'
2
+ import { tempo, tempoDevnet, tempoTestnet } from 'viem/tempo/chains'
3
3
 
4
- /** Moderato Zone on Tempo testnet. */
5
- export const zoneModerato = defineChain({
4
+ /** Internal Moderato Zone on Tempo testnet. */
5
+ export const zoneModeratoInternal = defineChain({
6
6
  ...tempoTestnet,
7
7
  contracts: {
8
8
  ...tempoTestnet.contracts,
9
- messenger: { address: '0xc9C88278eA934A03CE8c90793F0B903e1C63B735' },
10
- portal: { address: '0xd8fDA2e3f421F272C56752cBCf5Ae0782c8B9ed2' },
9
+ messenger: { address: '0x2fB7Aba18510622cd88F5f45B3AC0E7Dd70606a5' },
10
+ portal: { address: '0x5765e8B9003054e479df44D12D3dEeaADEfa8b7c' },
11
+ verifier: { address: '0xfa16b9C6A356a096F0e7ceF0135C393A81d4a355' },
11
12
  },
12
- id: 421_700_001,
13
- name: 'zone-moderato',
13
+ id: 1_424_310_001,
14
+ name: 'zone-moderato-internal',
14
15
  rpcUrls: {
15
16
  default: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
16
17
  internal: { http: ['https://zone-internal-rpc.testnet.tempo.xyz'] },
@@ -19,6 +20,25 @@ export const zoneModerato = defineChain({
19
20
  sourceId: tempoTestnet.id,
20
21
  })
21
22
 
23
+ /** Internal Zone on Tempo mainnet. */
24
+ export const zoneMainnetInternal = defineChain({
25
+ ...tempo,
26
+ contracts: {
27
+ ...tempo.contracts,
28
+ messenger: { address: '0x171699d2B5211414C23E5Cd306d05046b78FdD16' },
29
+ portal: { address: '0xe5208b9604972CA6a2E1EF656a9d2bDF2e530B9A' },
30
+ verifier: { address: '0x3E7C1cC9C049052eb061116A4Ee7a7C281fa1F30' },
31
+ },
32
+ id: 421_700_001,
33
+ name: 'zone-mainnet-internal',
34
+ rpcUrls: {
35
+ default: { http: ['https://zone-internal-rpc.tempo.xyz'] },
36
+ internal: { http: ['https://zone-internal-rpc.tempo.xyz'] },
37
+ tidx: { http: ['https://indexer-zone-internal.tempo.xyz'] },
38
+ },
39
+ sourceId: tempo.id,
40
+ })
41
+
22
42
  /** Stable hosted Zone on Tempo devnet. */
23
43
  export const zoneStable = defineChain({
24
44
  ...tempoDevnet,
@@ -38,4 +58,4 @@ export const zoneStable = defineChain({
38
58
  })
39
59
 
40
60
  /** Hosted Zone chains served by the API and admin. */
41
- export const chains = [zoneModerato, zoneStable] as const
61
+ export const chains = [zoneModeratoInternal, zoneMainnetInternal, zoneStable] as const
@@ -197,6 +197,7 @@ describe('data()', () => {
197
197
  42431,
198
198
  421700001,
199
199
  421700006,
200
+ 1424310001,
200
201
  ],
201
202
  }
202
203
  `)
@@ -325,6 +326,7 @@ describe('funding()', () => {
325
326
  ),
326
327
  ),
327
328
  ).toEqual([
329
+ 'listFundingDepositAddresses',
328
330
  'createFundingDepositAddress',
329
331
  'reconcileFundingDepositAddress',
330
332
  'getFundingDepositAddress',
@@ -436,8 +436,8 @@ describe('sandbox chain guard', () => {
436
436
  })
437
437
 
438
438
  async function exhaustPublicQuota(store: Store.Store) {
439
- const limit = { perMinute: 60 }
439
+ const limit = { limit: 60, period: 'minute' } satisfies RateLimit.Limit
440
440
  const rateLimit = RateLimit.memory({ store })
441
- for (let index = 0; index < limit.perMinute; index++)
441
+ for (let index = 0; index < limit.limit; index++)
442
442
  await rateLimit.consume({ key: 'public:anonymous', limit })
443
443
  }
@@ -237,6 +237,8 @@ export function data(options: data.Options = {}) {
237
237
  indexerHandlers: indexerRouteHandlers,
238
238
  rpcOnlyHandlers: rpcOnlyRouteHandlers,
239
239
  })
240
+ if (selection.matched && !selection.conflict && !selection.invalid)
241
+ c.set('chainId', selection.chainId)
240
242
  return (
241
243
  selection.matched &&
242
244
  !selection.conflict &&
@@ -0,0 +1,41 @@
1
+ import * as QueryBench from '../../../../test/QueryBench.js'
2
+
3
+ const fixtures = {
4
+ 4217: {
5
+ address: '0xc24357119432595a547cb2c1e41c51d753645519',
6
+ transactionHash: '0x7f98e4b2bf4d1444b257526f7dd294ac3480d73cd91f723bf0df6062d1ba1c82',
7
+ },
8
+ 42431: {
9
+ address: '0x15496d3123afb2cfadc0ac068eadd11d0f8ae799',
10
+ transactionHash: '0x1c8ccebb169f863b72388cc057fcecee240032eb7d2c64aa6f6fb8e5a60d3f9a',
11
+ },
12
+ } as const
13
+
14
+ QueryBench.bench({
15
+ name: 'getAddressActivities',
16
+ path: {
17
+ 4217: `/v1/addresses/${fixtures[4217].address}/activities`,
18
+ 42431: `/v1/addresses/${fixtures[42431].address}/activities`,
19
+ },
20
+ queries: [
21
+ 'group=true',
22
+ 'include=token.logoUri',
23
+ 'include=token.verified',
24
+ 'logs=true',
25
+ 'valuation.currency=USD',
26
+ ],
27
+ })
28
+
29
+ QueryBench.bench({
30
+ name: 'getTransactionActivities',
31
+ path: {
32
+ 4217: `/v1/transactions/${fixtures[4217].transactionHash}/activities`,
33
+ 42431: `/v1/transactions/${fixtures[42431].transactionHash}/activities`,
34
+ },
35
+ queries: [
36
+ 'include=token.logoUri',
37
+ 'include=token.verified',
38
+ 'logs=true',
39
+ 'valuation.currency=USD',
40
+ ],
41
+ })
@@ -699,11 +699,12 @@ describe('Activities.list precompile classification', () => {
699
699
  logIdx: number
700
700
  }): Activities.Row {
701
701
  type Param = { indexed?: boolean; name?: string; type: string }
702
- const event = Abis.abis.find((a) => a.type === 'event' && a.name === options.eventName) as {
702
+ const abi = [...Abis.abis, ...Abis.earnRouter, ...Abis.earnVault]
703
+ const event = abi.find((a) => a.type === 'event' && a.name === options.eventName) as {
703
704
  inputs: readonly Param[]
704
705
  }
705
706
  const topics = encodeEventTopics({
706
- abi: Abis.abis,
707
+ abi,
707
708
  eventName: options.eventName as never,
708
709
  args: options.args as never,
709
710
  }) as (string | null)[]
@@ -751,6 +752,106 @@ describe('Activities.list precompile classification', () => {
751
752
  return items
752
753
  }
753
754
 
755
+ test('classifies every Earn vault and private-router event', async () => {
756
+ const requestId = `0x${'c'.repeat(64)}` as Hex.Hex
757
+ const cases = [
758
+ ['Deposited', { assets: 100n, caller: viewer, earnShares: 90n, receiver: viewer }],
759
+ [
760
+ 'VenueSharesDeposited',
761
+ {
762
+ caller: viewer,
763
+ earnShares: 90n,
764
+ receivedEngineShares: 95n,
765
+ receiver: viewer,
766
+ requestedVenueShares: 100n,
767
+ },
768
+ ],
769
+ ['Redeemed', { assets: 100n, caller: viewer, earnShares: 90n, receiver: viewer }],
770
+ ['WithdrewExact', { assets: 100n, caller: viewer, earnSharesBurned: 90n, receiver: viewer }],
771
+ ['RedeemRequested', { earnShares: 90n, receiver: viewer, requestId, requester: viewer }],
772
+ [
773
+ 'RedeemFinalized',
774
+ { asset: tokenA, assets: 100n, earnShares: 90n, receiver: viewer, requestId },
775
+ ],
776
+ ['RedeemCancelled', { earnShares: 90n, receiver: viewer, requestId }],
777
+ [
778
+ 'EarnDeposit',
779
+ {
780
+ actionId: requestId,
781
+ earnShares: 90n,
782
+ earnVault: tokenA,
783
+ inputAmount: 100n,
784
+ inputToken: tokenA,
785
+ vaultAssets: 100n,
786
+ zoneDepositHash: requestId,
787
+ },
788
+ ],
789
+ [
790
+ 'EarnRedeem',
791
+ {
792
+ actionId: requestId,
793
+ earnShares: 90n,
794
+ earnVault: tokenA,
795
+ outputAmount: 100n,
796
+ outputToken: tokenA,
797
+ vaultAssets: 100n,
798
+ zoneDepositHash: requestId,
799
+ },
800
+ ],
801
+ ] as const
802
+
803
+ const types = []
804
+ for (const [eventName, args] of cases) {
805
+ const items = await classify([logRow({ address: tokenA, args, eventName, logIdx: 0 })])
806
+ types.push(items[0]?.type)
807
+ }
808
+
809
+ expect(types).toMatchInlineSnapshot(`
810
+ [
811
+ "assets-deposited",
812
+ "shares-deposited",
813
+ "shares-redeemed",
814
+ "assets-withdrawn",
815
+ "shares-redemption-requested",
816
+ "shares-redemption-finalized",
817
+ "shares-redemption-cancelled",
818
+ "private-assets-deposited",
819
+ "private-shares-redeemed",
820
+ ]
821
+ `)
822
+ })
823
+
824
+ test('prefers a private Earn event over its underlying vault event', async () => {
825
+ const actionId = `0x${'c'.repeat(64)}` as Hex.Hex
826
+ const items = await classify([
827
+ logRow({
828
+ address: tokenA,
829
+ args: { assets: 100n, caller: viewer, earnShares: 90n, receiver: viewer },
830
+ eventName: 'Deposited',
831
+ logIdx: 0,
832
+ }),
833
+ logRow({
834
+ address: tokenA,
835
+ args: {
836
+ actionId,
837
+ earnShares: 90n,
838
+ earnVault: tokenA,
839
+ inputAmount: 100n,
840
+ inputToken: tokenA,
841
+ vaultAssets: 100n,
842
+ zoneDepositHash: actionId,
843
+ },
844
+ eventName: 'EarnDeposit',
845
+ logIdx: 1,
846
+ }),
847
+ ])
848
+ expect(items.map((item) => item.type)).toMatchInlineSnapshot(`
849
+ [
850
+ "private-assets-deposited",
851
+ ]
852
+ `)
853
+ })
854
+
754
855
  test('classifies ChannelOpened as `channel-opened` with the deposit token', async () => {
755
856
  const items = await classify([
756
857
  logRow({