@onekeyfe/hd-core 1.1.2-alpha.0 → 1.1.2-alpha.2
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/api/BaseMethod.d.ts +2 -0
- package/dist/api/BaseMethod.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddress.d.ts +4 -28
- package/dist/api/allnetwork/AllNetworkGetAddress.d.ts.map +1 -1
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts +46 -0
- package/dist/api/allnetwork/AllNetworkGetAddressBase.d.ts.map +1 -0
- package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts +8 -0
- package/dist/api/allnetwork/AllNetworkGetAddressByLoop.d.ts.map +1 -0
- package/dist/api/cosmos/CosmosGetPublicKey.d.ts +1 -1
- package/dist/api/cosmos/CosmosGetPublicKey.d.ts.map +1 -1
- package/dist/api/evm/EVMGetPublicKey.d.ts +1 -0
- package/dist/api/evm/EVMGetPublicKey.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/core/RequestQueue.d.ts +4 -0
- package/dist/core/RequestQueue.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -2
- package/dist/core/index.d.ts.map +1 -1
- package/dist/device/Device.d.ts +1 -0
- package/dist/device/Device.d.ts.map +1 -1
- package/dist/events/call.d.ts +9 -0
- package/dist/events/call.d.ts.map +1 -1
- package/dist/events/core.d.ts +2 -2
- package/dist/events/core.d.ts.map +1 -1
- package/dist/events/iframe.d.ts +11 -1
- package/dist/events/iframe.d.ts.map +1 -1
- package/dist/index.d.ts +39 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +272 -104
- package/dist/inject.d.ts +3 -0
- package/dist/inject.d.ts.map +1 -1
- package/dist/types/api/allNetworkGetAddress.d.ts +11 -1
- package/dist/types/api/allNetworkGetAddress.d.ts.map +1 -1
- package/dist/types/api/evmGetPublicKey.d.ts +1 -0
- package/dist/types/api/evmGetPublicKey.d.ts.map +1 -1
- package/dist/types/api/index.d.ts +2 -1
- package/dist/types/api/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/BaseMethod.ts +3 -0
- package/src/api/allnetwork/AllNetworkGetAddress.ts +5 -407
- package/src/api/allnetwork/AllNetworkGetAddressBase.ts +427 -0
- package/src/api/allnetwork/AllNetworkGetAddressByLoop.ts +104 -0
- package/src/api/cosmos/CosmosGetPublicKey.ts +1 -1
- package/src/api/evm/EVMGetPublicKey.ts +9 -3
- package/src/api/index.ts +1 -0
- package/src/core/RequestQueue.ts +26 -0
- package/src/core/index.ts +28 -2
- package/src/device/Device.ts +14 -0
- package/src/events/call.ts +10 -0
- package/src/events/core.ts +7 -1
- package/src/events/iframe.ts +12 -1
- package/src/index.ts +2 -1
- package/src/inject.ts +47 -0
- package/src/types/api/allNetworkGetAddress.ts +17 -1
- package/src/types/api/evmGetPublicKey.ts +1 -0
- package/src/types/api/index.ts +2 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
import { ERRORS, HardwareError, HardwareErrorCode } from '@onekeyfe/hd-shared';
|
|
3
|
+
|
|
4
|
+
import { serializedPath } from '../helpers/pathUtils';
|
|
5
|
+
import { BaseMethod } from '../BaseMethod';
|
|
6
|
+
import { validateParams } from '../helpers/paramsValidator';
|
|
7
|
+
import { CoreApi } from '../../types';
|
|
8
|
+
import type {
|
|
9
|
+
AllNetworkAddressParams,
|
|
10
|
+
INetwork,
|
|
11
|
+
AllNetworkAddress,
|
|
12
|
+
CommonResponseParams,
|
|
13
|
+
} from '../../types/api/allNetworkGetAddress';
|
|
14
|
+
import { PROTO } from '../../constants';
|
|
15
|
+
|
|
16
|
+
import { findMethod } from '../utils';
|
|
17
|
+
import { IFRAME } from '../../events';
|
|
18
|
+
import { getDeviceFirmwareVersion, getMethodVersionRange } from '../../utils';
|
|
19
|
+
import { Device } from '../../device/Device';
|
|
20
|
+
import { UI_REQUEST } from '../../constants/ui-request';
|
|
21
|
+
|
|
22
|
+
const Mainnet = 'mainnet';
|
|
23
|
+
|
|
24
|
+
export type NetworkConfig = {
|
|
25
|
+
methodName: keyof CoreApi;
|
|
26
|
+
getParams?: (baseParams: AllNetworkAddressParams, chainName?: string, methodName?: string) => any;
|
|
27
|
+
dependOnMethodName?: (keyof CoreApi)[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type INetworkReal = Exclude<INetwork, 'tbtc' | 'bch' | 'doge' | 'ltc' | 'neurai'>;
|
|
31
|
+
|
|
32
|
+
export type NetworkConfigMap = {
|
|
33
|
+
[K in INetworkReal]: NetworkConfig;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const networkAliases: {
|
|
37
|
+
[key: string]: { name: INetworkReal; coin: string };
|
|
38
|
+
} = {
|
|
39
|
+
tbtc: { name: 'btc', coin: 'Testnet' },
|
|
40
|
+
bch: { name: 'btc', coin: 'Bcash' },
|
|
41
|
+
doge: { name: 'btc', coin: 'Dogecoin' },
|
|
42
|
+
ltc: { name: 'btc', coin: 'Litecoin' },
|
|
43
|
+
neurai: { name: 'btc', coin: 'Neurai' },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const networkConfigMap: NetworkConfigMap = {
|
|
47
|
+
btc: {
|
|
48
|
+
methodName: 'btcGetPublicKey',
|
|
49
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => ({
|
|
50
|
+
coin: chainName,
|
|
51
|
+
...baseParams,
|
|
52
|
+
}),
|
|
53
|
+
},
|
|
54
|
+
evm: {
|
|
55
|
+
methodName: 'evmGetAddress',
|
|
56
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
57
|
+
const { path, showOnOneKey } = baseParams;
|
|
58
|
+
let chainId;
|
|
59
|
+
if (chainName) {
|
|
60
|
+
chainId = parseInt(chainName);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
chainId,
|
|
64
|
+
path,
|
|
65
|
+
showOnOneKey,
|
|
66
|
+
};
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
sol: {
|
|
70
|
+
methodName: 'solGetAddress',
|
|
71
|
+
},
|
|
72
|
+
algo: {
|
|
73
|
+
methodName: 'algoGetAddress',
|
|
74
|
+
},
|
|
75
|
+
near: {
|
|
76
|
+
methodName: 'nearGetAddress',
|
|
77
|
+
},
|
|
78
|
+
stc: {
|
|
79
|
+
methodName: 'starcoinGetAddress',
|
|
80
|
+
},
|
|
81
|
+
cfx: {
|
|
82
|
+
methodName: 'confluxGetAddress',
|
|
83
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
84
|
+
const { path, showOnOneKey } = baseParams;
|
|
85
|
+
return {
|
|
86
|
+
chainId: parseInt(chainName ?? '1029'),
|
|
87
|
+
path,
|
|
88
|
+
showOnOneKey,
|
|
89
|
+
};
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
tron: {
|
|
93
|
+
methodName: 'tronGetAddress',
|
|
94
|
+
},
|
|
95
|
+
aptos: {
|
|
96
|
+
methodName: 'aptosGetAddress',
|
|
97
|
+
},
|
|
98
|
+
xrp: {
|
|
99
|
+
methodName: 'xrpGetAddress',
|
|
100
|
+
},
|
|
101
|
+
cosmos: {
|
|
102
|
+
methodName: 'cosmosGetPublicKey',
|
|
103
|
+
getParams: (baseParams: AllNetworkAddressParams) => {
|
|
104
|
+
const { path, prefix, showOnOneKey } = baseParams;
|
|
105
|
+
return {
|
|
106
|
+
hrp: prefix,
|
|
107
|
+
path,
|
|
108
|
+
showOnOneKey,
|
|
109
|
+
};
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
ada: {
|
|
113
|
+
methodName: 'cardanoGetAddress',
|
|
114
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
115
|
+
const { path, showOnOneKey } = baseParams;
|
|
116
|
+
|
|
117
|
+
const addressPath =
|
|
118
|
+
typeof path === 'string' ? `${path}/0/0` : serializedPath([...path, 0, 0]);
|
|
119
|
+
const stakingPath =
|
|
120
|
+
typeof path === 'string' ? `${path}/2/0` : serializedPath([...path, 2, 0]);
|
|
121
|
+
|
|
122
|
+
let networkId = 1;
|
|
123
|
+
if (chainName) {
|
|
124
|
+
networkId = chainName === Mainnet ? 1 : 0;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
addressParameters: {
|
|
129
|
+
addressType: PROTO.CardanoAddressType.BASE,
|
|
130
|
+
path: addressPath,
|
|
131
|
+
stakingPath,
|
|
132
|
+
},
|
|
133
|
+
protocolMagic: 764824073,
|
|
134
|
+
networkId,
|
|
135
|
+
derivationType: PROTO.CardanoDerivationType.ICARUS,
|
|
136
|
+
showOnOneKey,
|
|
137
|
+
address: '',
|
|
138
|
+
isCheck: false,
|
|
139
|
+
};
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
sui: {
|
|
143
|
+
methodName: 'suiGetAddress',
|
|
144
|
+
},
|
|
145
|
+
benfen: {
|
|
146
|
+
methodName: 'benfenGetAddress',
|
|
147
|
+
},
|
|
148
|
+
fil: {
|
|
149
|
+
methodName: 'filecoinGetAddress',
|
|
150
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
151
|
+
const { path, showOnOneKey } = baseParams;
|
|
152
|
+
let isTestnet = false;
|
|
153
|
+
if (chainName) {
|
|
154
|
+
isTestnet = chainName !== Mainnet;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
isTestnet,
|
|
158
|
+
path,
|
|
159
|
+
showOnOneKey,
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
dot: {
|
|
164
|
+
methodName: 'polkadotGetAddress',
|
|
165
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
166
|
+
const { path, prefix, showOnOneKey } = baseParams;
|
|
167
|
+
if (!prefix || !chainName) {
|
|
168
|
+
throw new Error('Invalid params');
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
prefix: parseInt(prefix),
|
|
172
|
+
network: chainName,
|
|
173
|
+
path,
|
|
174
|
+
showOnOneKey,
|
|
175
|
+
};
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
kaspa: {
|
|
179
|
+
methodName: 'kaspaGetAddress',
|
|
180
|
+
getParams: (baseParams: AllNetworkAddressParams) => {
|
|
181
|
+
const { path, prefix, showOnOneKey, useTweak } = baseParams;
|
|
182
|
+
return {
|
|
183
|
+
scheme: 'schnorr',
|
|
184
|
+
prefix,
|
|
185
|
+
path,
|
|
186
|
+
showOnOneKey,
|
|
187
|
+
useTweak,
|
|
188
|
+
};
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
nexa: {
|
|
192
|
+
methodName: 'nexaGetAddress',
|
|
193
|
+
getParams: (baseParams: AllNetworkAddressParams) => {
|
|
194
|
+
const { path, prefix, showOnOneKey } = baseParams;
|
|
195
|
+
return {
|
|
196
|
+
scheme: 'Schnorr',
|
|
197
|
+
prefix,
|
|
198
|
+
path,
|
|
199
|
+
showOnOneKey,
|
|
200
|
+
};
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
dynex: {
|
|
204
|
+
methodName: 'dnxGetAddress',
|
|
205
|
+
},
|
|
206
|
+
nervos: {
|
|
207
|
+
methodName: 'nervosGetAddress',
|
|
208
|
+
getParams: (baseParams: AllNetworkAddressParams, chainName?: string) => {
|
|
209
|
+
const { path, showOnOneKey } = baseParams;
|
|
210
|
+
return {
|
|
211
|
+
network: chainName,
|
|
212
|
+
path,
|
|
213
|
+
showOnOneKey,
|
|
214
|
+
};
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
scdo: {
|
|
218
|
+
methodName: 'scdoGetAddress',
|
|
219
|
+
},
|
|
220
|
+
ton: {
|
|
221
|
+
methodName: 'tonGetAddress',
|
|
222
|
+
},
|
|
223
|
+
alph: {
|
|
224
|
+
methodName: 'alephiumGetAddress',
|
|
225
|
+
},
|
|
226
|
+
nostr: {
|
|
227
|
+
methodName: 'nostrGetPublicKey',
|
|
228
|
+
},
|
|
229
|
+
neo: {
|
|
230
|
+
methodName: 'neoGetAddress',
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
type MethodParams = {
|
|
235
|
+
methodName: keyof CoreApi;
|
|
236
|
+
params: Parameters<CoreApi[keyof CoreApi]>[0];
|
|
237
|
+
_originRequestParams: AllNetworkAddressParams;
|
|
238
|
+
_originalIndex: number;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
export default abstract class AllNetworkGetAddressBase extends BaseMethod<
|
|
242
|
+
{
|
|
243
|
+
address_n: number[];
|
|
244
|
+
show_display: boolean;
|
|
245
|
+
network: string;
|
|
246
|
+
chain_name?: string;
|
|
247
|
+
}[]
|
|
248
|
+
> {
|
|
249
|
+
init() {
|
|
250
|
+
this.checkDeviceId = true;
|
|
251
|
+
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
|
|
252
|
+
|
|
253
|
+
// check payload
|
|
254
|
+
validateParams(this.payload, [{ name: 'bundle', type: 'array' }]);
|
|
255
|
+
|
|
256
|
+
// check bundle
|
|
257
|
+
this.payload?.bundle?.forEach((batch: AllNetworkAddressParams) => {
|
|
258
|
+
validateParams(batch, [
|
|
259
|
+
{ name: 'path', required: true },
|
|
260
|
+
{ name: 'network', type: 'string', required: true },
|
|
261
|
+
{ name: 'chainName', type: 'string' },
|
|
262
|
+
{ name: 'showOnOneKey', type: 'boolean' },
|
|
263
|
+
]);
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
generateMethodName({
|
|
268
|
+
network,
|
|
269
|
+
payload,
|
|
270
|
+
originalIndex,
|
|
271
|
+
}: {
|
|
272
|
+
network: INetwork;
|
|
273
|
+
payload: AllNetworkAddressParams;
|
|
274
|
+
originalIndex: number;
|
|
275
|
+
}): MethodParams {
|
|
276
|
+
const { name: networkName, coin } = networkAliases[network] || {
|
|
277
|
+
name: network,
|
|
278
|
+
coin: payload?.chainName,
|
|
279
|
+
};
|
|
280
|
+
const config = networkConfigMap[networkName];
|
|
281
|
+
if (!config) {
|
|
282
|
+
throw new Error(`Unsupported network: ${network}`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
methodName: config.methodName,
|
|
287
|
+
params: {
|
|
288
|
+
...(config?.getParams?.(payload, coin, config.methodName) ?? payload),
|
|
289
|
+
originPayload: payload,
|
|
290
|
+
},
|
|
291
|
+
_originRequestParams: payload,
|
|
292
|
+
_originalIndex: originalIndex,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async callMethod(
|
|
297
|
+
methodName: keyof CoreApi,
|
|
298
|
+
params: any & {
|
|
299
|
+
bundle: (any & { _originRequestParams: CommonResponseParams })[];
|
|
300
|
+
}
|
|
301
|
+
) {
|
|
302
|
+
const method: BaseMethod = findMethod({
|
|
303
|
+
event: IFRAME.CALL,
|
|
304
|
+
type: IFRAME.CALL,
|
|
305
|
+
payload: {
|
|
306
|
+
connectId: this.payload.connectId,
|
|
307
|
+
deviceId: this.payload.deviceId,
|
|
308
|
+
method: methodName,
|
|
309
|
+
...params,
|
|
310
|
+
},
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
method.connector = this.connector;
|
|
314
|
+
method.postMessage = this.postMessage;
|
|
315
|
+
|
|
316
|
+
let result: AllNetworkAddress[];
|
|
317
|
+
try {
|
|
318
|
+
method.init();
|
|
319
|
+
method.setDevice?.(this.device);
|
|
320
|
+
|
|
321
|
+
preCheckDeviceSupport(this.device, method);
|
|
322
|
+
|
|
323
|
+
const response = await method.run();
|
|
324
|
+
|
|
325
|
+
if (!Array.isArray(response) || response.length === 0) {
|
|
326
|
+
throw new Error('No response');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
result = response.map((item, index) => ({
|
|
330
|
+
...params.bundle[index]._originRequestParams,
|
|
331
|
+
success: true,
|
|
332
|
+
payload: item,
|
|
333
|
+
}));
|
|
334
|
+
} catch (e: any) {
|
|
335
|
+
const error = handleSkippableHardwareError(e, this.device, method);
|
|
336
|
+
|
|
337
|
+
if (error) {
|
|
338
|
+
result = params.bundle.map((item: { _originRequestParams: any }) => ({
|
|
339
|
+
...item._originRequestParams,
|
|
340
|
+
success: false,
|
|
341
|
+
payload: {
|
|
342
|
+
error: error.message,
|
|
343
|
+
code: error.errorCode,
|
|
344
|
+
params: error.params,
|
|
345
|
+
connectId: method.connectId,
|
|
346
|
+
deviceId: method.deviceId,
|
|
347
|
+
},
|
|
348
|
+
}));
|
|
349
|
+
} else {
|
|
350
|
+
throw e;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
return result;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
abstract getAllNetworkAddress(): Promise<AllNetworkAddress[]>;
|
|
358
|
+
|
|
359
|
+
async run() {
|
|
360
|
+
return Promise.resolve(this.getAllNetworkAddress());
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* @experiment Check if the device supports the method
|
|
366
|
+
* @param device
|
|
367
|
+
* @param method BaseMethod
|
|
368
|
+
*/
|
|
369
|
+
function preCheckDeviceSupport(device: Device, method: BaseMethod) {
|
|
370
|
+
const versionRange = getMethodVersionRange(
|
|
371
|
+
device.features,
|
|
372
|
+
type => method.getVersionRange()[type]
|
|
373
|
+
);
|
|
374
|
+
const currentVersion = getDeviceFirmwareVersion(device.features).join('.');
|
|
375
|
+
|
|
376
|
+
if (
|
|
377
|
+
versionRange &&
|
|
378
|
+
semver.valid(versionRange.min) &&
|
|
379
|
+
semver.lt(currentVersion, versionRange.min)
|
|
380
|
+
) {
|
|
381
|
+
throw ERRORS.createNeedUpgradeFirmwareHardwareError(currentVersion, versionRange.min);
|
|
382
|
+
} else if (method.strictCheckDeviceSupport && !versionRange) {
|
|
383
|
+
throw ERRORS.TypedError(HardwareErrorCode.DeviceNotSupportMethod);
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function handleSkippableHardwareError(
|
|
388
|
+
e: any,
|
|
389
|
+
device: Device,
|
|
390
|
+
method: BaseMethod
|
|
391
|
+
): HardwareError | undefined {
|
|
392
|
+
let error: HardwareError | undefined;
|
|
393
|
+
|
|
394
|
+
if (e instanceof HardwareError && e.errorCode !== HardwareErrorCode.RuntimeError) {
|
|
395
|
+
const { errorCode } = e;
|
|
396
|
+
if (errorCode === HardwareErrorCode.CallMethodInvalidParameter) {
|
|
397
|
+
error = e;
|
|
398
|
+
} else if (errorCode === HardwareErrorCode.CallMethodNeedUpgradeFirmware) {
|
|
399
|
+
error = e;
|
|
400
|
+
} else if (errorCode === HardwareErrorCode.DeviceNotSupportMethod) {
|
|
401
|
+
error = e;
|
|
402
|
+
}
|
|
403
|
+
} else if (e.message?.includes('Failure_UnexpectedMessage')) {
|
|
404
|
+
const versionRange = getMethodVersionRange(
|
|
405
|
+
device.features,
|
|
406
|
+
type => method.getVersionRange()[type]
|
|
407
|
+
);
|
|
408
|
+
const currentVersion = getDeviceFirmwareVersion(device.features).join('.');
|
|
409
|
+
|
|
410
|
+
if (
|
|
411
|
+
versionRange &&
|
|
412
|
+
semver.valid(versionRange.min) &&
|
|
413
|
+
semver.lt(currentVersion, versionRange.min)
|
|
414
|
+
) {
|
|
415
|
+
error = ERRORS.createNeedUpgradeFirmwareHardwareError(currentVersion, versionRange.min);
|
|
416
|
+
} else {
|
|
417
|
+
error = ERRORS.TypedError(HardwareErrorCode.DeviceNotSupportMethod, e.message);
|
|
418
|
+
}
|
|
419
|
+
} else if (
|
|
420
|
+
e.message?.toLowerCase()?.includes('forbidden key path') ||
|
|
421
|
+
e.message?.toLowerCase()?.includes('invalid path')
|
|
422
|
+
) {
|
|
423
|
+
error = ERRORS.TypedError(HardwareErrorCode.CallMethodInvalidParameter, e.message);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
return error;
|
|
427
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { createDeferred } from '@onekeyfe/hd-shared';
|
|
2
|
+
import type {
|
|
3
|
+
AllNetworkAddress,
|
|
4
|
+
AllNetworkGetAddressParamsByLoop,
|
|
5
|
+
} from '../../types/api/allNetworkGetAddress';
|
|
6
|
+
|
|
7
|
+
import { IFRAME } from '../../events';
|
|
8
|
+
import AllNetworkGetAddressBase from './AllNetworkGetAddressBase';
|
|
9
|
+
|
|
10
|
+
export default class AllNetworkGetAddressByLoop extends AllNetworkGetAddressBase {
|
|
11
|
+
async getAllNetworkAddress() {
|
|
12
|
+
const { callbackId, callbackIdFinish } = this.payload as AllNetworkGetAddressParamsByLoop;
|
|
13
|
+
if (!callbackId) {
|
|
14
|
+
throw new Error('callbackId is required');
|
|
15
|
+
}
|
|
16
|
+
if (!callbackIdFinish) {
|
|
17
|
+
throw new Error('callbackIdFinish is required');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const bundle = this.payload.bundle || [this.payload];
|
|
21
|
+
|
|
22
|
+
// process callbacks in background
|
|
23
|
+
const callbackPromise = this.processCallbacksInBackground(bundle, callbackId, callbackIdFinish);
|
|
24
|
+
this.device.pendingCallbackPromise = createDeferred(callbackPromise);
|
|
25
|
+
|
|
26
|
+
// register to context for scheduling management
|
|
27
|
+
if (this.context && this.payload.connectId) {
|
|
28
|
+
this.context.registerCallbackTask(this.payload.connectId, this.device.pendingCallbackPromise);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// return empty array immediately
|
|
32
|
+
return Promise.resolve([]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private async processCallbacksInBackground(
|
|
36
|
+
bundle: any[],
|
|
37
|
+
callbackId: string,
|
|
38
|
+
callbackIdFinish: string
|
|
39
|
+
): Promise<void> {
|
|
40
|
+
try {
|
|
41
|
+
const allResults: AllNetworkAddress[] = [];
|
|
42
|
+
|
|
43
|
+
for (let i = 0; i < bundle.length; i++) {
|
|
44
|
+
const item = bundle[i];
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const methodParams = this.generateMethodName({
|
|
48
|
+
network: item.network,
|
|
49
|
+
payload: item,
|
|
50
|
+
originalIndex: i,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const singleMethodParams = {
|
|
54
|
+
bundle: [methodParams.params],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const response = await this.callMethod(methodParams.methodName, singleMethodParams);
|
|
58
|
+
|
|
59
|
+
const singleResult = {
|
|
60
|
+
...item,
|
|
61
|
+
...response[0],
|
|
62
|
+
};
|
|
63
|
+
allResults.push(singleResult);
|
|
64
|
+
|
|
65
|
+
this.sendItemCallback(callbackId, singleResult, null, i);
|
|
66
|
+
} catch (error: any) {
|
|
67
|
+
this.sendItemCallback(callbackId, null, error, i);
|
|
68
|
+
// continue to process other items, do not throw error
|
|
69
|
+
console.error(`Error processing item ${i}:`, error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.sendFinishCallback(callbackIdFinish, allResults);
|
|
74
|
+
} finally {
|
|
75
|
+
this.context?.cancelCallbackTasks(this.payload.connectId);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private sendFinishCallback(callbackId: string, data: AllNetworkAddress[]) {
|
|
80
|
+
this.postMessage({
|
|
81
|
+
event: IFRAME.CALLBACK,
|
|
82
|
+
type: IFRAME.CALLBACK,
|
|
83
|
+
payload: {
|
|
84
|
+
callbackId,
|
|
85
|
+
data,
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private sendItemCallback(callbackId: string, data: any, error: any, itemIndex: number) {
|
|
91
|
+
this.postMessage({
|
|
92
|
+
event: IFRAME.CALLBACK,
|
|
93
|
+
type: IFRAME.CALLBACK,
|
|
94
|
+
payload: {
|
|
95
|
+
callbackId,
|
|
96
|
+
data: {
|
|
97
|
+
...data,
|
|
98
|
+
index: itemIndex,
|
|
99
|
+
},
|
|
100
|
+
error: error ? { message: error.message, code: error.code } : null,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
@@ -2,7 +2,7 @@ import { UI_REQUEST } from '../../constants/ui-request';
|
|
|
2
2
|
import { serializedPath, validatePath } from '../helpers/pathUtils';
|
|
3
3
|
import { BaseMethod } from '../BaseMethod';
|
|
4
4
|
import { validateParams, validateResult } from '../helpers/paramsValidator';
|
|
5
|
-
import { CosmosAddress, CosmosGetPublicKeyParams } from '../../types';
|
|
5
|
+
import type { CosmosAddress, CosmosGetPublicKeyParams } from '../../types';
|
|
6
6
|
import { batchGetPublickeys } from '../helpers/batchGetPublickeys';
|
|
7
7
|
|
|
8
8
|
export default class CosmosGetPublicKey extends BaseMethod<any> {
|
|
@@ -13,6 +13,8 @@ import { batchGetPublickeys } from '../helpers/batchGetPublickeys';
|
|
|
13
13
|
export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneKey[]> {
|
|
14
14
|
hasBundle = false;
|
|
15
15
|
|
|
16
|
+
confirmShowOnOneKey = false;
|
|
17
|
+
|
|
16
18
|
useBatch = false;
|
|
17
19
|
|
|
18
20
|
init() {
|
|
@@ -20,9 +22,13 @@ export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneK
|
|
|
20
22
|
this.allowDeviceMode = [...this.allowDeviceMode, UI_REQUEST.NOT_INITIALIZE];
|
|
21
23
|
|
|
22
24
|
this.hasBundle = !!this.payload?.bundle;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
+
|
|
26
|
+
this.confirmShowOnOneKey = this.payload?.bundle?.some(
|
|
27
|
+
(item: EVMGetPublicKeyParams) => !!item.showOnOneKey
|
|
25
28
|
);
|
|
29
|
+
|
|
30
|
+
this.useBatch = !this.confirmShowOnOneKey && this.hasBundle && this.payload.useBatch;
|
|
31
|
+
|
|
26
32
|
const payload = this.hasBundle ? this.payload : { bundle: [this.payload] };
|
|
27
33
|
|
|
28
34
|
// check payload
|
|
@@ -66,7 +72,7 @@ export default class EVMGetPublicKey extends BaseMethod<EthereumGetPublicKeyOneK
|
|
|
66
72
|
async run() {
|
|
67
73
|
const responses: EVMPublicKey[] = [];
|
|
68
74
|
|
|
69
|
-
if (this.useBatch &&
|
|
75
|
+
if (this.useBatch && supportBatchPublicKey(this.device?.features)) {
|
|
70
76
|
try {
|
|
71
77
|
const res = await batchGetPublickeys(this.device, this.params, 'secp256k1', 60, {
|
|
72
78
|
includeNode: false,
|
package/src/api/index.ts
CHANGED
|
@@ -41,6 +41,7 @@ export { default as promptWebDeviceAccess } from './PromptWebDeviceAccess';
|
|
|
41
41
|
export { default as cipherKeyValue } from './CipherKeyValue';
|
|
42
42
|
|
|
43
43
|
export { default as allNetworkGetAddress } from './allnetwork/AllNetworkGetAddress';
|
|
44
|
+
export { default as allNetworkGetAddressByLoop } from './allnetwork/AllNetworkGetAddressByLoop';
|
|
44
45
|
|
|
45
46
|
export { default as btcGetAddress } from './btc/BTCGetAddress';
|
|
46
47
|
export { default as btcGetPublicKey } from './btc/BTCGetPublicKey';
|
package/src/core/RequestQueue.ts
CHANGED
|
@@ -13,6 +13,8 @@ export type RequestTask = {
|
|
|
13
13
|
export default class RequestQueue {
|
|
14
14
|
private requestQueue = new Map<number, RequestTask>();
|
|
15
15
|
|
|
16
|
+
private pendingCallbackTasks = new Map<string, Deferred<void>>();
|
|
17
|
+
|
|
16
18
|
// 生成唯一请求ID
|
|
17
19
|
public generateRequestId = (method?: BaseMethod) => {
|
|
18
20
|
if (method && method.responseID != null) {
|
|
@@ -104,4 +106,28 @@ export default class RequestQueue {
|
|
|
104
106
|
public releaseTask(requestId: number) {
|
|
105
107
|
this.requestQueue.delete(requestId);
|
|
106
108
|
}
|
|
109
|
+
|
|
110
|
+
public registerPendingCallbackTask(connectId: string, callbackPromise: Deferred<void>) {
|
|
111
|
+
this.pendingCallbackTasks.set(connectId, callbackPromise);
|
|
112
|
+
|
|
113
|
+
callbackPromise.promise.finally(() => {
|
|
114
|
+
Log.debug(`Callback task completed for connectId: ${connectId}`);
|
|
115
|
+
this.pendingCallbackTasks.delete(connectId);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
public async waitForPendingCallbackTasks(connectId: string): Promise<void> {
|
|
120
|
+
const pendingTask = this.pendingCallbackTasks.get(connectId);
|
|
121
|
+
if (pendingTask) {
|
|
122
|
+
Log.debug(`Waiting for pending callback task to complete for connectId: ${connectId}`);
|
|
123
|
+
await pendingTask.promise;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public cancelCallbackTasks(connectId: string) {
|
|
128
|
+
const pendingTask = this.pendingCallbackTasks.get(connectId);
|
|
129
|
+
if (pendingTask) {
|
|
130
|
+
pendingTask.resolve();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
107
133
|
}
|
package/src/core/index.ts
CHANGED
|
@@ -52,7 +52,7 @@ import { getSynchronize } from '../utils/getSynchronize';
|
|
|
52
52
|
|
|
53
53
|
const Log = getLogger(LoggerNames.Core);
|
|
54
54
|
|
|
55
|
-
type CoreContext = ReturnType<Core['getCoreContext']>;
|
|
55
|
+
export type CoreContext = ReturnType<Core['getCoreContext']>;
|
|
56
56
|
|
|
57
57
|
function hasDeriveCardano(method: BaseMethod): boolean {
|
|
58
58
|
if (
|
|
@@ -195,6 +195,11 @@ const onCallDevice = async (
|
|
|
195
195
|
DevicePool.clearDeviceCache(method.payload.connectId);
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
+
// 等待之前的 callback 任务完成(确保设备不会并发调用)
|
|
199
|
+
if (method.connectId) {
|
|
200
|
+
await context.waitForCallbackTasks(method.connectId);
|
|
201
|
+
}
|
|
202
|
+
|
|
198
203
|
await waitForPendingPromise(getPrePendingCallPromise, setPrePendingCallPromise);
|
|
199
204
|
|
|
200
205
|
const task = requestQueue.createTask(method);
|
|
@@ -225,6 +230,7 @@ const onCallDevice = async (
|
|
|
225
230
|
|
|
226
231
|
Log.debug('Call API - setDevice: ', device.mainId);
|
|
227
232
|
method.setDevice?.(device);
|
|
233
|
+
method.context = context;
|
|
228
234
|
|
|
229
235
|
device.on(DEVICE.PIN, onDevicePinHandler);
|
|
230
236
|
device.on(DEVICE.BUTTON, onDeviceButtonHandler);
|
|
@@ -240,6 +246,10 @@ const onCallDevice = async (
|
|
|
240
246
|
);
|
|
241
247
|
|
|
242
248
|
try {
|
|
249
|
+
if (method.connectId) {
|
|
250
|
+
await context.waitForCallbackTasks(method.connectId);
|
|
251
|
+
}
|
|
252
|
+
|
|
243
253
|
await waitForPendingPromise(getPrePendingCallPromise, setPrePendingCallPromise);
|
|
244
254
|
|
|
245
255
|
const inner = async (): Promise<void> => {
|
|
@@ -710,6 +720,10 @@ export const cancel = (context: CoreContext, connectId?: string) => {
|
|
|
710
720
|
// }
|
|
711
721
|
// setPrePendingCallPromise(device?.interruptionFromUser());
|
|
712
722
|
// requestQueue.abortRequestsByConnectId(connectId);
|
|
723
|
+
|
|
724
|
+
// cancel callback tasks
|
|
725
|
+
requestQueue.cancelCallbackTasks(connectId);
|
|
726
|
+
|
|
713
727
|
const requestIds = requestQueue.getRequestTasksId();
|
|
714
728
|
Log.debug(
|
|
715
729
|
`Cancel Api connect requestQueues: length:${requestIds.length} requestIds:${requestIds.join(
|
|
@@ -947,7 +961,7 @@ const removeUiPromise = (promise: Deferred<any>) => {
|
|
|
947
961
|
export default class Core extends EventEmitter {
|
|
948
962
|
private requestQueue = new RequestQueue();
|
|
949
963
|
|
|
950
|
-
//
|
|
964
|
+
// background task
|
|
951
965
|
private prePendingCallPromise: Promise<void> | undefined;
|
|
952
966
|
|
|
953
967
|
private methodSynchronize = getSynchronize();
|
|
@@ -960,6 +974,13 @@ export default class Core extends EventEmitter {
|
|
|
960
974
|
setPrePendingCallPromise: (promise: Promise<void> | undefined) => {
|
|
961
975
|
this.prePendingCallPromise = promise;
|
|
962
976
|
},
|
|
977
|
+
// callback 任务管理
|
|
978
|
+
registerCallbackTask: (connectId: string, callbackPromise: Deferred<any>) => {
|
|
979
|
+
this.requestQueue.registerPendingCallbackTask(connectId, callbackPromise);
|
|
980
|
+
},
|
|
981
|
+
waitForCallbackTasks: (connectId: string) =>
|
|
982
|
+
this.requestQueue.waitForPendingCallbackTasks(connectId),
|
|
983
|
+
cancelCallbackTasks: (connectId: string) => this.requestQueue.cancelCallbackTasks(connectId),
|
|
963
984
|
};
|
|
964
985
|
}
|
|
965
986
|
|
|
@@ -1010,6 +1031,11 @@ export default class Core extends EventEmitter {
|
|
|
1010
1031
|
cancel(this.getCoreContext(), message.payload.connectId);
|
|
1011
1032
|
break;
|
|
1012
1033
|
}
|
|
1034
|
+
case IFRAME.CALLBACK: {
|
|
1035
|
+
Log.log('callback message: ', message);
|
|
1036
|
+
postMessage(message);
|
|
1037
|
+
break;
|
|
1038
|
+
}
|
|
1013
1039
|
default:
|
|
1014
1040
|
break;
|
|
1015
1041
|
}
|