) | null = null
@@ -44,7 +46,9 @@ export const handleRequestAccounts: MethodHandler = async (_params, context) =>
throw Object.assign(new Error('Wallet picker not available'), { code: BioErrorCodes.INTERNAL_ERROR })
}
- const wallet = await showWalletPicker()
+ const wallet = await showWalletPicker({
+ app: { name: context.appName, icon: context.appIcon },
+ })
if (!wallet) {
throw Object.assign(new Error('User rejected'), { code: BioErrorCodes.USER_REJECTED })
}
@@ -69,7 +73,10 @@ export const handleSelectAccount: MethodHandler = async (params, context) => {
}
const opts = params as { chain?: string } | undefined
- const wallet = await showWalletPicker(opts)
+ const wallet = await showWalletPicker({
+ ...opts,
+ app: { name: context.appName, icon: context.appIcon },
+ })
if (!wallet) {
throw Object.assign(new Error('User rejected'), { code: BioErrorCodes.USER_REJECTED })
}
@@ -85,7 +92,10 @@ export const handlePickWallet: MethodHandler = async (params, context) => {
}
const opts = params as { chain?: string; exclude?: string } | undefined
- const account = await showWalletPicker(opts)
+ const account = await showWalletPicker({
+ ...opts,
+ app: { name: context.appName, icon: context.appIcon },
+ })
if (!account) {
throw Object.assign(new Error('User rejected'), { code: BioErrorCodes.USER_REJECTED })
}
@@ -106,6 +116,17 @@ export const handleGetBalance: MethodHandler = async (params, _context) => {
throw Object.assign(new Error('Missing address or chain'), { code: BioErrorCodes.INVALID_PARAMS })
}
- // TODO: Query actual balance from chain adapter
- return '0'
+ // Get biowallet API endpoint from chain config
+ const biowalletApi = chainConfigService.getBiowalletApi(opts.chain)
+ if (!biowalletApi) {
+ // Chain doesn't have biowallet API configured, return '0'
+ return '0'
+ }
+
+ try {
+ return await getBioforestBalance(biowalletApi, opts.chain, opts.address)
+ } catch (error) {
+ console.warn('[bio_getBalance] Failed to query balance:', error)
+ return '0'
+ }
}
diff --git a/src/services/ecosystem/provider.ts b/src/services/ecosystem/provider.ts
index e9b5e1d9a..fec07d669 100644
--- a/src/services/ecosystem/provider.ts
+++ b/src/services/ecosystem/provider.ts
@@ -24,8 +24,15 @@ import {
registerTronHandlers,
} from './handlers'
+/** Track if handlers have been registered */
+let initialized = false
+
/** Initialize the Bio provider with all handlers */
export function initBioProvider(): void {
+ // Prevent double initialization
+ if (initialized) return
+ initialized = true
+
// Bio methods (BioChain + wallet features)
bridge.registerHandler('bio_connect', handleConnect)
bridge.registerHandler('bio_closeSplashScreen', handleCloseSplashScreen)
@@ -91,6 +98,10 @@ export function initBioProvider(): void {
})
}
+// Auto-initialize handlers at module load time to prevent race conditions
+// where miniapp calls methods before React useEffect runs
+initBioProvider()
+
/** Get the bridge instance */
export function getBridge() {
return bridge
diff --git a/src/stackflow/activities/sheets/MiniappDestroyConfirmJob.tsx b/src/stackflow/activities/sheets/MiniappDestroyConfirmJob.tsx
index a04825116..086ac3560 100644
--- a/src/stackflow/activities/sheets/MiniappDestroyConfirmJob.tsx
+++ b/src/stackflow/activities/sheets/MiniappDestroyConfirmJob.tsx
@@ -8,16 +8,16 @@ import type { ActivityComponentType } from '@stackflow/react'
import { BottomSheet } from '@/components/layout/bottom-sheet'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
-import { IconFlame, IconAlertTriangle, IconLoader2, IconApps } from '@tabler/icons-react'
+import { IconFlame, IconAlertTriangle, IconLoader2 } from '@tabler/icons-react'
import { useFlow } from '../../stackflow'
import { ActivityParamsProvider, useActivityParams } from '../../hooks'
import { setWalletLockConfirmCallback } from './WalletLockConfirmJob'
import { useCurrentWallet, useChainConfigState, chainConfigSelectors } from '@/stores'
-import { walletStorageService, WalletStorageError, WalletStorageErrorCode } from '@/services/wallet-storage'
import { submitBioforestBurn } from '@/hooks/use-burn.bioforest'
import { Amount } from '@/types/amount'
import { AddressDisplay } from '@/components/wallet/address-display'
import { AmountDisplay } from '@/components/common/amount-display'
+import { MiniappSheetHeader } from '@/components/ecosystem'
type MiniappDestroyConfirmJobParams = {
/** 来源小程序名称 */
@@ -134,21 +134,12 @@ function MiniappDestroyConfirmJobContent() {
{/* Header */}
-
-
- {appIcon ? (
-

- ) : (
-
- )}
-
-
- {t('transaction:destroyPage.title')}
-
-
- {appName || t('common:unknownDApp')} {t('common:requestsDestroy', '请求销毁资产')}
-
-
+
{/* Content */}
diff --git a/src/stackflow/activities/sheets/MiniappSignTransactionJob.tsx b/src/stackflow/activities/sheets/MiniappSignTransactionJob.tsx
index 6c23d57cd..2d937b435 100644
--- a/src/stackflow/activities/sheets/MiniappSignTransactionJob.tsx
+++ b/src/stackflow/activities/sheets/MiniappSignTransactionJob.tsx
@@ -8,13 +8,14 @@ import type { ActivityComponentType } from '@stackflow/react'
import { BottomSheet } from '@/components/layout/bottom-sheet'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
-import { IconApps, IconAlertTriangle, IconLoader2 } from '@tabler/icons-react'
+import { IconAlertTriangle, IconLoader2 } from '@tabler/icons-react'
import { useFlow } from '../../stackflow'
import { ActivityParamsProvider, useActivityParams } from '../../hooks'
import { setWalletLockConfirmCallback } from './WalletLockConfirmJob'
import { walletStore } from '@/stores'
import type { BioUnsignedTransaction } from '@/services/ecosystem'
import { signUnsignedTransaction } from '@/services/ecosystem/handlers'
+import { MiniappSheetHeader } from '@/components/ecosystem'
type MiniappSignTransactionJobParams = {
/** 来源小程序名称 */
@@ -127,19 +128,12 @@ function MiniappSignTransactionJobContent() {
-
-
- {appIcon ? (
-

- ) : (
-
- )}
-
-
{t('signTransaction', '签名交易')}
-
- {appName || t('unknownDApp', '未知 DApp')}
-
-
+
{!unsignedTx && (
diff --git a/src/stackflow/activities/sheets/MiniappTransferConfirmJob.tsx b/src/stackflow/activities/sheets/MiniappTransferConfirmJob.tsx
index b61c16399..5370027d8 100644
--- a/src/stackflow/activities/sheets/MiniappTransferConfirmJob.tsx
+++ b/src/stackflow/activities/sheets/MiniappTransferConfirmJob.tsx
@@ -8,7 +8,7 @@ import type { ActivityComponentType } from '@stackflow/react'
import { BottomSheet } from '@/components/layout/bottom-sheet'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
-import { IconArrowDown, IconAlertTriangle, IconLoader2, IconApps } from '@tabler/icons-react'
+import { IconArrowDown, IconAlertTriangle, IconLoader2 } from '@tabler/icons-react'
import { useFlow } from '../../stackflow'
import { ActivityParamsProvider, useActivityParams } from '../../hooks'
import { setWalletLockConfirmCallback } from './WalletLockConfirmJob'
@@ -16,6 +16,7 @@ import { useCurrentWallet } from '@/stores'
import { SignatureAuthService, plaocAdapter } from '@/services/authorize'
import { AddressDisplay } from '@/components/wallet/address-display'
import { AmountDisplay } from '@/components/common/amount-display'
+import { MiniappSheetHeader } from '@/components/ecosystem'
type MiniappTransferConfirmJobParams = {
/** 来源小程序名称 */
@@ -132,21 +133,12 @@ function MiniappTransferConfirmJobContent() {
{/* Header */}
-
-
- {appIcon ? (
-

- ) : (
-
- )}
-
-
- {t('confirmTransfer', '确认转账')}
-
-
- {appName || t('unknownDApp', '未知 DApp')} {t('requestsTransfer', '请求发送转账')}
-
-
+
{/* Content */}
diff --git a/src/stackflow/activities/sheets/SigningConfirmJob.tsx b/src/stackflow/activities/sheets/SigningConfirmJob.tsx
index fe76edfdb..f8fe0d2a1 100644
--- a/src/stackflow/activities/sheets/SigningConfirmJob.tsx
+++ b/src/stackflow/activities/sheets/SigningConfirmJob.tsx
@@ -8,12 +8,13 @@ import type { ActivityComponentType } from '@stackflow/react'
import { BottomSheet } from '@/components/layout/bottom-sheet'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
-import { IconAlertTriangle, IconLoader2, IconApps } from '@tabler/icons-react'
+import { IconAlertTriangle, IconLoader2 } from '@tabler/icons-react'
import { useFlow } from '../../stackflow'
import { ActivityParamsProvider, useActivityParams } from '../../hooks'
import { setWalletLockConfirmCallback } from './WalletLockConfirmJob'
import { useCurrentWallet } from '@/stores'
import { SignatureAuthService, plaocAdapter } from '@/services/authorize'
+import { MiniappSheetHeader } from '@/components/ecosystem'
import { AddressDisplay } from '@/components/wallet/address-display'
type SigningConfirmJobParams = {
@@ -111,21 +112,12 @@ function SigningConfirmJobContent() {
{/* Header */}
-
-
- {appIcon ? (
-

- ) : (
-
- )}
-
-
- {t('signMessage', '签名请求')}
-
-
- {appName || t('unknownDApp', '未知 DApp')}
-
-
+
{/* Content */}
diff --git a/src/stackflow/activities/sheets/WalletPickerJob.tsx b/src/stackflow/activities/sheets/WalletPickerJob.tsx
index d921cffce..6a74a8d08 100644
--- a/src/stackflow/activities/sheets/WalletPickerJob.tsx
+++ b/src/stackflow/activities/sheets/WalletPickerJob.tsx
@@ -30,7 +30,7 @@ type WalletPickerJobParams = {
* 将任意链标识符转换为 KeyApp 内部 ID
* 支持:
* - EVM hex chainId: '0x38' -> 'binance'
- * - API 名称: 'BSC', 'ETH' -> 'binance', 'ethereum'
+ * - API 名称: 'BSC', 'ETH', 'BFMCHAIN' -> 'binance', 'ethereum', 'bfmeta'
* - 已有的 KeyApp ID: 'binance' -> 'binance'
*/
function resolveChainId(chain: string | undefined): string | undefined {
@@ -42,7 +42,7 @@ function resolveChainId(chain: string | undefined): string | undefined {
if (keyAppId) return keyAppId
}
- // Try API name normalization (e.g., 'BSC' -> 'binance')
+ // Try API name normalization (e.g., 'BSC' -> 'binance', 'BFMCHAIN' -> 'bfmeta')
const normalized = normalizeChainId(chain)
// Check if it's a known chain
@@ -54,6 +54,11 @@ function resolveChainId(chain: string | undefined): string | undefined {
return normalized
}
+/** Get display name for chain ID */
+function getChainDisplayName(chainId: string): string {
+ return CHAIN_DISPLAY_NAMES[chainId] || chainId
+}
+
function WalletPickerJobContent() {
const { t } = useTranslation('common')
const { pop } = useFlow()
diff --git a/turbo.json b/turbo.json
index 9e2fc83b6..66ce27580 100644
--- a/turbo.json
+++ b/turbo.json
@@ -2,7 +2,7 @@
"$schema": "https://turbo.build/schema.json",
"tasks": {
"lint:run": {
- "dependsOn": [],
+ "dependsOn": ["eslint-plugin-file-component-constraints#build"],
"inputs": ["src/**/*.ts", "src/**/*.tsx", ".oxlintrc.json"],
"outputs": [],
"cache": true