tapimo 0.4.4 → 0.5.1
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.
- package/dist/App.d.ts +4701 -3416
- package/dist/App.d.ts.map +1 -1
- package/dist/App.js +24 -2
- package/dist/App.js.map +1 -1
- package/dist/Assets.js +3 -3
- package/dist/Assets.js.map +1 -1
- package/dist/Scope.d.ts +18 -1
- package/dist/Scope.d.ts.map +1 -1
- package/dist/Scope.js +23 -3
- package/dist/Scope.js.map +1 -1
- package/dist/Webhooks.d.ts +1 -1
- package/dist/Webhooks.d.ts.map +1 -1
- package/dist/Webhooks.js +5 -10
- package/dist/Webhooks.js.map +1 -1
- package/dist/admin/App.d.ts +6 -34
- package/dist/admin/App.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.d.ts +3 -3
- package/dist/admin/apps/api-keys.d.ts.map +1 -1
- package/dist/admin/apps/api-keys.js +4 -1
- package/dist/admin/apps/api-keys.js.map +1 -1
- package/dist/admin/apps/scopes.d.ts +6 -34
- package/dist/admin/apps/scopes.d.ts.map +1 -1
- package/dist/admin/apps/scopes.js +2 -2
- package/dist/admin/apps/scopes.js.map +1 -1
- package/dist/admin/apps/verified-tokens.d.ts +57 -57
- package/dist/admin/ui.generated.d.ts +1 -1
- package/dist/admin/ui.generated.js +33 -33
- package/dist/admin/ui.generated.js.map +1 -1
- package/dist/apps/data/App.d.ts +4574 -4277
- package/dist/apps/data/App.d.ts.map +1 -1
- package/dist/apps/data/App.js +155 -77
- package/dist/apps/data/App.js.map +1 -1
- package/dist/apps/data/FundingQuoteProviders.d.ts +109 -0
- package/dist/apps/data/FundingQuoteProviders.d.ts.map +1 -0
- package/dist/apps/data/FundingQuoteProviders.js +464 -0
- package/dist/apps/data/FundingQuoteProviders.js.map +1 -0
- package/dist/apps/data/index.d.ts +1 -1
- package/dist/apps/data/index.js +1 -1
- package/dist/apps/data/routes/activities.d.ts +26 -26
- package/dist/apps/data/routes/addresses.d.ts +38 -38
- package/dist/apps/data/routes/balances.d.ts +45 -45
- package/dist/apps/data/routes/balances.d.ts.map +1 -1
- package/dist/apps/data/routes/balances.js +67 -149
- package/dist/apps/data/routes/balances.js.map +1 -1
- package/dist/apps/data/routes/blocks.d.ts +2 -3
- package/dist/apps/data/routes/blocks.d.ts.map +1 -1
- package/dist/apps/data/routes/blocks.js +3 -5
- package/dist/apps/data/routes/blocks.js.map +1 -1
- package/dist/apps/data/routes/coingecko.d.ts +177 -176
- package/dist/apps/data/routes/coingecko.d.ts.map +1 -1
- package/dist/apps/data/routes/coingecko.js +3 -8
- package/dist/apps/data/routes/coingecko.js.map +1 -1
- package/dist/apps/data/routes/funding.d.ts +131 -228
- package/dist/apps/data/routes/funding.d.ts.map +1 -1
- package/dist/apps/data/routes/funding.js +152 -219
- package/dist/apps/data/routes/funding.js.map +1 -1
- package/dist/apps/data/routes/indexer.d.ts +34 -34
- package/dist/apps/data/routes/indexer.d.ts.map +1 -1
- package/dist/apps/data/routes/indexer.js +9 -2
- package/dist/apps/data/routes/indexer.js.map +1 -1
- package/dist/apps/data/routes/receipts.d.ts +228 -228
- package/dist/apps/data/routes/rpc.d.ts.map +1 -1
- package/dist/apps/data/routes/rpc.js +86 -16
- package/dist/apps/data/routes/rpc.js.map +1 -1
- package/dist/apps/data/routes/tokenlist.d.ts +12 -12
- package/dist/apps/data/routes/verified-tokens.d.ts +5 -5
- package/dist/apps/data/routes/webhooks.d.ts +340 -0
- package/dist/apps/data/routes/webhooks.d.ts.map +1 -1
- package/dist/apps/data/routes/webhooks.js +13 -1
- package/dist/apps/data/routes/webhooks.js.map +1 -1
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/index.js +1 -1
- package/dist/apps/management/App.d.ts +1833 -851
- package/dist/apps/management/App.d.ts.map +1 -1
- package/dist/apps/management/App.js +4 -0
- package/dist/apps/management/App.js.map +1 -1
- package/dist/apps/management/routes/api-keys.d.ts +41 -41
- package/dist/apps/management/routes/api-keys.js +2 -2
- package/dist/apps/management/routes/api-keys.js.map +1 -1
- package/dist/apps/management/routes/billing.d.ts +48 -48
- package/dist/apps/management/routes/invitations.d.ts +132 -132
- package/dist/apps/management/routes/invite-links.d.ts +1100 -0
- package/dist/apps/management/routes/invite-links.d.ts.map +1 -0
- package/dist/apps/management/routes/invite-links.js +411 -0
- package/dist/apps/management/routes/invite-links.js.map +1 -0
- package/dist/apps/management/routes/members.d.ts +41 -41
- package/dist/apps/management/routes/orgs.d.ts +92 -92
- package/dist/apps/management/routes/projects.d.ts +9 -9
- package/dist/apps/management/routes/scopes.d.ts.map +1 -1
- package/dist/apps/management/routes/scopes.js +2 -2
- package/dist/apps/management/routes/scopes.js.map +1 -1
- package/dist/apps/management/routes/usage.d.ts +24 -24
- package/dist/apps/mcp.js +2 -2
- package/dist/apps/mcp.js.map +1 -1
- package/dist/apps/relay/App.d.ts +2 -2
- package/dist/apps/relay/App.d.ts.map +1 -1
- package/dist/apps/relay/App.js +44 -6
- package/dist/apps/relay/App.js.map +1 -1
- package/dist/db/Db.d.ts +3 -0
- package/dist/db/Db.d.ts.map +1 -1
- package/dist/db/Db.js +57 -0
- package/dist/db/Db.js.map +1 -1
- package/dist/db/Schema.d.ts +31 -0
- package/dist/db/Schema.d.ts.map +1 -1
- package/dist/db/Schema.js +31 -0
- package/dist/db/Schema.js.map +1 -1
- package/dist/db/tables/inviteLinks.d.ts +42 -0
- package/dist/db/tables/inviteLinks.d.ts.map +1 -0
- package/dist/db/tables/inviteLinks.js +148 -0
- package/dist/db/tables/inviteLinks.js.map +1 -0
- package/dist/db/tables/organizations.d.ts.map +1 -1
- package/dist/db/tables/organizations.js +2 -0
- package/dist/db/tables/organizations.js.map +1 -1
- package/dist/db/tables/sponsoredTransactions.d.ts.map +1 -1
- package/dist/db/tables/sponsoredTransactions.js +6 -2
- package/dist/db/tables/sponsoredTransactions.js.map +1 -1
- package/dist/handlers/relay.d.ts.map +1 -1
- package/dist/handlers/relay.js +13 -3
- package/dist/handlers/relay.js.map +1 -1
- package/dist/internal/Auth.d.ts +9 -1
- package/dist/internal/Auth.d.ts.map +1 -1
- package/dist/internal/Auth.js +138 -10
- package/dist/internal/Auth.js.map +1 -1
- package/dist/internal/EdgeCache.d.ts +3 -1
- package/dist/internal/EdgeCache.d.ts.map +1 -1
- package/dist/internal/EdgeCache.js +17 -2
- package/dist/internal/EdgeCache.js.map +1 -1
- package/dist/internal/{FundingRoutes.d.ts → FundingQuotes.d.ts} +240 -369
- package/dist/internal/FundingQuotes.d.ts.map +1 -0
- package/dist/internal/{FundingRoutes.js → FundingQuotes.js} +144 -183
- package/dist/internal/FundingQuotes.js.map +1 -0
- package/dist/internal/Log.d.ts +18 -12
- package/dist/internal/Log.d.ts.map +1 -1
- package/dist/internal/Log.js +2 -0
- package/dist/internal/Log.js.map +1 -1
- package/dist/internal/Tidx.d.ts +9 -3
- package/dist/internal/Tidx.d.ts.map +1 -1
- package/dist/internal/Tidx.js +13 -7
- package/dist/internal/Tidx.js.map +1 -1
- package/dist/internal/Viem.d.ts +17 -2
- package/dist/internal/Viem.d.ts.map +1 -1
- package/dist/internal/Viem.js +30 -3
- package/dist/internal/Viem.js.map +1 -1
- package/dist/internal/index.d.ts +1 -1
- package/dist/internal/index.js +1 -1
- package/package.json +2 -2
- package/src/ApiKeys.test.ts +25 -0
- package/src/App.test-d.ts +2 -0
- package/src/App.test.ts +13 -2
- package/src/App.ts +37 -5
- package/src/Assets.ts +3 -3
- package/src/Client.test-d.ts +21 -11
- package/src/Scope.test.ts +1 -0
- package/src/Scope.ts +32 -4
- package/src/Webhooks.ts +5 -10
- package/src/admin/apps/api-keys.test.ts +27 -0
- package/src/admin/apps/api-keys.ts +8 -1
- package/src/admin/apps/scopes.test.ts +7 -2
- package/src/admin/apps/scopes.ts +2 -2
- package/src/admin/ui/src/components/Dialog.tsx +8 -2
- package/src/admin/ui/src/lib/scopes.test.ts +19 -0
- package/src/admin/ui/src/lib/scopes.ts +12 -0
- package/src/admin/ui/src/routes/api-keys.tsx +128 -27
- package/src/admin/ui.generated.ts +33 -33
- package/src/apps/composition.test.ts +77 -0
- package/src/apps/data/App.test.ts +354 -0
- package/src/apps/data/App.ts +178 -91
- package/src/apps/data/FundingQuoteProviders.test.ts +577 -0
- package/src/apps/data/FundingQuoteProviders.ts +633 -0
- package/src/apps/data/index.ts +1 -1
- package/src/apps/data/routes/balances.test.ts +64 -18
- package/src/apps/data/routes/balances.ts +76 -177
- package/src/apps/data/routes/blocks.ts +3 -5
- package/src/apps/data/routes/coingecko.ts +3 -8
- package/src/apps/data/routes/funding.test.ts +304 -192
- package/src/apps/data/routes/funding.ts +166 -286
- package/src/apps/data/routes/indexer.test.ts +173 -15
- package/src/apps/data/routes/indexer.ts +8 -2
- package/src/apps/data/routes/rpc.test.ts +219 -0
- package/src/apps/data/routes/rpc.ts +92 -17
- package/src/apps/data/routes/webhooks.test.ts +21 -0
- package/src/apps/data/routes/webhooks.ts +13 -1
- package/src/apps/index.ts +1 -1
- package/src/apps/management/App.ts +4 -0
- package/src/apps/management/Billing.test.ts +2 -2
- package/src/apps/management/routes/api-keys.test.ts +47 -3
- package/src/apps/management/routes/api-keys.ts +2 -2
- package/src/apps/management/routes/invite-links.test.ts +385 -0
- package/src/apps/management/routes/invite-links.ts +570 -0
- package/src/apps/management/routes/scopes.test.ts +3 -2
- package/src/apps/management/routes/scopes.ts +4 -2
- package/src/apps/mcp.test.ts +18 -0
- package/src/apps/mcp.ts +2 -2
- package/src/apps/relay/App.test.ts +328 -7
- package/src/apps/relay/App.ts +42 -6
- package/src/apps/relay/Sponsorships.test.ts +2 -2
- package/src/db/Db.test.ts +5 -5
- package/src/db/Db.ts +65 -0
- package/src/db/Schema.ts +39 -0
- package/src/db/tables/billingSettings.test.ts +2 -2
- package/src/db/tables/inviteLinks.ts +187 -0
- package/src/db/tables/organizations.test.ts +2 -2
- package/src/db/tables/organizations.ts +2 -0
- package/src/db/tables/sponsoredTransactions.test.ts +19 -2
- package/src/db/tables/sponsoredTransactions.ts +21 -14
- package/src/db/tables/stripeCustomers.test.ts +2 -2
- package/src/handlers/relay.ts +16 -4
- package/src/internal/Auth.test.ts +132 -22
- package/src/internal/Auth.ts +181 -14
- package/src/internal/EdgeCache.test.ts +24 -3
- package/src/internal/EdgeCache.ts +18 -2
- package/src/internal/FundingQuotes.test.ts +268 -0
- package/src/internal/{FundingRoutes.ts → FundingQuotes.ts} +216 -277
- package/src/internal/Log.ts +21 -14
- package/src/internal/Tidx.test.ts +48 -0
- package/src/internal/Tidx.ts +21 -7
- package/src/internal/Viem.test.ts +46 -0
- package/src/internal/Viem.ts +48 -6
- package/src/internal/index.test.ts +1 -1
- package/src/internal/index.ts +1 -1
- package/dist/apps/data/FundingRouteProviders.d.ts +0 -36
- package/dist/apps/data/FundingRouteProviders.d.ts.map +0 -1
- package/dist/apps/data/FundingRouteProviders.js +0 -245
- package/dist/apps/data/FundingRouteProviders.js.map +0 -1
- package/dist/internal/FundingRoutes.d.ts.map +0 -1
- package/dist/internal/FundingRoutes.js.map +0 -1
- package/src/apps/data/FundingRouteProviders.test.ts +0 -225
- package/src/apps/data/FundingRouteProviders.ts +0 -312
- package/src/internal/FundingRoutes.test.ts +0 -213
|
@@ -31,30 +31,6 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
31
31
|
logs?: string | string[];
|
|
32
32
|
} | undefined;
|
|
33
33
|
};
|
|
34
|
-
} | {
|
|
35
|
-
output: {
|
|
36
|
-
error: {
|
|
37
|
-
code: "upstream_error";
|
|
38
|
-
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
39
|
-
message: string;
|
|
40
|
-
};
|
|
41
|
-
requestId: string;
|
|
42
|
-
};
|
|
43
|
-
outputFormat: "json";
|
|
44
|
-
status: 502;
|
|
45
|
-
input: {
|
|
46
|
-
param: {
|
|
47
|
-
address: `0x${string}`;
|
|
48
|
-
};
|
|
49
|
-
} & {
|
|
50
|
-
query?: {
|
|
51
|
-
chainId?: string | string[];
|
|
52
|
-
cursor?: string | string[];
|
|
53
|
-
group?: string | string[];
|
|
54
|
-
limit?: string | string[];
|
|
55
|
-
logs?: string | string[];
|
|
56
|
-
} | undefined;
|
|
57
|
-
};
|
|
58
34
|
} | {
|
|
59
35
|
output: {
|
|
60
36
|
error: {
|
|
@@ -154,7 +130,7 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
154
130
|
} | {
|
|
155
131
|
output: {
|
|
156
132
|
error: {
|
|
157
|
-
code: "
|
|
133
|
+
code: "address_invalid";
|
|
158
134
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
159
135
|
message: string;
|
|
160
136
|
};
|
|
@@ -178,7 +154,7 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
178
154
|
} | {
|
|
179
155
|
output: {
|
|
180
156
|
error: {
|
|
181
|
-
code: "
|
|
157
|
+
code: "query_invalid";
|
|
182
158
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
183
159
|
message: string;
|
|
184
160
|
};
|
|
@@ -3401,6 +3377,30 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3401
3377
|
logs?: string | string[];
|
|
3402
3378
|
} | undefined;
|
|
3403
3379
|
};
|
|
3380
|
+
} | {
|
|
3381
|
+
output: {
|
|
3382
|
+
error: {
|
|
3383
|
+
code: "upstream_error";
|
|
3384
|
+
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3385
|
+
message: string;
|
|
3386
|
+
};
|
|
3387
|
+
requestId: string;
|
|
3388
|
+
};
|
|
3389
|
+
outputFormat: "json";
|
|
3390
|
+
status: 502;
|
|
3391
|
+
input: {
|
|
3392
|
+
param: {
|
|
3393
|
+
address: `0x${string}`;
|
|
3394
|
+
};
|
|
3395
|
+
} & {
|
|
3396
|
+
query?: {
|
|
3397
|
+
chainId?: string | string[];
|
|
3398
|
+
cursor?: string | string[];
|
|
3399
|
+
group?: string | string[];
|
|
3400
|
+
limit?: string | string[];
|
|
3401
|
+
logs?: string | string[];
|
|
3402
|
+
} | undefined;
|
|
3403
|
+
};
|
|
3404
3404
|
};
|
|
3405
3405
|
};
|
|
3406
3406
|
}, "/"> | import("hono/types").MergeSchemaPath<{
|
|
@@ -3428,14 +3428,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3428
3428
|
} | {
|
|
3429
3429
|
output: {
|
|
3430
3430
|
error: {
|
|
3431
|
-
code: "
|
|
3431
|
+
code: "api_key_malformed";
|
|
3432
3432
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3433
3433
|
message: string;
|
|
3434
3434
|
};
|
|
3435
3435
|
requestId: string;
|
|
3436
3436
|
};
|
|
3437
3437
|
outputFormat: "json";
|
|
3438
|
-
status:
|
|
3438
|
+
status: 400;
|
|
3439
3439
|
input: {
|
|
3440
3440
|
param: {
|
|
3441
3441
|
address: `0x${string}`;
|
|
@@ -3455,14 +3455,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3455
3455
|
} | {
|
|
3456
3456
|
output: {
|
|
3457
3457
|
error: {
|
|
3458
|
-
code: "
|
|
3458
|
+
code: "api_key_invalid" | "api_key_missing";
|
|
3459
3459
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3460
3460
|
message: string;
|
|
3461
3461
|
};
|
|
3462
3462
|
requestId: string;
|
|
3463
3463
|
};
|
|
3464
3464
|
outputFormat: "json";
|
|
3465
|
-
status:
|
|
3465
|
+
status: 401;
|
|
3466
3466
|
input: {
|
|
3467
3467
|
param: {
|
|
3468
3468
|
address: `0x${string}`;
|
|
@@ -3482,14 +3482,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3482
3482
|
} | {
|
|
3483
3483
|
output: {
|
|
3484
3484
|
error: {
|
|
3485
|
-
code: "
|
|
3485
|
+
code: "api_key_forbidden";
|
|
3486
3486
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3487
3487
|
message: string;
|
|
3488
3488
|
};
|
|
3489
3489
|
requestId: string;
|
|
3490
3490
|
};
|
|
3491
3491
|
outputFormat: "json";
|
|
3492
|
-
status:
|
|
3492
|
+
status: 403;
|
|
3493
3493
|
input: {
|
|
3494
3494
|
param: {
|
|
3495
3495
|
address: `0x${string}`;
|
|
@@ -3509,14 +3509,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3509
3509
|
} | {
|
|
3510
3510
|
output: {
|
|
3511
3511
|
error: {
|
|
3512
|
-
code: "
|
|
3512
|
+
code: "payment_required" | "rate_limit_exceeded";
|
|
3513
3513
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3514
3514
|
message: string;
|
|
3515
3515
|
};
|
|
3516
3516
|
requestId: string;
|
|
3517
3517
|
};
|
|
3518
3518
|
outputFormat: "json";
|
|
3519
|
-
status:
|
|
3519
|
+
status: 429;
|
|
3520
3520
|
input: {
|
|
3521
3521
|
param: {
|
|
3522
3522
|
address: `0x${string}`;
|
|
@@ -3536,14 +3536,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3536
3536
|
} | {
|
|
3537
3537
|
output: {
|
|
3538
3538
|
error: {
|
|
3539
|
-
code: "
|
|
3539
|
+
code: "address_invalid";
|
|
3540
3540
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3541
3541
|
message: string;
|
|
3542
3542
|
};
|
|
3543
3543
|
requestId: string;
|
|
3544
3544
|
};
|
|
3545
3545
|
outputFormat: "json";
|
|
3546
|
-
status:
|
|
3546
|
+
status: 400;
|
|
3547
3547
|
input: {
|
|
3548
3548
|
param: {
|
|
3549
3549
|
address: `0x${string}`;
|
|
@@ -3590,14 +3590,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
3590
3590
|
} | {
|
|
3591
3591
|
output: {
|
|
3592
3592
|
error: {
|
|
3593
|
-
code: "
|
|
3593
|
+
code: "upstream_error";
|
|
3594
3594
|
details?: readonly import("../../../internal/Response.js").error.Detail[] | undefined;
|
|
3595
3595
|
message: string;
|
|
3596
3596
|
};
|
|
3597
3597
|
requestId: string;
|
|
3598
3598
|
};
|
|
3599
3599
|
outputFormat: "json";
|
|
3600
|
-
status:
|
|
3600
|
+
status: 502;
|
|
3601
3601
|
input: {
|
|
3602
3602
|
param: {
|
|
3603
3603
|
address: `0x${string}`;
|
|
@@ -86,9 +86,31 @@ export declare namespace schema {
|
|
|
86
86
|
export declare function addresses(): import("hono/hono-base").HonoBase<App.Environment, {
|
|
87
87
|
"/v1/addresses/:address/balances": {
|
|
88
88
|
$get: {
|
|
89
|
-
output:
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
output: {
|
|
90
|
+
data: {
|
|
91
|
+
amount: string;
|
|
92
|
+
formatted: string;
|
|
93
|
+
id: string;
|
|
94
|
+
feeEligible?: boolean | undefined;
|
|
95
|
+
token: {
|
|
96
|
+
address: `0x${string}`;
|
|
97
|
+
currency: string;
|
|
98
|
+
decimals: number;
|
|
99
|
+
id: string;
|
|
100
|
+
logoUri?: string | undefined;
|
|
101
|
+
name: string;
|
|
102
|
+
symbol: string;
|
|
103
|
+
verified: boolean;
|
|
104
|
+
};
|
|
105
|
+
}[];
|
|
106
|
+
meta?: {
|
|
107
|
+
totalCountCapped: boolean;
|
|
108
|
+
totalCount: number;
|
|
109
|
+
} | undefined;
|
|
110
|
+
nextCursor: string | null;
|
|
111
|
+
};
|
|
112
|
+
outputFormat: "json";
|
|
113
|
+
status: 200;
|
|
92
114
|
input: {
|
|
93
115
|
param: {
|
|
94
116
|
address: `0x${string}`;
|
|
@@ -135,14 +157,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
135
157
|
} | {
|
|
136
158
|
output: {
|
|
137
159
|
error: {
|
|
138
|
-
code: "
|
|
160
|
+
code: "query_invalid";
|
|
139
161
|
details?: readonly Response.error.Detail[] | undefined;
|
|
140
162
|
message: string;
|
|
141
163
|
};
|
|
142
164
|
requestId: string;
|
|
143
165
|
};
|
|
144
166
|
outputFormat: "json";
|
|
145
|
-
status:
|
|
167
|
+
status: 400;
|
|
146
168
|
input: {
|
|
147
169
|
param: {
|
|
148
170
|
address: `0x${string}`;
|
|
@@ -162,14 +184,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
162
184
|
} | {
|
|
163
185
|
output: {
|
|
164
186
|
error: {
|
|
165
|
-
code: "
|
|
187
|
+
code: "address_invalid";
|
|
166
188
|
details?: readonly Response.error.Detail[] | undefined;
|
|
167
189
|
message: string;
|
|
168
190
|
};
|
|
169
191
|
requestId: string;
|
|
170
192
|
};
|
|
171
193
|
outputFormat: "json";
|
|
172
|
-
status:
|
|
194
|
+
status: 400;
|
|
173
195
|
input: {
|
|
174
196
|
param: {
|
|
175
197
|
address: `0x${string}`;
|
|
@@ -189,14 +211,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
189
211
|
} | {
|
|
190
212
|
output: {
|
|
191
213
|
error: {
|
|
192
|
-
code: "
|
|
214
|
+
code: "api_key_invalid" | "api_key_missing";
|
|
193
215
|
details?: readonly Response.error.Detail[] | undefined;
|
|
194
216
|
message: string;
|
|
195
217
|
};
|
|
196
218
|
requestId: string;
|
|
197
219
|
};
|
|
198
220
|
outputFormat: "json";
|
|
199
|
-
status:
|
|
221
|
+
status: 401;
|
|
200
222
|
input: {
|
|
201
223
|
param: {
|
|
202
224
|
address: `0x${string}`;
|
|
@@ -214,16 +236,9 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
214
236
|
} | undefined;
|
|
215
237
|
};
|
|
216
238
|
} | {
|
|
217
|
-
output:
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
details?: readonly Response.error.Detail[] | undefined;
|
|
221
|
-
message: string;
|
|
222
|
-
};
|
|
223
|
-
requestId: string;
|
|
224
|
-
};
|
|
225
|
-
outputFormat: "json";
|
|
226
|
-
status: 400;
|
|
239
|
+
output: null;
|
|
240
|
+
outputFormat: "body";
|
|
241
|
+
status: 402;
|
|
227
242
|
input: {
|
|
228
243
|
param: {
|
|
229
244
|
address: `0x${string}`;
|
|
@@ -243,14 +258,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
243
258
|
} | {
|
|
244
259
|
output: {
|
|
245
260
|
error: {
|
|
246
|
-
code: "
|
|
261
|
+
code: "api_key_forbidden";
|
|
247
262
|
details?: readonly Response.error.Detail[] | undefined;
|
|
248
263
|
message: string;
|
|
249
264
|
};
|
|
250
265
|
requestId: string;
|
|
251
266
|
};
|
|
252
267
|
outputFormat: "json";
|
|
253
|
-
status:
|
|
268
|
+
status: 403;
|
|
254
269
|
input: {
|
|
255
270
|
param: {
|
|
256
271
|
address: `0x${string}`;
|
|
@@ -270,14 +285,14 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
270
285
|
} | {
|
|
271
286
|
output: {
|
|
272
287
|
error: {
|
|
273
|
-
code: "
|
|
288
|
+
code: "payment_required" | "rate_limit_exceeded";
|
|
274
289
|
details?: readonly Response.error.Detail[] | undefined;
|
|
275
290
|
message: string;
|
|
276
291
|
};
|
|
277
292
|
requestId: string;
|
|
278
293
|
};
|
|
279
294
|
outputFormat: "json";
|
|
280
|
-
status:
|
|
295
|
+
status: 429;
|
|
281
296
|
input: {
|
|
282
297
|
param: {
|
|
283
298
|
address: `0x${string}`;
|
|
@@ -296,30 +311,15 @@ export declare function addresses(): import("hono/hono-base").HonoBase<App.Envir
|
|
|
296
311
|
};
|
|
297
312
|
} | {
|
|
298
313
|
output: {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
address: `0x${string}`;
|
|
306
|
-
currency: string;
|
|
307
|
-
decimals: number;
|
|
308
|
-
id: string;
|
|
309
|
-
logoUri?: string | undefined;
|
|
310
|
-
name: string;
|
|
311
|
-
symbol: string;
|
|
312
|
-
verified: boolean;
|
|
313
|
-
};
|
|
314
|
-
}[];
|
|
315
|
-
meta?: {
|
|
316
|
-
totalCountCapped: boolean;
|
|
317
|
-
totalCount: number;
|
|
318
|
-
} | undefined;
|
|
319
|
-
nextCursor: string | null;
|
|
314
|
+
error: {
|
|
315
|
+
code: "upstream_error";
|
|
316
|
+
details?: readonly Response.error.Detail[] | undefined;
|
|
317
|
+
message: string;
|
|
318
|
+
};
|
|
319
|
+
requestId: string;
|
|
320
320
|
};
|
|
321
321
|
outputFormat: "json";
|
|
322
|
-
status:
|
|
322
|
+
status: 502;
|
|
323
323
|
input: {
|
|
324
324
|
param: {
|
|
325
325
|
address: `0x${string}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"balances.d.ts","sourceRoot":"","sources":["../../../../src/apps/data/routes/balances.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAA;AAK3C,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;
|
|
1
|
+
{"version":3,"file":"balances.d.ts","sourceRoot":"","sources":["../../../../src/apps/data/routes/balances.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAA;AAE7B,OAAO,KAAK,KAAK,GAAG,MAAM,iBAAiB,CAAA;AAK3C,OAAO,KAAK,QAAQ,MAAM,+BAA+B,CAAA;AAazD,iDAAiD;AACjD,yBAAiB,MAAM,CAAC;IACtB,oDAAoD;IACpD,UAAiB,kBAAkB,CAAC;QAClC,oDAAoD;QAC7C,MAAM,MAAM;;yBAM6D,CAAA;QAEhF,qDAAqD;QAC9C,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;0BAyCf,CAAA;QAEH;;;;;WAKG;QACI,MAAM,OAAO;;;;;;;;;;;;;;;yBA0CnB,CAAA;QAED,sFAAsF;QAC/E,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;yBAUwD,CAAA;KAC9E;CACF;AAED;;;GAGG;AACH,wBAAgB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2CAqFxB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from 'hono';
|
|
2
|
-
import {
|
|
2
|
+
import { Value as core_Value } from 'ox';
|
|
3
3
|
import { Actions } from 'viem/tempo';
|
|
4
4
|
import * as z from 'zod/mini';
|
|
5
5
|
import * as Auth from '../../../internal/Auth.js';
|
|
@@ -9,15 +9,13 @@ import * as OpenApi from '../../../internal/OpenApi.js';
|
|
|
9
9
|
import * as Response from '../../../internal/Response.js';
|
|
10
10
|
import * as Schema from '../../../internal/Schema.js';
|
|
11
11
|
import * as Timing from '../../../internal/Timing.js';
|
|
12
|
-
import * as Value from '../../../internal/Value.js';
|
|
13
12
|
import * as VerifiedTokens from '../../../internal/VerifiedTokens.js';
|
|
14
13
|
import * as FeeAmm from './fee-amm.js';
|
|
15
14
|
import * as Tokens from './tokens.js';
|
|
16
15
|
// TIP-20 tokens are minted by the TIP-20 factory and live at deterministic
|
|
17
16
|
// `0x20c0…`-prefixed addresses (e.g. pathUSD `0x20c0…0000`). The indexer's
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
// non-TIP-20 tokens (which have no resolvable TIP-20 metadata) out of results.
|
|
17
|
+
// balance sources include every Transfer-emitting contract, so discovery
|
|
18
|
+
// filters on this prefix to keep non-TIP-20 tokens out of results.
|
|
21
19
|
const tip20AddressPrefix = '0x20c0';
|
|
22
20
|
/** Zod schemas owned by the balance handlers. */
|
|
23
21
|
export var schema;
|
|
@@ -155,19 +153,6 @@ export function addresses() {
|
|
|
155
153
|
throw cause;
|
|
156
154
|
return undefined;
|
|
157
155
|
});
|
|
158
|
-
// `totalCount` (the number of matching holdings) is opt-in and shares
|
|
159
|
-
// the page's filters; run it concurrently with the page. Best-effort: a
|
|
160
|
-
// count failure omits `meta` rather than failing the page.
|
|
161
|
-
const countPromise = query.include.includes('totalCount')
|
|
162
|
-
? countAddressBalances(c, {
|
|
163
|
-
address,
|
|
164
|
-
chainId,
|
|
165
|
-
currency: query.currency,
|
|
166
|
-
feeEligible,
|
|
167
|
-
feeTokens,
|
|
168
|
-
verified,
|
|
169
|
-
}).catch(() => undefined)
|
|
170
|
-
: undefined;
|
|
171
156
|
const balances = await getAddressBalances(c, {
|
|
172
157
|
address,
|
|
173
158
|
chainId,
|
|
@@ -175,15 +160,12 @@ export function addresses() {
|
|
|
175
160
|
cursor: query.cursor,
|
|
176
161
|
feeEligible,
|
|
177
162
|
feeTokens,
|
|
163
|
+
includeTotalCount: query.include.includes('totalCount'),
|
|
178
164
|
limit: query.limit,
|
|
179
165
|
page: query.page,
|
|
180
166
|
verified,
|
|
181
167
|
});
|
|
182
|
-
|
|
183
|
-
return c.json(Response.validated(schema.getAddressBalances.Response, {
|
|
184
|
-
...balances,
|
|
185
|
-
...(meta ? { meta } : {}),
|
|
186
|
-
}), 200);
|
|
168
|
+
return c.json(Response.validated(schema.getAddressBalances.Response, balances), 200);
|
|
187
169
|
}
|
|
188
170
|
catch (cause) {
|
|
189
171
|
return Response.upstream(c, cause);
|
|
@@ -191,17 +173,10 @@ export function addresses() {
|
|
|
191
173
|
});
|
|
192
174
|
}
|
|
193
175
|
async function getAddressBalances(c, options) {
|
|
194
|
-
const { address, chainId, currency, feeEligible, feeTokens, limit, verified } = options;
|
|
176
|
+
const { address, chainId, currency, feeEligible, feeTokens, includeTotalCount, limit, verified } = options;
|
|
195
177
|
const tidx = c.get('getTidx')(chainId);
|
|
196
|
-
// Keyset pagination on `(balance, token)`: balance is descending and `token`
|
|
197
|
-
// is a stable tiebreaker for the many holdings sharing a balance. A malformed
|
|
198
|
-
// cursor falls back to the head page. Note: because `balance` is mutable, this
|
|
199
|
-
// is best-effort across balance changes (the inherent limit of ranking feeds).
|
|
200
178
|
const cursor = options.cursor ? Cursor.decode(options.cursor, ['uint', 'address']) : undefined;
|
|
201
|
-
|
|
202
|
-
// the head page, so it shares the head's SQL and cache entries; deeper pages
|
|
203
|
-
// translate to a SQL OFFSET of `(page - 1) * limit` rows.
|
|
204
|
-
const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : undefined;
|
|
179
|
+
const offset = options.page !== undefined && options.page > 1 ? (options.page - 1) * limit : 0;
|
|
205
180
|
// Build the optional `token IN (…)` restriction before hitting TIDX. The
|
|
206
181
|
// verified/`currency` filter and the `feeEligible` filter each contribute a set
|
|
207
182
|
// of allowed addresses (`currency` matched case-insensitively so callers can
|
|
@@ -213,90 +188,48 @@ async function getAddressBalances(c, options) {
|
|
|
213
188
|
const allowed = allowedTokens({ currency, feeEligible, feeTokens, snapshot, verified });
|
|
214
189
|
const tokenFilter = allowed?.map((address) => `'${address}'`);
|
|
215
190
|
if (tokenFilter?.length === 0)
|
|
216
|
-
return {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
// snapshot refresh — see the indexer's `address_holder_deltas` MV). The
|
|
223
|
-
// `holder` equality prunes the view by its leading sort key, so this stays
|
|
224
|
-
// a bounded read per request. Fetch one extra row to detect `hasMore`
|
|
225
|
-
// without a separate count query. `startsWith` restricts results to TIP-20
|
|
226
|
-
// tokens (see `tip20AddressPrefix`) before pagination, so `hasMore`/page
|
|
227
|
-
// sizes stay correct and every returned token has resolvable metadata. The
|
|
228
|
-
// inline query is cast to `string` so TIDX treats it as a dynamic
|
|
229
|
-
// ClickHouse query that needs no event signature for the
|
|
230
|
-
// `address_balances` view.
|
|
231
|
-
//
|
|
232
|
-
// Let upstream failures propagate: this is a dedicated endpoint, so a
|
|
233
|
-
// failure should surface as the declared `502` rather than masquerade as
|
|
234
|
-
// an address holding zero tokens.
|
|
235
|
-
const keyset = cursor !== undefined
|
|
236
|
-
? ` AND ${Cursor.keyset([
|
|
237
|
-
{ literal: Cursor.literal(cursor[0], 'uint'), name: 'balance', order: 'desc' },
|
|
238
|
-
{ literal: Cursor.literal(cursor[1], 'address'), name: 'token', order: 'asc' },
|
|
239
|
-
])}`
|
|
240
|
-
: '';
|
|
191
|
+
return {
|
|
192
|
+
data: [],
|
|
193
|
+
...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
|
|
194
|
+
nextCursor: null,
|
|
195
|
+
};
|
|
196
|
+
const holdings = await Timing.time(c, 'balances_discovery', async () => {
|
|
241
197
|
const tokenIn = tokenFilter ? ` AND token IN (${tokenFilter.join(', ')})` : '';
|
|
242
198
|
const result = await tidx.fetch({
|
|
243
199
|
chainId,
|
|
244
200
|
engine: 'clickhouse',
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
// row's exact balance, so any rounding would re-include the cursor
|
|
248
|
-
// row on the next page. Alias is `balance_str` (not `balance`)
|
|
249
|
-
// because TIDX rejects expression aliases that shadow the source
|
|
250
|
-
// column (422).
|
|
201
|
+
// Discovery tolerates stale and reorged rows: RPC removes candidates
|
|
202
|
+
// with no current balance, so avoid the cost of `FINAL` and aggregation.
|
|
251
203
|
query: `
|
|
252
|
-
SELECT token
|
|
253
|
-
FROM
|
|
254
|
-
WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}')
|
|
255
|
-
ORDER BY balance DESC, token ASC
|
|
256
|
-
LIMIT ${limit + 1}${offset !== undefined ? ` OFFSET ${offset}` : ''}
|
|
204
|
+
SELECT DISTINCT token
|
|
205
|
+
FROM address_holder_deltas
|
|
206
|
+
WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}')${tokenIn}
|
|
257
207
|
`,
|
|
258
208
|
});
|
|
259
|
-
|
|
260
|
-
const page = Cursor.paginate({
|
|
261
|
-
rows: result.rows,
|
|
262
|
-
limit,
|
|
263
|
-
key: (row) => {
|
|
264
|
-
const balance = Value.toIntegerString(row['balance_str']);
|
|
265
|
-
const token = Schema.Address.safeParse(row['token']);
|
|
266
|
-
return balance !== undefined && token.success ? [balance, token.data] : undefined;
|
|
267
|
-
},
|
|
268
|
-
});
|
|
269
|
-
const data = [];
|
|
270
|
-
for (const row of page.rows) {
|
|
209
|
+
return result.rows.flatMap((row) => {
|
|
271
210
|
const token = Schema.Address.safeParse(row['token']);
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
data.push({ address: token.data, amount });
|
|
275
|
-
}
|
|
276
|
-
return { data, nextCursor: page.nextCursor };
|
|
211
|
+
return token.success ? [{ address: token.data }] : [];
|
|
212
|
+
});
|
|
277
213
|
});
|
|
278
|
-
if (holdings.
|
|
279
|
-
return {
|
|
214
|
+
if (holdings.length === 0)
|
|
215
|
+
return {
|
|
216
|
+
data: [],
|
|
217
|
+
...(includeTotalCount ? { meta: { totalCount: 0, totalCountCapped: false } } : {}),
|
|
218
|
+
nextCursor: null,
|
|
219
|
+
};
|
|
280
220
|
const client = c.get('getClient')(chainId);
|
|
281
|
-
// TODO: remove once https://github.com/tempoxyz/tidx/commit/2f37b44172d381fd00234ef23f79ed1e1d69c470 deployed.
|
|
282
221
|
const corrected = await Timing.time(c, 'balances_rpc', async () => {
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
continue;
|
|
295
|
-
}
|
|
296
|
-
if (result.result === 0n)
|
|
297
|
-
continue;
|
|
298
|
-
rows.push({ address: holding.address, amount: result.result.toString() });
|
|
299
|
-
}
|
|
222
|
+
// Concurrent reads enter viem's shared batch window and become one
|
|
223
|
+
// deployless multicall. A failed read fails the request rather than serving
|
|
224
|
+
// a stale or partial balance page.
|
|
225
|
+
const results = await Promise.all(holdings.map(async (holding) => {
|
|
226
|
+
const { amount } = await Actions.token.getBalance(client, {
|
|
227
|
+
account: address,
|
|
228
|
+
token: holding.address,
|
|
229
|
+
});
|
|
230
|
+
return amount === 0n ? undefined : { address: holding.address, amount: amount.toString() };
|
|
231
|
+
}));
|
|
232
|
+
const rows = results.filter((holding) => holding !== undefined);
|
|
300
233
|
rows.sort((a, b) => {
|
|
301
234
|
const delta = BigInt(b.amount) - BigInt(a.amount);
|
|
302
235
|
if (delta !== 0n)
|
|
@@ -305,8 +238,27 @@ async function getAddressBalances(c, options) {
|
|
|
305
238
|
});
|
|
306
239
|
return rows;
|
|
307
240
|
});
|
|
308
|
-
|
|
309
|
-
|
|
241
|
+
const positioned = (() => {
|
|
242
|
+
if (!cursor)
|
|
243
|
+
return corrected.slice(offset);
|
|
244
|
+
const amount = BigInt(cursor[0]);
|
|
245
|
+
const address = String(cursor[1]);
|
|
246
|
+
return corrected.filter((holding) => BigInt(holding.amount) < amount ||
|
|
247
|
+
(BigInt(holding.amount) === amount && holding.address > address));
|
|
248
|
+
})();
|
|
249
|
+
const page = Cursor.paginate({
|
|
250
|
+
rows: positioned,
|
|
251
|
+
limit,
|
|
252
|
+
key: (holding) => [holding.amount, holding.address],
|
|
253
|
+
});
|
|
254
|
+
if (page.rows.length === 0)
|
|
255
|
+
return {
|
|
256
|
+
data: [],
|
|
257
|
+
...(includeTotalCount
|
|
258
|
+
? { meta: { totalCount: corrected.length, totalCountCapped: false } }
|
|
259
|
+
: {}),
|
|
260
|
+
nextCursor: page.nextCursor,
|
|
261
|
+
};
|
|
310
262
|
// Resolve token metadata for each balance. The endpoint's contract is a
|
|
311
263
|
// balance with its `token` reference inlined per row (and `formatted` needs
|
|
312
264
|
// the token `decimals`), so a row whose metadata cannot be resolved is
|
|
@@ -317,7 +269,7 @@ async function getAddressBalances(c, options) {
|
|
|
317
269
|
// The verified `snapshot` fetched above is reused across the page instead of
|
|
318
270
|
// re-resolved per row. `createdAt` is not part of this endpoint's response,
|
|
319
271
|
// so it is never fetched here.
|
|
320
|
-
const resolved = await Timing.time(c, 'tokens', () => Promise.all(
|
|
272
|
+
const resolved = await Timing.time(c, 'tokens', () => Promise.all(page.rows.map((holding) => Tokens.resolveToken(c, {
|
|
321
273
|
address: holding.address,
|
|
322
274
|
chainId,
|
|
323
275
|
snapshot,
|
|
@@ -347,7 +299,13 @@ async function getAddressBalances(c, options) {
|
|
|
347
299
|
},
|
|
348
300
|
});
|
|
349
301
|
}
|
|
350
|
-
return {
|
|
302
|
+
return {
|
|
303
|
+
data,
|
|
304
|
+
...(includeTotalCount
|
|
305
|
+
? { meta: { totalCount: corrected.length, totalCountCapped: false } }
|
|
306
|
+
: {}),
|
|
307
|
+
nextCursor: page.nextCursor,
|
|
308
|
+
};
|
|
351
309
|
}
|
|
352
310
|
/**
|
|
353
311
|
* Computes the optional set of allowed token addresses for the page's
|
|
@@ -381,44 +339,4 @@ function allowedTokens(options) {
|
|
|
381
339
|
}
|
|
382
340
|
return allowed;
|
|
383
341
|
}
|
|
384
|
-
/**
|
|
385
|
-
* Exact count of an address's matching TIP-20 holdings, sharing
|
|
386
|
-
* {@link getAddressBalances}'s `holder`/`verified`/`currency` filters (minus
|
|
387
|
-
* pagination) so the count matches the page it annotates. The `holder` equality
|
|
388
|
-
* prunes the `token_balances_snapshot` view by its sort key, so ClickHouse
|
|
389
|
-
* counts via the sparse primary index without a row scan — the count is exact
|
|
390
|
-
* and cheap with no cap (`totalCountCapped` is always `false`), verified at
|
|
391
|
-
* ~370k holdings in <1s. Feeds the opt-in `meta.totalCount`.
|
|
392
|
-
*/
|
|
393
|
-
async function countAddressBalances(c, options) {
|
|
394
|
-
const { address, chainId, currency, feeEligible, feeTokens, verified } = options;
|
|
395
|
-
const tidx = c.get('getTidx')(chainId);
|
|
396
|
-
// Same verified/currency/feeEligible `token IN (…)` restriction as the page; an
|
|
397
|
-
// empty filter means nothing matches, so the count is zero without a round
|
|
398
|
-
// trip.
|
|
399
|
-
const snapshot = await VerifiedTokens.snapshot(c, chainId);
|
|
400
|
-
const allowed = allowedTokens({ currency, feeEligible, feeTokens, snapshot, verified });
|
|
401
|
-
const tokenFilter = allowed?.map((address) => `'${address}'`);
|
|
402
|
-
if (tokenFilter?.length === 0)
|
|
403
|
-
return { totalCountCapped: false, totalCount: 0 };
|
|
404
|
-
const tokenIn = tokenFilter ? ` AND token IN (${tokenFilter.join(', ')})` : '';
|
|
405
|
-
return Timing.time(c, 'address_balances_count', async () => {
|
|
406
|
-
// Exact count over the holder-pruned `address_balances` rows (mirrors the
|
|
407
|
-
// page's WHERE, minus the keyset cursor). The `holder` sort-key prune lets
|
|
408
|
-
// ClickHouse count via the sparse index, so no cap is needed. The inline
|
|
409
|
-
// query is cast to `string` so TIDX treats it as a dynamic ClickHouse
|
|
410
|
-
// query needing no signature.
|
|
411
|
-
const result = await tidx.fetch({
|
|
412
|
-
chainId,
|
|
413
|
-
engine: 'clickhouse',
|
|
414
|
-
query: `
|
|
415
|
-
SELECT count(*) AS total
|
|
416
|
-
FROM address_balances
|
|
417
|
-
WHERE holder = '${address}' AND startsWith(token, '${tip20AddressPrefix}') AND balance > 0${tokenIn}
|
|
418
|
-
`,
|
|
419
|
-
});
|
|
420
|
-
const totalCount = Value.toNumber(result.rows[0]?.['total']) ?? 0;
|
|
421
|
-
return { totalCountCapped: false, totalCount };
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
342
|
//# sourceMappingURL=balances.js.map
|