@swapkit/wallet-hardware 4.10.0 → 5.0.0
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/chunk-9gy0xve4.js +4 -0
- package/dist/{chunk-qs60k0yv.js.map → chunk-9gy0xve4.js.map} +3 -3
- package/dist/chunk-egtwbe6q.js +4 -0
- package/dist/{chunk-gwx23jdp.js.map → chunk-egtwbe6q.js.map} +3 -3
- package/dist/keepkey/index.cjs +2 -2
- package/dist/keepkey/index.cjs.map +3 -3
- package/dist/keepkey/index.js +2 -2
- package/dist/keepkey/index.js.map +3 -3
- package/dist/ledger/index.cjs +2 -2
- package/dist/ledger/index.cjs.map +7 -6
- package/dist/ledger/index.js +2 -2
- package/dist/ledger/index.js.map +6 -5
- package/dist/trezor/index.cjs +2 -2
- package/dist/trezor/index.cjs.map +4 -4
- package/dist/trezor/index.js +2 -2
- package/dist/trezor/index.js.map +3 -3
- package/dist/types/keepkey/chains/utxo.d.ts.map +1 -1
- package/dist/types/ledger/clients/evm.d.ts +3 -0
- package/dist/types/ledger/clients/evm.d.ts.map +1 -1
- package/dist/types/ledger/clients/utxo-psbt.d.ts +2 -0
- package/dist/types/ledger/clients/utxo-psbt.d.ts.map +1 -1
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts +14 -0
- package/dist/types/ledger/helpers/ledgerNetworkInfo.d.ts.map +1 -0
- package/dist/types/ledger/index.d.ts.map +1 -1
- package/dist/types/trezor/evmSigner.d.ts.map +1 -1
- package/dist/types/trezor/index.d.ts +2 -2
- package/dist/types/trezor/index.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/keepkey/chains/utxo.ts +5 -2
- package/src/ledger/clients/evm.ts +84 -2
- package/src/ledger/clients/utxo-psbt.ts +1 -0
- package/src/ledger/helpers/ledgerNetworkInfo.ts +127 -0
- package/src/ledger/index.ts +14 -4
- package/src/trezor/evmSigner.ts +3 -4
- package/src/trezor/index.ts +12 -6
- package/dist/chunk-gwx23jdp.js +0 -4
- package/dist/chunk-qs60k0yv.js +0 -4
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"@ledgerhq/errors": "~6.29.0",
|
|
10
10
|
"@ledgerhq/hw-app-btc": "~10.17.0",
|
|
11
11
|
"@ledgerhq/hw-app-cosmos": "~6.33.0",
|
|
12
|
-
"@ledgerhq/hw-app-eth": "~7.
|
|
12
|
+
"@ledgerhq/hw-app-eth": "~7.8.18",
|
|
13
13
|
"@ledgerhq/hw-app-near": "~6.32.0",
|
|
14
14
|
"@ledgerhq/hw-app-sui": "~1.5.0",
|
|
15
15
|
"@ledgerhq/hw-app-trx": "~6.32.0",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"@near-js/transactions": "~2.5.0",
|
|
23
23
|
"@scure/base": "2.2.0",
|
|
24
24
|
"@scure/bip32": "2.2.0",
|
|
25
|
-
"@swapkit/helpers": "^
|
|
26
|
-
"@swapkit/toolboxes": "^
|
|
25
|
+
"@swapkit/helpers": "^6.0.0",
|
|
26
|
+
"@swapkit/toolboxes": "^6.0.0",
|
|
27
27
|
"@swapkit/utxo-signer": "^3.1.0",
|
|
28
|
-
"@swapkit/wallet-core": "^5.0.
|
|
28
|
+
"@swapkit/wallet-core": "^5.0.10",
|
|
29
29
|
"@trezor/connect-web": "~9.7.3",
|
|
30
30
|
"cosmjs-types": "~0.10.1",
|
|
31
31
|
"ethers": "^6.14.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@ledgerhq/errors": "6.29.0",
|
|
45
45
|
"@ledgerhq/hw-app-btc": "10.17.0",
|
|
46
46
|
"@ledgerhq/hw-app-cosmos": "6.33.0",
|
|
47
|
-
"@ledgerhq/hw-app-eth": "7.
|
|
47
|
+
"@ledgerhq/hw-app-eth": "7.8.18",
|
|
48
48
|
"@ledgerhq/hw-app-near": "6.32.0",
|
|
49
49
|
"@ledgerhq/hw-app-sui": "1.5.0",
|
|
50
50
|
"@ledgerhq/hw-app-trx": "6.32.0",
|
|
@@ -109,5 +109,5 @@
|
|
|
109
109
|
"type-check:go": "tsgo"
|
|
110
110
|
},
|
|
111
111
|
"type": "module",
|
|
112
|
-
"version": "
|
|
112
|
+
"version": "5.0.0"
|
|
113
113
|
}
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
type GenericTransferParams,
|
|
9
9
|
SwapKitError,
|
|
10
10
|
type UTXOChain,
|
|
11
|
+
UTXOScriptType,
|
|
11
12
|
} from "@swapkit/helpers";
|
|
12
13
|
import {
|
|
13
14
|
assertDerivationIndex,
|
|
@@ -44,11 +45,13 @@ export async function utxoWalletMethods({
|
|
|
44
45
|
derivationPath?: DerivationPathArray;
|
|
45
46
|
}): Promise<KeepKeyUTXOWalletMethods> {
|
|
46
47
|
const { getUtxoToolbox } = await import("@swapkit/toolboxes/utxo");
|
|
47
|
-
// This might not work for BCH
|
|
48
|
-
const toolbox = await getUtxoToolbox(chain);
|
|
49
48
|
const scriptType = [Chain.Bitcoin, Chain.Litecoin].includes(chain as typeof Chain.Bitcoin)
|
|
50
49
|
? ("p2wpkh" as const)
|
|
51
50
|
: ("p2pkh" as const);
|
|
51
|
+
// This might not work for BCH
|
|
52
|
+
const toolbox = await getUtxoToolbox(chain, {
|
|
53
|
+
scriptType: scriptType === "p2wpkh" ? UTXOScriptType.P2WPKH : UTXOScriptType.P2PKH,
|
|
54
|
+
});
|
|
52
55
|
|
|
53
56
|
const derivationPathString = derivationPath ? derivationPathToString(derivationPath) : `${DerivationPath[chain]}/0`;
|
|
54
57
|
|
|
@@ -16,6 +16,32 @@ import {
|
|
|
16
16
|
} from "ethers";
|
|
17
17
|
|
|
18
18
|
import { getLedgerTransport } from "../helpers/getLedgerTransport";
|
|
19
|
+
import {
|
|
20
|
+
fetchLedgerNetworkCertificate,
|
|
21
|
+
fetchLedgerNetworkDescriptor,
|
|
22
|
+
provideLedgerCertificate,
|
|
23
|
+
provideLedgerNetworkInformation,
|
|
24
|
+
} from "../helpers/ledgerNetworkInfo";
|
|
25
|
+
|
|
26
|
+
const LEDGER_INCORRECT_DATA = 0x6a80;
|
|
27
|
+
|
|
28
|
+
const ARC_CHAIN_ID = Number(ChainId.Arc);
|
|
29
|
+
|
|
30
|
+
type LedgerTransactionResolution = Awaited<
|
|
31
|
+
ReturnType<typeof import("@ledgerhq/hw-app-eth")["ledgerService"]["resolveTransaction"]>
|
|
32
|
+
>;
|
|
33
|
+
|
|
34
|
+
function isLedgerIncorrectDataError(error: unknown) {
|
|
35
|
+
return (
|
|
36
|
+
error instanceof Error &&
|
|
37
|
+
"statusCode" in error &&
|
|
38
|
+
(error as { statusCode: number }).statusCode === LEDGER_INCORRECT_DATA
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function hasClearSigningPayload(resolution: LedgerTransactionResolution | null) {
|
|
43
|
+
return Object.values(resolution ?? {}).some((entries) => Array.isArray(entries) && entries.length);
|
|
44
|
+
}
|
|
19
45
|
|
|
20
46
|
function parseLedgerSignatureV(v: number | string) {
|
|
21
47
|
if (typeof v === "number") return v;
|
|
@@ -31,6 +57,7 @@ class EVMLedgerInterface extends AbstractSigner {
|
|
|
31
57
|
ledgerTimeout = 50000;
|
|
32
58
|
private transport?: Transport;
|
|
33
59
|
private readonly injectedTransport?: Transport;
|
|
60
|
+
private arcNetworkRegistered = false;
|
|
34
61
|
|
|
35
62
|
constructor({
|
|
36
63
|
provider,
|
|
@@ -172,9 +199,22 @@ class EVMLedgerInterface extends AbstractSigner {
|
|
|
172
199
|
|
|
173
200
|
const { ledgerService } = await import("@ledgerhq/hw-app-eth");
|
|
174
201
|
|
|
175
|
-
const
|
|
202
|
+
const chainId = Number(baseTx.chainId);
|
|
203
|
+
const isArc = chainId === ARC_CHAIN_ID;
|
|
204
|
+
|
|
205
|
+
const resolution = await ledgerService
|
|
206
|
+
.resolveTransaction(unsignedTx, {}, { erc20: true, externalPlugins: true })
|
|
207
|
+
.catch((error) => {
|
|
208
|
+
if (!isArc) throw error;
|
|
209
|
+
|
|
210
|
+
console.warn("Ledger: could not fetch clear-signing metadata for Arc, signing blind");
|
|
211
|
+
|
|
212
|
+
return null;
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
if (isArc && !this.arcNetworkRegistered) await this.registerNetworkOnDevice(chainId);
|
|
176
216
|
|
|
177
|
-
const signature = await this.
|
|
217
|
+
const signature = await this.signWithLedgerApp(unsignedTx, resolution, chainId);
|
|
178
218
|
|
|
179
219
|
if (!signature) throw new SwapKitError("wallet_ledger_signing_error");
|
|
180
220
|
|
|
@@ -183,6 +223,48 @@ class EVMLedgerInterface extends AbstractSigner {
|
|
|
183
223
|
return Transaction.from({ ...baseTx, signature: { r: `0x${r}`, s: `0x${s}`, v: parseLedgerSignatureV(v) } })
|
|
184
224
|
.serialized;
|
|
185
225
|
};
|
|
226
|
+
|
|
227
|
+
private signWithLedgerApp = async (
|
|
228
|
+
unsignedTx: string,
|
|
229
|
+
resolution: LedgerTransactionResolution | null,
|
|
230
|
+
chainId: number,
|
|
231
|
+
) => {
|
|
232
|
+
try {
|
|
233
|
+
return await this.ledgerApp?.signTransaction(this.derivationPath, unsignedTx, resolution);
|
|
234
|
+
} catch (error) {
|
|
235
|
+
const canSignBlind =
|
|
236
|
+
chainId === ARC_CHAIN_ID && isLedgerIncorrectDataError(error) && hasClearSigningPayload(resolution);
|
|
237
|
+
|
|
238
|
+
if (!canSignBlind) throw error;
|
|
239
|
+
|
|
240
|
+
console.warn("Ledger: the app rejected the Arc metadata, signing blind");
|
|
241
|
+
|
|
242
|
+
return await this.ledgerApp?.signTransaction(this.derivationPath, unsignedTx, null);
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
private registerNetworkOnDevice = async (chainId: number) => {
|
|
247
|
+
const deviceModelId = this.transport?.deviceModel?.id;
|
|
248
|
+
|
|
249
|
+
if (!(this.transport && deviceModelId)) return;
|
|
250
|
+
|
|
251
|
+
try {
|
|
252
|
+
const [descriptor, certificate] = await Promise.all([
|
|
253
|
+
fetchLedgerNetworkDescriptor(chainId, deviceModelId),
|
|
254
|
+
fetchLedgerNetworkCertificate(deviceModelId),
|
|
255
|
+
]);
|
|
256
|
+
|
|
257
|
+
if (!descriptor) return;
|
|
258
|
+
|
|
259
|
+
if (certificate) await provideLedgerCertificate(this.transport, certificate);
|
|
260
|
+
|
|
261
|
+
await provideLedgerNetworkInformation(this.transport, descriptor);
|
|
262
|
+
|
|
263
|
+
this.arcNetworkRegistered = true;
|
|
264
|
+
} catch {
|
|
265
|
+
// the app will reject the metadata and signWithLedgerApp falls back to blind signing
|
|
266
|
+
}
|
|
267
|
+
};
|
|
186
268
|
}
|
|
187
269
|
|
|
188
270
|
type LedgerParams = { provider: Provider; derivationPath?: DerivationPathArray; transport?: Transport };
|
|
@@ -135,6 +135,7 @@ const BaseLedgerPsbtUTXO = ({ chain }: { chain: SupportedCoin }) => {
|
|
|
135
135
|
const app = await getAppClient();
|
|
136
136
|
return app.getExtendedPubkey(`m/${normalizeLedgerPath(path)}`);
|
|
137
137
|
},
|
|
138
|
+
getPublicKey: getLeafPubkey,
|
|
138
139
|
signTransaction: async (tx: Transaction): Promise<Transaction> => {
|
|
139
140
|
const { app, policy, fpr } = await buildPolicy();
|
|
140
141
|
const fingerprintBE = Number.parseInt(fpr, 16) >>> 0;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type Transport from "@ledgerhq/hw-transport";
|
|
2
|
+
|
|
3
|
+
const LEDGER_CAL_SERVICE_URL = "https://crypto-assets-service.api.ledger.com/v1";
|
|
4
|
+
|
|
5
|
+
const LEDGER_DEVICE_TO_CAL_MODEL: Record<string, string> = {
|
|
6
|
+
apex: "apexp",
|
|
7
|
+
europa: "flex",
|
|
8
|
+
nanoS: "nanos",
|
|
9
|
+
nanoSP: "nanosp",
|
|
10
|
+
nanoX: "nanox",
|
|
11
|
+
stax: "stax",
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const APDU_CLA = 0xe0;
|
|
15
|
+
const APDU_CLA_PKI = 0xb0;
|
|
16
|
+
const APDU_INS_LOAD_CERTIFICATE = 0x06;
|
|
17
|
+
const LEDGER_KEY_USAGE_NETWORK = 0x0c;
|
|
18
|
+
const APDU_INS_PROVIDE_NETWORK_INFORMATION = 0x30;
|
|
19
|
+
const APDU_P1_FIRST_CHUNK = 0x01;
|
|
20
|
+
const APDU_P1_FOLLOWING_CHUNK = 0x00;
|
|
21
|
+
const APDU_P2_NETWORK_CONFIG = 0x00;
|
|
22
|
+
const APDU_P2_NETWORK_ICON = 0x01;
|
|
23
|
+
const APDU_MAX_CHUNK_SIZE = 0xff;
|
|
24
|
+
const TLV_TAG_DER_SIGNATURE = 0x15;
|
|
25
|
+
|
|
26
|
+
export type LedgerNetworkDescriptor = { data: string; icon?: string; signature: string };
|
|
27
|
+
|
|
28
|
+
type CalNetwork = {
|
|
29
|
+
chain_id: number;
|
|
30
|
+
descriptors?: Record<string, { data?: string; signatures?: { prod?: string } }>;
|
|
31
|
+
icons?: Record<string, string>;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export async function fetchLedgerNetworkCertificate(
|
|
35
|
+
deviceModelId: string,
|
|
36
|
+
fetchFn: typeof fetch = fetch,
|
|
37
|
+
): Promise<string | null> {
|
|
38
|
+
const calModel = LEDGER_DEVICE_TO_CAL_MODEL[deviceModelId];
|
|
39
|
+
if (!calModel) return null;
|
|
40
|
+
|
|
41
|
+
const url = `${LEDGER_CAL_SERVICE_URL}/certificates?output=descriptor&public_key_usage=network&target_device=${calModel}`;
|
|
42
|
+
const response = await fetchFn(url);
|
|
43
|
+
if (!response.ok) return null;
|
|
44
|
+
|
|
45
|
+
const certificates = (await response.json()) as Array<{
|
|
46
|
+
descriptor?: { data?: string; signatures?: { prod?: string } };
|
|
47
|
+
}>;
|
|
48
|
+
const descriptor = certificates[0]?.descriptor;
|
|
49
|
+
const signature = descriptor?.signatures?.prod;
|
|
50
|
+
|
|
51
|
+
if (!(descriptor?.data && signature)) return null;
|
|
52
|
+
|
|
53
|
+
return `${descriptor.data}${appendSignatureTlv(signature)}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function provideLedgerCertificate(transport: Transport, payloadHex: string) {
|
|
57
|
+
await transport.send(
|
|
58
|
+
APDU_CLA_PKI,
|
|
59
|
+
APDU_INS_LOAD_CERTIFICATE,
|
|
60
|
+
LEDGER_KEY_USAGE_NETWORK,
|
|
61
|
+
0x00,
|
|
62
|
+
Buffer.from(payloadHex, "hex"),
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function fetchLedgerNetworkDescriptor(
|
|
67
|
+
chainId: number,
|
|
68
|
+
deviceModelId: string,
|
|
69
|
+
fetchFn: typeof fetch = fetch,
|
|
70
|
+
): Promise<LedgerNetworkDescriptor | null> {
|
|
71
|
+
const calModel = LEDGER_DEVICE_TO_CAL_MODEL[deviceModelId];
|
|
72
|
+
if (!calModel) return null;
|
|
73
|
+
|
|
74
|
+
const url = `${LEDGER_CAL_SERVICE_URL}/networks?chain_id=${chainId}&output=chain_id,descriptors,icons`;
|
|
75
|
+
const response = await fetchFn(url);
|
|
76
|
+
if (!response.ok) return null;
|
|
77
|
+
|
|
78
|
+
const networks = (await response.json()) as CalNetwork[];
|
|
79
|
+
const network = networks.find((entry) => entry.chain_id === chainId);
|
|
80
|
+
const descriptor = network?.descriptors?.[calModel];
|
|
81
|
+
const signature = descriptor?.signatures?.prod;
|
|
82
|
+
|
|
83
|
+
if (!(descriptor?.data && signature)) return null;
|
|
84
|
+
|
|
85
|
+
return { data: descriptor.data, icon: network?.icons?.[calModel], signature };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function appendSignatureTlv(signature: string) {
|
|
89
|
+
return encodeTlv(TLV_TAG_DER_SIGNATURE, Buffer.from(signature, "hex")).toString("hex");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function encodeTlv(tag: number, value: Buffer) {
|
|
93
|
+
return Buffer.concat([Buffer.from([tag, value.length]), value]);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function encodeNetworkInfoPayload({ data, signature }: LedgerNetworkDescriptor) {
|
|
97
|
+
const tlv = Buffer.concat([
|
|
98
|
+
Buffer.from(data, "hex"),
|
|
99
|
+
encodeTlv(TLV_TAG_DER_SIGNATURE, Buffer.from(signature, "hex")),
|
|
100
|
+
]);
|
|
101
|
+
const length = Buffer.alloc(2);
|
|
102
|
+
length.writeUInt16BE(tlv.length, 0);
|
|
103
|
+
return Buffer.concat([length, tlv]);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function sendChunked(transport: Transport, p2: number, payload: Buffer) {
|
|
107
|
+
for (let offset = 0; offset < payload.length; offset += APDU_MAX_CHUNK_SIZE) {
|
|
108
|
+
const p1 = offset === 0 ? APDU_P1_FIRST_CHUNK : APDU_P1_FOLLOWING_CHUNK;
|
|
109
|
+
const chunk = payload.subarray(offset, offset + APDU_MAX_CHUNK_SIZE);
|
|
110
|
+
await transport.send(APDU_CLA, APDU_INS_PROVIDE_NETWORK_INFORMATION, p1, p2, chunk);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export async function provideLedgerNetworkInformation(transport: Transport, descriptor: LedgerNetworkDescriptor) {
|
|
115
|
+
const payload = encodeNetworkInfoPayload(descriptor);
|
|
116
|
+
await sendChunked(transport, APDU_P2_NETWORK_CONFIG, payload);
|
|
117
|
+
|
|
118
|
+
if (!descriptor.icon) return { iconAccepted: false };
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
await sendChunked(transport, APDU_P2_NETWORK_ICON, Buffer.from(descriptor.icon, "hex"));
|
|
122
|
+
return { iconAccepted: true };
|
|
123
|
+
} catch {
|
|
124
|
+
await sendChunked(transport, APDU_P2_NETWORK_CONFIG, payload);
|
|
125
|
+
return { iconAccepted: false };
|
|
126
|
+
}
|
|
127
|
+
}
|
package/src/ledger/index.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
NetworkDerivationPath,
|
|
12
12
|
SwapKitError,
|
|
13
13
|
type UTXOChain,
|
|
14
|
+
UTXOScriptType,
|
|
14
15
|
WalletOption,
|
|
15
16
|
} from "@swapkit/helpers";
|
|
16
17
|
import {
|
|
@@ -19,6 +20,7 @@ import {
|
|
|
19
20
|
compileMemo,
|
|
20
21
|
createHDWalletHelpers,
|
|
21
22
|
getNetworkForChain,
|
|
23
|
+
getScriptTypeForAddress,
|
|
22
24
|
getUTXOAccountIndexFromPath,
|
|
23
25
|
getUTXOAccountPath,
|
|
24
26
|
getUTXOAddressPath,
|
|
@@ -172,6 +174,7 @@ async function getWalletMethods({
|
|
|
172
174
|
const signer = await getLedgerClient({ chain, derivationPath, transport });
|
|
173
175
|
|
|
174
176
|
const address = providedAddress ?? (await getLedgerAddress({ chain, ledgerClient: signer }));
|
|
177
|
+
const scriptType = getScriptTypeForAddress(address, utxoChain);
|
|
175
178
|
|
|
176
179
|
// V3 toolbox signer:
|
|
177
180
|
// - BTC uses the modern `ledger-bitcoin` AppClient with native PSBT signing.
|
|
@@ -181,13 +184,19 @@ async function getWalletMethods({
|
|
|
181
184
|
// policy APDUs and returns CLA_NOT_SUPPORTED.
|
|
182
185
|
// - ZEC stays on the bespoke `signPCZT` flow for now.
|
|
183
186
|
let toolboxSigner:
|
|
184
|
-
| {
|
|
187
|
+
| {
|
|
188
|
+
getAddress: () => Promise<string>;
|
|
189
|
+
publicKey?: Uint8Array;
|
|
190
|
+
signTransaction: (tx: Transaction) => Promise<Transaction>;
|
|
191
|
+
}
|
|
185
192
|
| undefined;
|
|
193
|
+
let publicKey: Uint8Array | undefined;
|
|
186
194
|
let signAndBroadcastLegacyPsbtTransaction: ((tx: Transaction) => Promise<string>) | undefined;
|
|
187
195
|
if (chain === Chain.Bitcoin) {
|
|
188
196
|
const { BitcoinPsbtLedger } = await import("./clients/utxo-psbt");
|
|
189
197
|
const psbtClient = BitcoinPsbtLedger(derivationPath, transport);
|
|
190
|
-
|
|
198
|
+
publicKey = scriptType === UTXOScriptType.P2SH_P2WPKH ? await psbtClient.getPublicKey() : undefined;
|
|
199
|
+
toolboxSigner = { getAddress: psbtClient.getAddress, publicKey, signTransaction: psbtClient.signTransaction };
|
|
191
200
|
} else if (
|
|
192
201
|
chain === Chain.BitcoinCash ||
|
|
193
202
|
chain === Chain.Dogecoin ||
|
|
@@ -203,8 +212,8 @@ async function getWalletMethods({
|
|
|
203
212
|
}
|
|
204
213
|
|
|
205
214
|
const toolbox = toolboxSigner
|
|
206
|
-
? await getUtxoToolbox(utxoChain, { signer: toolboxSigner })
|
|
207
|
-
: getUtxoToolbox(utxoChain);
|
|
215
|
+
? await getUtxoToolbox(utxoChain, { scriptType, signer: toolboxSigner })
|
|
216
|
+
: getUtxoToolbox(utxoChain, { scriptType });
|
|
208
217
|
const signAndBroadcastTransaction = signAndBroadcastLegacyPsbtTransaction ?? toolbox.signAndBroadcastTransaction;
|
|
209
218
|
|
|
210
219
|
const transfer = async (params: UTXOBuildTxParams) => {
|
|
@@ -216,6 +225,7 @@ async function getWalletMethods({
|
|
|
216
225
|
feeRate,
|
|
217
226
|
fetchTxHex: true,
|
|
218
227
|
memo,
|
|
228
|
+
publicKey: params.publicKey ?? publicKey,
|
|
219
229
|
sender: address,
|
|
220
230
|
});
|
|
221
231
|
|
package/src/trezor/evmSigner.ts
CHANGED
|
@@ -123,14 +123,13 @@ export async function getEVMSigner({ chain, derivationPath, provider }: TrezorEV
|
|
|
123
123
|
if (!to) throw new SwapKitError({ errorKey: "wallet_missing_params", info: { to } });
|
|
124
124
|
if (!gasLimit) throw new SwapKitError({ errorKey: "wallet_missing_params", info: { gasLimit } });
|
|
125
125
|
|
|
126
|
-
|
|
126
|
+
// Check presence, not truthiness: a zero-wei tip is legitimate on chains with a negligible
|
|
127
|
+
// priority fee, such as Arc, where it used to be read as missing fee data.
|
|
128
|
+
const isEIP1559 = maxFeePerGas != null || maxPriorityFeePerGas != null;
|
|
127
129
|
|
|
128
130
|
if (isEIP1559 && !maxFeePerGas) {
|
|
129
131
|
throw new SwapKitError({ errorKey: "wallet_missing_params", info: { maxFeePerGas } });
|
|
130
132
|
}
|
|
131
|
-
if (isEIP1559 && !maxPriorityFeePerGas) {
|
|
132
|
-
throw new SwapKitError({ errorKey: "wallet_missing_params", info: { maxPriorityFeePerGas } });
|
|
133
|
-
}
|
|
134
133
|
if (!(isEIP1559 || gasPrice)) {
|
|
135
134
|
throw new SwapKitError({ errorKey: "wallet_missing_params", info: { gasPrice } });
|
|
136
135
|
}
|
package/src/trezor/index.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
SKConfig,
|
|
11
11
|
SwapKitError,
|
|
12
12
|
type UTXOChain,
|
|
13
|
+
UTXOScriptType,
|
|
13
14
|
WalletOption,
|
|
14
15
|
} from "@swapkit/helpers";
|
|
15
16
|
import {
|
|
@@ -208,11 +209,11 @@ function decodeOpReturnData(script: Uint8Array): string | null {
|
|
|
208
209
|
function getScriptType(derivationPath: DerivationPathArray) {
|
|
209
210
|
switch (derivationPath[0]) {
|
|
210
211
|
case 84:
|
|
211
|
-
return { input: "SPENDWITNESS", output: "PAYTOWITNESS" } as const;
|
|
212
|
+
return { input: "SPENDWITNESS", output: "PAYTOWITNESS", utxo: UTXOScriptType.P2WPKH } as const;
|
|
212
213
|
case 49:
|
|
213
|
-
return { input: "SPENDP2SHWITNESS", output: "PAYTOP2SHWITNESS" } as const;
|
|
214
|
+
return { input: "SPENDP2SHWITNESS", output: "PAYTOP2SHWITNESS", utxo: UTXOScriptType.P2SH_P2WPKH } as const;
|
|
214
215
|
case 44:
|
|
215
|
-
return { input: "SPENDADDRESS", output: "PAYTOADDRESS" } as const;
|
|
216
|
+
return { input: "SPENDADDRESS", output: "PAYTOADDRESS", utxo: UTXOScriptType.P2PKH } as const;
|
|
216
217
|
default:
|
|
217
218
|
return null;
|
|
218
219
|
}
|
|
@@ -498,6 +499,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
498
499
|
}) {
|
|
499
500
|
switch (chain) {
|
|
500
501
|
case Chain.Arbitrum:
|
|
502
|
+
case Chain.Arc:
|
|
501
503
|
case Chain.Aurora:
|
|
502
504
|
case Chain.Avalanche:
|
|
503
505
|
case Chain.Base:
|
|
@@ -689,6 +691,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
689
691
|
}
|
|
690
692
|
|
|
691
693
|
const resolvedScriptType = scriptType;
|
|
694
|
+
const toolboxParams = { scriptType: scriptType.utxo };
|
|
692
695
|
const coin = chain.toLowerCase();
|
|
693
696
|
|
|
694
697
|
const getAddress = async (path: DerivationPathArray = derivationPath) => {
|
|
@@ -716,7 +719,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
716
719
|
};
|
|
717
720
|
|
|
718
721
|
const address = providedAddress ?? (await getAddress());
|
|
719
|
-
const baseToolbox = getUtxoToolbox(chain);
|
|
722
|
+
const baseToolbox = getUtxoToolbox(chain, toolboxParams);
|
|
720
723
|
|
|
721
724
|
const signTransaction = async (tx: Transaction, inputs: UTXOType[], memo = "") => {
|
|
722
725
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
@@ -997,7 +1000,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
997
1000
|
feeRate?: number;
|
|
998
1001
|
feeOptionKey?: (typeof FeeOption)[keyof typeof FeeOption];
|
|
999
1002
|
}) => {
|
|
1000
|
-
const toolbox = getUtxoToolbox(chain);
|
|
1003
|
+
const toolbox = getUtxoToolbox(chain, toolboxParams);
|
|
1001
1004
|
const txFeeRate = feeRate || (await toolbox.getFeeRates())[feeOptionKey || FeeOption.Fast];
|
|
1002
1005
|
|
|
1003
1006
|
const { tx, inputs: selectedInputs } = await toolbox.createTransaction({
|
|
@@ -1037,7 +1040,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1037
1040
|
});
|
|
1038
1041
|
}
|
|
1039
1042
|
|
|
1040
|
-
const toolbox = getUtxoToolbox(chain);
|
|
1043
|
+
const toolbox = getUtxoToolbox(chain, toolboxParams);
|
|
1041
1044
|
|
|
1042
1045
|
const feeRate = paramFeeRate || (await toolbox.getFeeRates())[feeOptionKey || FeeOption.Fast];
|
|
1043
1046
|
|
|
@@ -1060,6 +1063,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1060
1063
|
|
|
1061
1064
|
const toolbox = shouldUseTrezorPsbtSigner(chain)
|
|
1062
1065
|
? await getUtxoToolbox(utxoChain, {
|
|
1066
|
+
...toolboxParams,
|
|
1063
1067
|
signer: { getAddress: async () => address, signTransaction: signPsbtTransaction },
|
|
1064
1068
|
})
|
|
1065
1069
|
: baseToolbox;
|
|
@@ -1358,6 +1362,7 @@ export const trezorWallet = createWallet({
|
|
|
1358
1362
|
},
|
|
1359
1363
|
directSigningSupport: {
|
|
1360
1364
|
[Chain.Arbitrum]: true,
|
|
1365
|
+
[Chain.Arc]: true,
|
|
1361
1366
|
[Chain.Aurora]: true,
|
|
1362
1367
|
[Chain.Avalanche]: true,
|
|
1363
1368
|
[Chain.Base]: true,
|
|
@@ -1380,6 +1385,7 @@ export const trezorWallet = createWallet({
|
|
|
1380
1385
|
name: "connectTrezor",
|
|
1381
1386
|
supportedChains: [
|
|
1382
1387
|
Chain.Arbitrum,
|
|
1388
|
+
Chain.Arc,
|
|
1383
1389
|
Chain.Aurora,
|
|
1384
1390
|
Chain.Avalanche,
|
|
1385
1391
|
Chain.Base,
|
package/dist/chunk-gwx23jdp.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{c as C}from"./chunk-3yr76n9s.js";import{d as D}from"./chunk-n05bv2n5.js";import{base64 as m}from"@scure/base";import{HDKey as b}from"@scure/bip32";import{derivationPathToString as P,getWalletFormatFor as x,SwapKitError as X}from"@swapkit/helpers";function g(G){switch(G){case"bech32":return"wpkh(@0/**)";case"p2sh":return"sh(wpkh(@0/**))";case"legacy":return"pkh(@0/**)";default:return"wpkh(@0/**)"}}function u(G){return typeof G==="string"?G:P(G)}function k(G){return G.replace(/^m\//,"").replace(/^\/+/,"")}function l(G){return G.replace(/^m\//,"").split("/").filter(Boolean).map((Q)=>{let R=Q.endsWith("'"),V=Number.parseInt(R?Q.slice(0,-1):Q,10);return R?(V|2147483648)>>>0:V})}function s(G,Q){let R=G.getInput(Q);return Boolean(R.bip32Derivation?.length)}var F=({chain:G})=>{return(Q,R)=>{let V,z;async function _(){if(!V){let q=R??await C(),{AppClient:J}=await import("ledger-bitcoin");V=new J(q)}return V}async function S(){if(!z)z=await(await _()).getMasterFingerprint();return z}let $=k(Q?u(Q):"84'/0'/0'/0/0"),W=$.split("/").filter(Boolean),H=W.slice(0,3).join("/"),w=W.slice(3),E=Number(w[0]??0),K=Number(w[1]??0),L=x(`m/${$}`),T=g(L),j,N;async function O(){let q=await _(),J=await S();if(!j)j=await q.getExtendedPubkey(`m/${H}`);let{DefaultWalletPolicy:M}=await import("ledger-bitcoin"),U=new M(T,`[${J}/${H}]${j}`);return{app:q,fpr:J,policy:U,xpub:j}}async function I(){if(!N){let{xpub:q}=await O(),M=b.fromExtendedKey(q).derive(`m/${E}/${K}`);if(!M.publicKey)throw new X("wallet_ledger_get_address_error",{message:`Cannot derive leaf pubkey for ${G}`});N=M.publicKey}return N}return{connect:async()=>{await _()},getAddress:async()=>{let{app:q,policy:J}=await O(),M=await q.getWalletAddress(J,null,E,K,!1);if(!M)throw new X("wallet_ledger_get_address_error",{message:`Cannot get ${G} address from ledger derivation path: ${$}`});return M},getExtendedPublicKey:async(q=`m/${H}`)=>{return(await _()).getExtendedPubkey(`m/${k(q)}`)},signTransaction:async(q)=>{let{app:J,policy:M,fpr:U}=await O(),v=Number.parseInt(U,16)>>>0,A=l($),B=Array.from({length:q.inputsLength},(Y,Z)=>Z).filter((Y)=>!s(q,Y));if(B.length>0){let Y=await I();for(let Z of B)q.updateInput(Z,{bip32Derivation:[[Y,{fingerprint:v,path:A}]]})}let f=m.encode(q.toPSBT(0)),y=await J.signPsbt(f,M,null);for(let[Y,Z]of y)q.updateInput(Y,{partialSig:[[new Uint8Array(Z.pubkey),new Uint8Array(Z.signature)]]});return q}}}},n=F({chain:"bitcoin"}),p=F({chain:"litecoin"});export{p as LitecoinPsbtLedger,n as BitcoinPsbtLedger};
|
|
2
|
-
|
|
3
|
-
//# debugId=ACED2AE00D3D0A0F64756E2164756E21
|
|
4
|
-
//# sourceMappingURL=chunk-gwx23jdp.js.map
|
package/dist/chunk-qs60k0yv.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import{d as Q}from"./chunk-n05bv2n5.js";import{ChainToChainId as b,derivationPathToString as $,SwapKitError as B,WalletOption as K}from"@swapkit/helpers";async function G({chain:_,derivationPath:f,provider:C}){let{AbstractSigner:H}=await import("ethers");class A extends H{address;chain;derivationPath;provider;constructor({chain:j,derivationPath:q,provider:J}){super(J);this.address="",this.chain=j,this.derivationPath=q,this.provider=J}getAddress=async()=>{if(!this.address){let q=await(await import("@trezor/connect-web")).default.ethereumGetAddress({path:$(this.derivationPath),showOnTrezor:!0});if(!q.success)throw new B({errorKey:"wallet_trezor_failed_to_get_address",info:{...q,chain:this.chain,derivationPath:this.derivationPath}});this.address=q.payload.address}return this.address};signMessage=async(j)=>{let J=await(await import("@trezor/connect-web")).default.ethereumSignMessage({message:j,path:$(this.derivationPath)});if(!J.success)throw new B({errorKey:"wallet_trezor_failed_to_sign_transaction",info:{...J,chain:this.chain,derivationPath:this.derivationPath,message:j}});return J.payload.signature};signTypedData=async(j,q,J,N)=>{let O=(await import("@trezor/connect-web")).default,{buildEIP712DomainType:V}=await import("@swapkit/toolboxes/evm"),{TypedDataEncoder:X}=await import("ethers"),{EIP712Domain:Y,...R}=q,W=N??X.from(R).primaryType,M=V(j),D={domain:j,message:J,primaryType:W,types:{EIP712Domain:M,...R}},U=await O.ethereumSignTypedData({data:D,metamask_v4_compat:!0,path:$(this.derivationPath)});if(!U.success)throw new B({errorKey:"wallet_trezor_failed_to_sign_transaction",info:{chain:this.chain,error:U.payload.error}});return U.payload.signature.startsWith("0x")?U.payload.signature:`0x${U.payload.signature}`};signTransaction=async({to:j,gasLimit:q,value:J,data:N,nonce:O,maxFeePerGas:V,maxPriorityFeePerGas:X,gasPrice:Y})=>{if(!j)throw new B({errorKey:"wallet_missing_params",info:{to:j}});if(!q)throw new B({errorKey:"wallet_missing_params",info:{gasLimit:q}});let R=V&&X;if(R&&!V)throw new B({errorKey:"wallet_missing_params",info:{maxFeePerGas:V}});if(R&&!X)throw new B({errorKey:"wallet_missing_params",info:{maxPriorityFeePerGas:X}});if(!(R||Y))throw new B({errorKey:"wallet_missing_params",info:{gasPrice:Y}});let W=(await import("@trezor/connect-web")).default,{toHexString:M}=await import("@swapkit/toolboxes/evm"),D=R?{maxFeePerGas:M(BigInt(V?.toString()||0)),maxPriorityFeePerGas:M(BigInt(X?.toString()||0))}:Y&&{gasPrice:M(BigInt(Y?.toString()||0))}||{gasPrice:"0x0"},U=M(BigInt(O||await this.provider.getTransactionCount(await this.getAddress(),"pending"))),I={chainId:Number.parseInt(b[this.chain],10),data:N?.toString()||"0x",gasLimit:M(BigInt(q?.toString()||0)),nonce:U,to:j.toString(),value:M(BigInt(J?.toString()||0)),...D},{success:L,payload:Z}=await W.ethereumSignTransaction({path:$(this.derivationPath),transaction:I});if(!L)throw new B({errorKey:"wallet_trezor_failed_to_sign_transaction",info:{...Z,chain:this.chain,derivationPath:this.derivationPath}});let k=Z.serializedTx?Z.serializedTx.startsWith("0x")?Z.serializedTx:`0x${Z.serializedTx}`:void 0;if(!k)throw new B({errorKey:"wallet_trezor_failed_to_sign_transaction",info:{chain:this.chain,derivationPath:this.derivationPath}});return k};connect=(j)=>{if(!j)throw new B({errorKey:"wallet_provider_not_found",info:{chain:this.chain,derivationPath:this.derivationPath,wallet:K.TREZOR}});return new A({chain:this.chain,derivationPath:this.derivationPath,provider:j})}}return new A({chain:_,derivationPath:f,provider:C})}export{G as getEVMSigner};
|
|
2
|
-
|
|
3
|
-
//# debugId=654BE0775B0291CD64756E2164756E21
|
|
4
|
-
//# sourceMappingURL=chunk-qs60k0yv.js.map
|