@onekeyfe/hwk-ledger-adapter 1.2.3-alpha.1 → 1.2.3-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/index.d.mts +14 -12
- package/dist/index.d.ts +14 -12
- package/dist/index.js +684 -559
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +679 -554
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -3
package/dist/index.js
CHANGED
|
@@ -550,7 +550,7 @@ var LEDGER_UNSUPPORTED_ALLNETWORK_NETWORKS = /* @__PURE__ */ new Set(["doge", "d
|
|
|
550
550
|
function createAllNetworkGetAddress({
|
|
551
551
|
callChain,
|
|
552
552
|
getChainFingerprint,
|
|
553
|
-
|
|
553
|
+
retainOperation,
|
|
554
554
|
errorToFailure
|
|
555
555
|
}) {
|
|
556
556
|
return async function allNetworkGetAddress(connectId, _deviceId, params) {
|
|
@@ -559,19 +559,19 @@ function createAllNetworkGetAddress({
|
|
|
559
559
|
connectId,
|
|
560
560
|
itemCount: params.bundle.length
|
|
561
561
|
});
|
|
562
|
-
const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.
|
|
562
|
+
const target = (0, import_hwk_adapter_core2.resolveHardwareOperationTarget)(connectId, params.operationId, "ledger");
|
|
563
563
|
if (!target.success) return target;
|
|
564
564
|
const effectiveTargetId = target.payload.targetId ?? "";
|
|
565
|
-
let
|
|
565
|
+
let releaseOperationRetention;
|
|
566
566
|
try {
|
|
567
|
-
|
|
567
|
+
releaseOperationRetention = target.payload.operationId ? retainOperation(target.payload.operationId) : void 0;
|
|
568
568
|
} catch (error) {
|
|
569
569
|
return errorToFailure(error);
|
|
570
570
|
}
|
|
571
571
|
const installContext = {};
|
|
572
572
|
const commonParams = {
|
|
573
573
|
autoInstallApp: params.autoInstallApp,
|
|
574
|
-
|
|
574
|
+
operationId: target.payload.operationId,
|
|
575
575
|
knownConnections: params.knownConnections,
|
|
576
576
|
extra: params.extra,
|
|
577
577
|
allowDeviceSelection: params.allowDeviceSelection
|
|
@@ -622,7 +622,7 @@ function createAllNetworkGetAddress({
|
|
|
622
622
|
});
|
|
623
623
|
return result;
|
|
624
624
|
} finally {
|
|
625
|
-
|
|
625
|
+
releaseOperationRetention?.();
|
|
626
626
|
}
|
|
627
627
|
};
|
|
628
628
|
}
|
|
@@ -631,7 +631,7 @@ function isTopLevelAllNetworkFailure(response) {
|
|
|
631
631
|
return false;
|
|
632
632
|
}
|
|
633
633
|
const code = response.payload?.code;
|
|
634
|
-
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.
|
|
634
|
+
return code === import_hwk_adapter_core2.HardwareErrorCode.DeviceMismatch || code === import_hwk_adapter_core2.HardwareErrorCode.DeviceDisconnected || code === import_hwk_adapter_core2.HardwareErrorCode.OperationTimeout || code === import_hwk_adapter_core2.HardwareErrorCode.TransportError || code === import_hwk_adapter_core2.HardwareErrorCode.OperationEnded || code === import_hwk_adapter_core2.HardwareErrorCode.OperationNotFound || code === import_hwk_adapter_core2.HardwareErrorCode.UserAborted || code === import_hwk_adapter_core2.HardwareErrorCode.UserRejected;
|
|
635
635
|
}
|
|
636
636
|
function getItemDeviceId(item) {
|
|
637
637
|
const { deviceId } = item;
|
|
@@ -794,26 +794,26 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
794
794
|
constructor(connector, options) {
|
|
795
795
|
this.vendor = "ledger";
|
|
796
796
|
this.emitter = new import_hwk_adapter_core3.TypedEventEmitter();
|
|
797
|
-
this.
|
|
797
|
+
this._operations = new import_hwk_adapter_core3.OperationRegistry({
|
|
798
798
|
vendor: "ledger",
|
|
799
|
-
onEnded: (
|
|
800
|
-
const binding = this.
|
|
799
|
+
onEnded: (operation, reason) => {
|
|
800
|
+
const binding = this._pendingOperationBindings.get(operation.operationId);
|
|
801
801
|
if (binding?.selectedConnection?.requestId === this._bindingSelectionRequestId) {
|
|
802
802
|
this._finishBleBinding("cancelled");
|
|
803
803
|
}
|
|
804
|
-
this.
|
|
805
|
-
this.emitter.emit(import_hwk_adapter_core3.SDK.
|
|
806
|
-
type: import_hwk_adapter_core3.SDK.
|
|
807
|
-
payload: {
|
|
804
|
+
this._pendingOperationBindings.delete(operation.operationId);
|
|
805
|
+
this.emitter.emit(import_hwk_adapter_core3.SDK.OPERATION_ENDED, {
|
|
806
|
+
type: import_hwk_adapter_core3.SDK.OPERATION_ENDED,
|
|
807
|
+
payload: { operationId: operation.operationId, reason }
|
|
808
808
|
});
|
|
809
809
|
if (reason === "timeout") {
|
|
810
|
-
void this.
|
|
810
|
+
void this._releaseOperationConnection(operation);
|
|
811
811
|
}
|
|
812
812
|
}
|
|
813
813
|
});
|
|
814
814
|
this._discoveredDevices = /* @__PURE__ */ new Map();
|
|
815
815
|
this._sessions = /* @__PURE__ */ new Map();
|
|
816
|
-
this.
|
|
816
|
+
this._pendingOperationBindings = /* @__PURE__ */ new Map();
|
|
817
817
|
this._verifiedBleReconnectTargets = /* @__PURE__ */ new Map();
|
|
818
818
|
this._uiRegistry = new import_hwk_adapter_core3.UiRequestRegistry();
|
|
819
819
|
// BTC App rejects account index >= 100 unless display=true. Cached per
|
|
@@ -834,8 +834,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
834
834
|
this._stateGeneration = 0;
|
|
835
835
|
this._connectorTeardownTail = Promise.resolve();
|
|
836
836
|
this._pendingConnectorTeardowns = 0;
|
|
837
|
-
this.
|
|
838
|
-
this.
|
|
837
|
+
this._activeOperationJobs = /* @__PURE__ */ new Set();
|
|
838
|
+
this._pendingOperationDisconnects = /* @__PURE__ */ new Set();
|
|
839
839
|
this._installProgressLastEmittedValue = -Infinity;
|
|
840
840
|
this.allNetworkGetAddress = createAllNetworkGetAddress({
|
|
841
841
|
callChain: this.callChain.bind(this),
|
|
@@ -850,7 +850,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
850
850
|
return this.errorToFailure(error);
|
|
851
851
|
}
|
|
852
852
|
},
|
|
853
|
-
|
|
853
|
+
retainOperation: (operationId) => this._operations.retain(operationId),
|
|
854
854
|
errorToFailure: (error) => this.errorToFailure(error)
|
|
855
855
|
});
|
|
856
856
|
// ---------------------------------------------------------------------------
|
|
@@ -878,11 +878,11 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
878
878
|
});
|
|
879
879
|
};
|
|
880
880
|
this.deviceDisconnectHandler = (data) => {
|
|
881
|
-
const
|
|
882
|
-
if (
|
|
883
|
-
this.
|
|
881
|
+
const activeOperation = this._operations.findActiveByConnectionKey(data.connectId);
|
|
882
|
+
if (activeOperation && this._activeOperationJobs.has(activeOperation.operationId)) {
|
|
883
|
+
this._pendingOperationDisconnects.add(activeOperation.operationId);
|
|
884
884
|
} else {
|
|
885
|
-
this.
|
|
885
|
+
this._operations.endByConnectionKey(data.connectId, "disconnect");
|
|
886
886
|
}
|
|
887
887
|
this._discoveredDevices.delete(data.connectId);
|
|
888
888
|
this._sessions.delete(data.connectId);
|
|
@@ -985,7 +985,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
985
985
|
const sessionIds = new Set(this._sessions.values());
|
|
986
986
|
this._stateGeneration += 1;
|
|
987
987
|
this._finishBleBinding("cancelled");
|
|
988
|
-
this.
|
|
988
|
+
this._operations.endAll("runtime-reset");
|
|
989
989
|
this._doConnectAbortController?.abort();
|
|
990
990
|
this._discoveredDevices.clear();
|
|
991
991
|
this._sessions.clear();
|
|
@@ -1094,8 +1094,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1094
1094
|
}));
|
|
1095
1095
|
}
|
|
1096
1096
|
// USB single-session invariant: evict all sessions, best-effort (see connectDevice).
|
|
1097
|
-
async _evictAllSessions(
|
|
1098
|
-
this.
|
|
1097
|
+
async _evictAllSessions(preserveOperationId) {
|
|
1098
|
+
this._operations.endAll("explicit", preserveOperationId);
|
|
1099
1099
|
if (this._sessions.size === 0) return;
|
|
1100
1100
|
const stale = [...this._sessions.values()];
|
|
1101
1101
|
this._sessions.clear();
|
|
@@ -1114,11 +1114,129 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1114
1114
|
});
|
|
1115
1115
|
}
|
|
1116
1116
|
async connectDevice(searchTargetId) {
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1117
|
+
try {
|
|
1118
|
+
return await this._jobQueue.enqueue(
|
|
1119
|
+
searchTargetId || "__ledger_connect__",
|
|
1120
|
+
async () => {
|
|
1121
|
+
const connected = await this._connectTarget(searchTargetId);
|
|
1122
|
+
if (!connected.success) return connected;
|
|
1123
|
+
return this._createOperation(searchTargetId, connected.payload);
|
|
1124
|
+
},
|
|
1125
|
+
{
|
|
1126
|
+
label: "connectDevice",
|
|
1127
|
+
rejectIfBusy: true,
|
|
1128
|
+
busyError: _LedgerAdapter._createDeviceBusyError("connectDevice")
|
|
1129
|
+
}
|
|
1130
|
+
);
|
|
1131
|
+
} catch (error) {
|
|
1132
|
+
return this.errorToFailure(error);
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
async bindBleDevice(params) {
|
|
1136
|
+
if (params.identity.vendor !== "ledger" || !params.identity.value) {
|
|
1137
|
+
return (0, import_hwk_adapter_core3.failure)(import_hwk_adapter_core3.HardwareErrorCode.InvalidParams, "Ledger wallet identity is required");
|
|
1138
|
+
}
|
|
1139
|
+
const { chain, value: expectedFingerprint } = params.identity;
|
|
1140
|
+
try {
|
|
1141
|
+
return await this._jobQueue.enqueue(
|
|
1142
|
+
expectedFingerprint,
|
|
1143
|
+
async (signal) => {
|
|
1144
|
+
if (!this.getAvailableTransports().includes("ble")) {
|
|
1145
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1146
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.TransportNotAvailable,
|
|
1147
|
+
message: "Ledger Bluetooth transport is not available"
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
this._activeConnectionType = "ble";
|
|
1151
|
+
await this._ensureDevicePermission(void 0, void 0, signal);
|
|
1152
|
+
const attempt = {
|
|
1153
|
+
extra: params.extra,
|
|
1154
|
+
bindingReason: "manual-rebind"
|
|
1155
|
+
};
|
|
1156
|
+
try {
|
|
1157
|
+
for (; ; ) {
|
|
1158
|
+
const connectId = await this._connectFirstOrSelect(
|
|
1159
|
+
[],
|
|
1160
|
+
void 0,
|
|
1161
|
+
true,
|
|
1162
|
+
void 0,
|
|
1163
|
+
attempt,
|
|
1164
|
+
signal
|
|
1165
|
+
);
|
|
1166
|
+
const sessionId = this._sessions.get(connectId);
|
|
1167
|
+
if (!sessionId) {
|
|
1168
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1169
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
1170
|
+
message: "Selected Ledger connection ended"
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
let saved = false;
|
|
1174
|
+
try {
|
|
1175
|
+
const installContext = {
|
|
1176
|
+
connection: { connectId, sessionId }
|
|
1177
|
+
};
|
|
1178
|
+
const fingerprint = await this._computeChainFingerprint(
|
|
1179
|
+
chain,
|
|
1180
|
+
(method, callParams) => this._runConnectorCall(
|
|
1181
|
+
connectId,
|
|
1182
|
+
method,
|
|
1183
|
+
callParams,
|
|
1184
|
+
signal,
|
|
1185
|
+
void 0,
|
|
1186
|
+
void 0,
|
|
1187
|
+
{ autoInstallApp: true },
|
|
1188
|
+
installContext
|
|
1189
|
+
)
|
|
1190
|
+
);
|
|
1191
|
+
if (fingerprint !== expectedFingerprint) {
|
|
1192
|
+
attempt.rejectedConnectIds ?? (attempt.rejectedConnectIds = /* @__PURE__ */ new Set());
|
|
1193
|
+
attempt.rejectedConnectIds.add(connectId);
|
|
1194
|
+
attempt.rejectedConnectId = connectId;
|
|
1195
|
+
} else {
|
|
1196
|
+
const persisted = await this._publishVerifiedBleBinding(
|
|
1197
|
+
connectId,
|
|
1198
|
+
chain,
|
|
1199
|
+
fingerprint,
|
|
1200
|
+
attempt,
|
|
1201
|
+
void 0,
|
|
1202
|
+
signal
|
|
1203
|
+
);
|
|
1204
|
+
if (!persisted) {
|
|
1205
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
1206
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.UnknownError,
|
|
1207
|
+
message: "Bluetooth binding could not be saved",
|
|
1208
|
+
origin: "host"
|
|
1209
|
+
});
|
|
1210
|
+
}
|
|
1211
|
+
saved = true;
|
|
1212
|
+
return (0, import_hwk_adapter_core3.success)(connectId);
|
|
1213
|
+
}
|
|
1214
|
+
} finally {
|
|
1215
|
+
if (!saved && this._sessions.get(connectId) === sessionId) {
|
|
1216
|
+
this._sessions.delete(connectId);
|
|
1217
|
+
const teardown = this._runConnectorTeardown(
|
|
1218
|
+
() => this.connector.disconnect(sessionId)
|
|
1219
|
+
).catch(() => void 0);
|
|
1220
|
+
if (!signal.aborted) await teardown;
|
|
1221
|
+
}
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
1226
|
+
throw error;
|
|
1227
|
+
}
|
|
1228
|
+
},
|
|
1229
|
+
{
|
|
1230
|
+
label: "bindBleDevice",
|
|
1231
|
+
rejectIfBusy: true,
|
|
1232
|
+
busyError: _LedgerAdapter._createDeviceBusyError("bindBleDevice")
|
|
1233
|
+
}
|
|
1234
|
+
);
|
|
1235
|
+
} catch (error) {
|
|
1236
|
+
return this.errorToFailure(error);
|
|
1237
|
+
}
|
|
1120
1238
|
}
|
|
1121
|
-
async
|
|
1239
|
+
async acquireOperation(connectId, context) {
|
|
1122
1240
|
try {
|
|
1123
1241
|
return await this._jobQueue.enqueue(
|
|
1124
1242
|
connectId || "__ledger_acquire__",
|
|
@@ -1131,8 +1249,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1131
1249
|
await this._ensureDevicePermission(target, void 0, signal);
|
|
1132
1250
|
const attempt = {
|
|
1133
1251
|
...context,
|
|
1134
|
-
extra: context.extra ? { ...context.extra } : void 0
|
|
1135
|
-
previousConnectId: target
|
|
1252
|
+
extra: context.extra ? { ...context.extra } : void 0
|
|
1136
1253
|
};
|
|
1137
1254
|
try {
|
|
1138
1255
|
const resolvedConnectId = await this.ensureConnected(
|
|
@@ -1143,9 +1260,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1143
1260
|
attempt
|
|
1144
1261
|
);
|
|
1145
1262
|
_LedgerAdapter._throwIfAborted(signal);
|
|
1146
|
-
const result = this.
|
|
1263
|
+
const result = this._createOperation(connectId, resolvedConnectId);
|
|
1147
1264
|
if (result.success && attempt.selectedConnection) {
|
|
1148
|
-
this.
|
|
1265
|
+
this._pendingOperationBindings.set(result.payload, attempt);
|
|
1149
1266
|
}
|
|
1150
1267
|
return result;
|
|
1151
1268
|
} catch (error) {
|
|
@@ -1154,19 +1271,19 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1154
1271
|
}
|
|
1155
1272
|
},
|
|
1156
1273
|
{
|
|
1157
|
-
label: "
|
|
1274
|
+
label: "acquireOperation",
|
|
1158
1275
|
rejectIfBusy: true,
|
|
1159
|
-
busyError: _LedgerAdapter._createDeviceBusyError("
|
|
1276
|
+
busyError: _LedgerAdapter._createDeviceBusyError("acquireOperation")
|
|
1160
1277
|
}
|
|
1161
1278
|
);
|
|
1162
1279
|
} catch (error) {
|
|
1163
1280
|
return this.errorToFailure(error);
|
|
1164
1281
|
}
|
|
1165
1282
|
}
|
|
1166
|
-
|
|
1167
|
-
this.
|
|
1283
|
+
_createOperation(searchTargetId, resolvedConnectId) {
|
|
1284
|
+
this._operations.endByConnectionKey(resolvedConnectId, "explicit");
|
|
1168
1285
|
const sessionId = this._sessions.get(resolvedConnectId);
|
|
1169
|
-
if (sessionId) this.
|
|
1286
|
+
if (sessionId) this._operations.endByConnectionKey(sessionId, "explicit");
|
|
1170
1287
|
const device = this._discoveredDevices.get(resolvedConnectId) ?? {
|
|
1171
1288
|
vendor: "ledger",
|
|
1172
1289
|
model: "unknown",
|
|
@@ -1175,15 +1292,15 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1175
1292
|
connectId: resolvedConnectId,
|
|
1176
1293
|
connectionType: this.connector.connectionType
|
|
1177
1294
|
};
|
|
1178
|
-
const
|
|
1295
|
+
const operation = this._operations.create({
|
|
1179
1296
|
searchTargetId,
|
|
1180
1297
|
connectId: resolvedConnectId,
|
|
1181
1298
|
device,
|
|
1182
1299
|
connectionKeys: [this._sessions.get(resolvedConnectId) ?? ""]
|
|
1183
1300
|
});
|
|
1184
|
-
return (0, import_hwk_adapter_core3.success)(
|
|
1301
|
+
return (0, import_hwk_adapter_core3.success)(operation.operationId);
|
|
1185
1302
|
}
|
|
1186
|
-
async _connectTarget(connectId,
|
|
1303
|
+
async _connectTarget(connectId, preserveOperationId, signal) {
|
|
1187
1304
|
debugLog("[LedgerAdapter][REQ]", { method: "connectDevice", connectId, params: { connectId } });
|
|
1188
1305
|
try {
|
|
1189
1306
|
this._assertConnectorReady("connectDevice");
|
|
@@ -1199,21 +1316,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1199
1316
|
await this._ensureDevicePermission(connectId, void 0, signal);
|
|
1200
1317
|
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1201
1318
|
if (this.connector.availableTransports && this.connector.availableTransports.length > 1) {
|
|
1202
|
-
await this._evictAllSessions(
|
|
1319
|
+
await this._evictAllSessions(preserveOperationId);
|
|
1203
1320
|
} else if (this._isBleConnection()) {
|
|
1204
1321
|
const previousSessionId = this._sessions.get(connectId);
|
|
1205
|
-
this.
|
|
1322
|
+
this._operations.endByConnectionKey(connectId, "explicit", preserveOperationId);
|
|
1206
1323
|
if (previousSessionId) {
|
|
1207
|
-
this.
|
|
1208
|
-
previousSessionId,
|
|
1209
|
-
"explicit",
|
|
1210
|
-
preserveInteractionId
|
|
1211
|
-
);
|
|
1324
|
+
this._operations.endByConnectionKey(previousSessionId, "explicit", preserveOperationId);
|
|
1212
1325
|
this._sessions.delete(connectId);
|
|
1213
1326
|
await this.connector.disconnect(previousSessionId).catch(() => void 0);
|
|
1214
1327
|
}
|
|
1215
1328
|
} else {
|
|
1216
|
-
await this._evictAllSessions(
|
|
1329
|
+
await this._evictAllSessions(preserveOperationId);
|
|
1217
1330
|
}
|
|
1218
1331
|
if (signal) _LedgerAdapter._throwIfAborted(signal);
|
|
1219
1332
|
const stateGeneration = this._stateGeneration;
|
|
@@ -1250,37 +1363,37 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1250
1363
|
return failureResult;
|
|
1251
1364
|
}
|
|
1252
1365
|
}
|
|
1253
|
-
async
|
|
1254
|
-
const
|
|
1255
|
-
if (!
|
|
1256
|
-
this.
|
|
1366
|
+
async releaseOperation(operationId) {
|
|
1367
|
+
const operation = this._operations.find(operationId);
|
|
1368
|
+
if (!operation) {
|
|
1369
|
+
this._operations.resolve(operationId);
|
|
1257
1370
|
return;
|
|
1258
1371
|
}
|
|
1259
|
-
const
|
|
1260
|
-
if (!
|
|
1261
|
-
const { connectId } =
|
|
1372
|
+
const endedOperation = this._operations.end(operationId, "explicit");
|
|
1373
|
+
if (!endedOperation) return;
|
|
1374
|
+
const { connectId } = operation;
|
|
1262
1375
|
debugLog("[LedgerAdapter][REQ]", {
|
|
1263
|
-
method: "
|
|
1376
|
+
method: "releaseOperation",
|
|
1264
1377
|
connectId,
|
|
1265
1378
|
params: { connectId }
|
|
1266
1379
|
});
|
|
1267
1380
|
try {
|
|
1268
|
-
await this.
|
|
1269
|
-
debugLog("[LedgerAdapter][RES]", { method: "
|
|
1381
|
+
await this._releaseOperationConnection(endedOperation);
|
|
1382
|
+
debugLog("[LedgerAdapter][RES]", { method: "releaseOperation", success: true });
|
|
1270
1383
|
} catch (err) {
|
|
1271
1384
|
const e = err;
|
|
1272
1385
|
debugLog("[LedgerAdapter][RES]", {
|
|
1273
|
-
method: "
|
|
1386
|
+
method: "releaseOperation",
|
|
1274
1387
|
success: false,
|
|
1275
1388
|
error: { message: e?.message, _tag: e?._tag, code: e?.code ?? e?.errorCode }
|
|
1276
1389
|
});
|
|
1277
1390
|
throw err;
|
|
1278
1391
|
}
|
|
1279
1392
|
}
|
|
1280
|
-
async
|
|
1393
|
+
async _releaseOperationConnection(operation) {
|
|
1281
1394
|
const sessionIds = /* @__PURE__ */ new Set();
|
|
1282
1395
|
for (const [connectId, sessionId] of this._sessions) {
|
|
1283
|
-
if (connectId ===
|
|
1396
|
+
if (connectId === operation.connectId || operation.connectionKeys.includes(connectId) || operation.connectionKeys.includes(sessionId)) {
|
|
1284
1397
|
this._sessions.delete(connectId);
|
|
1285
1398
|
sessionIds.add(sessionId);
|
|
1286
1399
|
}
|
|
@@ -1291,16 +1404,16 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1291
1404
|
);
|
|
1292
1405
|
}
|
|
1293
1406
|
}
|
|
1294
|
-
async
|
|
1295
|
-
const
|
|
1296
|
-
if (!
|
|
1297
|
-
this._discoveredDevices.delete(
|
|
1298
|
-
await this.
|
|
1407
|
+
async _releaseLostOperationConnection(operationId) {
|
|
1408
|
+
const endedOperation = this._operations.end(operationId, "disconnect");
|
|
1409
|
+
if (!endedOperation) return;
|
|
1410
|
+
this._discoveredDevices.delete(endedOperation.connectId);
|
|
1411
|
+
await this._releaseOperationConnection(endedOperation);
|
|
1299
1412
|
}
|
|
1300
|
-
async getDeviceInfo(
|
|
1413
|
+
async getDeviceInfo(connectIdOrOperationId, deviceId) {
|
|
1301
1414
|
let connectId;
|
|
1302
1415
|
try {
|
|
1303
|
-
connectId = (0, import_hwk_adapter_core3.
|
|
1416
|
+
connectId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectIdOrOperationId) ? this._operations.resolve(connectIdOrOperationId).connectId : connectIdOrOperationId;
|
|
1304
1417
|
} catch (error) {
|
|
1305
1418
|
return this.errorToFailure(error);
|
|
1306
1419
|
}
|
|
@@ -1341,9 +1454,6 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1341
1454
|
throw err;
|
|
1342
1455
|
}
|
|
1343
1456
|
}
|
|
1344
|
-
getSupportedChains() {
|
|
1345
|
-
return ["evm", "btc", "sol", "tron", "zcash"];
|
|
1346
|
-
}
|
|
1347
1457
|
// ---------------------------------------------------------------------------
|
|
1348
1458
|
// Chain call helper
|
|
1349
1459
|
// ---------------------------------------------------------------------------
|
|
@@ -1378,7 +1488,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1378
1488
|
if (params && typeof params === "object") {
|
|
1379
1489
|
const {
|
|
1380
1490
|
autoInstallApp,
|
|
1381
|
-
|
|
1491
|
+
operationId,
|
|
1382
1492
|
passphraseState: _passphraseState,
|
|
1383
1493
|
useEmptyPassphrase: _useEmptyPassphrase,
|
|
1384
1494
|
knownConnections,
|
|
@@ -1389,7 +1499,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1389
1499
|
return {
|
|
1390
1500
|
commonParams: {
|
|
1391
1501
|
autoInstallApp: typeof autoInstallApp === "boolean" ? autoInstallApp : void 0,
|
|
1392
|
-
|
|
1502
|
+
operationId: typeof operationId === "string" ? operationId : void 0,
|
|
1393
1503
|
knownConnections,
|
|
1394
1504
|
extra,
|
|
1395
1505
|
allowDeviceSelection: typeof allowDeviceSelection === "boolean" ? allowDeviceSelection : void 0
|
|
@@ -1718,6 +1828,20 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1718
1828
|
this.emitter.off(event, listener);
|
|
1719
1829
|
}
|
|
1720
1830
|
cancel(connectId) {
|
|
1831
|
+
const namedOperationIsLive = (id) => {
|
|
1832
|
+
try {
|
|
1833
|
+
this._operations.resolve(id);
|
|
1834
|
+
return true;
|
|
1835
|
+
} catch {
|
|
1836
|
+
return false;
|
|
1837
|
+
}
|
|
1838
|
+
};
|
|
1839
|
+
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) && !namedOperationIsLive(connectId)) {
|
|
1840
|
+
debugLog("[LedgerAdapter] cancel target already ended; nothing to cancel", {
|
|
1841
|
+
connectId
|
|
1842
|
+
});
|
|
1843
|
+
return;
|
|
1844
|
+
}
|
|
1721
1845
|
const userAbortReason = Object.assign(new Error("User aborted operation"), {
|
|
1722
1846
|
code: import_hwk_adapter_core3.HardwareErrorCode.UserAborted,
|
|
1723
1847
|
_tag: ERROR_TAG.UserAborted
|
|
@@ -1728,29 +1852,29 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1728
1852
|
this._lastCancelReason = void 0;
|
|
1729
1853
|
}
|
|
1730
1854
|
}, 2e3);
|
|
1731
|
-
this._uiRegistry.cancel();
|
|
1732
|
-
this._finishBleBinding("cancelled");
|
|
1733
1855
|
const activeJobId = this._jobQueue.getActiveJob()?.deviceId;
|
|
1734
|
-
let
|
|
1735
|
-
if ((0, import_hwk_adapter_core3.
|
|
1736
|
-
|
|
1737
|
-
} else if (!connectId && (0, import_hwk_adapter_core3.
|
|
1738
|
-
|
|
1856
|
+
let operationId;
|
|
1857
|
+
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
|
|
1858
|
+
operationId = connectId;
|
|
1859
|
+
} else if (!connectId && (0, import_hwk_adapter_core3.isHardwareOperationId)(activeJobId)) {
|
|
1860
|
+
operationId = activeJobId;
|
|
1739
1861
|
}
|
|
1740
1862
|
let resolvedConnectId = connectId;
|
|
1741
|
-
if (
|
|
1863
|
+
if (operationId) {
|
|
1742
1864
|
try {
|
|
1743
|
-
resolvedConnectId = this.
|
|
1865
|
+
resolvedConnectId = this._operations.resolve(operationId).connectId;
|
|
1744
1866
|
} catch {
|
|
1745
1867
|
resolvedConnectId = void 0;
|
|
1746
1868
|
}
|
|
1747
1869
|
}
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
const
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1870
|
+
this._uiRegistry.cancel();
|
|
1871
|
+
this._finishBleBinding("cancelled");
|
|
1872
|
+
const interactionForPhysicalId = !operationId && connectId ? this._operations.findActiveByConnectionKey(connectId) : void 0;
|
|
1873
|
+
const queueKey = operationId ?? (activeJobId === connectId ? connectId : interactionForPhysicalId?.operationId) ?? connectId;
|
|
1874
|
+
const pendingOperationId = operationId ?? interactionForPhysicalId?.operationId;
|
|
1875
|
+
if (!connectId) this._pendingOperationBindings.clear();
|
|
1876
|
+
else if (pendingOperationId) {
|
|
1877
|
+
this._pendingOperationBindings.delete(pendingOperationId);
|
|
1754
1878
|
}
|
|
1755
1879
|
if (queueKey) {
|
|
1756
1880
|
this._jobQueue.cancelActiveAndPending(queueKey, userAbortReason);
|
|
@@ -1784,10 +1908,10 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1784
1908
|
formatDeviceMismatchError(deviceId, fingerprint)
|
|
1785
1909
|
);
|
|
1786
1910
|
}
|
|
1787
|
-
if ((0, import_hwk_adapter_core3.
|
|
1788
|
-
const
|
|
1911
|
+
if ((0, import_hwk_adapter_core3.isHardwareOperationId)(connectId)) {
|
|
1912
|
+
const operation = this._operations.resolve(connectId);
|
|
1789
1913
|
await this._publishVerifiedBleBinding(
|
|
1790
|
-
|
|
1914
|
+
operation.connectId,
|
|
1791
1915
|
chain,
|
|
1792
1916
|
fingerprint,
|
|
1793
1917
|
void 0,
|
|
@@ -1802,39 +1926,53 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
1802
1926
|
}
|
|
1803
1927
|
}
|
|
1804
1928
|
/** Discovery may select a BLE target before a later call verifies its wallet. */
|
|
1805
|
-
async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt,
|
|
1806
|
-
const binding =
|
|
1807
|
-
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId)
|
|
1808
|
-
|
|
1809
|
-
this.emitter,
|
|
1810
|
-
this._uiRegistry,
|
|
1811
|
-
{
|
|
1812
|
-
selectionRequestId: binding.selectedConnection.requestId,
|
|
1813
|
-
connection: { transport: "ble", connectId },
|
|
1814
|
-
identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
|
|
1815
|
-
extra: binding.extra
|
|
1816
|
-
},
|
|
1817
|
-
signal
|
|
1818
|
-
);
|
|
1819
|
-
if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
|
|
1820
|
-
this._bindingSelectionRequestId = void 0;
|
|
1821
|
-
}
|
|
1822
|
-
if (interactionId) {
|
|
1823
|
-
this._interactions.resolve(interactionId);
|
|
1824
|
-
this._pendingInteractionBindings.delete(interactionId);
|
|
1929
|
+
async _publishVerifiedBleBinding(connectId, chain, fingerprint, attempt, operationId, signal) {
|
|
1930
|
+
const binding = operationId ? this._pendingOperationBindings.get(operationId) : attempt;
|
|
1931
|
+
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== connectId) {
|
|
1932
|
+
return false;
|
|
1825
1933
|
}
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1934
|
+
try {
|
|
1935
|
+
const outcome = await (0, import_hwk_adapter_core3.requestSaveDeviceBinding)(
|
|
1936
|
+
this.emitter,
|
|
1937
|
+
this._uiRegistry,
|
|
1938
|
+
{
|
|
1939
|
+
selectionRequestId: binding.selectedConnection.requestId,
|
|
1940
|
+
connection: { transport: "ble", connectId },
|
|
1941
|
+
identity: { vendor: "ledger", type: "chainFingerprint", chain, value: fingerprint },
|
|
1942
|
+
extra: binding.extra
|
|
1943
|
+
},
|
|
1944
|
+
signal
|
|
1945
|
+
);
|
|
1946
|
+
if (operationId) this._operations.resolve(operationId);
|
|
1947
|
+
if (!outcome.saved) {
|
|
1948
|
+
debugLog("[LedgerAdapter] BLE binding not persisted by host", {
|
|
1949
|
+
connectId,
|
|
1950
|
+
reason: outcome.reason
|
|
1951
|
+
});
|
|
1836
1952
|
}
|
|
1837
|
-
|
|
1953
|
+
return outcome.saved;
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
if (operationId) {
|
|
1956
|
+
this._pendingOperationBindings.delete(operationId);
|
|
1957
|
+
this._operations.end(operationId, "explicit");
|
|
1958
|
+
}
|
|
1959
|
+
const sessionId = this._sessions.get(connectId);
|
|
1960
|
+
this._sessions.delete(connectId);
|
|
1961
|
+
if (sessionId) {
|
|
1962
|
+
const teardown = this._runConnectorTeardown(
|
|
1963
|
+
() => this.connector.disconnect(sessionId)
|
|
1964
|
+
).catch(() => void 0);
|
|
1965
|
+
if (!signal?.aborted) await teardown;
|
|
1966
|
+
}
|
|
1967
|
+
throw error;
|
|
1968
|
+
} finally {
|
|
1969
|
+
if (this._bindingSelectionRequestId === binding.selectedConnection.requestId) {
|
|
1970
|
+
this._bindingSelectionRequestId = void 0;
|
|
1971
|
+
}
|
|
1972
|
+
if (operationId) {
|
|
1973
|
+
this._pendingOperationBindings.delete(operationId);
|
|
1974
|
+
}
|
|
1975
|
+
}
|
|
1838
1976
|
}
|
|
1839
1977
|
/** Verify on the acquired session without re-entering the job queue. */
|
|
1840
1978
|
async _verifyDeviceFingerprintWithSession(sessionId, deviceId, chain) {
|
|
@@ -2006,7 +2144,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2006
2144
|
// Layer 1 entry. Caller signal only races the outer awaiter; the shared
|
|
2007
2145
|
// `_doConnect` runs under its own internal controller so caller A's cancel
|
|
2008
2146
|
// doesn't kill caller B's await.
|
|
2009
|
-
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false,
|
|
2147
|
+
async ensureConnected(connectId, signal, allowUsbEphemeralFallback = false, preserveOperationId, context) {
|
|
2010
2148
|
if (signal.aborted) _LedgerAdapter._throwIfAborted(signal);
|
|
2011
2149
|
this._assertConnectorReady("connectDevice");
|
|
2012
2150
|
if (this._isBleConnection() && !connectId && !allowUsbEphemeralFallback) {
|
|
@@ -2036,7 +2174,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2036
2174
|
innerSignal,
|
|
2037
2175
|
connectId,
|
|
2038
2176
|
allowUsbEphemeralFallback,
|
|
2039
|
-
|
|
2177
|
+
preserveOperationId,
|
|
2040
2178
|
context
|
|
2041
2179
|
);
|
|
2042
2180
|
} finally {
|
|
@@ -2052,7 +2190,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2052
2190
|
// Layer 1 main loop — the ONLY place in SDK that emits unlock dialog.
|
|
2053
2191
|
// Bounded by MAX_DOCONNECT_CONFIRMS — after N Confirms with no progress,
|
|
2054
2192
|
// throw DeviceNotFound so the user is kicked out of the loop.
|
|
2055
|
-
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false,
|
|
2193
|
+
async _doConnect(internalSignal, targetConnectId, allowUsbEphemeralFallback = false, preserveOperationId, context) {
|
|
2056
2194
|
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2057
2195
|
if (this.connector.availableTransports?.includes("usb") && this.connector.availableTransports.includes("ble")) {
|
|
2058
2196
|
this._activeConnectionType = "usb";
|
|
@@ -2067,7 +2205,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2067
2205
|
usbDevices,
|
|
2068
2206
|
usbTarget,
|
|
2069
2207
|
allowUsbEphemeralFallback,
|
|
2070
|
-
|
|
2208
|
+
preserveOperationId,
|
|
2071
2209
|
context,
|
|
2072
2210
|
internalSignal
|
|
2073
2211
|
);
|
|
@@ -2077,24 +2215,26 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2077
2215
|
(connection) => connection.transport === "ble"
|
|
2078
2216
|
);
|
|
2079
2217
|
if (knownBle?.transport === "ble") {
|
|
2080
|
-
return this._connectDeviceOrThrow(
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2218
|
+
return this._connectDeviceOrThrow(knownBle.connectId, preserveOperationId, internalSignal);
|
|
2219
|
+
}
|
|
2220
|
+
if (targetConnectId && context?.knownConnections === void 0) {
|
|
2221
|
+
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2222
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound,
|
|
2223
|
+
message: "Ledger connection metadata is required before starting Bluetooth binding"
|
|
2224
|
+
});
|
|
2085
2225
|
}
|
|
2086
2226
|
const bleDevices = await this._searchDevices({ transportType: "ble" }, internalSignal);
|
|
2087
2227
|
return this._connectFirstOrSelect(
|
|
2088
2228
|
bleDevices,
|
|
2089
2229
|
void 0,
|
|
2090
2230
|
allowUsbEphemeralFallback,
|
|
2091
|
-
|
|
2231
|
+
preserveOperationId,
|
|
2092
2232
|
context,
|
|
2093
2233
|
internalSignal
|
|
2094
2234
|
);
|
|
2095
2235
|
}
|
|
2096
2236
|
if (this._isBleConnection() && targetConnectId) {
|
|
2097
|
-
return this._connectDeviceOrThrow(targetConnectId,
|
|
2237
|
+
return this._connectDeviceOrThrow(targetConnectId, preserveOperationId, internalSignal);
|
|
2098
2238
|
}
|
|
2099
2239
|
let confirms = 0;
|
|
2100
2240
|
while (!internalSignal.aborted) {
|
|
@@ -2121,7 +2261,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2121
2261
|
devices,
|
|
2122
2262
|
targetConnectId,
|
|
2123
2263
|
allowUsbEphemeralFallback,
|
|
2124
|
-
|
|
2264
|
+
preserveOperationId,
|
|
2125
2265
|
context,
|
|
2126
2266
|
internalSignal
|
|
2127
2267
|
);
|
|
@@ -2152,20 +2292,20 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2152
2292
|
_LedgerAdapter._throwIfAborted(internalSignal);
|
|
2153
2293
|
throw new Error("_doConnect aborted");
|
|
2154
2294
|
}
|
|
2155
|
-
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback
|
|
2156
|
-
|
|
2295
|
+
async _connectFirstOrSelect(devices, targetConnectId, allowUsbEphemeralFallback, preserveOperationId, context, signal) {
|
|
2296
|
+
_LedgerAdapter._throwIfAborted(signal);
|
|
2157
2297
|
if (targetConnectId) {
|
|
2158
2298
|
const target = devices.find(
|
|
2159
2299
|
(d) => d.connectId === targetConnectId || d.deviceId === targetConnectId
|
|
2160
2300
|
);
|
|
2161
2301
|
if (target) {
|
|
2162
|
-
return this._connectDeviceOrThrow(target.connectId,
|
|
2302
|
+
return this._connectDeviceOrThrow(target.connectId, preserveOperationId, signal);
|
|
2163
2303
|
}
|
|
2164
2304
|
if (!this._isBleConnection() && devices.length === 1 && allowUsbEphemeralFallback) {
|
|
2165
2305
|
debugLog(
|
|
2166
2306
|
`[LedgerAdapter] target ${targetConnectId} not in fresh enumeration; accepting sole USB device ${devices[0].connectId} for fingerprint-verified recovery`
|
|
2167
2307
|
);
|
|
2168
|
-
return this._connectDeviceOrThrow(devices[0].connectId,
|
|
2308
|
+
return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
|
|
2169
2309
|
}
|
|
2170
2310
|
if (!this._isBleConnection() || !allowUsbEphemeralFallback) {
|
|
2171
2311
|
const err = Object.assign(new Error(`Target Ledger unavailable: ${targetConnectId}`), {
|
|
@@ -2186,11 +2326,26 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2186
2326
|
if (requiresBleSelection && context?.allowDeviceSelection !== false) {
|
|
2187
2327
|
const bindingSessionId = context?.bindingSessionId ?? this._uiRegistry.createRequestId();
|
|
2188
2328
|
if (context) context.bindingSessionId = bindingSessionId;
|
|
2329
|
+
const allowUsbFallback = context?.bindingReason !== "manual-rebind" && Boolean(this.connector.availableTransports?.includes("usb"));
|
|
2330
|
+
const knownUsb = context?.knownConnections?.find(
|
|
2331
|
+
(connection) => connection.transport === "usb"
|
|
2332
|
+
);
|
|
2333
|
+
const usbConnectId = knownUsb?.transport === "usb" ? knownUsb.connectId : targetConnectId;
|
|
2189
2334
|
const { device, requestId } = await (0, import_hwk_adapter_core3.requestBleDeviceSelection)({
|
|
2190
2335
|
emitter: this.emitter,
|
|
2191
2336
|
registry: this._uiRegistry,
|
|
2192
|
-
signal
|
|
2193
|
-
|
|
2337
|
+
signal,
|
|
2338
|
+
allowUsbFallback,
|
|
2339
|
+
scan: async () => {
|
|
2340
|
+
if (allowUsbFallback) {
|
|
2341
|
+
const usbDevices = await this._searchDevices({ transportType: "usb" }, signal);
|
|
2342
|
+
const candidate = usbDevices.find(
|
|
2343
|
+
(device2) => device2.connectionType === "usb" && device2.connectId === usbConnectId
|
|
2344
|
+
) ?? (usbDevices.length === 1 && usbDevices[0].connectionType === "usb" ? usbDevices[0] : void 0);
|
|
2345
|
+
if (candidate) return [candidate];
|
|
2346
|
+
}
|
|
2347
|
+
return (await this._searchDevices({ transportType: "ble", waitForAllTransports: true }, signal)).filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId));
|
|
2348
|
+
},
|
|
2194
2349
|
request: {
|
|
2195
2350
|
devices: devices.filter((device2) => !context?.rejectedConnectIds?.has(device2.connectId)),
|
|
2196
2351
|
bindingSessionId,
|
|
@@ -2198,14 +2353,25 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2198
2353
|
context: {
|
|
2199
2354
|
kind: "bind-connection",
|
|
2200
2355
|
transport: "ble",
|
|
2201
|
-
reason: targetConnectId ? "known-connection-unavailable" : "missing-binding"
|
|
2356
|
+
reason: context?.bindingReason ?? (targetConnectId ? "known-connection-unavailable" : "missing-binding")
|
|
2202
2357
|
},
|
|
2203
2358
|
extra: context?.extra
|
|
2204
2359
|
}
|
|
2205
2360
|
});
|
|
2361
|
+
if (device.connectionType === "usb") {
|
|
2362
|
+
this._activeConnectionType = "usb";
|
|
2363
|
+
if (context) context.selectedConnection = void 0;
|
|
2364
|
+
if (preserveOperationId) this._pendingOperationBindings.delete(preserveOperationId);
|
|
2365
|
+
this._bindingSelectionRequestId = void 0;
|
|
2366
|
+
this.emitter.emit(import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS, {
|
|
2367
|
+
type: import_hwk_adapter_core3.UI_REQUEST.DEVICE_BINDING_STATUS,
|
|
2368
|
+
payload: { selectionRequestId: requestId, status: "cancelled" }
|
|
2369
|
+
});
|
|
2370
|
+
return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
|
|
2371
|
+
}
|
|
2206
2372
|
if (context) context.selectedConnection = { connectId: device.connectId, requestId };
|
|
2207
2373
|
this._bindingSelectionRequestId = requestId;
|
|
2208
|
-
return this._connectDeviceOrThrow(device.connectId,
|
|
2374
|
+
return this._connectDeviceOrThrow(device.connectId, preserveOperationId, signal);
|
|
2209
2375
|
}
|
|
2210
2376
|
if (devices.length > 0 && (devices.length > 1 || requiresBleSelection)) {
|
|
2211
2377
|
if (context?.allowDeviceSelection === false || !this.emitter.listenerCount(import_hwk_adapter_core3.UI_REQUEST.REQUEST_SELECT_DEVICE)) {
|
|
@@ -2242,17 +2408,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2242
2408
|
}
|
|
2243
2409
|
if (context && requiresBleSelection)
|
|
2244
2410
|
context.selectedConnection = { connectId: selected.connectId, requestId };
|
|
2245
|
-
return this._connectDeviceOrThrow(selected.connectId,
|
|
2411
|
+
return this._connectDeviceOrThrow(selected.connectId, preserveOperationId, signal);
|
|
2246
2412
|
}
|
|
2247
2413
|
if (devices.length !== 1) {
|
|
2248
2414
|
throw Object.assign(new Error("Ledger device not found."), {
|
|
2249
2415
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceNotFound
|
|
2250
2416
|
});
|
|
2251
2417
|
}
|
|
2252
|
-
return this._connectDeviceOrThrow(devices[0].connectId,
|
|
2418
|
+
return this._connectDeviceOrThrow(devices[0].connectId, preserveOperationId, signal);
|
|
2253
2419
|
}
|
|
2254
|
-
async _connectDeviceOrThrow(chosenConnectId,
|
|
2255
|
-
const result = await this._connectTarget(chosenConnectId,
|
|
2420
|
+
async _connectDeviceOrThrow(chosenConnectId, preserveOperationId, signal) {
|
|
2421
|
+
const result = await this._connectTarget(chosenConnectId, preserveOperationId, signal);
|
|
2256
2422
|
if (!result.success) {
|
|
2257
2423
|
const payload = result.payload;
|
|
2258
2424
|
const rethrow = Object.assign(new Error(payload.error), {
|
|
@@ -2294,6 +2460,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2294
2460
|
*/
|
|
2295
2461
|
async _callConnector(sessionId, method, params, signal) {
|
|
2296
2462
|
this._assertConnectorReady(method);
|
|
2463
|
+
if (signal?.aborted) throw this._abortReason(signal);
|
|
2297
2464
|
const releaseOperation = this._retainConnectorOperation(`call:${sessionId}`);
|
|
2298
2465
|
let promise;
|
|
2299
2466
|
try {
|
|
@@ -2358,32 +2525,32 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2358
2525
|
};
|
|
2359
2526
|
}
|
|
2360
2527
|
async connectorCall(connectId, method, params, fingerprint, permissionDeviceId, commonParams, installContext) {
|
|
2361
|
-
const
|
|
2362
|
-
if (
|
|
2528
|
+
const positionalOperationId = (0, import_hwk_adapter_core3.isHardwareOperationId)(connectId) ? connectId : void 0;
|
|
2529
|
+
if (positionalOperationId && commonParams?.operationId && positionalOperationId !== commonParams.operationId) {
|
|
2363
2530
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2364
2531
|
code: import_hwk_adapter_core3.HardwareErrorCode.InvalidParams,
|
|
2365
|
-
message: "Conflicting Ledger
|
|
2532
|
+
message: "Conflicting Ledger operation ids",
|
|
2366
2533
|
params: {
|
|
2367
|
-
|
|
2368
|
-
|
|
2534
|
+
positionalOperationId,
|
|
2535
|
+
commonOperationId: commonParams.operationId
|
|
2369
2536
|
}
|
|
2370
2537
|
});
|
|
2371
2538
|
}
|
|
2372
|
-
const
|
|
2373
|
-
const
|
|
2374
|
-
const
|
|
2375
|
-
const effectiveConnectId =
|
|
2539
|
+
const operationId = commonParams?.operationId ?? positionalOperationId;
|
|
2540
|
+
const operation = operationId ? this._operations.resolve(operationId) : void 0;
|
|
2541
|
+
const releaseOperationRetention = operationId ? this._operations.retain(operationId) : void 0;
|
|
2542
|
+
const effectiveConnectId = operation?.connectId ?? connectId;
|
|
2376
2543
|
debugLog("[LedgerAdapter][REQ]", {
|
|
2377
2544
|
method,
|
|
2378
2545
|
connectId: effectiveConnectId || "(empty)",
|
|
2379
2546
|
params
|
|
2380
2547
|
});
|
|
2381
|
-
const queueKey = (
|
|
2548
|
+
const queueKey = (operationId ?? effectiveConnectId) || "__ledger_default__";
|
|
2382
2549
|
try {
|
|
2383
2550
|
const result = await this._jobQueue.enqueue(
|
|
2384
2551
|
queueKey,
|
|
2385
2552
|
async (signal) => {
|
|
2386
|
-
if (
|
|
2553
|
+
if (operationId) this._activeOperationJobs.add(operationId);
|
|
2387
2554
|
try {
|
|
2388
2555
|
return await this._runConnectorCall(
|
|
2389
2556
|
effectiveConnectId,
|
|
@@ -2394,16 +2561,16 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2394
2561
|
permissionDeviceId,
|
|
2395
2562
|
commonParams,
|
|
2396
2563
|
installContext ?? {},
|
|
2397
|
-
|
|
2564
|
+
operationId
|
|
2398
2565
|
);
|
|
2399
2566
|
} catch (error) {
|
|
2400
2567
|
this._finishBleBinding(signal.aborted ? "cancelled" : "failed");
|
|
2401
2568
|
throw error;
|
|
2402
2569
|
} finally {
|
|
2403
|
-
if (
|
|
2404
|
-
this.
|
|
2405
|
-
if (this.
|
|
2406
|
-
await this.
|
|
2570
|
+
if (operationId) {
|
|
2571
|
+
this._activeOperationJobs.delete(operationId);
|
|
2572
|
+
if (this._pendingOperationDisconnects.delete(operationId)) {
|
|
2573
|
+
await this._releaseLostOperationConnection(operationId);
|
|
2407
2574
|
}
|
|
2408
2575
|
}
|
|
2409
2576
|
}
|
|
@@ -2429,15 +2596,19 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2429
2596
|
});
|
|
2430
2597
|
throw err;
|
|
2431
2598
|
} finally {
|
|
2432
|
-
|
|
2599
|
+
releaseOperationRetention?.();
|
|
2433
2600
|
}
|
|
2434
2601
|
}
|
|
2435
2602
|
/**
|
|
2436
2603
|
* Race a promise against an abort signal. On abort, rejects with
|
|
2437
2604
|
* signal.reason → instance _lastCancelReason → generic Error('Aborted').
|
|
2438
2605
|
*/
|
|
2606
|
+
/** Hermes/RN polyfills don't always populate signal.reason; fall back. */
|
|
2607
|
+
_abortReason(signal) {
|
|
2608
|
+
return signal.reason ?? this._lastCancelReason ?? new Error("Aborted");
|
|
2609
|
+
}
|
|
2439
2610
|
_abortable(signal, promise) {
|
|
2440
|
-
const getAbortReason = () =>
|
|
2611
|
+
const getAbortReason = () => this._abortReason(signal);
|
|
2441
2612
|
if (signal.aborted) {
|
|
2442
2613
|
void promise.catch(() => void 0);
|
|
2443
2614
|
return Promise.reject(getAbortReason());
|
|
@@ -2466,9 +2637,9 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2466
2637
|
}
|
|
2467
2638
|
}
|
|
2468
2639
|
/** Actual work done under the job queue — connection, fingerprint, call, and recovery. */
|
|
2469
|
-
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext,
|
|
2640
|
+
async _runConnectorCall(connectId, method, params, signal, fingerprint, permissionDeviceId, commonParams, installContext, operationId, lockedRetryBudget = _LedgerAdapter.MAX_BUSINESS_RETRY_BUDGET) {
|
|
2470
2641
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2471
|
-
if (!
|
|
2642
|
+
if (!operationId) {
|
|
2472
2643
|
await this._ensureDevicePermission(
|
|
2473
2644
|
connectId,
|
|
2474
2645
|
permissionDeviceId ?? fingerprint?.deviceId,
|
|
@@ -2504,7 +2675,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2504
2675
|
message: "Ledger all-network connection ended"
|
|
2505
2676
|
});
|
|
2506
2677
|
}
|
|
2507
|
-
let resolvedConnectId =
|
|
2678
|
+
let resolvedConnectId = operationId ? this._operations.resolve(operationId).connectId : bundleConnection?.connectId ?? await this.ensureConnected(
|
|
2508
2679
|
preferredConnectId,
|
|
2509
2680
|
signal,
|
|
2510
2681
|
allowUsbEphemeralFallback,
|
|
@@ -2516,12 +2687,12 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2516
2687
|
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2517
2688
|
}
|
|
2518
2689
|
if (!sessionId) {
|
|
2519
|
-
if (
|
|
2520
|
-
this.
|
|
2690
|
+
if (operationId) {
|
|
2691
|
+
this._operations.end(operationId, "disconnect");
|
|
2521
2692
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2522
|
-
code: import_hwk_adapter_core3.HardwareErrorCode.
|
|
2523
|
-
message: "Ledger
|
|
2524
|
-
params: {
|
|
2693
|
+
code: import_hwk_adapter_core3.HardwareErrorCode.OperationEnded,
|
|
2694
|
+
message: "Ledger operation connection is no longer active",
|
|
2695
|
+
params: { operationId, reason: "disconnect" }
|
|
2525
2696
|
});
|
|
2526
2697
|
}
|
|
2527
2698
|
throw Object.assign(new Error("Auto-connect succeeded but no session found"), {
|
|
@@ -2540,7 +2711,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2540
2711
|
)
|
|
2541
2712
|
);
|
|
2542
2713
|
if (fp.success) break;
|
|
2543
|
-
const binding =
|
|
2714
|
+
const binding = operationId ? this._pendingOperationBindings.get(operationId) : connectionAttempt;
|
|
2544
2715
|
if (!this._isBleConnection() || binding?.selectedConnection?.connectId !== resolvedConnectId) {
|
|
2545
2716
|
throw Object.assign(new Error(formatDeviceMismatchError(fp.expected, fp.actual)), {
|
|
2546
2717
|
code: import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch
|
|
@@ -2551,13 +2722,13 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2551
2722
|
binding.rejectedConnectId = resolvedConnectId;
|
|
2552
2723
|
this._sessions.delete(resolvedConnectId);
|
|
2553
2724
|
await this.connector.disconnect(sessionId);
|
|
2554
|
-
if (
|
|
2725
|
+
if (operationId) this._pendingOperationDisconnects.delete(operationId);
|
|
2555
2726
|
_LedgerAdapter._throwIfAborted(signal);
|
|
2556
2727
|
resolvedConnectId = await this._connectFirstOrSelect(
|
|
2557
2728
|
[],
|
|
2558
2729
|
void 0,
|
|
2559
2730
|
true,
|
|
2560
|
-
|
|
2731
|
+
operationId,
|
|
2561
2732
|
binding,
|
|
2562
2733
|
signal
|
|
2563
2734
|
);
|
|
@@ -2569,8 +2740,8 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2569
2740
|
message: "Selected Ledger connection ended"
|
|
2570
2741
|
});
|
|
2571
2742
|
sessionId = selectedSession;
|
|
2572
|
-
if (
|
|
2573
|
-
this.
|
|
2743
|
+
if (operationId)
|
|
2744
|
+
this._operations.rebind(operationId, {
|
|
2574
2745
|
connectId: resolvedConnectId,
|
|
2575
2746
|
device: selectedDevice,
|
|
2576
2747
|
connectionKeys: [sessionId]
|
|
@@ -2578,22 +2749,21 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2578
2749
|
if (installContext)
|
|
2579
2750
|
installContext.connection = { connectId: resolvedConnectId, sessionId };
|
|
2580
2751
|
}
|
|
2581
|
-
if (!interactionId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
|
|
2582
|
-
this._verifiedBleReconnectTargets.set(connectId, {
|
|
2583
|
-
connectId: resolvedConnectId,
|
|
2584
|
-
chain: fingerprint.chain,
|
|
2585
|
-
fingerprint: fingerprint.deviceId
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
2752
|
await this._publishVerifiedBleBinding(
|
|
2589
2753
|
resolvedConnectId,
|
|
2590
2754
|
fingerprint.chain,
|
|
2591
2755
|
fingerprint.deviceId,
|
|
2592
2756
|
connectionAttempt,
|
|
2593
|
-
|
|
2594
|
-
connectId,
|
|
2757
|
+
operationId,
|
|
2595
2758
|
signal
|
|
2596
2759
|
);
|
|
2760
|
+
if (!operationId && connectionAttempt.selectedConnection?.connectId === resolvedConnectId && this._isBleConnection()) {
|
|
2761
|
+
this._verifiedBleReconnectTargets.set(connectId, {
|
|
2762
|
+
connectId: resolvedConnectId,
|
|
2763
|
+
chain: fingerprint.chain,
|
|
2764
|
+
fingerprint: fingerprint.deviceId
|
|
2765
|
+
});
|
|
2766
|
+
}
|
|
2597
2767
|
}
|
|
2598
2768
|
businessCallStarted = true;
|
|
2599
2769
|
return await this._callConnector(sessionId, method, effectiveParams, signal);
|
|
@@ -2601,17 +2771,17 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2601
2771
|
if (signal.aborted) throw err;
|
|
2602
2772
|
if (isDeviceDisconnectedError(err) || isDeviceNotAdvertisingError(err) || isTimeoutError(err) || isConnectionLevelError(err)) {
|
|
2603
2773
|
this._discoveredDevices.delete(resolvedConnectId);
|
|
2604
|
-
if (
|
|
2774
|
+
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2605
2775
|
else {
|
|
2606
2776
|
this._sessions.delete(resolvedConnectId);
|
|
2607
2777
|
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2608
2778
|
}
|
|
2609
2779
|
const ambiguous = businessCallStarted && !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method);
|
|
2610
|
-
const interactionParams =
|
|
2780
|
+
const interactionParams = operationId ? { operationId, reason: "disconnect" } : void 0;
|
|
2611
2781
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2612
|
-
code:
|
|
2782
|
+
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(err).code,
|
|
2613
2783
|
message: "Ledger operation connection was lost; start a new operation",
|
|
2614
|
-
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
|
|
2784
|
+
params: ambiguous ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, { operationId }) : interactionParams,
|
|
2615
2785
|
recovery: ambiguous ? { scope: "unknown" } : void 0
|
|
2616
2786
|
});
|
|
2617
2787
|
}
|
|
@@ -2630,7 +2800,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2630
2800
|
await this._waitForDeviceConnect(signal);
|
|
2631
2801
|
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2632
2802
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2633
|
-
code:
|
|
2803
|
+
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2634
2804
|
message: "Ledger connection ended while waiting for unlock"
|
|
2635
2805
|
});
|
|
2636
2806
|
}
|
|
@@ -2643,7 +2813,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2643
2813
|
permissionDeviceId,
|
|
2644
2814
|
commonParams,
|
|
2645
2815
|
installContext,
|
|
2646
|
-
|
|
2816
|
+
operationId,
|
|
2647
2817
|
lockedRetryBudget - 1
|
|
2648
2818
|
);
|
|
2649
2819
|
}
|
|
@@ -2651,7 +2821,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2651
2821
|
await this._sleepAbortable(_LedgerAdapter.STUCK_APP_RETRY_DELAY_MS, signal);
|
|
2652
2822
|
if (this._sessions.get(resolvedConnectId) !== sessionId) {
|
|
2653
2823
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2654
|
-
code:
|
|
2824
|
+
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : import_hwk_adapter_core3.HardwareErrorCode.DeviceDisconnected,
|
|
2655
2825
|
message: "Ledger connection ended during the app transition"
|
|
2656
2826
|
});
|
|
2657
2827
|
}
|
|
@@ -2660,26 +2830,26 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2660
2830
|
} catch (retryErr) {
|
|
2661
2831
|
if (isStuckAppStateError(retryErr)) throw err;
|
|
2662
2832
|
if (isDeviceDisconnectedError(retryErr) || isDeviceNotAdvertisingError(retryErr) || isTimeoutError(retryErr) || isConnectionLevelError(retryErr)) {
|
|
2663
|
-
if (
|
|
2833
|
+
if (operationId) await this._releaseLostOperationConnection(operationId);
|
|
2664
2834
|
else {
|
|
2665
2835
|
this._sessions.delete(resolvedConnectId);
|
|
2666
2836
|
this._discoveredDevices.delete(resolvedConnectId);
|
|
2667
2837
|
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
2668
2838
|
}
|
|
2669
2839
|
throw (0, import_hwk_adapter_core3.createHwkError)({
|
|
2670
|
-
code:
|
|
2840
|
+
code: operationId ? import_hwk_adapter_core3.HardwareErrorCode.OperationEnded : mapLedgerError(retryErr).code,
|
|
2671
2841
|
message: `Ledger ${method} may have completed before the connection was lost`,
|
|
2672
2842
|
params: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? (0, import_hwk_adapter_core3.operationMayHaveCompletedParams)(method, {
|
|
2673
|
-
|
|
2843
|
+
operationId,
|
|
2674
2844
|
reason: "disconnect"
|
|
2675
|
-
}) : {
|
|
2845
|
+
}) : { operationId, reason: "disconnect" },
|
|
2676
2846
|
recovery: !(0, import_hwk_adapter_core3.canReplayHardwareMethodAfterTransportFailure)(method) ? { scope: "unknown" } : void 0
|
|
2677
2847
|
});
|
|
2678
2848
|
}
|
|
2679
2849
|
throw retryErr;
|
|
2680
2850
|
}
|
|
2681
2851
|
}
|
|
2682
|
-
if (!
|
|
2852
|
+
if (!operationId && err?.code === import_hwk_adapter_core3.HardwareErrorCode.DeviceMismatch) {
|
|
2683
2853
|
this._sessions.delete(resolvedConnectId);
|
|
2684
2854
|
this._discoveredDevices.delete(resolvedConnectId);
|
|
2685
2855
|
await this.connector.disconnect(sessionId).catch(() => void 0);
|
|
@@ -2741,7 +2911,7 @@ var _LedgerAdapter = class _LedgerAdapter {
|
|
|
2741
2911
|
permissionDeviceId,
|
|
2742
2912
|
commonParams,
|
|
2743
2913
|
installContext,
|
|
2744
|
-
|
|
2914
|
+
operationId
|
|
2745
2915
|
);
|
|
2746
2916
|
}
|
|
2747
2917
|
}
|
|
@@ -2894,7 +3064,7 @@ _LedgerAdapter.APP_INSTALL_PROGRESS_MIN_DELTA = 0.05;
|
|
|
2894
3064
|
var LedgerAdapter = _LedgerAdapter;
|
|
2895
3065
|
|
|
2896
3066
|
// src/connector/LedgerConnectorBase.ts
|
|
2897
|
-
var
|
|
3067
|
+
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
2898
3068
|
|
|
2899
3069
|
// src/device/LedgerDeviceManager.ts
|
|
2900
3070
|
var LedgerDeviceManager = class {
|
|
@@ -4124,360 +4294,115 @@ async function _createZcashSigner(ctx, sessionId) {
|
|
|
4124
4294
|
}
|
|
4125
4295
|
|
|
4126
4296
|
// src/connector/chains/tron.ts
|
|
4127
|
-
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
4128
|
-
var import_hw_app_trx = __toESM(require("@ledgerhq/hw-app-trx"));
|
|
4129
|
-
|
|
4130
|
-
// src/connector/chains/legacyChainCall.ts
|
|
4131
|
-
var import_hwk_adapter_core12 = require("@onekeyfe/hwk-adapter-core");
|
|
4132
|
-
|
|
4133
|
-
// src/app/AppManager.ts
|
|
4134
|
-
var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
|
|
4135
4297
|
var import_hwk_adapter_core11 = require("@onekeyfe/hwk-adapter-core");
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
XRP: "XRP",
|
|
4143
|
-
ADA: "Cardano",
|
|
4144
|
-
DOT: "Polkadot",
|
|
4145
|
-
ATOM: "Cosmos"
|
|
4146
|
-
};
|
|
4147
|
-
var DASHBOARD_APP_NAME = "BOLOS";
|
|
4148
|
-
var AppManager = class {
|
|
4149
|
-
constructor(dmk, options) {
|
|
4150
|
-
this._dmk = dmk;
|
|
4151
|
-
this._waitMs = options?.waitMs ?? 1e3;
|
|
4152
|
-
this._maxRetries = options?.maxRetries ?? 10;
|
|
4298
|
+
|
|
4299
|
+
// src/signer/SignerTron.ts
|
|
4300
|
+
var SignerTron = class {
|
|
4301
|
+
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
4302
|
+
constructor(_sdk) {
|
|
4303
|
+
this._sdk = _sdk;
|
|
4153
4304
|
}
|
|
4154
|
-
/**
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4305
|
+
/** Base58 Tron address plus the uncompressed public key at `derivationPath`. */
|
|
4306
|
+
async getAddress(derivationPath, options) {
|
|
4307
|
+
const action = this._sdk.getAddress(derivationPath, options);
|
|
4308
|
+
const result = await deviceActionToPromise(
|
|
4309
|
+
action,
|
|
4310
|
+
this.onInteraction,
|
|
4311
|
+
void 0,
|
|
4312
|
+
this.onRegisterCanceller
|
|
4313
|
+
);
|
|
4314
|
+
return { address: result.address, publicKey: result.publicKey };
|
|
4160
4315
|
}
|
|
4161
|
-
/**
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
*/
|
|
4171
|
-
/**
|
|
4172
|
-
* @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
|
|
4173
|
-
* device is about to display "Open <app>" on screen and wait for the
|
|
4174
|
-
* user's button press. UI consumers should show their "open app" prompt
|
|
4175
|
-
* in response. NOT called when the target app is already open (no user
|
|
4176
|
-
* interaction needed in that case).
|
|
4177
|
-
*
|
|
4178
|
-
* Important: OpenAppCommand is blocking. It does not resolve until the user
|
|
4179
|
-
* has physically confirmed on the device, so anything that runs AFTER
|
|
4180
|
-
* `await this._openApp(...)` lands AFTER the prompt is already gone.
|
|
4181
|
-
* Hence the callback must fire BEFORE that await.
|
|
4182
|
-
*/
|
|
4183
|
-
async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
|
|
4184
|
-
const currentApp = await this._getCurrentApp(sessionId);
|
|
4185
|
-
if (currentApp === targetAppName) {
|
|
4186
|
-
return;
|
|
4187
|
-
}
|
|
4188
|
-
if (!this._isDashboard(currentApp)) {
|
|
4189
|
-
await this._closeCurrentApp(sessionId);
|
|
4190
|
-
await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
|
|
4191
|
-
}
|
|
4192
|
-
onConfirmOnDevice?.();
|
|
4193
|
-
await this._openApp(sessionId, targetAppName);
|
|
4194
|
-
await this._waitForApp(sessionId, targetAppName);
|
|
4316
|
+
/** Sign a protobuf-encoded raw transaction. */
|
|
4317
|
+
async signTransaction(derivationPath, transaction, options) {
|
|
4318
|
+
const action = this._sdk.signTransaction(derivationPath, transaction, options);
|
|
4319
|
+
return deviceActionToPromise(
|
|
4320
|
+
action,
|
|
4321
|
+
this.onInteraction,
|
|
4322
|
+
void 0,
|
|
4323
|
+
this.onRegisterCanceller
|
|
4324
|
+
);
|
|
4195
4325
|
}
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
if ((0, import_device_management_kit2.isSuccessCommandResult)(result)) {
|
|
4205
|
-
debugLog("[AppManager] currentApp:", result.data.name);
|
|
4206
|
-
return result.data.name;
|
|
4207
|
-
}
|
|
4208
|
-
const errResult = result;
|
|
4209
|
-
const dmkErr = errResult.error ?? {};
|
|
4210
|
-
const original = dmkErr.originalError;
|
|
4211
|
-
debugLog(
|
|
4212
|
-
"[AppManager] _getCurrentApp failed sessionId=",
|
|
4213
|
-
sessionId,
|
|
4214
|
-
"tag=",
|
|
4215
|
-
dmkErr._tag,
|
|
4216
|
-
"errorCode=",
|
|
4217
|
-
dmkErr.errorCode,
|
|
4218
|
-
"message=",
|
|
4219
|
-
dmkErr.message,
|
|
4220
|
-
"originalErrorMessage=",
|
|
4221
|
-
original?.message ?? String(original ?? "")
|
|
4326
|
+
/** Sign a personal message (TIP-191). */
|
|
4327
|
+
async signPersonalMessage(derivationPath, message, options) {
|
|
4328
|
+
const action = this._sdk.signPersonalMessage(derivationPath, message, options);
|
|
4329
|
+
return deviceActionToPromise(
|
|
4330
|
+
action,
|
|
4331
|
+
this.onInteraction,
|
|
4332
|
+
void 0,
|
|
4333
|
+
this.onRegisterCanceller
|
|
4222
4334
|
);
|
|
4335
|
+
}
|
|
4336
|
+
};
|
|
4337
|
+
|
|
4338
|
+
// src/connector/chains/tron.ts
|
|
4339
|
+
async function tronGetAddress(ctx, sessionId, params) {
|
|
4340
|
+
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4341
|
+
const path = normalizePath(params.path);
|
|
4342
|
+
try {
|
|
4343
|
+
const result = await tronSigner.getAddress(path, {
|
|
4344
|
+
checkOnDevice: params.showOnDevice ?? false
|
|
4345
|
+
});
|
|
4346
|
+
return { address: result.address, publicKey: result.publicKey, path: params.path };
|
|
4347
|
+
} catch (err) {
|
|
4348
|
+
ctx.invalidateSession(sessionId);
|
|
4349
|
+
throw ctx.wrapError(err);
|
|
4350
|
+
} finally {
|
|
4351
|
+
ctx.clearCanceller(sessionId);
|
|
4352
|
+
}
|
|
4353
|
+
}
|
|
4354
|
+
async function tronSignTransaction(ctx, sessionId, params) {
|
|
4355
|
+
if (!params.rawTxHex) {
|
|
4223
4356
|
throw Object.assign(
|
|
4224
|
-
new Error(
|
|
4225
|
-
|
|
4226
|
-
),
|
|
4227
|
-
{
|
|
4228
|
-
_tag: dmkErr._tag,
|
|
4229
|
-
errorCode: dmkErr.errorCode,
|
|
4230
|
-
originalError: original
|
|
4231
|
-
}
|
|
4357
|
+
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
4358
|
+
{ code: import_hwk_adapter_core11.HardwareErrorCode.InvalidParams }
|
|
4232
4359
|
);
|
|
4233
4360
|
}
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
sessionId,
|
|
4237
|
-
command: new import_device_management_kit2.OpenAppCommand({ appName })
|
|
4238
|
-
});
|
|
4239
|
-
if (!(0, import_device_management_kit2.isSuccessCommandResult)(result)) {
|
|
4240
|
-
const dmkErr = result.error;
|
|
4241
|
-
const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
|
|
4242
|
-
const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
|
|
4243
|
-
debugLog(
|
|
4244
|
-
"[AppManager] openApp failed:",
|
|
4245
|
-
appName,
|
|
4246
|
-
"errorCode:",
|
|
4247
|
-
errorCode,
|
|
4248
|
-
"tag:",
|
|
4249
|
-
dmkErr._tag
|
|
4250
|
-
);
|
|
4251
|
-
let code;
|
|
4252
|
-
if (errorCode === "6807" || /unknown application/i.test(message)) {
|
|
4253
|
-
code = import_hwk_adapter_core11.HardwareErrorCode.AppNotInstalled;
|
|
4254
|
-
} else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
|
|
4255
|
-
code = import_hwk_adapter_core11.HardwareErrorCode.UserRejected;
|
|
4256
|
-
}
|
|
4257
|
-
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
4258
|
-
_tag: ERROR_TAG.OpenAppCommand,
|
|
4259
|
-
code,
|
|
4260
|
-
errorCode,
|
|
4261
|
-
statusCode: errorCode,
|
|
4262
|
-
appName,
|
|
4263
|
-
originalError: dmkErr
|
|
4264
|
-
});
|
|
4265
|
-
}
|
|
4266
|
-
}
|
|
4267
|
-
async _closeCurrentApp(sessionId) {
|
|
4268
|
-
debugLog("[AppManager] closeCurrentApp");
|
|
4269
|
-
await this._dmk.sendCommand({
|
|
4270
|
-
sessionId,
|
|
4271
|
-
command: new import_device_management_kit2.CloseAppCommand()
|
|
4272
|
-
});
|
|
4273
|
-
}
|
|
4274
|
-
/**
|
|
4275
|
-
* Poll the device until the expected app is reported as running,
|
|
4276
|
-
* or throw after `_maxRetries` attempts.
|
|
4277
|
-
*/
|
|
4278
|
-
async _waitForApp(sessionId, expectedAppName) {
|
|
4279
|
-
let lastSeen = "";
|
|
4280
|
-
for (let i = 0; i < this._maxRetries; i++) {
|
|
4281
|
-
await this._wait();
|
|
4282
|
-
const current = await this._getCurrentApp(sessionId);
|
|
4283
|
-
lastSeen = current;
|
|
4284
|
-
if (current === expectedAppName) {
|
|
4285
|
-
return;
|
|
4286
|
-
}
|
|
4287
|
-
}
|
|
4288
|
-
debugLog(
|
|
4289
|
-
"[AppManager] waitForApp exhausted: expected=",
|
|
4290
|
-
expectedAppName,
|
|
4291
|
-
"lastSeen=",
|
|
4292
|
-
lastSeen
|
|
4293
|
-
);
|
|
4294
|
-
throw new Error(
|
|
4295
|
-
`Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
|
|
4296
|
-
);
|
|
4297
|
-
}
|
|
4298
|
-
_isDashboard(appName) {
|
|
4299
|
-
return appName === DASHBOARD_APP_NAME;
|
|
4300
|
-
}
|
|
4301
|
-
_wait() {
|
|
4302
|
-
return new Promise((resolve) => setTimeout(resolve, this._waitMs));
|
|
4303
|
-
}
|
|
4304
|
-
};
|
|
4305
|
-
|
|
4306
|
-
// src/connector/chains/legacyChainCall.ts
|
|
4307
|
-
function isLegacyWrongAppError(err, _appName) {
|
|
4308
|
-
return isWrongAppError(err);
|
|
4309
|
-
}
|
|
4310
|
-
async function withLegacyChainCall(ctx, sessionId, options, action) {
|
|
4311
|
-
const { appName, needsConfirmation } = options;
|
|
4312
|
-
let openAppPromptShown = false;
|
|
4313
|
-
const onAppOpenPrompt = () => {
|
|
4314
|
-
openAppPromptShown = true;
|
|
4315
|
-
ctx.emit("ui-event", {
|
|
4316
|
-
type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOpenApp,
|
|
4317
|
-
payload: { sessionId }
|
|
4318
|
-
});
|
|
4319
|
-
};
|
|
4320
|
-
const closeOpenAppUiIfShown = () => {
|
|
4321
|
-
if (openAppPromptShown) {
|
|
4322
|
-
ctx.emit("ui-event", {
|
|
4323
|
-
type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
|
|
4324
|
-
payload: { sessionId }
|
|
4325
|
-
});
|
|
4326
|
-
openAppPromptShown = false;
|
|
4327
|
-
}
|
|
4328
|
-
};
|
|
4329
|
-
try {
|
|
4330
|
-
await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
|
|
4331
|
-
} catch (err) {
|
|
4332
|
-
debugLog(
|
|
4333
|
-
"[LegacyChainCall] pre-flight ensureAppOpen failed:",
|
|
4334
|
-
appName,
|
|
4335
|
-
err?.message
|
|
4336
|
-
);
|
|
4337
|
-
closeOpenAppUiIfShown();
|
|
4338
|
-
throw ctx.wrapError(err, { defaultAppName: appName });
|
|
4339
|
-
}
|
|
4340
|
-
const runOnce = async () => {
|
|
4341
|
-
let confirmEmitted = false;
|
|
4342
|
-
if (needsConfirmation) {
|
|
4343
|
-
ctx.emit("ui-event", {
|
|
4344
|
-
type: import_hwk_adapter_core12.EConnectorInteraction.ConfirmOnDevice,
|
|
4345
|
-
payload: { sessionId }
|
|
4346
|
-
});
|
|
4347
|
-
confirmEmitted = true;
|
|
4348
|
-
}
|
|
4349
|
-
try {
|
|
4350
|
-
return await action(sessionId);
|
|
4351
|
-
} finally {
|
|
4352
|
-
if (confirmEmitted || openAppPromptShown) {
|
|
4353
|
-
ctx.emit("ui-event", {
|
|
4354
|
-
type: import_hwk_adapter_core12.EConnectorInteraction.InteractionComplete,
|
|
4355
|
-
payload: { sessionId }
|
|
4356
|
-
});
|
|
4357
|
-
openAppPromptShown = false;
|
|
4358
|
-
}
|
|
4359
|
-
}
|
|
4360
|
-
};
|
|
4361
|
+
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4362
|
+
const path = normalizePath(params.path);
|
|
4361
4363
|
try {
|
|
4362
|
-
|
|
4364
|
+
const signature = await tronSigner.signTransaction(path, (0, import_hwk_adapter_core11.hexToBytes)(params.rawTxHex));
|
|
4365
|
+
return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
|
|
4363
4366
|
} catch (err) {
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
}
|
|
4369
|
-
debugLog("[LegacyChainCall] wrong-app detected, retrying:", appName);
|
|
4370
|
-
try {
|
|
4371
|
-
await _ensureAppOpen(ctx, sessionId, appName, onAppOpenPrompt);
|
|
4372
|
-
} catch (switchErr) {
|
|
4373
|
-
debugLog(
|
|
4374
|
-
"[LegacyChainCall] retry ensureAppOpen failed:",
|
|
4375
|
-
appName,
|
|
4376
|
-
switchErr?.message
|
|
4377
|
-
);
|
|
4378
|
-
closeOpenAppUiIfShown();
|
|
4379
|
-
throw ctx.wrapError(switchErr, { defaultAppName: appName });
|
|
4380
|
-
}
|
|
4381
|
-
ctx.clearAllSigners();
|
|
4382
|
-
const result = await runOnce();
|
|
4383
|
-
debugLog("[LegacyChainCall] retry succeeded:", appName);
|
|
4384
|
-
return result;
|
|
4385
|
-
}
|
|
4386
|
-
}
|
|
4387
|
-
async function _ensureAppOpen(ctx, sessionId, appName, onPrompt) {
|
|
4388
|
-
const dmk = await ctx.getOrCreateDmk();
|
|
4389
|
-
const appManager = new AppManager(dmk);
|
|
4390
|
-
await appManager.ensureAppOpen(sessionId, appName, onPrompt);
|
|
4391
|
-
}
|
|
4392
|
-
|
|
4393
|
-
// src/transport/DmkTransport.ts
|
|
4394
|
-
var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
|
|
4395
|
-
var DmkTransport = class extends import_hw_transport.default {
|
|
4396
|
-
constructor(dmk, sessionId) {
|
|
4397
|
-
super();
|
|
4398
|
-
this._dmk = dmk;
|
|
4399
|
-
this._sessionId = sessionId;
|
|
4400
|
-
}
|
|
4401
|
-
async exchange(apdu) {
|
|
4402
|
-
const response = await this._dmk.sendApdu({
|
|
4403
|
-
sessionId: this._sessionId,
|
|
4404
|
-
apdu: new Uint8Array(apdu)
|
|
4405
|
-
});
|
|
4406
|
-
const { data, statusCode } = response;
|
|
4407
|
-
const result = Buffer.alloc(data.length + 2);
|
|
4408
|
-
if (data.length > 0) {
|
|
4409
|
-
result.set(data, 0);
|
|
4410
|
-
}
|
|
4411
|
-
result.set(statusCode, data.length);
|
|
4412
|
-
return result;
|
|
4413
|
-
}
|
|
4414
|
-
async close() {
|
|
4367
|
+
ctx.invalidateSession(sessionId);
|
|
4368
|
+
throw ctx.wrapError(err);
|
|
4369
|
+
} finally {
|
|
4370
|
+
ctx.clearCanceller(sessionId);
|
|
4415
4371
|
}
|
|
4416
|
-
};
|
|
4417
|
-
|
|
4418
|
-
// src/connector/chains/tron.ts
|
|
4419
|
-
async function tronGetAddress(ctx, sessionId, params) {
|
|
4420
|
-
const path = normalizePath(params.path);
|
|
4421
|
-
const showOnDevice = params.showOnDevice ?? false;
|
|
4422
|
-
return withLegacyChainCall(
|
|
4423
|
-
ctx,
|
|
4424
|
-
sessionId,
|
|
4425
|
-
{
|
|
4426
|
-
appName: "Tron",
|
|
4427
|
-
// Only show "confirm on device" UI when the device is actually going
|
|
4428
|
-
// to display the address for the user to verify.
|
|
4429
|
-
needsConfirmation: showOnDevice
|
|
4430
|
-
},
|
|
4431
|
-
async (sid) => {
|
|
4432
|
-
const trx = await _createTrx(ctx, sid);
|
|
4433
|
-
const result = await trx.getAddress(path, showOnDevice);
|
|
4434
|
-
return { address: result.address, publicKey: result.publicKey, path: params.path };
|
|
4435
|
-
}
|
|
4436
|
-
);
|
|
4437
|
-
}
|
|
4438
|
-
async function tronSignTransaction(ctx, sessionId, params) {
|
|
4439
|
-
if (!params.rawTxHex) {
|
|
4440
|
-
throw Object.assign(
|
|
4441
|
-
new Error("TRON signing requires a protobuf-encoded raw transaction hex (rawTxHex)."),
|
|
4442
|
-
{ code: import_hwk_adapter_core13.HardwareErrorCode.InvalidParams }
|
|
4443
|
-
);
|
|
4444
|
-
}
|
|
4445
|
-
const path = normalizePath(params.path);
|
|
4446
|
-
return withLegacyChainCall(
|
|
4447
|
-
ctx,
|
|
4448
|
-
sessionId,
|
|
4449
|
-
{ appName: "Tron", needsConfirmation: true },
|
|
4450
|
-
async (sid) => {
|
|
4451
|
-
const trx = await _createTrx(ctx, sid);
|
|
4452
|
-
const signature = await trx.signTransaction(
|
|
4453
|
-
path,
|
|
4454
|
-
params.rawTxHex,
|
|
4455
|
-
params.tokenSignatures ?? []
|
|
4456
|
-
);
|
|
4457
|
-
return { signature };
|
|
4458
|
-
}
|
|
4459
|
-
);
|
|
4460
4372
|
}
|
|
4461
4373
|
async function tronSignMessage(ctx, sessionId, params) {
|
|
4374
|
+
const tronSigner = await _createTronSigner(ctx, sessionId);
|
|
4462
4375
|
const path = normalizePath(params.path);
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
);
|
|
4376
|
+
try {
|
|
4377
|
+
const signature = await tronSigner.signPersonalMessage(path, (0, import_hwk_adapter_core11.hexToBytes)(params.messageHex));
|
|
4378
|
+
return { signature: (0, import_hwk_adapter_core11.bytesToHex)(signature) };
|
|
4379
|
+
} catch (err) {
|
|
4380
|
+
ctx.invalidateSession(sessionId);
|
|
4381
|
+
throw ctx.wrapError(err);
|
|
4382
|
+
} finally {
|
|
4383
|
+
ctx.clearCanceller(sessionId);
|
|
4384
|
+
}
|
|
4473
4385
|
}
|
|
4474
|
-
async function
|
|
4386
|
+
async function _createTronSigner(ctx, sessionId) {
|
|
4475
4387
|
const dmk = await ctx.getOrCreateDmk();
|
|
4476
|
-
|
|
4388
|
+
const { SignerTrxBuilder } = await ctx.importLedgerKit("@ledgerhq/device-signer-kit-tron");
|
|
4389
|
+
const sdkSigner = new SignerTrxBuilder({ dmk, sessionId }).build();
|
|
4390
|
+
const signer = new SignerTron(sdkSigner);
|
|
4391
|
+
signer.onInteraction = (interaction) => {
|
|
4392
|
+
debugLog("[LedgerConnector] tron.onInteraction:", interaction);
|
|
4393
|
+
ctx.emit("ui-event", {
|
|
4394
|
+
type: collapseSignerInteraction(interaction),
|
|
4395
|
+
payload: { sessionId }
|
|
4396
|
+
});
|
|
4397
|
+
};
|
|
4398
|
+
signer.onRegisterCanceller = (cancel) => {
|
|
4399
|
+
ctx.registerCanceller(sessionId, cancel);
|
|
4400
|
+
};
|
|
4401
|
+
return signer;
|
|
4477
4402
|
}
|
|
4478
4403
|
|
|
4479
4404
|
// src/device-apps/customActions.ts
|
|
4480
|
-
var
|
|
4405
|
+
var import_device_management_kit2 = require("@ledgerhq/device-management-kit");
|
|
4481
4406
|
var import_rxjs = require("rxjs");
|
|
4482
4407
|
var GetOsVersionDeviceAction = class {
|
|
4483
4408
|
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
@@ -4491,7 +4416,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4491
4416
|
(async () => {
|
|
4492
4417
|
try {
|
|
4493
4418
|
subject.next({
|
|
4494
|
-
status:
|
|
4419
|
+
status: import_device_management_kit2.DeviceActionStatus.Pending,
|
|
4495
4420
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4496
4421
|
});
|
|
4497
4422
|
const result = await internalApi.sendCommand(new this._deps.GetOsVersionCommand());
|
|
@@ -4500,11 +4425,11 @@ var GetOsVersionDeviceAction = class {
|
|
|
4500
4425
|
const errObj = result?.error;
|
|
4501
4426
|
throw new Error(errObj?.message ?? "GetOsVersionCommand failed");
|
|
4502
4427
|
}
|
|
4503
|
-
subject.next({ status:
|
|
4428
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: result.data });
|
|
4504
4429
|
subject.complete();
|
|
4505
4430
|
} catch (err) {
|
|
4506
4431
|
if (cancelled) return;
|
|
4507
|
-
subject.next({ status:
|
|
4432
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
|
|
4508
4433
|
subject.complete();
|
|
4509
4434
|
}
|
|
4510
4435
|
})();
|
|
@@ -4512,7 +4437,7 @@ var GetOsVersionDeviceAction = class {
|
|
|
4512
4437
|
observable: subject.asObservable(),
|
|
4513
4438
|
cancel: () => {
|
|
4514
4439
|
cancelled = true;
|
|
4515
|
-
subject.next({ status:
|
|
4440
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
|
|
4516
4441
|
subject.complete();
|
|
4517
4442
|
}
|
|
4518
4443
|
};
|
|
@@ -4530,7 +4455,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4530
4455
|
(async () => {
|
|
4531
4456
|
try {
|
|
4532
4457
|
subject.next({
|
|
4533
|
-
status:
|
|
4458
|
+
status: import_device_management_kit2.DeviceActionStatus.Pending,
|
|
4534
4459
|
intermediateValue: { requiredUserInteraction: "none" }
|
|
4535
4460
|
});
|
|
4536
4461
|
const osVersionResult = await internalApi.sendCommand(new this._GetOsVersionCommand());
|
|
@@ -4547,11 +4472,11 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4547
4472
|
throw new Error(httpErr?.message ?? "Manager API getAppList failed");
|
|
4548
4473
|
}
|
|
4549
4474
|
const apps = either.extract();
|
|
4550
|
-
subject.next({ status:
|
|
4475
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Completed, output: apps });
|
|
4551
4476
|
subject.complete();
|
|
4552
4477
|
} catch (err) {
|
|
4553
4478
|
if (cancelled) return;
|
|
4554
|
-
subject.next({ status:
|
|
4479
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Error, error: err });
|
|
4555
4480
|
subject.complete();
|
|
4556
4481
|
}
|
|
4557
4482
|
})();
|
|
@@ -4559,7 +4484,7 @@ var ListAvailableAppsDeviceAction = class {
|
|
|
4559
4484
|
observable: subject.asObservable(),
|
|
4560
4485
|
cancel: () => {
|
|
4561
4486
|
cancelled = true;
|
|
4562
|
-
subject.next({ status:
|
|
4487
|
+
subject.next({ status: import_device_management_kit2.DeviceActionStatus.Stopped });
|
|
4563
4488
|
subject.complete();
|
|
4564
4489
|
}
|
|
4565
4490
|
};
|
|
@@ -4652,7 +4577,7 @@ var DeviceApps = class {
|
|
|
4652
4577
|
seTargetId: v.seTargetId,
|
|
4653
4578
|
mcuTargetId: v.mcuTargetId,
|
|
4654
4579
|
seVersion: v.seVersion,
|
|
4655
|
-
seFlagsHex:
|
|
4580
|
+
seFlagsHex: bytesToHex4(v.seFlags),
|
|
4656
4581
|
mcuSephVersion: v.mcuSephVersion,
|
|
4657
4582
|
mcuBootloaderVersion: v.mcuBootloaderVersion,
|
|
4658
4583
|
hwVersion: v.hwVersion
|
|
@@ -4726,7 +4651,7 @@ var DeviceApps = class {
|
|
|
4726
4651
|
}
|
|
4727
4652
|
}
|
|
4728
4653
|
};
|
|
4729
|
-
function
|
|
4654
|
+
function bytesToHex4(bytes) {
|
|
4730
4655
|
if (!bytes) return "";
|
|
4731
4656
|
return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
4732
4657
|
}
|
|
@@ -4773,7 +4698,7 @@ var METHOD_PREFIX_TO_APP_NAME = {
|
|
|
4773
4698
|
zcash: "Zcash"
|
|
4774
4699
|
};
|
|
4775
4700
|
var HARDWARE_ERROR_CODE_VALUES = new Set(
|
|
4776
|
-
Object.values(
|
|
4701
|
+
Object.values(import_hwk_adapter_core12.HardwareErrorCode).filter((value) => typeof value === "number")
|
|
4777
4702
|
);
|
|
4778
4703
|
var BLE_CONNECT_SCAN_TIMEOUT_MS = 1500;
|
|
4779
4704
|
var LEDGER_RELAY_ALLOWED_ROOT_DOMAINS = ["onekeytest.com", "onekey.com"];
|
|
@@ -4810,6 +4735,8 @@ async function defaultLedgerKitImporter(pkg) {
|
|
|
4810
4735
|
return import("@ledgerhq/device-signer-kit-bitcoin");
|
|
4811
4736
|
case "@ledgerhq/device-signer-kit-solana":
|
|
4812
4737
|
return import("@ledgerhq/device-signer-kit-solana");
|
|
4738
|
+
case "@ledgerhq/device-signer-kit-tron":
|
|
4739
|
+
return import("@ledgerhq/device-signer-kit-tron");
|
|
4813
4740
|
case "@ledgerhq/device-signer-kit-zcash":
|
|
4814
4741
|
return import("@ledgerhq/device-signer-kit-zcash");
|
|
4815
4742
|
case "@ledgerhq/context-module":
|
|
@@ -4922,7 +4849,7 @@ var LedgerConnectorBase = class {
|
|
|
4922
4849
|
async searchDevices() {
|
|
4923
4850
|
const dm = await this._getDeviceManager();
|
|
4924
4851
|
const descriptors = await this._discoverDescriptors(dm);
|
|
4925
|
-
const resolvedDescriptors = descriptors.filter((d) => !(0,
|
|
4852
|
+
const resolvedDescriptors = descriptors.filter((d) => !(0, import_hwk_adapter_core12.isKnownNonTargetHardwareVendor)(d, "ledger")).map((d) => ({
|
|
4926
4853
|
descriptor: d,
|
|
4927
4854
|
connectId: this._resolveConnectId(d)
|
|
4928
4855
|
}));
|
|
@@ -4970,7 +4897,7 @@ var LedgerConnectorBase = class {
|
|
|
4970
4897
|
`Ledger BLE connect did not return within ${HANG_CEILING_MS / 6e4}min \u2014 DMK hang fallback.`
|
|
4971
4898
|
);
|
|
4972
4899
|
err._tag = ERROR_TAG.BlePairingTimeout;
|
|
4973
|
-
err.code =
|
|
4900
|
+
err.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
|
|
4974
4901
|
reject(err);
|
|
4975
4902
|
}, HANG_CEILING_MS);
|
|
4976
4903
|
});
|
|
@@ -5003,7 +4930,7 @@ var LedgerConnectorBase = class {
|
|
|
5003
4930
|
"Ledger device is not currently advertising. Wake up and unlock the device, keep it nearby, then try again."
|
|
5004
4931
|
);
|
|
5005
4932
|
err._tag = ERROR_TAG.DeviceNotAdvertising;
|
|
5006
|
-
err.code =
|
|
4933
|
+
err.code = import_hwk_adapter_core12.HardwareErrorCode.DeviceNotFound;
|
|
5007
4934
|
throw err;
|
|
5008
4935
|
};
|
|
5009
4936
|
const doConnect = async (path) => {
|
|
@@ -5067,7 +4994,7 @@ var LedgerConnectorBase = class {
|
|
|
5067
4994
|
"Ledger Bluetooth pairing failed. Make sure the device is unlocked and nearby, then try again."
|
|
5068
4995
|
);
|
|
5069
4996
|
wrapped._tag = ERROR_TAG.BleGattBondingFailed;
|
|
5070
|
-
wrapped.code =
|
|
4997
|
+
wrapped.code = import_hwk_adapter_core12.HardwareErrorCode.BlePairingTimeout;
|
|
5071
4998
|
wrapped.originalError = err;
|
|
5072
4999
|
throw wrapped;
|
|
5073
5000
|
}
|
|
@@ -5145,7 +5072,7 @@ var LedgerConnectorBase = class {
|
|
|
5145
5072
|
this._unwatchSessionState(sessionId);
|
|
5146
5073
|
this._signerManager?.invalidate(sessionId);
|
|
5147
5074
|
this._cancellers.get(sessionId)?.({
|
|
5148
|
-
code:
|
|
5075
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.DeviceDisconnected,
|
|
5149
5076
|
tag: "DeviceDisconnected",
|
|
5150
5077
|
message: "Device disconnected"
|
|
5151
5078
|
});
|
|
@@ -5169,9 +5096,9 @@ var LedgerConnectorBase = class {
|
|
|
5169
5096
|
if (isAppStuckByApdu(err)) {
|
|
5170
5097
|
return {
|
|
5171
5098
|
success: false,
|
|
5172
|
-
error: (0,
|
|
5099
|
+
error: (0, import_hwk_adapter_core12.serializeConnectorError)(
|
|
5173
5100
|
Object.assign(new Error("Ledger app is unresponsive"), {
|
|
5174
|
-
code:
|
|
5101
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.DeviceAppStuck,
|
|
5175
5102
|
_tag: ERROR_TAG.DeviceAppStuck,
|
|
5176
5103
|
originalError: err
|
|
5177
5104
|
})
|
|
@@ -5181,16 +5108,16 @@ var LedgerConnectorBase = class {
|
|
|
5181
5108
|
if (isTransportStuck(err)) {
|
|
5182
5109
|
return {
|
|
5183
5110
|
success: false,
|
|
5184
|
-
error: (0,
|
|
5111
|
+
error: (0, import_hwk_adapter_core12.serializeConnectorError)(
|
|
5185
5112
|
Object.assign(new Error("Device communication interrupted, please retry"), {
|
|
5186
|
-
code:
|
|
5113
|
+
code: import_hwk_adapter_core12.HardwareErrorCode.TransportError,
|
|
5187
5114
|
_tag: ERROR_TAG.DeviceTransportStuck,
|
|
5188
5115
|
originalError: err
|
|
5189
5116
|
})
|
|
5190
5117
|
)
|
|
5191
5118
|
};
|
|
5192
5119
|
}
|
|
5193
|
-
return { success: false, error: (0,
|
|
5120
|
+
return { success: false, error: (0, import_hwk_adapter_core12.serializeConnectorError)(err) };
|
|
5194
5121
|
}
|
|
5195
5122
|
}
|
|
5196
5123
|
async _dispatch(sessionId, method, params) {
|
|
@@ -5258,7 +5185,7 @@ var LedgerConnectorBase = class {
|
|
|
5258
5185
|
try {
|
|
5259
5186
|
return await apps.install(p.appName, ({ progress }) => {
|
|
5260
5187
|
ctx.emit("ui-event", {
|
|
5261
|
-
type:
|
|
5188
|
+
type: import_hwk_adapter_core12.EConnectorInteraction.AppInstallProgress,
|
|
5262
5189
|
payload: {
|
|
5263
5190
|
sessionId,
|
|
5264
5191
|
appName: p.appName,
|
|
@@ -5597,6 +5524,204 @@ var LedgerConnectorBase = class {
|
|
|
5597
5524
|
return error;
|
|
5598
5525
|
}
|
|
5599
5526
|
};
|
|
5527
|
+
|
|
5528
|
+
// src/transport/DmkTransport.ts
|
|
5529
|
+
var import_hw_transport = __toESM(require("@ledgerhq/hw-transport"));
|
|
5530
|
+
var DmkTransport = class extends import_hw_transport.default {
|
|
5531
|
+
constructor(dmk, sessionId) {
|
|
5532
|
+
super();
|
|
5533
|
+
this._dmk = dmk;
|
|
5534
|
+
this._sessionId = sessionId;
|
|
5535
|
+
}
|
|
5536
|
+
async exchange(apdu) {
|
|
5537
|
+
const response = await this._dmk.sendApdu({
|
|
5538
|
+
sessionId: this._sessionId,
|
|
5539
|
+
apdu: new Uint8Array(apdu)
|
|
5540
|
+
});
|
|
5541
|
+
const { data, statusCode } = response;
|
|
5542
|
+
const result = Buffer.alloc(data.length + 2);
|
|
5543
|
+
if (data.length > 0) {
|
|
5544
|
+
result.set(data, 0);
|
|
5545
|
+
}
|
|
5546
|
+
result.set(statusCode, data.length);
|
|
5547
|
+
return result;
|
|
5548
|
+
}
|
|
5549
|
+
async close() {
|
|
5550
|
+
}
|
|
5551
|
+
};
|
|
5552
|
+
|
|
5553
|
+
// src/app/AppManager.ts
|
|
5554
|
+
var import_device_management_kit3 = require("@ledgerhq/device-management-kit");
|
|
5555
|
+
var import_hwk_adapter_core13 = require("@onekeyfe/hwk-adapter-core");
|
|
5556
|
+
var APP_NAME_MAP = {
|
|
5557
|
+
ETH: "Ethereum",
|
|
5558
|
+
BTC: "Bitcoin",
|
|
5559
|
+
SOL: "Solana",
|
|
5560
|
+
TRX: "Tron",
|
|
5561
|
+
ZEC: "Zcash",
|
|
5562
|
+
XRP: "XRP",
|
|
5563
|
+
ADA: "Cardano",
|
|
5564
|
+
DOT: "Polkadot",
|
|
5565
|
+
ATOM: "Cosmos"
|
|
5566
|
+
};
|
|
5567
|
+
var DASHBOARD_APP_NAME = "BOLOS";
|
|
5568
|
+
var AppManager = class {
|
|
5569
|
+
constructor(dmk, options) {
|
|
5570
|
+
this._dmk = dmk;
|
|
5571
|
+
this._waitMs = options?.waitMs ?? 1e3;
|
|
5572
|
+
this._maxRetries = options?.maxRetries ?? 10;
|
|
5573
|
+
}
|
|
5574
|
+
/**
|
|
5575
|
+
* Return the Ledger app name for a given chain ticker,
|
|
5576
|
+
* or undefined if the chain is not supported.
|
|
5577
|
+
*/
|
|
5578
|
+
static getAppName(chain) {
|
|
5579
|
+
return APP_NAME_MAP[chain];
|
|
5580
|
+
}
|
|
5581
|
+
/**
|
|
5582
|
+
* Ensure the target app is open on the device identified by `sessionId`.
|
|
5583
|
+
*
|
|
5584
|
+
* Flow:
|
|
5585
|
+
* 1. Check the currently running app.
|
|
5586
|
+
* 2. If it is already the target, return immediately.
|
|
5587
|
+
* 3. If a different app is running (not dashboard), close it first.
|
|
5588
|
+
* 4. Open the target app.
|
|
5589
|
+
* 5. Poll until the device confirms the target app is running.
|
|
5590
|
+
*/
|
|
5591
|
+
/**
|
|
5592
|
+
* @param onConfirmOnDevice Called BEFORE OpenAppCommand is issued — the
|
|
5593
|
+
* device is about to display "Open <app>" on screen and wait for the
|
|
5594
|
+
* user's button press. UI consumers should show their "open app" prompt
|
|
5595
|
+
* in response. NOT called when the target app is already open (no user
|
|
5596
|
+
* interaction needed in that case).
|
|
5597
|
+
*
|
|
5598
|
+
* Important: OpenAppCommand is blocking. It does not resolve until the user
|
|
5599
|
+
* has physically confirmed on the device, so anything that runs AFTER
|
|
5600
|
+
* `await this._openApp(...)` lands AFTER the prompt is already gone.
|
|
5601
|
+
* Hence the callback must fire BEFORE that await.
|
|
5602
|
+
*/
|
|
5603
|
+
async ensureAppOpen(sessionId, targetAppName, onConfirmOnDevice) {
|
|
5604
|
+
const currentApp = await this._getCurrentApp(sessionId);
|
|
5605
|
+
if (currentApp === targetAppName) {
|
|
5606
|
+
return;
|
|
5607
|
+
}
|
|
5608
|
+
if (!this._isDashboard(currentApp)) {
|
|
5609
|
+
await this._closeCurrentApp(sessionId);
|
|
5610
|
+
await this._waitForApp(sessionId, DASHBOARD_APP_NAME);
|
|
5611
|
+
}
|
|
5612
|
+
onConfirmOnDevice?.();
|
|
5613
|
+
await this._openApp(sessionId, targetAppName);
|
|
5614
|
+
await this._waitForApp(sessionId, targetAppName);
|
|
5615
|
+
}
|
|
5616
|
+
// ---------------------------------------------------------------------------
|
|
5617
|
+
// Private helpers
|
|
5618
|
+
// ---------------------------------------------------------------------------
|
|
5619
|
+
async _getCurrentApp(sessionId) {
|
|
5620
|
+
const result = await this._dmk.sendCommand({
|
|
5621
|
+
sessionId,
|
|
5622
|
+
command: new import_device_management_kit3.GetAppAndVersionCommand()
|
|
5623
|
+
});
|
|
5624
|
+
if ((0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5625
|
+
debugLog("[AppManager] currentApp:", result.data.name);
|
|
5626
|
+
return result.data.name;
|
|
5627
|
+
}
|
|
5628
|
+
const errResult = result;
|
|
5629
|
+
const dmkErr = errResult.error ?? {};
|
|
5630
|
+
const original = dmkErr.originalError;
|
|
5631
|
+
debugLog(
|
|
5632
|
+
"[AppManager] _getCurrentApp failed sessionId=",
|
|
5633
|
+
sessionId,
|
|
5634
|
+
"tag=",
|
|
5635
|
+
dmkErr._tag,
|
|
5636
|
+
"errorCode=",
|
|
5637
|
+
dmkErr.errorCode,
|
|
5638
|
+
"message=",
|
|
5639
|
+
dmkErr.message,
|
|
5640
|
+
"originalErrorMessage=",
|
|
5641
|
+
original?.message ?? String(original ?? "")
|
|
5642
|
+
);
|
|
5643
|
+
throw Object.assign(
|
|
5644
|
+
new Error(
|
|
5645
|
+
dmkErr.message ?? "Failed to get current app from device"
|
|
5646
|
+
),
|
|
5647
|
+
{
|
|
5648
|
+
_tag: dmkErr._tag,
|
|
5649
|
+
errorCode: dmkErr.errorCode,
|
|
5650
|
+
originalError: original
|
|
5651
|
+
}
|
|
5652
|
+
);
|
|
5653
|
+
}
|
|
5654
|
+
async _openApp(sessionId, appName) {
|
|
5655
|
+
const result = await this._dmk.sendCommand({
|
|
5656
|
+
sessionId,
|
|
5657
|
+
command: new import_device_management_kit3.OpenAppCommand({ appName })
|
|
5658
|
+
});
|
|
5659
|
+
if (!(0, import_device_management_kit3.isSuccessCommandResult)(result)) {
|
|
5660
|
+
const dmkErr = result.error;
|
|
5661
|
+
const errorCode = "errorCode" in dmkErr && dmkErr.errorCode != null ? String(dmkErr.errorCode) : "";
|
|
5662
|
+
const message = "message" in dmkErr && typeof dmkErr.message === "string" ? dmkErr.message : "";
|
|
5663
|
+
debugLog(
|
|
5664
|
+
"[AppManager] openApp failed:",
|
|
5665
|
+
appName,
|
|
5666
|
+
"errorCode:",
|
|
5667
|
+
errorCode,
|
|
5668
|
+
"tag:",
|
|
5669
|
+
dmkErr._tag
|
|
5670
|
+
);
|
|
5671
|
+
let code;
|
|
5672
|
+
if (errorCode === "6807" || /unknown application/i.test(message)) {
|
|
5673
|
+
code = import_hwk_adapter_core13.HardwareErrorCode.AppNotInstalled;
|
|
5674
|
+
} else if (errorCode === "5501" || dmkErr._tag === "ActionRefusedError") {
|
|
5675
|
+
code = import_hwk_adapter_core13.HardwareErrorCode.UserRejected;
|
|
5676
|
+
}
|
|
5677
|
+
throw Object.assign(new Error(`Failed to open "${appName}"`), {
|
|
5678
|
+
_tag: ERROR_TAG.OpenAppCommand,
|
|
5679
|
+
code,
|
|
5680
|
+
errorCode,
|
|
5681
|
+
statusCode: errorCode,
|
|
5682
|
+
appName,
|
|
5683
|
+
originalError: dmkErr
|
|
5684
|
+
});
|
|
5685
|
+
}
|
|
5686
|
+
}
|
|
5687
|
+
async _closeCurrentApp(sessionId) {
|
|
5688
|
+
debugLog("[AppManager] closeCurrentApp");
|
|
5689
|
+
await this._dmk.sendCommand({
|
|
5690
|
+
sessionId,
|
|
5691
|
+
command: new import_device_management_kit3.CloseAppCommand()
|
|
5692
|
+
});
|
|
5693
|
+
}
|
|
5694
|
+
/**
|
|
5695
|
+
* Poll the device until the expected app is reported as running,
|
|
5696
|
+
* or throw after `_maxRetries` attempts.
|
|
5697
|
+
*/
|
|
5698
|
+
async _waitForApp(sessionId, expectedAppName) {
|
|
5699
|
+
let lastSeen = "";
|
|
5700
|
+
for (let i = 0; i < this._maxRetries; i++) {
|
|
5701
|
+
await this._wait();
|
|
5702
|
+
const current = await this._getCurrentApp(sessionId);
|
|
5703
|
+
lastSeen = current;
|
|
5704
|
+
if (current === expectedAppName) {
|
|
5705
|
+
return;
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
debugLog(
|
|
5709
|
+
"[AppManager] waitForApp exhausted: expected=",
|
|
5710
|
+
expectedAppName,
|
|
5711
|
+
"lastSeen=",
|
|
5712
|
+
lastSeen
|
|
5713
|
+
);
|
|
5714
|
+
throw new Error(
|
|
5715
|
+
`Ledger: failed to open "${expectedAppName}" after ${this._maxRetries} retries (last seen: ${lastSeen})`
|
|
5716
|
+
);
|
|
5717
|
+
}
|
|
5718
|
+
_isDashboard(appName) {
|
|
5719
|
+
return appName === DASHBOARD_APP_NAME;
|
|
5720
|
+
}
|
|
5721
|
+
_wait() {
|
|
5722
|
+
return new Promise((resolve) => setTimeout(resolve, this._waitMs));
|
|
5723
|
+
}
|
|
5724
|
+
};
|
|
5600
5725
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5601
5726
|
0 && (module.exports = {
|
|
5602
5727
|
AppManager,
|