@swapkit/wallet-hardware 6.0.0 → 6.0.1
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/src/trezor/index.ts
CHANGED
|
@@ -199,11 +199,55 @@ function tryNormalizeTrezorExtendedPublicKey(xpub: string | undefined, chain: UT
|
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
function decodeOpReturnData(script: Uint8Array)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
202
|
+
async function decodeOpReturnData(script: Uint8Array) {
|
|
203
|
+
const { Script } = await import("@swapkit/utxo-signer");
|
|
204
|
+
|
|
205
|
+
try {
|
|
206
|
+
const [opcode, data] = Script.decode(script);
|
|
207
|
+
const bytes = data === 0 ? new Uint8Array() : data;
|
|
208
|
+
if (opcode !== "RETURN" || !(bytes instanceof Uint8Array)) return null;
|
|
209
|
+
|
|
210
|
+
// Trezor rebuilds the script from the data, so only accept scripts it reproduces byte for byte
|
|
211
|
+
return hex.encode(Script.encode(["RETURN", bytes])) === hex.encode(script) ? hex.encode(bytes) : null;
|
|
212
|
+
} catch {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
async function toTrezorOpReturnOutput(script: Uint8Array, amount: bigint | undefined, chain: Chain) {
|
|
218
|
+
if (amount !== 0n) {
|
|
219
|
+
throw new SwapKitError({
|
|
220
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
221
|
+
info: { chain, error: "OP_RETURN output carrying value cannot be signed" },
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const opReturnData = await decodeOpReturnData(script);
|
|
226
|
+
|
|
227
|
+
if (opReturnData === null) {
|
|
228
|
+
throw new SwapKitError({
|
|
229
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
230
|
+
info: { chain, error: "Malformed OP_RETURN output cannot be signed" },
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return { amount: "0", op_return_data: opReturnData, script_type: "PAYTOOPRETURN" as const };
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
async function assertTransactionCarriesMemo(tx: Transaction, memo: string, chain: Chain) {
|
|
238
|
+
if (!memo) return;
|
|
239
|
+
|
|
240
|
+
const expected = hex.encode(new TextEncoder().encode(memo));
|
|
241
|
+
|
|
242
|
+
for (let i = 0; i < tx.outputsLength; i++) {
|
|
243
|
+
const script = tx.getOutput(i).script;
|
|
244
|
+
if (script?.[0] === 0x6a && (await decodeOpReturnData(script)) === expected) return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
throw new SwapKitError({
|
|
248
|
+
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
249
|
+
info: { chain, error: "Transaction does not carry the provided memo" },
|
|
250
|
+
});
|
|
207
251
|
}
|
|
208
252
|
|
|
209
253
|
function getScriptType(chain: Chain, derivationPath: DerivationPathArray) {
|
|
@@ -327,16 +371,9 @@ async function buildPCZTOutputsForTrezor(pczt: PCZT, address_n: number[], myAddr
|
|
|
327
371
|
const output = pczt.getOutput(i);
|
|
328
372
|
const script = output.scriptPubkey;
|
|
329
373
|
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
outputs.push({ amount: "0", op_return_data: opReturnData, script_type: "PAYTOOPRETURN" as const });
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
throw new SwapKitError({
|
|
337
|
-
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
338
|
-
info: { chain, error: "Malformed OP_RETURN output cannot be signed" },
|
|
339
|
-
});
|
|
374
|
+
if (script?.[0] === 0x6a) {
|
|
375
|
+
outputs.push(await toTrezorOpReturnOutput(script, output.value, chain));
|
|
376
|
+
continue;
|
|
340
377
|
}
|
|
341
378
|
|
|
342
379
|
const outputAddress = await decodeOutputAddress(script);
|
|
@@ -411,7 +448,7 @@ function buildZcashTxInputsForTrezor(
|
|
|
411
448
|
return inputs;
|
|
412
449
|
}
|
|
413
450
|
|
|
414
|
-
function buildZcashTxOutputsForTrezor({
|
|
451
|
+
async function buildZcashTxOutputsForTrezor({
|
|
415
452
|
addressN,
|
|
416
453
|
chain,
|
|
417
454
|
myAddress,
|
|
@@ -430,12 +467,8 @@ function buildZcashTxOutputsForTrezor({
|
|
|
430
467
|
const outputAddress = tx.getOutputAddress(i, network);
|
|
431
468
|
const script = output.script;
|
|
432
469
|
|
|
433
|
-
if (
|
|
434
|
-
|
|
435
|
-
if (opReturnData) {
|
|
436
|
-
outputs.push({ amount: "0", op_return_data: opReturnData, script_type: "PAYTOOPRETURN" as const });
|
|
437
|
-
continue;
|
|
438
|
-
}
|
|
470
|
+
if (script?.[0] === 0x6a) {
|
|
471
|
+
outputs.push(await toTrezorOpReturnOutput(script, output.amount, chain));
|
|
439
472
|
continue;
|
|
440
473
|
}
|
|
441
474
|
|
|
@@ -453,12 +486,11 @@ function buildZcashTxOutputsForTrezor({
|
|
|
453
486
|
return outputs;
|
|
454
487
|
}
|
|
455
488
|
|
|
456
|
-
function buildUtxoOutputsForTrezor(
|
|
489
|
+
async function buildUtxoOutputsForTrezor(
|
|
457
490
|
tx: Transaction,
|
|
458
491
|
network: BTCNetwork,
|
|
459
492
|
address_n: number[],
|
|
460
493
|
myAddress: string,
|
|
461
|
-
memo: string,
|
|
462
494
|
chain: Chain,
|
|
463
495
|
scriptType: { input: string; output: string },
|
|
464
496
|
toCashAddress: (addr: string) => string,
|
|
@@ -469,17 +501,12 @@ function buildUtxoOutputsForTrezor(
|
|
|
469
501
|
const output = tx.getOutput(i);
|
|
470
502
|
const outputAddress = tx.getOutputAddress(i, network);
|
|
471
503
|
|
|
472
|
-
if (
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
amount: "0",
|
|
477
|
-
op_return_data: opReturnData ?? Buffer.from(memo).toString("hex"),
|
|
478
|
-
script_type: "PAYTOOPRETURN",
|
|
479
|
-
});
|
|
480
|
-
continue;
|
|
481
|
-
}
|
|
504
|
+
if (output.script?.[0] === 0x6a) {
|
|
505
|
+
outputs.push(await toTrezorOpReturnOutput(output.script, output.amount, chain));
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
482
508
|
|
|
509
|
+
if (!outputAddress) {
|
|
483
510
|
throw new SwapKitError({
|
|
484
511
|
errorKey: "wallet_trezor_failed_to_sign_transaction",
|
|
485
512
|
info: { chain, error: "Unable to decode output address from scriptPubkey" },
|
|
@@ -637,7 +664,7 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
637
664
|
const address_n = hardenDerivationPath(derivationPath);
|
|
638
665
|
|
|
639
666
|
const inputs = buildZcashTxInputsForTrezor(tx, [], address_n, hexEncode);
|
|
640
|
-
const outputs = buildZcashTxOutputsForTrezor({
|
|
667
|
+
const outputs = await buildZcashTxOutputsForTrezor({
|
|
641
668
|
addressN: address_n,
|
|
642
669
|
chain,
|
|
643
670
|
myAddress: address,
|
|
@@ -779,16 +806,17 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
779
806
|
const baseToolbox = getUtxoToolbox(chain, toolboxParams);
|
|
780
807
|
|
|
781
808
|
const signTransaction = async (tx: Transaction, inputs: UTXOType[], memo = "") => {
|
|
809
|
+
await assertTransactionCarriesMemo(tx, memo, chain);
|
|
810
|
+
|
|
782
811
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
783
812
|
const address_n = hardenDerivationPath(derivationPath);
|
|
784
813
|
const network = getNetworkForChain(chain as UTXOChain);
|
|
785
814
|
|
|
786
|
-
const outputs = buildUtxoOutputsForTrezor(
|
|
815
|
+
const outputs = await buildUtxoOutputsForTrezor(
|
|
787
816
|
tx,
|
|
788
817
|
network,
|
|
789
818
|
address_n,
|
|
790
819
|
address,
|
|
791
|
-
memo,
|
|
792
820
|
chain,
|
|
793
821
|
resolvedScriptType,
|
|
794
822
|
toCashAddress,
|
|
@@ -902,12 +930,11 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
902
930
|
});
|
|
903
931
|
}
|
|
904
932
|
|
|
905
|
-
const outputs = buildUtxoOutputsForTrezor(
|
|
933
|
+
const outputs = await buildUtxoOutputsForTrezor(
|
|
906
934
|
tx,
|
|
907
935
|
network,
|
|
908
936
|
address_n,
|
|
909
937
|
address,
|
|
910
|
-
"",
|
|
911
938
|
chain,
|
|
912
939
|
resolvedScriptType,
|
|
913
940
|
toCashAddress,
|
|
@@ -977,12 +1004,11 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
977
1004
|
});
|
|
978
1005
|
}
|
|
979
1006
|
|
|
980
|
-
const outputs = buildUtxoOutputsForTrezor(
|
|
1007
|
+
const outputs = await buildUtxoOutputsForTrezor(
|
|
981
1008
|
tx,
|
|
982
1009
|
network,
|
|
983
1010
|
address_n,
|
|
984
1011
|
address,
|
|
985
|
-
"",
|
|
986
1012
|
chain,
|
|
987
1013
|
resolvedScriptType,
|
|
988
1014
|
toCashAddress,
|
|
@@ -1020,16 +1046,17 @@ async function getTrezorWallet<T extends Chain>({
|
|
|
1020
1046
|
}>,
|
|
1021
1047
|
memo = "",
|
|
1022
1048
|
) => {
|
|
1049
|
+
await assertTransactionCarriesMemo(tx, memo, chain);
|
|
1050
|
+
|
|
1023
1051
|
const TrezorConnect = (await import("@trezor/connect-web")).default;
|
|
1024
1052
|
const network = getNetworkForChain(chain as UTXOChain);
|
|
1025
1053
|
const baseAddressN = hardenDerivationPath(derivationPath.slice(0, 3) as unknown as DerivationPathArray);
|
|
1026
1054
|
|
|
1027
|
-
const outputs = buildUtxoOutputsForTrezor(
|
|
1055
|
+
const outputs = await buildUtxoOutputsForTrezor(
|
|
1028
1056
|
tx,
|
|
1029
1057
|
network,
|
|
1030
1058
|
baseAddressN,
|
|
1031
1059
|
address,
|
|
1032
|
-
memo,
|
|
1033
1060
|
chain,
|
|
1034
1061
|
resolvedScriptType,
|
|
1035
1062
|
toCashAddress,
|