@onekeyfe/hwk-keystone-adapter 1.2.3-alpha.4 → 1.2.3-alpha.8
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/index.d.mts +17 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +394 -271
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +194 -69
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -27,6 +27,7 @@ var TronSignRequest = class _TronSignRequest extends RegistryItem {
|
|
|
27
27
|
this.getSignData = () => this.signData;
|
|
28
28
|
this.getSignType = () => this.signType;
|
|
29
29
|
this.getDerivationPath = () => this.derivationPath.getPath();
|
|
30
|
+
this.getOrigin = () => this.origin;
|
|
30
31
|
this.toDataItem = () => {
|
|
31
32
|
const map = {};
|
|
32
33
|
if (this.requestId) {
|
|
@@ -461,8 +462,10 @@ import {
|
|
|
461
462
|
getAllNetworkMethodChain,
|
|
462
463
|
hasHardwareRuntimeIdPrefix,
|
|
463
464
|
isAllNetworkMethodName,
|
|
464
|
-
|
|
465
|
+
isConnectionLost,
|
|
466
|
+
isHardwareOperationId as isHardwareOperationId2,
|
|
465
467
|
isHwkRecoveryHint,
|
|
468
|
+
isUserRefusal,
|
|
466
469
|
operationMayHaveCompletedParams,
|
|
467
470
|
parseBip32MasterFingerprint as parseBip32MasterFingerprint2,
|
|
468
471
|
rehydrateConnectorError,
|
|
@@ -581,8 +584,29 @@ function placeholderDeviceInfo() {
|
|
|
581
584
|
};
|
|
582
585
|
}
|
|
583
586
|
|
|
587
|
+
// src/utils/queueKey.ts
|
|
588
|
+
import { isHardwareOperationId } from "@onekeyfe/hwk-adapter-core";
|
|
589
|
+
var KEYSTONE_COLD_START_JOB_LABEL = "keystone-cold-start";
|
|
590
|
+
function keystoneQueueKey(connectId, deviceId) {
|
|
591
|
+
return isHardwareOperationId(connectId) ? connectId : deviceId || connectId || KEYSTONE_COLD_START_JOB_LABEL;
|
|
592
|
+
}
|
|
593
|
+
function keystoneWalletIdFromIdentifier(identifier) {
|
|
594
|
+
const value = identifier.startsWith(KEYSTONE_WALLET_CONNECT_ID_PREFIX) ? identifier.slice(KEYSTONE_WALLET_CONNECT_ID_PREFIX.length) : identifier;
|
|
595
|
+
return /^[0-9a-f]{64}$/i.test(value) ? value.toLowerCase() : void 0;
|
|
596
|
+
}
|
|
597
|
+
function keystoneCancelQueueKeys(identifiers) {
|
|
598
|
+
const keys = /* @__PURE__ */ new Set();
|
|
599
|
+
for (const identifier of identifiers) {
|
|
600
|
+
if (identifier) {
|
|
601
|
+
keys.add(identifier);
|
|
602
|
+
const walletId = keystoneWalletIdFromIdentifier(identifier);
|
|
603
|
+
if (walletId) keys.add(walletId);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
return keys;
|
|
607
|
+
}
|
|
608
|
+
|
|
584
609
|
// src/adapter/KeystoneAdapter.ts
|
|
585
|
-
var COLD_START_JOB_LABEL = "keystone-cold-start";
|
|
586
610
|
var KEYSTONE_USB_REATTACH_PROBE_ATTEMPTS = 4;
|
|
587
611
|
var KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS = 500;
|
|
588
612
|
function resolveHardwareOperationTarget(positionalTargetId, operationId) {
|
|
@@ -594,8 +618,11 @@ function waitForKeystoneUsbReattachProbe() {
|
|
|
594
618
|
setTimeout(resolve, KEYSTONE_USB_REATTACH_PROBE_INTERVAL_MS);
|
|
595
619
|
});
|
|
596
620
|
}
|
|
597
|
-
function
|
|
598
|
-
|
|
621
|
+
function buildCancelledFailure(signal) {
|
|
622
|
+
const reason = signal.reason;
|
|
623
|
+
const code = typeof reason?.code === "number" ? reason.code : HardwareErrorCode.UserAborted;
|
|
624
|
+
const message = typeof reason?.message === "string" ? reason.message : "";
|
|
625
|
+
return failure(code, message || "All-network get-address cancelled");
|
|
599
626
|
}
|
|
600
627
|
var BIP44_COIN_TYPE_TO_CHAIN = {
|
|
601
628
|
60: "evm",
|
|
@@ -610,6 +637,9 @@ function inferHwkChainFromPath(path) {
|
|
|
610
637
|
var KeystoneAdapter = class _KeystoneAdapter {
|
|
611
638
|
constructor(options) {
|
|
612
639
|
this.vendor = "keystone";
|
|
640
|
+
// No protocol-level cancel exists over Keystone USB, and QR has no transport
|
|
641
|
+
// to interrupt at all. Cancelling ends the wait, not the device's prompt.
|
|
642
|
+
this.cancelCapability = "stops-waiting";
|
|
613
643
|
this.emitter = new TypedEventEmitter();
|
|
614
644
|
this._operationRoutes = /* @__PURE__ */ new Map();
|
|
615
645
|
this._operations = new OperationRegistry({
|
|
@@ -663,6 +693,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
663
693
|
if (!operationTarget.success) return operationTarget;
|
|
664
694
|
const effectiveConnectId = operationTarget.payload.targetId ?? "";
|
|
665
695
|
const { operationId } = operationTarget.payload;
|
|
696
|
+
let cancelScope;
|
|
666
697
|
try {
|
|
667
698
|
const prefetched = await this._prefetchAllNetworkAccounts(
|
|
668
699
|
effectiveConnectId,
|
|
@@ -671,11 +702,20 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
671
702
|
);
|
|
672
703
|
const { book } = prefetched;
|
|
673
704
|
const itemDeviceId = deviceId || prefetched.walletId || "";
|
|
705
|
+
const scope = this._jobQueue.createCancelScope(
|
|
706
|
+
keystoneQueueKey(effectiveConnectId, itemDeviceId)
|
|
707
|
+
);
|
|
708
|
+
cancelScope = scope;
|
|
709
|
+
const cancelledIndexes = /* @__PURE__ */ new Set();
|
|
674
710
|
return await runAllNetworkGetAddress({
|
|
675
711
|
connectId: effectiveConnectId,
|
|
676
712
|
deviceId: itemDeviceId,
|
|
677
713
|
params,
|
|
678
|
-
callItem: async ({ method, item }) => {
|
|
714
|
+
callItem: async ({ method, item, index }) => {
|
|
715
|
+
if (scope.signal.aborted) {
|
|
716
|
+
cancelledIndexes.add(index);
|
|
717
|
+
return buildCancelledFailure(scope.signal);
|
|
718
|
+
}
|
|
679
719
|
const commonArgs = {
|
|
680
720
|
path: item.path,
|
|
681
721
|
showOnDevice: item.showOnDevice,
|
|
@@ -714,10 +754,19 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
714
754
|
} : void 0
|
|
715
755
|
}
|
|
716
756
|
});
|
|
757
|
+
},
|
|
758
|
+
// The gap check plus the shared top-level table: a refusal or a lost
|
|
759
|
+
// session ends the batch, every other per-item failure keeps its
|
|
760
|
+
// existing "carry on with the next chain" behaviour.
|
|
761
|
+
shouldAbortBundle: (response, { index }) => {
|
|
762
|
+
const { code } = response.payload ?? {};
|
|
763
|
+
return cancelledIndexes.has(index) || isUserRefusal(code) || isConnectionLost(code);
|
|
717
764
|
}
|
|
718
765
|
});
|
|
719
766
|
} catch (err) {
|
|
720
767
|
return this._errorToFailure(err);
|
|
768
|
+
} finally {
|
|
769
|
+
cancelScope?.release();
|
|
721
770
|
}
|
|
722
771
|
};
|
|
723
772
|
this._origin = options?.origin ?? "OneKey";
|
|
@@ -915,6 +964,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
915
964
|
searchTargetId,
|
|
916
965
|
connectId: connected.payload.connectId,
|
|
917
966
|
device: connected.payload,
|
|
967
|
+
connectionType: selectedConnectionType,
|
|
918
968
|
connectionKeys: selectedConnectionType === "usb" && record?.usbSessionId ? [record.usbSessionId] : []
|
|
919
969
|
});
|
|
920
970
|
this._operationRoutes.set(connected.payload.connectId, {
|
|
@@ -967,7 +1017,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
967
1017
|
}
|
|
968
1018
|
getDeviceInfo(connectIdOrOperationId, deviceId) {
|
|
969
1019
|
try {
|
|
970
|
-
const connectId =
|
|
1020
|
+
const connectId = isHardwareOperationId2(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
|
|
971
1021
|
const { record } = this._resolveTarget(connectId, deviceId);
|
|
972
1022
|
if (!record) {
|
|
973
1023
|
return Promise.resolve(
|
|
@@ -983,25 +1033,35 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
983
1033
|
}
|
|
984
1034
|
}
|
|
985
1035
|
cancel(connectId) {
|
|
1036
|
+
let namedOperationConnectId;
|
|
1037
|
+
if (isHardwareOperationId2(connectId)) {
|
|
1038
|
+
try {
|
|
1039
|
+
namedOperationConnectId = this._operations.resolve(connectId).connectId;
|
|
1040
|
+
} catch {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
986
1044
|
const reason = createHwkError({
|
|
987
1045
|
code: HardwareErrorCode.UserAborted,
|
|
988
1046
|
message: "User aborted operation"
|
|
989
1047
|
});
|
|
990
|
-
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
991
1048
|
if (connectId) {
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1049
|
+
const queueKeys = keystoneCancelQueueKeys([
|
|
1050
|
+
connectId,
|
|
1051
|
+
this._operationRoutes.get(connectId)?.operationId,
|
|
1052
|
+
namedOperationConnectId
|
|
1053
|
+
]);
|
|
1054
|
+
for (const key of queueKeys) {
|
|
1055
|
+
this._jobQueue.cancelActiveAndPending(key, reason);
|
|
1056
|
+
}
|
|
1057
|
+
const scopedOperationId = isHardwareOperationId2(connectId) ? connectId : this._operationRouteForIdentifier(connectId)?.operationId;
|
|
1058
|
+
if (scopedOperationId) {
|
|
1059
|
+
this._uiRegistry.cancel(void 0, void 0, scopedOperationId);
|
|
999
1060
|
}
|
|
1000
|
-
this._jobQueue.cancelActiveAndPending(activeJobId, reason);
|
|
1001
1061
|
} else {
|
|
1002
1062
|
this._jobQueue.cancelActiveAndPending(void 0, reason);
|
|
1063
|
+
this._uiRegistry.cancel();
|
|
1003
1064
|
}
|
|
1004
|
-
this._uiRegistry.cancel();
|
|
1005
1065
|
}
|
|
1006
1066
|
getChainFingerprint(connectId, deviceId, chain) {
|
|
1007
1067
|
try {
|
|
@@ -1036,20 +1096,21 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1036
1096
|
// ---------------------------------------------------------------------------
|
|
1037
1097
|
async importFromQr(options = {}) {
|
|
1038
1098
|
try {
|
|
1039
|
-
return await this._jobQueue.enqueue(
|
|
1099
|
+
return await this._jobQueue.enqueue(KEYSTONE_COLD_START_JOB_LABEL, async (signal) => {
|
|
1040
1100
|
const displayDevice = placeholderDeviceInfo();
|
|
1041
1101
|
let responseUr;
|
|
1042
1102
|
if (options.mode === "scan") {
|
|
1043
|
-
responseUr = await this._requestQrScanAndAwaitResponse(displayDevice);
|
|
1103
|
+
responseUr = await this._requestQrScanAndAwaitResponse(displayDevice, signal);
|
|
1044
1104
|
} else {
|
|
1045
1105
|
const requestUr = this.urEngine.buildKeyDerivationRequest({
|
|
1046
1106
|
schemas: [{ path: KEYSTONE_WALLET_ID_PATH, curve: "secp256k1" }],
|
|
1047
1107
|
origin: this._origin
|
|
1048
1108
|
});
|
|
1049
|
-
responseUr = await this._requestQrDisplayAndAwaitResponse(
|
|
1050
|
-
|
|
1051
|
-
animated: false
|
|
1052
|
-
|
|
1109
|
+
responseUr = await this._requestQrDisplayAndAwaitResponse(
|
|
1110
|
+
displayDevice,
|
|
1111
|
+
{ ...requestUr, animated: false },
|
|
1112
|
+
signal
|
|
1113
|
+
);
|
|
1053
1114
|
}
|
|
1054
1115
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1055
1116
|
const parsed = this.urEngine.parseAccountResponse(responseUr);
|
|
@@ -1080,7 +1141,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1080
1141
|
);
|
|
1081
1142
|
}
|
|
1082
1143
|
try {
|
|
1083
|
-
return await this._jobQueue.enqueue(
|
|
1144
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1084
1145
|
const { account } = await this._fetchAccount(
|
|
1085
1146
|
connectId,
|
|
1086
1147
|
deviceId,
|
|
@@ -1126,7 +1187,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1126
1187
|
const rawTxHex = stripHex(params.serializedTx);
|
|
1127
1188
|
const path = normalizePath(params.path);
|
|
1128
1189
|
try {
|
|
1129
|
-
return await this._jobQueue.enqueue(
|
|
1190
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1130
1191
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
|
|
1131
1192
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1132
1193
|
const requestId = uuidv4();
|
|
@@ -1137,7 +1198,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1137
1198
|
dataType,
|
|
1138
1199
|
path,
|
|
1139
1200
|
xfp: record.masterFingerprint,
|
|
1140
|
-
chainId: params.chainId
|
|
1201
|
+
chainId: params.chainId,
|
|
1202
|
+
origin: this._origin
|
|
1141
1203
|
});
|
|
1142
1204
|
const responseUr = await this._resolveUr(
|
|
1143
1205
|
record,
|
|
@@ -1176,7 +1238,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1176
1238
|
const messageHex = params.hex ? stripHex(params.message) : Buffer.from(params.message, "utf8").toString("hex");
|
|
1177
1239
|
const path = normalizePath(params.path);
|
|
1178
1240
|
try {
|
|
1179
|
-
return await this._jobQueue.enqueue(
|
|
1241
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1180
1242
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
|
|
1181
1243
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1182
1244
|
const requestId = uuidv4();
|
|
@@ -1186,7 +1248,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1186
1248
|
dataType: "personalMessage",
|
|
1187
1249
|
path,
|
|
1188
1250
|
xfp: record.masterFingerprint,
|
|
1189
|
-
chainId: params.chainId
|
|
1251
|
+
chainId: params.chainId,
|
|
1252
|
+
origin: this._origin
|
|
1190
1253
|
});
|
|
1191
1254
|
const responseUr = await this._resolveUr(
|
|
1192
1255
|
record,
|
|
@@ -1228,7 +1291,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1228
1291
|
).toString("hex");
|
|
1229
1292
|
const path = normalizePath(params.path);
|
|
1230
1293
|
try {
|
|
1231
|
-
return await this._jobQueue.enqueue(
|
|
1294
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1232
1295
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "evm", signal);
|
|
1233
1296
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1234
1297
|
const requestId = uuidv4();
|
|
@@ -1238,7 +1301,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1238
1301
|
dataType: "typedData",
|
|
1239
1302
|
path,
|
|
1240
1303
|
xfp: record.masterFingerprint,
|
|
1241
|
-
chainId: params.chainId
|
|
1304
|
+
chainId: params.chainId,
|
|
1305
|
+
origin: this._origin
|
|
1242
1306
|
});
|
|
1243
1307
|
const responseUr = await this._resolveUr(
|
|
1244
1308
|
record,
|
|
@@ -1297,7 +1361,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1297
1361
|
return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
|
|
1298
1362
|
}
|
|
1299
1363
|
try {
|
|
1300
|
-
return await this._jobQueue.enqueue(
|
|
1364
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1301
1365
|
const { account } = await this._fetchAccount(
|
|
1302
1366
|
connectId,
|
|
1303
1367
|
deviceId,
|
|
@@ -1353,7 +1417,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1353
1417
|
return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
|
|
1354
1418
|
}
|
|
1355
1419
|
try {
|
|
1356
|
-
return await this._jobQueue.enqueue(
|
|
1420
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1357
1421
|
const { account } = await this._fetchAccount(
|
|
1358
1422
|
connectId,
|
|
1359
1423
|
deviceId,
|
|
@@ -1404,7 +1468,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1404
1468
|
return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
|
|
1405
1469
|
}
|
|
1406
1470
|
try {
|
|
1407
|
-
return await this._jobQueue.enqueue(
|
|
1471
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1408
1472
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
|
|
1409
1473
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1410
1474
|
const requestUr = this.urEngine.buildBtcPsbtRequest(stripHex(params.psbt));
|
|
@@ -1443,14 +1507,15 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1443
1507
|
return failure(HardwareErrorCode.DevicePathForbidden, KEYSTONE_BTC_ACCOUNT_FORBIDDEN_MESSAGE);
|
|
1444
1508
|
}
|
|
1445
1509
|
try {
|
|
1446
|
-
return await this._jobQueue.enqueue(
|
|
1510
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1447
1511
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
|
|
1448
1512
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1449
1513
|
const requestId = uuidv4();
|
|
1450
1514
|
const requestUr = this.urEngine.buildBtcMessageSignRequest({
|
|
1451
1515
|
requestId,
|
|
1452
1516
|
messageHex,
|
|
1453
|
-
accounts: [{ path, xfp: record.masterFingerprint }]
|
|
1517
|
+
accounts: [{ path, xfp: record.masterFingerprint }],
|
|
1518
|
+
origin: this._origin
|
|
1454
1519
|
});
|
|
1455
1520
|
const responseUr = await this._resolveUr(
|
|
1456
1521
|
record,
|
|
@@ -1475,7 +1540,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1475
1540
|
const connectId = operationTarget.payload.targetId;
|
|
1476
1541
|
const deviceId = deviceIdArg ?? void 0;
|
|
1477
1542
|
try {
|
|
1478
|
-
return await this._jobQueue.enqueue(
|
|
1543
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1479
1544
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "btc", signal);
|
|
1480
1545
|
return success({ masterFingerprint: record.masterFingerprint });
|
|
1481
1546
|
});
|
|
@@ -1497,7 +1562,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1497
1562
|
return failure(HardwareErrorCode.InvalidParams, "solGetAddress requires params.path");
|
|
1498
1563
|
const path = normalizePath(params.path);
|
|
1499
1564
|
try {
|
|
1500
|
-
return await this._jobQueue.enqueue(
|
|
1565
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1501
1566
|
const { account } = await this._fetchAccount(connectId, deviceId, "sol", path, signal, {
|
|
1502
1567
|
book
|
|
1503
1568
|
});
|
|
@@ -1525,7 +1590,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1525
1590
|
}
|
|
1526
1591
|
const path = normalizePath(params.path);
|
|
1527
1592
|
try {
|
|
1528
|
-
return await this._jobQueue.enqueue(
|
|
1593
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1529
1594
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
|
|
1530
1595
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1531
1596
|
const requestId = uuidv4();
|
|
@@ -1534,7 +1599,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1534
1599
|
unsignedPayloadHex: stripHex(params.serializedTx),
|
|
1535
1600
|
dataType: "transaction",
|
|
1536
1601
|
path,
|
|
1537
|
-
xfp: record.masterFingerprint
|
|
1602
|
+
xfp: record.masterFingerprint,
|
|
1603
|
+
origin: this._origin
|
|
1538
1604
|
});
|
|
1539
1605
|
const responseUr = await this._resolveUr(
|
|
1540
1606
|
record,
|
|
@@ -1568,7 +1634,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1568
1634
|
}
|
|
1569
1635
|
const path = normalizePath(params.path);
|
|
1570
1636
|
try {
|
|
1571
|
-
return await this._jobQueue.enqueue(
|
|
1637
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1572
1638
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "sol", signal);
|
|
1573
1639
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1574
1640
|
const requestId = uuidv4();
|
|
@@ -1577,7 +1643,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1577
1643
|
unsignedPayloadHex: stripHex(params.message),
|
|
1578
1644
|
dataType: "message",
|
|
1579
1645
|
path,
|
|
1580
|
-
xfp: record.masterFingerprint
|
|
1646
|
+
xfp: record.masterFingerprint,
|
|
1647
|
+
origin: this._origin
|
|
1581
1648
|
});
|
|
1582
1649
|
const responseUr = await this._resolveUr(
|
|
1583
1650
|
record,
|
|
@@ -1621,7 +1688,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1621
1688
|
);
|
|
1622
1689
|
}
|
|
1623
1690
|
try {
|
|
1624
|
-
return await this._jobQueue.enqueue(
|
|
1691
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1625
1692
|
const { account } = await this._fetchAccount(
|
|
1626
1693
|
connectId,
|
|
1627
1694
|
deviceId,
|
|
@@ -1667,7 +1734,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1667
1734
|
const rawTxHex = stripHex(params.rawTxHex);
|
|
1668
1735
|
const path = normalizePath(params.path);
|
|
1669
1736
|
try {
|
|
1670
|
-
return await this._jobQueue.enqueue(
|
|
1737
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1671
1738
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
|
|
1672
1739
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1673
1740
|
const requestId = uuidv4();
|
|
@@ -1675,7 +1742,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1675
1742
|
requestId,
|
|
1676
1743
|
rawTxHex,
|
|
1677
1744
|
path,
|
|
1678
|
-
xfp: record.masterFingerprint
|
|
1745
|
+
xfp: record.masterFingerprint,
|
|
1746
|
+
origin: this._origin
|
|
1679
1747
|
});
|
|
1680
1748
|
const responseUr = await this._resolveUr(
|
|
1681
1749
|
record,
|
|
@@ -1716,7 +1784,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1716
1784
|
const messageHex = stripHex(params.messageHex);
|
|
1717
1785
|
const path = normalizePath(params.path);
|
|
1718
1786
|
try {
|
|
1719
|
-
return await this._jobQueue.enqueue(
|
|
1787
|
+
return await this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1720
1788
|
const { record } = await this._ensureWalletKnown(connectId, deviceId, "tron", signal);
|
|
1721
1789
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1722
1790
|
const requestId = uuidv4();
|
|
@@ -1725,7 +1793,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1725
1793
|
rawTxHex: messageHex,
|
|
1726
1794
|
path,
|
|
1727
1795
|
xfp: record.masterFingerprint,
|
|
1728
|
-
signType: 2 /* PersonalMessage
|
|
1796
|
+
signType: 2 /* PersonalMessage */,
|
|
1797
|
+
origin: this._origin
|
|
1729
1798
|
});
|
|
1730
1799
|
const responseUr = await this._resolveUr(
|
|
1731
1800
|
record,
|
|
@@ -1748,8 +1817,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1748
1817
|
// Internals
|
|
1749
1818
|
// ---------------------------------------------------------------------------
|
|
1750
1819
|
_walletIdFromIdentifier(identifier) {
|
|
1751
|
-
|
|
1752
|
-
return /^[0-9a-f]{64}$/i.test(value) ? value.toLowerCase() : void 0;
|
|
1820
|
+
return keystoneWalletIdFromIdentifier(identifier);
|
|
1753
1821
|
}
|
|
1754
1822
|
_allNetworkSyncSchema(item) {
|
|
1755
1823
|
if (!isAllNetworkMethodName(String(item.methodName)) || !item.path) return void 0;
|
|
@@ -1778,7 +1846,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1778
1846
|
* one-path-at-a-time export flow because the device limits that channel.
|
|
1779
1847
|
*/
|
|
1780
1848
|
async _prefetchAllNetworkAccounts(connectId, deviceId, params) {
|
|
1781
|
-
return this._jobQueue.enqueue(
|
|
1849
|
+
return this._jobQueue.enqueue(keystoneQueueKey(connectId, deviceId), async (signal) => {
|
|
1782
1850
|
const target = this._resolveTarget(connectId, deviceId);
|
|
1783
1851
|
const { record: targetRecord } = target;
|
|
1784
1852
|
let record = targetRecord;
|
|
@@ -1791,7 +1859,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1791
1859
|
if (!requestedByKey.size) {
|
|
1792
1860
|
return { book };
|
|
1793
1861
|
}
|
|
1794
|
-
const operation =
|
|
1862
|
+
const operation = isHardwareOperationId2(params.operationId) ? this._operations.find(params.operationId) : void 0;
|
|
1795
1863
|
const operationRoute = operation ? this._operationRoutes.get(operation.connectId) : void 0;
|
|
1796
1864
|
const routedToQr = operationRoute?.operationId === operation?.operationId && operationRoute?.connectionType === "qr";
|
|
1797
1865
|
if (this._forcedTransport !== "qr" && !routedToQr && !record?.usbSessionId && this._usbConnector && target.expectedWalletId) {
|
|
@@ -1857,7 +1925,8 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1857
1925
|
});
|
|
1858
1926
|
const responseUr = await this._requestQrDisplayAndAwaitResponse(
|
|
1859
1927
|
record ? toDeviceInfo(record) : placeholderDeviceInfo(),
|
|
1860
|
-
{ ...requestUr, animated: false }
|
|
1928
|
+
{ ...requestUr, animated: false },
|
|
1929
|
+
signal
|
|
1861
1930
|
);
|
|
1862
1931
|
_KeystoneAdapter._throwIfAborted(signal);
|
|
1863
1932
|
const parsed = this.urEngine.parseAccountResponse(responseUr);
|
|
@@ -1893,7 +1962,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
1893
1962
|
*/
|
|
1894
1963
|
_resolveTarget(connectId, deviceId) {
|
|
1895
1964
|
let resolvedConnectId = connectId;
|
|
1896
|
-
if (
|
|
1965
|
+
if (isHardwareOperationId2(connectId)) {
|
|
1897
1966
|
resolvedConnectId = this._operations.resolve(connectId).connectId;
|
|
1898
1967
|
}
|
|
1899
1968
|
const identifiers = [deviceId, resolvedConnectId].filter(
|
|
@@ -2143,7 +2212,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2143
2212
|
* closed rather than silently falling back to QR.
|
|
2144
2213
|
*/
|
|
2145
2214
|
async _resolveUr(record, requestUr, animated, operationId, signal, operationName) {
|
|
2146
|
-
const releaseOperationRetention =
|
|
2215
|
+
const releaseOperationRetention = isHardwareOperationId2(operationId) ? this._operations.retain(operationId) : void 0;
|
|
2147
2216
|
try {
|
|
2148
2217
|
return await this._resolveUrWithRoute(
|
|
2149
2218
|
record,
|
|
@@ -2159,7 +2228,7 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2159
2228
|
}
|
|
2160
2229
|
async _resolveUrWithRoute(record, requestUr, animated, operationId, signal, operationName) {
|
|
2161
2230
|
let interactionRoute;
|
|
2162
|
-
if (
|
|
2231
|
+
if (isHardwareOperationId2(operationId)) {
|
|
2163
2232
|
const operation = this._operations.resolve(operationId);
|
|
2164
2233
|
const route = this._operationRoutes.get(operation.connectId);
|
|
2165
2234
|
if (!route || route.operationId !== operationId) {
|
|
@@ -2208,10 +2277,11 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2208
2277
|
const usbErrorCode = usbError.code;
|
|
2209
2278
|
if (!interactionRoute && !this._forcedTransport && usbErrorCode === HardwareErrorCode.PayloadTooLarge && usbErrorOrigin !== "device") {
|
|
2210
2279
|
const displayDevice2 = toDeviceInfo(record);
|
|
2211
|
-
return this._requestQrDisplayAndAwaitResponse(
|
|
2212
|
-
|
|
2213
|
-
animated
|
|
2214
|
-
|
|
2280
|
+
return this._requestQrDisplayAndAwaitResponse(
|
|
2281
|
+
displayDevice2,
|
|
2282
|
+
{ ...requestUr, animated },
|
|
2283
|
+
signal
|
|
2284
|
+
);
|
|
2215
2285
|
}
|
|
2216
2286
|
const deviceAnswered = usbErrorOrigin !== void 0 ? usbErrorOrigin === "device" : usbErrorCode === HardwareErrorCode.UserRejected || usbErrorCode === HardwareErrorCode.UserAborted || usbErrorCode === HardwareErrorCode.DeviceLocked || usbErrorCode === HardwareErrorCode.DeviceMismatch;
|
|
2217
2287
|
if (!deviceAnswered) {
|
|
@@ -2249,10 +2319,11 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2249
2319
|
}
|
|
2250
2320
|
const displayDevice = record ? toDeviceInfo(record) : placeholderDeviceInfo();
|
|
2251
2321
|
try {
|
|
2252
|
-
return await this._requestQrDisplayAndAwaitResponse(
|
|
2253
|
-
|
|
2254
|
-
animated
|
|
2255
|
-
|
|
2322
|
+
return await this._requestQrDisplayAndAwaitResponse(
|
|
2323
|
+
displayDevice,
|
|
2324
|
+
{ ...requestUr, animated },
|
|
2325
|
+
signal
|
|
2326
|
+
);
|
|
2256
2327
|
} catch (error) {
|
|
2257
2328
|
const { code, _tag: tag } = error;
|
|
2258
2329
|
if (operationName && (code === HardwareErrorCode.OperationTimeout || tag === UI_REQUEST_TIMEOUT_TAG)) {
|
|
@@ -2387,28 +2458,76 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2387
2458
|
const record = this._upsertDeviceRecord(parsed);
|
|
2388
2459
|
return { record };
|
|
2389
2460
|
}
|
|
2390
|
-
|
|
2461
|
+
/**
|
|
2462
|
+
* The operation the running device job belongs to, so a UI request raised
|
|
2463
|
+
* mid-call can name it. A call pinned to an operation queues under its id
|
|
2464
|
+
* (`keystoneQueueKey`); a call without one queues under the wallet id or the
|
|
2465
|
+
* wallet connectId, and the live operation routed to that connection is still
|
|
2466
|
+
* the owner. Only a cold start comes back undefined.
|
|
2467
|
+
*/
|
|
2468
|
+
_activeOperationId() {
|
|
2469
|
+
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
2470
|
+
if (!activeJobId) return void 0;
|
|
2471
|
+
if (isHardwareOperationId2(activeJobId)) return activeJobId;
|
|
2472
|
+
return this._operationRouteForIdentifier(activeJobId)?.operationId;
|
|
2473
|
+
}
|
|
2474
|
+
/** Routes are keyed by connectId; a job key may be the bare wallet id. */
|
|
2475
|
+
_operationRouteForIdentifier(identifier) {
|
|
2476
|
+
for (const key of keystoneCancelQueueKeys([identifier])) {
|
|
2477
|
+
const route = this._operationRoutes.get(key);
|
|
2478
|
+
if (route) return route;
|
|
2479
|
+
}
|
|
2480
|
+
const walletId = keystoneWalletIdFromIdentifier(identifier);
|
|
2481
|
+
return walletId ? this._operationRoutes.get(walletConnectId(walletId)) : void 0;
|
|
2482
|
+
}
|
|
2483
|
+
/**
|
|
2484
|
+
* A QR prompt has no transport to interrupt, so an aborted job would sit here
|
|
2485
|
+
* until the QR timeout. Releasing the registry slot on abort is what lets a
|
|
2486
|
+
* cancel reach the wait at all.
|
|
2487
|
+
*/
|
|
2488
|
+
async _awaitQrResponse(requestType, pending, signal) {
|
|
2489
|
+
if (!signal) return pending;
|
|
2490
|
+
let settled = false;
|
|
2491
|
+
const onAbort = () => {
|
|
2492
|
+
if (!settled) this._uiRegistry.cancel(requestType);
|
|
2493
|
+
};
|
|
2494
|
+
if (signal.aborted) onAbort();
|
|
2495
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
2496
|
+
try {
|
|
2497
|
+
return await pending;
|
|
2498
|
+
} finally {
|
|
2499
|
+
settled = true;
|
|
2500
|
+
signal.removeEventListener("abort", onAbort);
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
async _requestQrDisplayAndAwaitResponse(device, data, signal) {
|
|
2504
|
+
const operationId = this._activeOperationId();
|
|
2391
2505
|
const waitPromise = this._uiRegistry.wait(
|
|
2392
2506
|
UI_REQUEST.REQUEST_QR_DISPLAY,
|
|
2393
|
-
{ timeoutMs: this._qrTimeoutMs }
|
|
2507
|
+
{ timeoutMs: this._qrTimeoutMs, operationId }
|
|
2394
2508
|
);
|
|
2395
2509
|
this.emitter.emit(UI_REQUEST.REQUEST_QR_DISPLAY, {
|
|
2396
2510
|
type: UI_REQUEST.REQUEST_QR_DISPLAY,
|
|
2397
|
-
payload: { device, data }
|
|
2511
|
+
payload: { device, data, operationId }
|
|
2398
2512
|
});
|
|
2399
|
-
const response = await
|
|
2513
|
+
const response = await this._awaitQrResponse(
|
|
2514
|
+
UI_REQUEST.REQUEST_QR_DISPLAY,
|
|
2515
|
+
waitPromise,
|
|
2516
|
+
signal
|
|
2517
|
+
);
|
|
2400
2518
|
return { urType: response.urType, urData: response.urData };
|
|
2401
2519
|
}
|
|
2402
|
-
async _requestQrScanAndAwaitResponse(device) {
|
|
2520
|
+
async _requestQrScanAndAwaitResponse(device, signal) {
|
|
2521
|
+
const operationId = this._activeOperationId();
|
|
2403
2522
|
const waitPromise = this._uiRegistry.wait(
|
|
2404
2523
|
UI_REQUEST.REQUEST_QR_SCAN,
|
|
2405
|
-
{ timeoutMs: this._qrTimeoutMs }
|
|
2524
|
+
{ timeoutMs: this._qrTimeoutMs, operationId }
|
|
2406
2525
|
);
|
|
2407
2526
|
this.emitter.emit(UI_REQUEST.REQUEST_QR_SCAN, {
|
|
2408
2527
|
type: UI_REQUEST.REQUEST_QR_SCAN,
|
|
2409
|
-
payload: { device }
|
|
2528
|
+
payload: { device, operationId }
|
|
2410
2529
|
});
|
|
2411
|
-
const response = await waitPromise;
|
|
2530
|
+
const response = await this._awaitQrResponse(UI_REQUEST.REQUEST_QR_SCAN, waitPromise, signal);
|
|
2412
2531
|
return { urType: response.urType, urData: response.urData };
|
|
2413
2532
|
}
|
|
2414
2533
|
async _callUsbConnector(sessionId, method, params, signal) {
|
|
@@ -2424,6 +2543,12 @@ var KeystoneAdapter = class _KeystoneAdapter {
|
|
|
2424
2543
|
message: `Keystone USB is busy while calling ${method}`
|
|
2425
2544
|
});
|
|
2426
2545
|
}
|
|
2546
|
+
if (signal?.aborted) {
|
|
2547
|
+
throw signal.reason instanceof Error ? signal.reason : createHwkError({
|
|
2548
|
+
code: HardwareErrorCode.UserAborted,
|
|
2549
|
+
message: "User aborted operation"
|
|
2550
|
+
});
|
|
2551
|
+
}
|
|
2427
2552
|
const releaseOperation = this._retainUsbOperation(`call:${sessionId}`);
|
|
2428
2553
|
let rawCall;
|
|
2429
2554
|
try {
|