From 2e44ba7394a56ac6e8db66fac94346d9b4f3b60e Mon Sep 17 00:00:00 2001 From: dafuga Date: Wed, 4 Mar 2026 10:19:13 +0900 Subject: [PATCH 1/8] Mimic Swift Lighthouse lookup fallback behavior --- src/lib/lookup.ts | 129 ++++++++++++++++++----- src/routes/lookup/[publicKey]/+server.ts | 2 +- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/lib/lookup.ts b/src/lib/lookup.ts index a0153a7..f95fd4c 100644 --- a/src/lib/lookup.ts +++ b/src/lib/lookup.ts @@ -1,38 +1,119 @@ import {APIClient} from '@wharfkit/antelope' -import type {API, PublicKey} from '@wharfkit/antelope' +import type {PublicKey} from '@wharfkit/antelope' import type {PermissionLevelType} from '@wharfkit/antelope' import type {Chain} from './chains' import {logger} from './utils/logger' +const CHAIN_LOOKUP_UNSUPPORTED = new Set([ + '21dcae42c0182200e93f954a074011f9048a7624c6fe81d3c9541a614a88bd1c', + 'b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e', +]) + +const withTimeout = async (promise: Promise, timeoutMs: number): Promise => { + let timeoutId: ReturnType | undefined + const timeoutPromise = new Promise((_resolve, reject) => { + timeoutId = setTimeout(() => { + reject(new Error('Request timed out.')) + }, timeoutMs) + }) + + try { + return await Promise.race([promise, timeoutPromise]) + } finally { + if (timeoutId) { + clearTimeout(timeoutId) + } + } +} + +const chainLookupSupport = (chain: Chain): boolean => !CHAIN_LOOKUP_UNSUPPORTED.has(String(chain.id)) + +const chainLookup = async ( + publicKey: PublicKey, + chain: Chain, + apiClient?: APIClient +): Promise => { + const client = apiClient || new APIClient(chain) + const response = await withTimeout( + client.v1.chain.get_accounts_by_authorizers({ + keys: [publicKey], + }), + 2000 + ) + + return response.accounts.map((account) => ({ + actor: account.account_name, + permission: account.permission_name, + })) +} + +const historyLookup = async ( + publicKey: PublicKey, + chain: Chain, + apiClient?: APIClient +): Promise => { + const client = apiClient || new APIClient(chain) + const targetKey = String(publicKey) + + const keyAccountsResponse = await withTimeout( + client.v1.history.get_key_accounts(publicKey), + 5000 + ) + + const accountNames = + keyAccountsResponse.account_names || + (keyAccountsResponse as unknown as {accountNames?: string[]}).accountNames || + [] + + const resolved = await Promise.all( + accountNames.map((accountName) => + withTimeout(client.v1.chain.get_account(accountName), 5000).catch(() => null) + ) + ) + + const accounts: PermissionLevelType[] = [] + for (const account of resolved) { + if (!account) { + continue + } + + for (const permission of account.permissions) { + const keys = permission.required_auth?.keys || [] + const hasPermission = keys.some((keyPermission) => String(keyPermission.key) === targetKey) + if (hasPermission) { + accounts.push({ + actor: account.account_name, + permission: permission.perm_name, + }) + } + } + } + + return accounts +} + export const networkRequest = ( publicKey: PublicKey, chain: Chain, apiClient?: APIClient ): Promise => { - return new Promise((resolve, reject) => { - const client = apiClient || new APIClient(chain) + return new Promise(async (resolve, reject) => { + try { + if (chainLookupSupport(chain)) { + try { + resolve(await chainLookup(publicKey, chain, apiClient)) + return + } catch (error) { + logger.warn( + `Chain lookup error on ${chain.name}: ${error}, falling back to history API` + ) + } + } - const timeoutId = setTimeout(() => { - reject(new Error('Request timed out.')) - }, 2000) - - client.v1.chain - .get_accounts_by_authorizers({ - keys: [publicKey], - }) - .then((response: API.v1.AccountsByAuthorizers) => { - clearTimeout(timeoutId) - resolve( - response.accounts.map((account) => ({ - actor: account.account_name, - permission: account.permission_name, - })) - ) - }) - .catch((error) => { - clearTimeout(timeoutId) - reject(error) - }) + resolve(await historyLookup(publicKey, chain, apiClient)) + } catch (error) { + reject(error) + } }) } diff --git a/src/routes/lookup/[publicKey]/+server.ts b/src/routes/lookup/[publicKey]/+server.ts index b4b9eb8..80354b5 100644 --- a/src/routes/lookup/[publicKey]/+server.ts +++ b/src/routes/lookup/[publicKey]/+server.ts @@ -8,7 +8,7 @@ import {lookupNetwork} from '$lib/lookup' export const GET = async ({params, url, fetch}: RequestEvent) => { const {publicKey} = params const testnetParam = url.searchParams.get('includeTestnets') - const includeTestnets = testnetParam !== null && testnetParam !== 'false' + const includeTestnets = testnetParam === 'true' if (!publicKey) { throw error(400, {message: 'Public key is required'}) From 58e34c00b08ca897e42ca6211da56cd8805fff60 Mon Sep 17 00:00:00 2001 From: dafuga Date: Wed, 4 Mar 2026 10:54:32 +0900 Subject: [PATCH 2/8] Add test for chain-to-history lookup fallback --- tests/index.test.ts | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/index.test.ts b/tests/index.test.ts index cd0a4b0..e61b36b 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -44,4 +44,42 @@ describe('lookupNetwork', () => { assert.equal(result.chain.name, chain.name) assert.equal(result.accounts.length, 0) }) + + it('should fallback to history lookup when chain lookup fails', async () => { + const publicKey = PublicKey.from(PUBLIC_KEY) + const chain = Chains.Jungle4 + + const stubClient = { + v1: { + chain: { + get_accounts_by_authorizers: async () => { + throw new Error('chain lookup unavailable') + }, + get_account: async (accountName: string) => ({ + account_name: accountName, + permissions: [ + { + perm_name: 'active', + required_auth: { + keys: [{key: publicKey}], + }, + }, + ], + }), + }, + history: { + get_key_accounts: async () => ({ + account_names: ['fallbackacct12'], + }), + }, + }, + } as any + + const result = await lookupNetwork(publicKey, chain, stubClient) + assert.containsAllKeys(result, ['chain', 'accounts']) + assert.equal(result.chain.name, chain.name) + assert.equal(result.accounts.length, 1) + assert.deepEqual(String(result.accounts[0].actor), 'fallbackacct12') + assert.deepEqual(String(result.accounts[0].permission), 'active') + }) }) From ac38716d67cec8e7e11168560ed543316af45dd9 Mon Sep 17 00:00:00 2001 From: dafuga Date: Thu, 5 Mar 2026 19:08:34 +0900 Subject: [PATCH 3/8] Fix CI lint failure in network request lookup --- src/lib/lookup.ts | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/lib/lookup.ts b/src/lib/lookup.ts index f95fd4c..6bf466e 100644 --- a/src/lib/lookup.ts +++ b/src/lib/lookup.ts @@ -26,7 +26,8 @@ const withTimeout = async (promise: Promise, timeoutMs: number): Promise !CHAIN_LOOKUP_UNSUPPORTED.has(String(chain.id)) +const chainLookupSupport = (chain: Chain): boolean => + !CHAIN_LOOKUP_UNSUPPORTED.has(String(chain.id)) const chainLookup = async ( publicKey: PublicKey, @@ -79,7 +80,9 @@ const historyLookup = async ( for (const permission of account.permissions) { const keys = permission.required_auth?.keys || [] - const hasPermission = keys.some((keyPermission) => String(keyPermission.key) === targetKey) + const hasPermission = keys.some( + (keyPermission) => String(keyPermission.key) === targetKey + ) if (hasPermission) { accounts.push({ actor: account.account_name, @@ -92,29 +95,22 @@ const historyLookup = async ( return accounts } -export const networkRequest = ( +export const networkRequest = async ( publicKey: PublicKey, chain: Chain, apiClient?: APIClient ): Promise => { - return new Promise(async (resolve, reject) => { + if (chainLookupSupport(chain)) { try { - if (chainLookupSupport(chain)) { - try { - resolve(await chainLookup(publicKey, chain, apiClient)) - return - } catch (error) { - logger.warn( - `Chain lookup error on ${chain.name}: ${error}, falling back to history API` - ) - } - } - - resolve(await historyLookup(publicKey, chain, apiClient)) + return await chainLookup(publicKey, chain, apiClient) } catch (error) { - reject(error) + logger.warn( + `Chain lookup error on ${chain.name}: ${error}, falling back to history API` + ) } - }) + } + + return await historyLookup(publicKey, chain, apiClient) } export const lookupNetwork = async (publicKey: PublicKey, chain: Chain, apiClient?: APIClient) => { From 134b5ab5e5040accf622e7e5d1af9a2788192f55 Mon Sep 17 00:00:00 2001 From: dafuga Date: Thu, 5 Mar 2026 19:28:08 +0900 Subject: [PATCH 4/8] Update CI to supported Node versions --- .github/workflows/test.yml | 6 +++--- package.json | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c0af562..ea26558 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,16 +6,16 @@ jobs: strategy: fail-fast: false matrix: - node-version: [18, 20] + node-version: [20.19.0, 22.12.0] name: Node.js v${{ matrix.node-version }} steps: - name: Setup Node.js - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install Bun uses: oven-sh/setup-bun@v1 diff --git a/package.json b/package.json index a87fe6c..01dd9b6 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,12 @@ "private": true, "version": "0.0.1", "type": "module", + "engines": { + "node": ">=20.19.0 || >=22.12.0" + }, "scripts": { "dev": "vite dev", - "build": "vite build", + "build": "svelte-kit sync && vite build", "preview": "vite preview", "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", From bb4c2704f7d7459396118fa09e80dd7a7fedf4cd Mon Sep 17 00:00:00 2001 From: dafuga Date: Thu, 5 Mar 2026 21:24:45 +0900 Subject: [PATCH 5/8] Align includeTestnets query param behavior --- src/routes/lookup/[publicKey]/+server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/routes/lookup/[publicKey]/+server.ts b/src/routes/lookup/[publicKey]/+server.ts index 80354b5..b4b9eb8 100644 --- a/src/routes/lookup/[publicKey]/+server.ts +++ b/src/routes/lookup/[publicKey]/+server.ts @@ -8,7 +8,7 @@ import {lookupNetwork} from '$lib/lookup' export const GET = async ({params, url, fetch}: RequestEvent) => { const {publicKey} = params const testnetParam = url.searchParams.get('includeTestnets') - const includeTestnets = testnetParam === 'true' + const includeTestnets = testnetParam !== null && testnetParam !== 'false' if (!publicKey) { throw error(400, {message: 'Public key is required'}) From 8c74a8966a24110049e1987b162bd14f84301fcc Mon Sep 17 00:00:00 2001 From: dafuga Date: Fri, 6 Mar 2026 17:00:01 +0900 Subject: [PATCH 6/8] chore: using correct mock client for new tests --- ...85db31946ddc148c617b8193cf76e22002d1b.json | 17 +++ ...e8c8004eed4b17ae7d19067e734e0df315b2e.json | 107 ++++++++++++++++++ tests/index.test.ts | 41 ++----- 3 files changed, 133 insertions(+), 32 deletions(-) create mode 100644 tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json create mode 100644 tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json diff --git a/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json b/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json new file mode 100644 index 0000000..d86d08b --- /dev/null +++ b/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json @@ -0,0 +1,17 @@ +{ + "request": { + "path": "https://jungle0.greymass.com/v1/history/get_key_accounts", + "params": { + "method": "POST", + "body": "{\"public_key\":\"PUB_K1_65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCZhX7vh\"}", + "headers": {} + } + }, + "status": 200, + "json": { + "account_names": [ + "testerman123" + ] + }, + "text": "{\"account_names\":[\"testerman123\"]}" +} diff --git a/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json b/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json new file mode 100644 index 0000000..d129988 --- /dev/null +++ b/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json @@ -0,0 +1,107 @@ +{ + "request": { + "path": "https://jungle0.greymass.com/v1/chain/get_account", + "params": { + "method": "POST", + "body": "{\"account_name\":\"testerman123\"}", + "headers": {} + } + }, + "status": 200, + "json": { + "account_name": "testerman123", + "head_block_num": 253851242, + "head_block_time": "2026-03-06T07:58:06.000", + "privileged": false, + "last_code_update": "1970-01-01T00:00:00.000", + "created": "2023-10-17T06:01:05.500", + "core_liquid_balance": "89.3921 EOS", + "ram_quota": 5495, + "net_weight": 10000, + "cpu_weight": 10000, + "net_limit": { + "used": 137, + "available": 15278, + "max": 15415, + "last_usage_update_time": "2025-12-19T07:52:37.500", + "current_used": 0 + }, + "cpu_limit": { + "used": 455, + "available": 2411, + "max": 2866, + "last_usage_update_time": "2025-12-19T07:52:37.500", + "current_used": 0 + }, + "ram_usage": 4291, + "permissions": [ + { + "perm_name": "active", + "parent": "owner", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + }, + { + "perm_name": "owner", + "parent": "", + "required_auth": { + "threshold": 1, + "keys": [ + { + "key": "EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf", + "weight": 1 + } + ], + "accounts": [], + "waits": [] + }, + "linked_actions": [] + } + ], + "total_resources": { + "owner": "testerman123", + "net_weight": "1.0000 EOS", + "cpu_weight": "1.0000 EOS", + "ram_bytes": 4095 + }, + "self_delegated_bandwidth": { + "from": "testerman123", + "to": "testerman123", + "net_weight": "1.0000 EOS", + "cpu_weight": "1.0000 EOS" + }, + "refund_request": null, + "voter_info": { + "owner": "testerman123", + "proxy": "", + "producers": [], + "staked": 220000, + "last_vote_weight": "0.00000000000000000", + "proxied_vote_weight": "0.00000000000000000", + "is_proxy": 0, + "flags1": 0, + "reserved2": 0, + "reserved3": "0 " + }, + "rex_info": null, + "subjective_cpu_bill_limit": { + "used": 0, + "available": 0, + "max": 0, + "last_usage_update_time": "2000-01-01T00:00:00.000", + "current_used": 0 + }, + "eosio_any_linked_actions": [] + }, + "text": "{\"account_name\":\"testerman123\",\"head_block_num\":253851242,\"head_block_time\":\"2026-03-06T07:58:06.000\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2023-10-17T06:01:05.500\",\"core_liquid_balance\":\"89.3921 EOS\",\"ram_quota\":5495,\"net_weight\":10000,\"cpu_weight\":10000,\"net_limit\":{\"used\":137,\"available\":15278,\"max\":15415,\"last_usage_update_time\":\"2025-12-19T07:52:37.500\",\"current_used\":0},\"cpu_limit\":{\"used\":455,\"available\":2411,\"max\":2866,\"last_usage_update_time\":\"2025-12-19T07:52:37.500\",\"current_used\":0},\"ram_usage\":4291,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"testerman123\",\"net_weight\":\"1.0000 EOS\",\"cpu_weight\":\"1.0000 EOS\",\"ram_bytes\":4095},\"self_delegated_bandwidth\":{\"from\":\"testerman123\",\"to\":\"testerman123\",\"net_weight\":\"1.0000 EOS\",\"cpu_weight\":\"1.0000 EOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"testerman123\",\"proxy\":\"\",\"producers\":[],\"staked\":220000,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}" +} \ No newline at end of file diff --git a/tests/index.test.ts b/tests/index.test.ts index e61b36b..ef144ed 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -38,7 +38,7 @@ describe('lookupNetwork', () => { const result = await lookupNetwork( publicKey, chain, - makeClient('https://jungle0.greymass.com') + makeClient('https://jungle9.greymass.com') ) assert.containsAllKeys(result, ['chain', 'accounts']) assert.equal(result.chain.name, chain.name) @@ -48,38 +48,15 @@ describe('lookupNetwork', () => { it('should fallback to history lookup when chain lookup fails', async () => { const publicKey = PublicKey.from(PUBLIC_KEY) const chain = Chains.Jungle4 - - const stubClient = { - v1: { - chain: { - get_accounts_by_authorizers: async () => { - throw new Error('chain lookup unavailable') - }, - get_account: async (accountName: string) => ({ - account_name: accountName, - permissions: [ - { - perm_name: 'active', - required_auth: { - keys: [{key: publicKey}], - }, - }, - ], - }), - }, - history: { - get_key_accounts: async () => ({ - account_names: ['fallbackacct12'], - }), - }, - }, - } as any - - const result = await lookupNetwork(publicKey, chain, stubClient) + const result = await lookupNetwork( + publicKey, + chain, + makeClient('https://jungle0.greymass.com') + ) assert.containsAllKeys(result, ['chain', 'accounts']) assert.equal(result.chain.name, chain.name) - assert.equal(result.accounts.length, 1) - assert.deepEqual(String(result.accounts[0].actor), 'fallbackacct12') - assert.deepEqual(String(result.accounts[0].permission), 'active') + assert.equal(result.accounts.length, 2) + assert.deepEqual(String(result.accounts[0].actor), 'testerman123') + assert.isTrue(result.accounts.some((account) => String(account.permission) === 'active')) }) }) From c5fd41f937c4cca7a92189728a884b42360a14a8 Mon Sep 17 00:00:00 2001 From: dafuga Date: Fri, 6 Mar 2026 17:12:25 +0900 Subject: [PATCH 7/8] chore: make swift parity timeouts explicit --- src/lib/lookup.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/lib/lookup.ts b/src/lib/lookup.ts index 6bf466e..a942a97 100644 --- a/src/lib/lookup.ts +++ b/src/lib/lookup.ts @@ -9,6 +9,11 @@ const CHAIN_LOOKUP_UNSUPPORTED = new Set([ 'b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e', ]) +// Keep timeout behavior aligned with the Swift Lighthouse implementation. +const CHAIN_LOOKUP_TIMEOUT_MS = 2000 +const HISTORY_KEY_ACCOUNTS_TIMEOUT_MS = 5000 +const HISTORY_GET_ACCOUNT_TIMEOUT_MS = 5000 + const withTimeout = async (promise: Promise, timeoutMs: number): Promise => { let timeoutId: ReturnType | undefined const timeoutPromise = new Promise((_resolve, reject) => { @@ -39,7 +44,7 @@ const chainLookup = async ( client.v1.chain.get_accounts_by_authorizers({ keys: [publicKey], }), - 2000 + CHAIN_LOOKUP_TIMEOUT_MS ) return response.accounts.map((account) => ({ @@ -58,7 +63,7 @@ const historyLookup = async ( const keyAccountsResponse = await withTimeout( client.v1.history.get_key_accounts(publicKey), - 5000 + HISTORY_KEY_ACCOUNTS_TIMEOUT_MS ) const accountNames = @@ -68,7 +73,10 @@ const historyLookup = async ( const resolved = await Promise.all( accountNames.map((accountName) => - withTimeout(client.v1.chain.get_account(accountName), 5000).catch(() => null) + withTimeout( + client.v1.chain.get_account(accountName), + HISTORY_GET_ACCOUNT_TIMEOUT_MS + ).catch(() => null) ) ) From a6bf5ecdd383d597d842b6cf3ecd44b2b70cf57d Mon Sep 17 00:00:00 2001 From: dafuga Date: Fri, 6 Mar 2026 21:46:41 +0900 Subject: [PATCH 8/8] Revert history fallback and restore chain-only lookup --- src/lib/lookup.ts | 74 +----------- ...85db31946ddc148c617b8193cf76e22002d1b.json | 17 --- ...e8c8004eed4b17ae7d19067e734e0df315b2e.json | 107 ------------------ tests/index.test.ts | 15 --- 4 files changed, 2 insertions(+), 211 deletions(-) delete mode 100644 tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json delete mode 100644 tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json diff --git a/src/lib/lookup.ts b/src/lib/lookup.ts index a942a97..d1b8899 100644 --- a/src/lib/lookup.ts +++ b/src/lib/lookup.ts @@ -4,15 +4,8 @@ import type {PermissionLevelType} from '@wharfkit/antelope' import type {Chain} from './chains' import {logger} from './utils/logger' -const CHAIN_LOOKUP_UNSUPPORTED = new Set([ - '21dcae42c0182200e93f954a074011f9048a7624c6fe81d3c9541a614a88bd1c', - 'b20901380af44ef59c5918439a1f9a41d83669020319a80574b804a5f95cbd7e', -]) - -// Keep timeout behavior aligned with the Swift Lighthouse implementation. +// Keep chain lookup timeout behavior aligned with previous production behavior. const CHAIN_LOOKUP_TIMEOUT_MS = 2000 -const HISTORY_KEY_ACCOUNTS_TIMEOUT_MS = 5000 -const HISTORY_GET_ACCOUNT_TIMEOUT_MS = 5000 const withTimeout = async (promise: Promise, timeoutMs: number): Promise => { let timeoutId: ReturnType | undefined @@ -31,9 +24,6 @@ const withTimeout = async (promise: Promise, timeoutMs: number): Promise - !CHAIN_LOOKUP_UNSUPPORTED.has(String(chain.id)) - const chainLookup = async ( publicKey: PublicKey, chain: Chain, @@ -53,72 +43,12 @@ const chainLookup = async ( })) } -const historyLookup = async ( - publicKey: PublicKey, - chain: Chain, - apiClient?: APIClient -): Promise => { - const client = apiClient || new APIClient(chain) - const targetKey = String(publicKey) - - const keyAccountsResponse = await withTimeout( - client.v1.history.get_key_accounts(publicKey), - HISTORY_KEY_ACCOUNTS_TIMEOUT_MS - ) - - const accountNames = - keyAccountsResponse.account_names || - (keyAccountsResponse as unknown as {accountNames?: string[]}).accountNames || - [] - - const resolved = await Promise.all( - accountNames.map((accountName) => - withTimeout( - client.v1.chain.get_account(accountName), - HISTORY_GET_ACCOUNT_TIMEOUT_MS - ).catch(() => null) - ) - ) - - const accounts: PermissionLevelType[] = [] - for (const account of resolved) { - if (!account) { - continue - } - - for (const permission of account.permissions) { - const keys = permission.required_auth?.keys || [] - const hasPermission = keys.some( - (keyPermission) => String(keyPermission.key) === targetKey - ) - if (hasPermission) { - accounts.push({ - actor: account.account_name, - permission: permission.perm_name, - }) - } - } - } - - return accounts -} - export const networkRequest = async ( publicKey: PublicKey, chain: Chain, apiClient?: APIClient ): Promise => { - if (chainLookupSupport(chain)) { - try { - return await chainLookup(publicKey, chain, apiClient) - } catch (error) { - logger.warn( - `Chain lookup error on ${chain.name}: ${error}, falling back to history API` - ) - } - } - - return await historyLookup(publicKey, chain, apiClient) + return await chainLookup(publicKey, chain, apiClient) } export const lookupNetwork = async (publicKey: PublicKey, chain: Chain, apiClient?: APIClient) => { diff --git a/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json b/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json deleted file mode 100644 index d86d08b..0000000 --- a/tests/data/requests/23f85db31946ddc148c617b8193cf76e22002d1b.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "request": { - "path": "https://jungle0.greymass.com/v1/history/get_key_accounts", - "params": { - "method": "POST", - "body": "{\"public_key\":\"PUB_K1_65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCZhX7vh\"}", - "headers": {} - } - }, - "status": 200, - "json": { - "account_names": [ - "testerman123" - ] - }, - "text": "{\"account_names\":[\"testerman123\"]}" -} diff --git a/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json b/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json deleted file mode 100644 index d129988..0000000 --- a/tests/data/requests/f40e8c8004eed4b17ae7d19067e734e0df315b2e.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "request": { - "path": "https://jungle0.greymass.com/v1/chain/get_account", - "params": { - "method": "POST", - "body": "{\"account_name\":\"testerman123\"}", - "headers": {} - } - }, - "status": 200, - "json": { - "account_name": "testerman123", - "head_block_num": 253851242, - "head_block_time": "2026-03-06T07:58:06.000", - "privileged": false, - "last_code_update": "1970-01-01T00:00:00.000", - "created": "2023-10-17T06:01:05.500", - "core_liquid_balance": "89.3921 EOS", - "ram_quota": 5495, - "net_weight": 10000, - "cpu_weight": 10000, - "net_limit": { - "used": 137, - "available": 15278, - "max": 15415, - "last_usage_update_time": "2025-12-19T07:52:37.500", - "current_used": 0 - }, - "cpu_limit": { - "used": 455, - "available": 2411, - "max": 2866, - "last_usage_update_time": "2025-12-19T07:52:37.500", - "current_used": 0 - }, - "ram_usage": 4291, - "permissions": [ - { - "perm_name": "active", - "parent": "owner", - "required_auth": { - "threshold": 1, - "keys": [ - { - "key": "EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf", - "weight": 1 - } - ], - "accounts": [], - "waits": [] - }, - "linked_actions": [] - }, - { - "perm_name": "owner", - "parent": "", - "required_auth": { - "threshold": 1, - "keys": [ - { - "key": "EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf", - "weight": 1 - } - ], - "accounts": [], - "waits": [] - }, - "linked_actions": [] - } - ], - "total_resources": { - "owner": "testerman123", - "net_weight": "1.0000 EOS", - "cpu_weight": "1.0000 EOS", - "ram_bytes": 4095 - }, - "self_delegated_bandwidth": { - "from": "testerman123", - "to": "testerman123", - "net_weight": "1.0000 EOS", - "cpu_weight": "1.0000 EOS" - }, - "refund_request": null, - "voter_info": { - "owner": "testerman123", - "proxy": "", - "producers": [], - "staked": 220000, - "last_vote_weight": "0.00000000000000000", - "proxied_vote_weight": "0.00000000000000000", - "is_proxy": 0, - "flags1": 0, - "reserved2": 0, - "reserved3": "0 " - }, - "rex_info": null, - "subjective_cpu_bill_limit": { - "used": 0, - "available": 0, - "max": 0, - "last_usage_update_time": "2000-01-01T00:00:00.000", - "current_used": 0 - }, - "eosio_any_linked_actions": [] - }, - "text": "{\"account_name\":\"testerman123\",\"head_block_num\":253851242,\"head_block_time\":\"2026-03-06T07:58:06.000\",\"privileged\":false,\"last_code_update\":\"1970-01-01T00:00:00.000\",\"created\":\"2023-10-17T06:01:05.500\",\"core_liquid_balance\":\"89.3921 EOS\",\"ram_quota\":5495,\"net_weight\":10000,\"cpu_weight\":10000,\"net_limit\":{\"used\":137,\"available\":15278,\"max\":15415,\"last_usage_update_time\":\"2025-12-19T07:52:37.500\",\"current_used\":0},\"cpu_limit\":{\"used\":455,\"available\":2411,\"max\":2866,\"last_usage_update_time\":\"2025-12-19T07:52:37.500\",\"current_used\":0},\"ram_usage\":4291,\"permissions\":[{\"perm_name\":\"active\",\"parent\":\"owner\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]},{\"perm_name\":\"owner\",\"parent\":\"\",\"required_auth\":{\"threshold\":1,\"keys\":[{\"key\":\"EOS65BFgzcH8uZW837HqadGcREfNViBV6Fqc1LsmwcWdfUCayHQzf\",\"weight\":1}],\"accounts\":[],\"waits\":[]},\"linked_actions\":[]}],\"total_resources\":{\"owner\":\"testerman123\",\"net_weight\":\"1.0000 EOS\",\"cpu_weight\":\"1.0000 EOS\",\"ram_bytes\":4095},\"self_delegated_bandwidth\":{\"from\":\"testerman123\",\"to\":\"testerman123\",\"net_weight\":\"1.0000 EOS\",\"cpu_weight\":\"1.0000 EOS\"},\"refund_request\":null,\"voter_info\":{\"owner\":\"testerman123\",\"proxy\":\"\",\"producers\":[],\"staked\":220000,\"last_vote_weight\":\"0.00000000000000000\",\"proxied_vote_weight\":\"0.00000000000000000\",\"is_proxy\":0,\"flags1\":0,\"reserved2\":0,\"reserved3\":\"0 \"},\"rex_info\":null,\"subjective_cpu_bill_limit\":{\"used\":0,\"available\":0,\"max\":0,\"last_usage_update_time\":\"2000-01-01T00:00:00.000\",\"current_used\":0},\"eosio_any_linked_actions\":[]}" -} \ No newline at end of file diff --git a/tests/index.test.ts b/tests/index.test.ts index ef144ed..ee16b81 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -44,19 +44,4 @@ describe('lookupNetwork', () => { assert.equal(result.chain.name, chain.name) assert.equal(result.accounts.length, 0) }) - - it('should fallback to history lookup when chain lookup fails', async () => { - const publicKey = PublicKey.from(PUBLIC_KEY) - const chain = Chains.Jungle4 - const result = await lookupNetwork( - publicKey, - chain, - makeClient('https://jungle0.greymass.com') - ) - assert.containsAllKeys(result, ['chain', 'accounts']) - assert.equal(result.chain.name, chain.name) - assert.equal(result.accounts.length, 2) - assert.deepEqual(String(result.accounts[0].actor), 'testerman123') - assert.isTrue(result.accounts.some((account) => String(account.permission) === 'active')) - }) })