@onekeyfe/hd-core 1.2.0-alpha.25 → 1.2.0-alpha.26
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/__tests__/protocol-v2.test.ts +129 -6
- package/__tests__/tron-sign-message-init.test.ts +28 -0
- package/dist/api/tron/TronSignMessage.d.ts +3 -0
- package/dist/api/tron/TronSignMessage.d.ts.map +1 -1
- package/dist/index.js +20 -11
- package/dist/protocols/protocol-v2/unlockRetry.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/api/UploadPortfolio.ts +1 -1
- package/src/api/tron/TronSignMessage.ts +3 -0
- package/src/protocols/protocol-v2/unlockRetry.ts +18 -11
|
@@ -200,6 +200,42 @@ describe('DeviceUploadWallpaper', () => {
|
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
describe('UploadPortfolio', () => {
|
|
203
|
+
test('writes and applies the portfolio while the device is locked without unlocking', async () => {
|
|
204
|
+
const packageBytes = new Uint8Array([1, 2, 3]);
|
|
205
|
+
const typedCall = jest
|
|
206
|
+
.fn()
|
|
207
|
+
.mockResolvedValueOnce({ message: { processed_byte: 3 } })
|
|
208
|
+
.mockResolvedValueOnce({ message: { message: 'Portfolio updated' } });
|
|
209
|
+
const unlockDevice = jest.fn().mockResolvedValue(undefined);
|
|
210
|
+
const device = stubDevice({
|
|
211
|
+
features: { unlocked: false },
|
|
212
|
+
commands: { typedCall },
|
|
213
|
+
isProtocolV2: () => true,
|
|
214
|
+
unlockDevice,
|
|
215
|
+
});
|
|
216
|
+
const method = new UploadPortfolio({
|
|
217
|
+
id: 1,
|
|
218
|
+
payload: {
|
|
219
|
+
method: 'uploadPortfolio',
|
|
220
|
+
packageBytes,
|
|
221
|
+
},
|
|
222
|
+
});
|
|
223
|
+
(method as any).device = device;
|
|
224
|
+
|
|
225
|
+
method.init();
|
|
226
|
+
await runMethodWithUnlockRetry(method, device as any);
|
|
227
|
+
|
|
228
|
+
expect(unlockDevice).not.toHaveBeenCalled();
|
|
229
|
+
expect(typedCall).toHaveBeenNthCalledWith(
|
|
230
|
+
1,
|
|
231
|
+
'FilesystemFileWrite',
|
|
232
|
+
'FilesystemFile',
|
|
233
|
+
expect.any(Object),
|
|
234
|
+
{ timeoutMs: undefined }
|
|
235
|
+
);
|
|
236
|
+
expect(typedCall).toHaveBeenNthCalledWith(2, 'PortfolioUpdate', 'Success', {});
|
|
237
|
+
});
|
|
238
|
+
|
|
203
239
|
test('stages the complete package before applying PortfolioUpdate', async () => {
|
|
204
240
|
const packageBytes = new Uint8Array([1, 2, 3]);
|
|
205
241
|
const typedCall = jest
|
|
@@ -219,7 +255,7 @@ describe('UploadPortfolio', () => {
|
|
|
219
255
|
method.init();
|
|
220
256
|
const result = await method.run();
|
|
221
257
|
|
|
222
|
-
expect(method.unlockPolicy).toBe('
|
|
258
|
+
expect(method.unlockPolicy).toBe('none');
|
|
223
259
|
expect(method.protocolV2UiMode).toBe('none');
|
|
224
260
|
expect(method.protocolV2UiInteraction).toBeUndefined();
|
|
225
261
|
expect(method.payload.emitProgress).toBe(false);
|
|
@@ -5359,6 +5395,93 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
5359
5395
|
]);
|
|
5360
5396
|
});
|
|
5361
5397
|
|
|
5398
|
+
test('restores the expected hidden-wallet session after pre-unlock without selecting Attach PIN', async () => {
|
|
5399
|
+
const calls: string[] = [];
|
|
5400
|
+
const method = {
|
|
5401
|
+
name: 'evmSignMessage',
|
|
5402
|
+
payload: { passphraseState: 'hidden-state' },
|
|
5403
|
+
useDevicePassphraseState: true,
|
|
5404
|
+
unlockPolicy: 'retry-on-locked',
|
|
5405
|
+
run: jest.fn(() => {
|
|
5406
|
+
calls.push('run');
|
|
5407
|
+
return Promise.resolve({ message: 'ok' });
|
|
5408
|
+
}),
|
|
5409
|
+
};
|
|
5410
|
+
const typedCall = jest.fn((requestType: string, _responseType: string, request: any) => {
|
|
5411
|
+
if (requestType === 'ProtocolInfoRequest') {
|
|
5412
|
+
calls.push('negotiate-session');
|
|
5413
|
+
return Promise.resolve({ message: { version: 2 } });
|
|
5414
|
+
}
|
|
5415
|
+
if (requestType === 'DeviceSessionGet') {
|
|
5416
|
+
calls.push('resume-hidden-session');
|
|
5417
|
+
expect(request).toEqual({ session_id: 'hidden-session' });
|
|
5418
|
+
return Promise.resolve({
|
|
5419
|
+
message: {
|
|
5420
|
+
session_id: 'hidden-session',
|
|
5421
|
+
btc_test_address: 'hidden-state',
|
|
5422
|
+
},
|
|
5423
|
+
});
|
|
5424
|
+
}
|
|
5425
|
+
throw new Error(`Unexpected request: ${requestType}`);
|
|
5426
|
+
});
|
|
5427
|
+
const features = {
|
|
5428
|
+
unlocked: false,
|
|
5429
|
+
unlockedAttachPin: true,
|
|
5430
|
+
passphraseProtection: true,
|
|
5431
|
+
};
|
|
5432
|
+
const device = {
|
|
5433
|
+
features,
|
|
5434
|
+
passphraseState: 'hidden-state',
|
|
5435
|
+
commands: { typedCall },
|
|
5436
|
+
isProtocolV2: () => true,
|
|
5437
|
+
unlockDevice: jest.fn(() => {
|
|
5438
|
+
calls.push('unlock-main');
|
|
5439
|
+
features.unlocked = true;
|
|
5440
|
+
features.unlockedAttachPin = false;
|
|
5441
|
+
return Promise.resolve();
|
|
5442
|
+
}),
|
|
5443
|
+
getCurrentPassphraseProtection: () => true,
|
|
5444
|
+
getInternalState: () => 'hidden-session',
|
|
5445
|
+
clearInternalState: jest.fn(),
|
|
5446
|
+
getCurrentDeviceId: () => 'wallet-device-id',
|
|
5447
|
+
updateInternalState: jest.fn(() => calls.push('validate-hidden-session')),
|
|
5448
|
+
};
|
|
5449
|
+
|
|
5450
|
+
await expect(runMethodWithUnlockRetry(method as any, device as any)).resolves.toEqual({
|
|
5451
|
+
message: 'ok',
|
|
5452
|
+
});
|
|
5453
|
+
expect(device.unlockDevice).toHaveBeenCalledWith();
|
|
5454
|
+
expect(calls).toEqual([
|
|
5455
|
+
'unlock-main',
|
|
5456
|
+
'negotiate-session',
|
|
5457
|
+
'resume-hidden-session',
|
|
5458
|
+
'validate-hidden-session',
|
|
5459
|
+
'run',
|
|
5460
|
+
]);
|
|
5461
|
+
});
|
|
5462
|
+
|
|
5463
|
+
test('does not restore a hidden-wallet session for a standard-wallet pre-unlock', async () => {
|
|
5464
|
+
const method = {
|
|
5465
|
+
name: 'evmGetAddress',
|
|
5466
|
+
payload: { useEmptyPassphrase: true },
|
|
5467
|
+
useDevicePassphraseState: true,
|
|
5468
|
+
unlockPolicy: 'retry-on-locked',
|
|
5469
|
+
run: jest.fn().mockResolvedValue({ address: 'standard-wallet-address' }),
|
|
5470
|
+
};
|
|
5471
|
+
const device = {
|
|
5472
|
+
features: { unlocked: false },
|
|
5473
|
+
passphraseState: 'stale-hidden-state',
|
|
5474
|
+
isProtocolV2: () => true,
|
|
5475
|
+
unlockDevice: jest.fn().mockResolvedValue(undefined),
|
|
5476
|
+
};
|
|
5477
|
+
|
|
5478
|
+
await expect(runMethodWithUnlockRetry(method as any, device as any)).resolves.toEqual({
|
|
5479
|
+
address: 'standard-wallet-address',
|
|
5480
|
+
});
|
|
5481
|
+
expect(device.unlockDevice).toHaveBeenCalledTimes(1);
|
|
5482
|
+
expect(method.run).toHaveBeenCalledTimes(1);
|
|
5483
|
+
});
|
|
5484
|
+
|
|
5362
5485
|
test('unlocks before showing the method interaction when cached status is locked', async () => {
|
|
5363
5486
|
const calls: string[] = [];
|
|
5364
5487
|
const method = {
|
|
@@ -5444,10 +5567,10 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
5444
5567
|
}
|
|
5445
5568
|
});
|
|
5446
5569
|
|
|
5447
|
-
test('
|
|
5570
|
+
test('runs lock-free eventless methods without unlocking or synthesized UI', async () => {
|
|
5448
5571
|
const method = {
|
|
5449
5572
|
name: 'uploadPortfolio',
|
|
5450
|
-
unlockPolicy: '
|
|
5573
|
+
unlockPolicy: 'none',
|
|
5451
5574
|
protocolV2UiMode: 'none',
|
|
5452
5575
|
run: jest.fn().mockResolvedValue({ message: 'ok' }),
|
|
5453
5576
|
};
|
|
@@ -5465,17 +5588,17 @@ describe('Protocol V2 protected method execution', () => {
|
|
|
5465
5588
|
await expect(
|
|
5466
5589
|
runMethodWithUnlockRetry(method as any, device as any, uiCoordinator as any)
|
|
5467
5590
|
).resolves.toEqual({ message: 'ok' });
|
|
5468
|
-
expect(device.unlockDevice).
|
|
5591
|
+
expect(device.unlockDevice).not.toHaveBeenCalled();
|
|
5469
5592
|
expect(uiCoordinator.enterMethodInteraction).not.toHaveBeenCalled();
|
|
5470
5593
|
expect(uiCoordinator.enterUnlockInteraction).not.toHaveBeenCalled();
|
|
5471
5594
|
expect(uiCoordinator.resumeMethodInteraction).not.toHaveBeenCalled();
|
|
5472
5595
|
});
|
|
5473
5596
|
|
|
5474
|
-
test('does not replay a state-changing method after a locked response', async () => {
|
|
5597
|
+
test('does not unlock or replay a lock-free state-changing method after a locked response', async () => {
|
|
5475
5598
|
const error = deviceLockedError();
|
|
5476
5599
|
const method = {
|
|
5477
5600
|
name: 'uploadPortfolio',
|
|
5478
|
-
unlockPolicy: '
|
|
5601
|
+
unlockPolicy: 'none',
|
|
5479
5602
|
run: jest.fn().mockRejectedValue(error),
|
|
5480
5603
|
};
|
|
5481
5604
|
const device = {
|
|
@@ -43,4 +43,32 @@ describe('TronSignMessage legacy message validation', () => {
|
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
);
|
|
46
|
+
|
|
47
|
+
test('allows Protocol V2 message signing on Pro2', async () => {
|
|
48
|
+
const method = new TronSignMessage({
|
|
49
|
+
id: 1,
|
|
50
|
+
payload: {
|
|
51
|
+
method: 'tronSignMessage',
|
|
52
|
+
path: "m/44'/195'/0'/0/0",
|
|
53
|
+
messageHex: '00',
|
|
54
|
+
messageType: 'V2',
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
method.init();
|
|
58
|
+
|
|
59
|
+
const typedCall = jest.fn().mockResolvedValue({ message: { signature: 'signature' } });
|
|
60
|
+
method.device = {
|
|
61
|
+
commands: { typedCall },
|
|
62
|
+
getCurrentFirmwareVersionString: jest.fn(() => '0.0.0'),
|
|
63
|
+
getCurrentMethodVersionRange: jest.fn(selector => selector('pro2')),
|
|
64
|
+
getCurrentFirmwareType: jest.fn(() => EFirmwareType.Universal),
|
|
65
|
+
} as unknown as Device;
|
|
66
|
+
|
|
67
|
+
await expect(method.run()).resolves.toEqual({ signature: 'signature' });
|
|
68
|
+
expect(typedCall).toHaveBeenCalledWith('TronSignMessage', 'TronMessageSignature', {
|
|
69
|
+
address_n: [2147483692, 2147483843, 2147483648, 0, 0],
|
|
70
|
+
message: '00',
|
|
71
|
+
message_type: 2,
|
|
72
|
+
});
|
|
73
|
+
});
|
|
46
74
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TronSignMessage.d.ts","sourceRoot":"","sources":["../../../src/api/tron/TronSignMessage.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EAAE,eAAe,IAAI,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzF,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,UAAU,CAAC,uBAAuB,CAAC;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IAEpC,qBAAqB;IAIrB,IAAI;IA4BJ,eAAe;;;;;;;;IAWf,wBAAwB
|
|
1
|
+
{"version":3,"file":"TronSignMessage.d.ts","sourceRoot":"","sources":["../../../src/api/tron/TronSignMessage.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAI3C,OAAO,KAAK,EAAE,eAAe,IAAI,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAEzF,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,UAAU,CAAC,uBAAuB,CAAC;IAC9E,OAAO,CAAC,mBAAmB,CAAS;IAEpC,qBAAqB;IAIrB,IAAI;IA4BJ,eAAe;;;;;;;;IAWf,wBAAwB;;;;;;;;;;;;;;;;;IAoBlB,GAAG;CA0BV"}
|
package/dist/index.js
CHANGED
|
@@ -51421,7 +51421,7 @@ class UploadPortfolio extends FileWrite {
|
|
|
51421
51421
|
const { packageBytes, timeoutMs } = this.payload;
|
|
51422
51422
|
this.payload = Object.assign(Object.assign({}, this.payload), { path: PORTFOLIO_PENDING_PATH, offset: 0, data: packageBytes, chunkSize: PORTFOLIO_CHUNK_SIZE, overwrite: true, append: false, emitProgress: false, timeoutMs });
|
|
51423
51423
|
super.init();
|
|
51424
|
-
this.unlockPolicy = '
|
|
51424
|
+
this.unlockPolicy = 'none';
|
|
51425
51425
|
this.protocolV2UiMode = 'none';
|
|
51426
51426
|
}
|
|
51427
51427
|
run() {
|
|
@@ -55761,6 +55761,9 @@ class TronSignMessage extends BaseMethod {
|
|
|
55761
55761
|
}
|
|
55762
55762
|
getMessageV2VersionRange() {
|
|
55763
55763
|
return {
|
|
55764
|
+
pro2: {
|
|
55765
|
+
min: '0.0.0',
|
|
55766
|
+
},
|
|
55764
55767
|
pro: {
|
|
55765
55768
|
min: '4.16.0',
|
|
55766
55769
|
},
|
|
@@ -61507,8 +61510,21 @@ class ProtocolV2UiInteractionCoordinator {
|
|
|
61507
61510
|
}
|
|
61508
61511
|
|
|
61509
61512
|
const Log$1 = getLogger(exports.LoggerNames.Core);
|
|
61513
|
+
const restoreExpectedWalletSessionAfterUnlock = (method, device) => __awaiter(void 0, void 0, void 0, function* () {
|
|
61514
|
+
var _a, _b, _c;
|
|
61515
|
+
const expectedPassphraseState = ((_a = method.payload) === null || _a === void 0 ? void 0 : _a.useEmptyPassphrase)
|
|
61516
|
+
? undefined
|
|
61517
|
+
: (_c = (_b = method.payload) === null || _b === void 0 ? void 0 : _b.passphraseState) !== null && _c !== void 0 ? _c : device.passphraseState;
|
|
61518
|
+
if (!method.useDevicePassphraseState ||
|
|
61519
|
+
typeof expectedPassphraseState !== 'string' ||
|
|
61520
|
+
expectedPassphraseState.length === 0) {
|
|
61521
|
+
return;
|
|
61522
|
+
}
|
|
61523
|
+
yield restoreProtocolV2WalletSession(device, expectedPassphraseState);
|
|
61524
|
+
Log$1.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
|
|
61525
|
+
});
|
|
61510
61526
|
function runMethodWithUnlockRetry(method, device, uiCoordinator) {
|
|
61511
|
-
var _a
|
|
61527
|
+
var _a;
|
|
61512
61528
|
return __awaiter(this, void 0, void 0, function* () {
|
|
61513
61529
|
const shouldEmitUi = isProtocolV2UiEnabled(method);
|
|
61514
61530
|
const shouldUnlockBeforeRun = device.isProtocolV2() && method.unlockPolicy !== 'none' && ((_a = device.features) === null || _a === void 0 ? void 0 : _a.unlocked) === false;
|
|
@@ -61518,6 +61534,7 @@ function runMethodWithUnlockRetry(method, device, uiCoordinator) {
|
|
|
61518
61534
|
}
|
|
61519
61535
|
yield device.unlockDevice();
|
|
61520
61536
|
Log$1.debug('Protocol V2 pre-unlock completed', { method: method.name });
|
|
61537
|
+
yield restoreExpectedWalletSessionAfterUnlock(method, device);
|
|
61521
61538
|
if (shouldEmitUi) {
|
|
61522
61539
|
uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
|
|
61523
61540
|
}
|
|
@@ -61541,15 +61558,7 @@ function runMethodWithUnlockRetry(method, device, uiCoordinator) {
|
|
|
61541
61558
|
}
|
|
61542
61559
|
yield device.unlockDevice();
|
|
61543
61560
|
Log$1.debug('Protocol V2 unlock completed', { method: method.name });
|
|
61544
|
-
|
|
61545
|
-
? undefined
|
|
61546
|
-
: (_d = (_c = method.payload) === null || _c === void 0 ? void 0 : _c.passphraseState) !== null && _d !== void 0 ? _d : device.passphraseState;
|
|
61547
|
-
if (method.useDevicePassphraseState &&
|
|
61548
|
-
typeof expectedPassphraseState === 'string' &&
|
|
61549
|
-
expectedPassphraseState.length > 0) {
|
|
61550
|
-
yield restoreProtocolV2WalletSession(device, expectedPassphraseState);
|
|
61551
|
-
Log$1.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
|
|
61552
|
-
}
|
|
61561
|
+
yield restoreExpectedWalletSessionAfterUnlock(method, device);
|
|
61553
61562
|
if (shouldEmitUi) {
|
|
61554
61563
|
uiCoordinator === null || uiCoordinator === void 0 ? void 0 : uiCoordinator.resumeMethodInteraction();
|
|
61555
61564
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unlockRetry.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/unlockRetry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,iBAAiB,CAAC;AAI1E,KAAK,cAAc,GAAG,IAAI,CACxB,UAAU,EACR,KAAK,GACL,cAAc,GACd,yBAAyB,GACzB,kBAAkB,GAClB,QAAQ,GACR,SAAS,GACT,0BAA0B,CAC7B,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACtB,KAAK,wBAAwB,GAAG,IAAI,CAClC,kCAAkC,EAClC,wBAAwB,GAAG,wBAAwB,GAAG,yBAAyB,CAChF,CAAC;
|
|
1
|
+
{"version":3,"file":"unlockRetry.d.ts","sourceRoot":"","sources":["../../../src/protocols/protocol-v2/unlockRetry.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,kCAAkC,EAAE,MAAM,iBAAiB,CAAC;AAI1E,KAAK,cAAc,GAAG,IAAI,CACxB,UAAU,EACR,KAAK,GACL,cAAc,GACd,yBAAyB,GACzB,kBAAkB,GAClB,QAAQ,GACR,SAAS,GACT,0BAA0B,CAC7B,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AACtB,KAAK,wBAAwB,GAAG,IAAI,CAClC,kCAAkC,EAClC,wBAAwB,GAAG,wBAAwB,GAAG,yBAAyB,CAChF,CAAC;AAkBF,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,cAAc,EACtB,MAAM,EAAE,MAAM,EACd,aAAa,CAAC,EAAE,wBAAwB,gBAoDzC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@onekeyfe/hd-core",
|
|
3
|
-
"version": "1.2.0-alpha.
|
|
3
|
+
"version": "1.2.0-alpha.26",
|
|
4
4
|
"description": "Core processes and APIs for communicating with OneKey hardware devices.",
|
|
5
5
|
"author": "OneKey",
|
|
6
6
|
"homepage": "https://github.com/OneKeyHQ/hardware-js-sdk#readme",
|
|
@@ -25,8 +25,8 @@
|
|
|
25
25
|
"url": "https://github.com/OneKeyHQ/hardware-js-sdk/issues"
|
|
26
26
|
},
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@onekeyfe/hd-shared": "1.2.0-alpha.
|
|
29
|
-
"@onekeyfe/hd-transport": "1.2.0-alpha.
|
|
28
|
+
"@onekeyfe/hd-shared": "1.2.0-alpha.26",
|
|
29
|
+
"@onekeyfe/hd-transport": "1.2.0-alpha.26",
|
|
30
30
|
"axios": "1.15.2",
|
|
31
31
|
"bignumber.js": "^9.0.2",
|
|
32
32
|
"bytebuffer": "^5.0.1",
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"@types/w3c-web-usb": "^1.0.10",
|
|
45
45
|
"@types/web-bluetooth": "^0.0.21"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "1401fef3eb93f5a83ed5e8375b99181b7aaa6054"
|
|
48
48
|
}
|
|
@@ -23,7 +23,7 @@ export default class UploadPortfolio extends FileWrite {
|
|
|
23
23
|
timeoutMs,
|
|
24
24
|
};
|
|
25
25
|
super.init();
|
|
26
|
-
this.unlockPolicy = '
|
|
26
|
+
this.unlockPolicy = 'none';
|
|
27
27
|
// Portfolio is a background write/apply flow and never synthesizes UI events.
|
|
28
28
|
this.protocolV2UiMode = 'none';
|
|
29
29
|
}
|
|
@@ -24,6 +24,22 @@ type UiInteractionCoordinator = Pick<
|
|
|
24
24
|
'enterMethodInteraction' | 'enterUnlockInteraction' | 'resumeMethodInteraction'
|
|
25
25
|
>;
|
|
26
26
|
|
|
27
|
+
const restoreExpectedWalletSessionAfterUnlock = async (method: RunnableMethod, device: Device) => {
|
|
28
|
+
const expectedPassphraseState = method.payload?.useEmptyPassphrase
|
|
29
|
+
? undefined
|
|
30
|
+
: method.payload?.passphraseState ?? device.passphraseState;
|
|
31
|
+
if (
|
|
32
|
+
!method.useDevicePassphraseState ||
|
|
33
|
+
typeof expectedPassphraseState !== 'string' ||
|
|
34
|
+
expectedPassphraseState.length === 0
|
|
35
|
+
) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
await restoreProtocolV2WalletSession(device, expectedPassphraseState);
|
|
40
|
+
Log.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
|
|
41
|
+
};
|
|
42
|
+
|
|
27
43
|
export async function runMethodWithUnlockRetry(
|
|
28
44
|
method: RunnableMethod,
|
|
29
45
|
device: Device,
|
|
@@ -39,6 +55,7 @@ export async function runMethodWithUnlockRetry(
|
|
|
39
55
|
}
|
|
40
56
|
await device.unlockDevice();
|
|
41
57
|
Log.debug('Protocol V2 pre-unlock completed', { method: method.name });
|
|
58
|
+
await restoreExpectedWalletSessionAfterUnlock(method, device);
|
|
42
59
|
if (shouldEmitUi) {
|
|
43
60
|
uiCoordinator?.enterMethodInteraction(resolveProtocolV2UiInteraction(method));
|
|
44
61
|
}
|
|
@@ -65,17 +82,7 @@ export async function runMethodWithUnlockRetry(
|
|
|
65
82
|
}
|
|
66
83
|
await device.unlockDevice();
|
|
67
84
|
Log.debug('Protocol V2 unlock completed', { method: method.name });
|
|
68
|
-
|
|
69
|
-
? undefined
|
|
70
|
-
: method.payload?.passphraseState ?? device.passphraseState;
|
|
71
|
-
if (
|
|
72
|
-
method.useDevicePassphraseState &&
|
|
73
|
-
typeof expectedPassphraseState === 'string' &&
|
|
74
|
-
expectedPassphraseState.length > 0
|
|
75
|
-
) {
|
|
76
|
-
await restoreProtocolV2WalletSession(device, expectedPassphraseState);
|
|
77
|
-
Log.debug('Protocol V2 wallet session restored after unlock', { method: method.name });
|
|
78
|
-
}
|
|
85
|
+
await restoreExpectedWalletSessionAfterUnlock(method, device);
|
|
79
86
|
if (shouldEmitUi) {
|
|
80
87
|
uiCoordinator?.resumeMethodInteraction();
|
|
81
88
|
}
|