From 89f7b141d8e612d01455974424a7cef6737523a3 Mon Sep 17 00:00:00 2001 From: Gaubee Date: Sat, 28 Feb 2026 23:47:27 +0800 Subject: [PATCH] fix(bioforest-api): require explicit magic from genesisBlock --- src/services/bioforest-api/client.test.ts | 60 +++++++++++++++++++++++ src/services/bioforest-api/client.ts | 14 ++++-- src/services/bioforest-api/index.ts | 3 +- 3 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 src/services/bioforest-api/client.test.ts diff --git a/src/services/bioforest-api/client.test.ts b/src/services/bioforest-api/client.test.ts new file mode 100644 index 000000000..a2e9fd9de --- /dev/null +++ b/src/services/bioforest-api/client.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from 'vitest' + +import { BioForestApiClient, BioForestApiError } from './client' + +describe('BioForestApiClient.getBalance', () => { + it('uses the provided magic from genesisBlock after trim', async () => { + const requests: Array<{ url: string; init: RequestInit | undefined }> = [] + const fetchFn: typeof fetch = async (input, init) => { + requests.push({ url: String(input), init }) + return new Response( + JSON.stringify({ + success: true, + result: { amount: '100' }, + }), + { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }, + ) + } + + const client = new BioForestApiClient({ + rpcUrl: 'https://walletapi.bfmeta.info', + chainId: 'bfm', + fetch: fetchFn, + }) + + await client.getBalance('b-test', 'BFM', ' LLLQL ') + const request = requests[0] + expect(request?.url).toBe('https://walletapi.bfmeta.info/wallet/bfm/address/balance') + expect(request?.init?.method).toBe('POST') + expect(request?.init?.body).toBe( + JSON.stringify({ + address: 'b-test', + magic: 'LLLQL', + assetType: 'BFM', + }), + ) + }) + + it('throws when magic is empty', async () => { + let called = false + const fetchFn: typeof fetch = async () => { + called = true + return new Response(JSON.stringify({ success: true, result: { amount: '0' } }), { + status: 200, + headers: { 'Content-Type': 'application/json' }, + }) + } + + const client = new BioForestApiClient({ + rpcUrl: 'https://walletapi.bfmeta.info', + chainId: 'bfm', + fetch: fetchFn, + }) + + await expect(client.getBalance('b-test', 'BFM', ' ')).rejects.toBeInstanceOf(BioForestApiError) + expect(called).toBe(false) + }) +}) diff --git a/src/services/bioforest-api/client.ts b/src/services/bioforest-api/client.ts index 52227af40..9715c3a49 100644 --- a/src/services/bioforest-api/client.ts +++ b/src/services/bioforest-api/client.ts @@ -57,7 +57,8 @@ export interface BioForestApiClientConfig { * const block = await client.getLastBlock() * console.log(`Height: ${block.height}`) * - * const balance = await client.getBalance('bXXX...', 'BFM') + * const magic = '...from genesisBlock.magic' + * const balance = await client.getBalance('bXXX...', 'BFM', magic) * console.log(`Balance: ${balance.amount}`) * ``` */ @@ -172,12 +173,17 @@ export class BioForestApiClient { * Get account balance for a specific asset * @param address - Account address * @param assetType - Asset type (e.g., 'BFM') - * @param magic - Chain magic (default: 'nxOGQ' for mainnet) + * @param magic - Chain magic (必须来自 default-config 的 genesisBlock.magic) */ - async getBalance(address: string, assetType: string, magic = 'nxOGQ'): Promise { + async getBalance(address: string, assetType: string, magic: string): Promise { + const chainMagic = magic.trim() + if (!chainMagic) { + throw new BioForestApiError('Chain magic is required. Use default-config genesisBlock.magic.') + } + return this.post('/address/balance', { address, - magic, + magic: chainMagic, assetType, }) } diff --git a/src/services/bioforest-api/index.ts b/src/services/bioforest-api/index.ts index ce582eefb..87c551be4 100644 --- a/src/services/bioforest-api/index.ts +++ b/src/services/bioforest-api/index.ts @@ -20,7 +20,8 @@ * const block = await client.getLastBlock() * * // Get balance - * const balance = await client.getBalance('bXXX...', 'BFM') + * const magic = '...from genesisBlock.magic' + * const balance = await client.getBalance('bXXX...', 'BFM', magic) * * // Check pay password status * const hasTwoStepSecret = await client.hasTwoStepSecret('bXXX...')