Skip to content

Commit d02e3f1

Browse files
committed
fix(miniapps): 修复 PR #142/#143 review 发现的问题
P0 高风险修复: - Teleport: signTransData 改用 signedTx.data(RLP encoded rawTx)而非 signature - Forge: 添加 bio_getPublicKey API 框架(含回退机制) P1 中风险修复: - Forge E2E mock: 使用正确的 endpoint 路径 /cot/recharge/support 和 /cot/recharge/V2 - Forge API config: 改为 fail-fast 策略,未配置 VITE_COT_API_BASE_URL 时报错 P2 改进: - Teleport types.ts: 添加 @bnqkl 包使用说明注释 详细变更: - packages/bio-sdk: 添加 bio_getPublicKey 方法定义 - src/services/ecosystem: 添加 handleGetPublicKey handler(待完整实现) - miniapps/forge: useForge 调用 bio_getPublicKey,失败时回退到 address - miniapps/forge: 更新测试以包含新的 API 调用 - miniapps/teleport: 修正 signTransData 数据源并添加说明注释
1 parent f1b7463 commit d02e3f1

File tree

10 files changed

+98
-13
lines changed

10 files changed

+98
-13
lines changed

miniapps/forge/e2e/ui.spec.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import { UI_TEXT } from './helpers/i18n'
33

44
const mockApiResponses = `
55
// Mock fetch for API calls
6+
// Real endpoints: /cot/recharge/support, /cot/recharge/V2
67
const originalFetch = window.fetch
78
window.fetch = async (url, options) => {
8-
if (url.includes('getSupport')) {
9+
const urlStr = typeof url === 'string' ? url : url.toString()
10+
11+
// Match real endpoint: /cot/recharge/support
12+
if (urlStr.includes('/cot/recharge/support') || urlStr.includes('/recharge/support')) {
913
return {
1014
ok: true,
1115
json: () => Promise.resolve({
@@ -24,7 +28,8 @@ const mockApiResponses = `
2428
}),
2529
}
2630
}
27-
if (url.includes('rechargeV2')) {
31+
// Match real endpoint: /cot/recharge/V2
32+
if (urlStr.includes('/cot/recharge/V2') || urlStr.includes('/recharge/V2')) {
2833
return {
2934
ok: true,
3035
json: () => Promise.resolve({ orderId: 'order-123456' }),

miniapps/forge/src/api/config.ts

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,28 @@
11
/**
22
* API Configuration
3-
* TODO: Base URL needs to be confirmed with backend team
3+
*
4+
* IMPORTANT: Base URL must be configured via VITE_COT_API_BASE_URL environment variable.
5+
* The COT Recharge API host has not been confirmed - do not use a hardcoded default.
46
*/
57

6-
/** API Base URL - to be configured via environment or runtime */
7-
export const API_BASE_URL = import.meta.env.VITE_COT_API_BASE_URL || 'https://api.eth-metaverse.com'
8+
/** API Base URL - must be configured via environment variable */
9+
function getApiBaseUrl(): string {
10+
const url = import.meta.env.VITE_COT_API_BASE_URL
11+
if (!url) {
12+
// Fail-fast in development to catch missing configuration early
13+
if (import.meta.env.DEV) {
14+
console.error(
15+
'[Forge API] VITE_COT_API_BASE_URL is not configured. ' +
16+
'Please set this environment variable to the COT Recharge API base URL.'
17+
)
18+
}
19+
// Return empty string - API calls will fail with clear error
20+
return ''
21+
}
22+
return url
23+
}
24+
25+
export const API_BASE_URL = getApiBaseUrl()
826

927
/** API Endpoints */
1028
export const API_ENDPOINTS = {

miniapps/forge/src/hooks/useForge.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ describe('useForge', () => {
4949
.mockResolvedValueOnce({ txHash: 'unsigned123' }) // bio_createTransaction
5050
.mockResolvedValueOnce({ data: '0xsigned123' }) // bio_signTransaction
5151
.mockResolvedValueOnce('signature123') // bio_signMessage
52+
.mockRejectedValueOnce(new Error('UNSUPPORTED_METHOD')) // bio_getPublicKey (not implemented yet)
5253

5354
vi.mocked(rechargeApi.submitRecharge).mockResolvedValue({ orderId: 'order123' })
5455

@@ -66,8 +67,8 @@ describe('useForge', () => {
6667
expect(result.current.orderId).toBe('order123')
6768
expect(result.current.error).toBeNull()
6869

69-
// Verify API calls
70-
expect(mockBio.request).toHaveBeenCalledTimes(3)
70+
// Verify API calls (4 calls: createTx, signTx, signMessage, getPublicKey)
71+
expect(mockBio.request).toHaveBeenCalledTimes(4)
7172
expect(rechargeApi.submitRecharge).toHaveBeenCalledTimes(1)
7273
})
7374

@@ -127,6 +128,7 @@ describe('useForge', () => {
127128
.mockResolvedValueOnce({ txHash: 'unsigned123' })
128129
.mockResolvedValueOnce({ data: '0xsigned123' })
129130
.mockResolvedValueOnce('signature123')
131+
.mockRejectedValueOnce(new Error('UNSUPPORTED_METHOD')) // bio_getPublicKey
130132

131133
vi.mocked(rechargeApi.submitRecharge).mockRejectedValue(new Error('Server error'))
132134

@@ -170,6 +172,7 @@ describe('useForge', () => {
170172
.mockResolvedValueOnce({ txHash: 'unsigned' })
171173
.mockResolvedValueOnce({ data: '0xsignedEthTx' })
172174
.mockResolvedValueOnce('sig')
175+
.mockRejectedValueOnce(new Error('UNSUPPORTED_METHOD')) // bio_getPublicKey
173176

174177
vi.mocked(rechargeApi.submitRecharge).mockResolvedValue({ orderId: 'order' })
175178

@@ -193,6 +196,7 @@ describe('useForge', () => {
193196
.mockResolvedValueOnce({ txHash: 'unsigned' })
194197
.mockResolvedValueOnce({ data: '0xsignedBscTx' })
195198
.mockResolvedValueOnce('sig')
199+
.mockRejectedValueOnce(new Error('UNSUPPORTED_METHOD')) // bio_getPublicKey
196200

197201
vi.mocked(rechargeApi.submitRecharge).mockResolvedValue({ orderId: 'order' })
198202

miniapps/forge/src/hooks/useForge.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -135,12 +135,27 @@ export function useForge() {
135135
}],
136136
})
137137

138-
// Build signature info
139-
// Note: publicKey format needs to be confirmed with backend
138+
// Get public key for signature verification
139+
// Note: publicKey format (hex/base58) needs to be confirmed with backend
140+
let publicKey: string
141+
try {
142+
publicKey = await window.bio.request<string>({
143+
method: 'bio_getPublicKey',
144+
params: [{ address: internalAccount.address }],
145+
})
146+
} catch (err) {
147+
// bio_getPublicKey not yet implemented - this is a known limitation
148+
// Backend integration will fail until this is resolved
149+
console.warn('[useForge] bio_getPublicKey failed, using address as fallback:', err)
150+
// Fallback: use address (will likely fail backend verification)
151+
// TODO: Remove this fallback once bio_getPublicKey is fully implemented
152+
publicKey = internalAccount.address
153+
}
154+
140155
const signatureInfo: SignatureInfo = {
141156
timestamp: rechargeMessage.timestamp,
142157
signature,
143-
publicKey: internalAccount.address, // TODO: Get actual public key
158+
publicKey,
144159
}
145160

146161
// Step 3: Submit recharge request

miniapps/teleport/src/App.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,13 +179,18 @@ export default function App() {
179179
})
180180

181181
// 3. 构造 fromTrJson(根据链类型)
182+
// 注意:signTransData 需要使用 signedTx.data(RLP encoded raw signed tx),
183+
// 而非 signedTx.signature(仅包含 r+s,不是可广播的 rawTx)
182184
const fromTrJson: FromTrJson = {}
183185
const chainLower = sourceAccount.chain.toLowerCase()
186+
const signTransData = typeof signedTx.data === 'string'
187+
? signedTx.data
188+
: JSON.stringify(signedTx.data)
184189

185190
if (chainLower === 'eth') {
186-
fromTrJson.eth = { signTransData: signedTx.signature }
191+
fromTrJson.eth = { signTransData }
187192
} else if (chainLower === 'bsc') {
188-
fromTrJson.bsc = { signTransData: signedTx.signature }
193+
fromTrJson.bsc = { signTransData }
189194
} else {
190195
// 内链交易
191196
fromTrJson.bcf = {

miniapps/teleport/src/api/types.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
/**
22
* Teleport API Types
3-
* 基于 @bnqkl/metabox-core@0.5.2 类型定义
3+
*
4+
* 类型定义参考 @bnqkl/metabox-core@0.5.2 和 @bnqkl/wallet-typings@0.23.8
5+
* 注意:这些包在 package.json 中作为依赖存在,但当前未被直接 import 使用。
6+
* 如果不需要运行时依赖,可以考虑移至 devDependencies 或移除。
47
*/
58

69
// 链名类型

packages/bio-sdk/src/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ export interface BioMethods {
8080
/** Pick another wallet address (shows wallet picker UI) */
8181
bio_pickWallet: (opts?: { chain?: string; exclude?: string }) => Promise<BioAccount>
8282

83+
/** Get public key for an address (hex encoded) */
84+
bio_getPublicKey: (params: { address: string }) => Promise<string>
85+
8386
/** Sign a message */
8487
bio_signMessage: (params: { message: string; address: string }) => Promise<string>
8588

src/services/ecosystem/handlers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export {
1212
handlePickWallet,
1313
handleChainId,
1414
handleGetBalance,
15+
handleGetPublicKey,
1516
setWalletPicker,
1617
setGetAccounts,
1718
} from './wallet'

src/services/ecosystem/handlers/wallet.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,3 +109,31 @@ export const handleGetBalance: MethodHandler = async (params, _context) => {
109109
// TODO: Query actual balance from chain adapter
110110
return '0'
111111
}
112+
113+
/** bio_getPublicKey - Get public key for an address */
114+
export const handleGetPublicKey: MethodHandler = async (params, context) => {
115+
const opts = params as { address?: string } | undefined
116+
if (!opts?.address) {
117+
throw Object.assign(new Error('Missing address'), { code: BioErrorCodes.INVALID_PARAMS })
118+
}
119+
120+
const getConnectedAccounts = getAccountsGetter(context.appId)
121+
if (!getConnectedAccounts) {
122+
throw Object.assign(new Error('Not connected'), { code: BioErrorCodes.UNAUTHORIZED })
123+
}
124+
125+
const accounts = getConnectedAccounts()
126+
const account = accounts.find(a => a.address.toLowerCase() === opts.address!.toLowerCase())
127+
if (!account) {
128+
throw Object.assign(new Error('Address not found in connected accounts'), { code: BioErrorCodes.UNAUTHORIZED })
129+
}
130+
131+
// TODO: Retrieve actual public key from wallet store
132+
// For BioForest chains, the public key can be derived from the mnemonic
133+
// For now, this returns a placeholder - needs to be implemented with wallet integration
134+
// The public key format should be confirmed with the backend (hex, base58, etc.)
135+
throw Object.assign(
136+
new Error('bio_getPublicKey not yet implemented - requires wallet store integration'),
137+
{ code: BioErrorCodes.UNSUPPORTED_METHOD }
138+
)
139+
}

src/services/ecosystem/provider.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
handlePickWallet,
1414
handleChainId,
1515
handleGetBalance,
16+
handleGetPublicKey,
1617
handleSignMessage,
1718
handleSignTypedData,
1819
handleCreateTransaction,
@@ -30,6 +31,7 @@ export function initBioProvider(): void {
3031
bridge.registerHandler('bio_pickWallet', handlePickWallet)
3132
bridge.registerHandler('bio_chainId', handleChainId)
3233
bridge.registerHandler('bio_getBalance', handleGetBalance)
34+
bridge.registerHandler('bio_getPublicKey', handleGetPublicKey)
3335

3436
// Signing methods
3537
bridge.registerHandler('bio_signMessage', handleSignMessage)
@@ -50,6 +52,7 @@ export function initBioProvider(): void {
5052
'bio_pickWallet',
5153
'bio_chainId',
5254
'bio_getBalance',
55+
'bio_getPublicKey',
5356
'bio_signMessage',
5457
'bio_signTypedData',
5558
'bio_createTransaction',

0 commit comments

Comments
 (0)