@ledgerhq/coin-bitcoin 0.29.0-nightly.20260116024452 → 0.29.0-nightly.20260116124336

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +12 -10
  2. package/lib/bridge/js.d.ts +1 -1
  3. package/lib/bridge/js.d.ts.map +1 -1
  4. package/lib/bridge/js.js +2 -3
  5. package/lib/bridge/js.js.map +1 -1
  6. package/lib/buildOptimisticOperation.d.ts +13 -0
  7. package/lib/buildOptimisticOperation.d.ts.map +1 -0
  8. package/lib/buildOptimisticOperation.js +20 -0
  9. package/lib/buildOptimisticOperation.js.map +1 -0
  10. package/lib/observable.d.ts +4 -0
  11. package/lib/observable.d.ts.map +1 -0
  12. package/lib/observable.js +9 -0
  13. package/lib/observable.js.map +1 -0
  14. package/lib/psbtFees.d.ts +9 -0
  15. package/lib/psbtFees.d.ts.map +1 -0
  16. package/lib/psbtFees.js +73 -0
  17. package/lib/psbtFees.js.map +1 -0
  18. package/lib/signOperation.d.ts.map +1 -1
  19. package/lib/signOperation.js +94 -99
  20. package/lib/signOperation.js.map +1 -1
  21. package/lib/signRawOperation.d.ts +6 -0
  22. package/lib/signRawOperation.d.ts.map +1 -0
  23. package/lib/signRawOperation.js +70 -0
  24. package/lib/signRawOperation.js.map +1 -0
  25. package/lib/signer.d.ts +15 -0
  26. package/lib/signer.d.ts.map +1 -1
  27. package/lib/types.d.ts +2 -0
  28. package/lib/types.d.ts.map +1 -1
  29. package/lib-es/bridge/js.d.ts +1 -1
  30. package/lib-es/bridge/js.d.ts.map +1 -1
  31. package/lib-es/bridge/js.js +2 -3
  32. package/lib-es/bridge/js.js.map +1 -1
  33. package/lib-es/buildOptimisticOperation.d.ts +13 -0
  34. package/lib-es/buildOptimisticOperation.d.ts.map +1 -0
  35. package/lib-es/buildOptimisticOperation.js +16 -0
  36. package/lib-es/buildOptimisticOperation.js.map +1 -0
  37. package/lib-es/observable.d.ts +4 -0
  38. package/lib-es/observable.d.ts.map +1 -0
  39. package/lib-es/observable.js +5 -0
  40. package/lib-es/observable.js.map +1 -0
  41. package/lib-es/psbtFees.d.ts +9 -0
  42. package/lib-es/psbtFees.d.ts.map +1 -0
  43. package/lib-es/psbtFees.js +69 -0
  44. package/lib-es/psbtFees.js.map +1 -0
  45. package/lib-es/signOperation.d.ts.map +1 -1
  46. package/lib-es/signOperation.js +94 -99
  47. package/lib-es/signOperation.js.map +1 -1
  48. package/lib-es/signRawOperation.d.ts +6 -0
  49. package/lib-es/signRawOperation.d.ts.map +1 -0
  50. package/lib-es/signRawOperation.js +66 -0
  51. package/lib-es/signRawOperation.js.map +1 -0
  52. package/lib-es/signer.d.ts +15 -0
  53. package/lib-es/signer.d.ts.map +1 -1
  54. package/lib-es/types.d.ts +2 -0
  55. package/lib-es/types.d.ts.map +1 -1
  56. package/package.json +13 -12
  57. package/src/__tests__/fixtures/common.fixtures.ts +6 -0
  58. package/src/__tests__/unit/psbtFees.fromFixture.unit.test.ts +31 -0
  59. package/src/__tests__/unit/signOperation.test.ts +226 -0
  60. package/src/__tests__/unit/signRawOperation.test.ts +188 -0
  61. package/src/bridge/js.test.ts +30 -0
  62. package/src/bridge/js.ts +2 -3
  63. package/src/buildOptimisticOperation.ts +34 -0
  64. package/src/hw-signMessage.test.ts +1 -0
  65. package/src/observable.ts +12 -0
  66. package/src/observable.unit.test.ts +27 -0
  67. package/src/psbtFees.ts +77 -0
  68. package/src/signOperation.ts +140 -126
  69. package/src/signRawOperation.ts +104 -0
  70. package/src/signer.ts +13 -0
  71. package/src/types.ts +2 -0
  72. package/src/wallet-btc/__tests__/fixtures/common.fixtures.ts +64 -1
  73. package/src/wallet-btc/__tests__/wallet.integration.test.ts +1 -1
  74. package/src/wallet-btc/__tests__/xpub.txs.dogecoin.integration.test.ts +1 -1
  75. package/src/wallet-btc/__tests__/xpub.txs.zcash.integration.test.ts +1 -1
  76. package/tsconfig.json +3 -12
  77. package/lib/mockBtcSigner.d.ts +0 -20
  78. package/lib/mockBtcSigner.d.ts.map +0 -1
  79. package/lib/mockBtcSigner.js +0 -50
  80. package/lib/mockBtcSigner.js.map +0 -1
  81. package/lib-es/mockBtcSigner.d.ts +0 -20
  82. package/lib-es/mockBtcSigner.d.ts.map +0 -1
  83. package/lib-es/mockBtcSigner.js +0 -45
  84. package/lib-es/mockBtcSigner.js.map +0 -1
  85. package/src/mockBtcSigner.ts +0 -65
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,OAAO,IAAI,aAAa,EAAE,iBAAiB,IAAI,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpG,OAAO,EACL,OAAO,EACP,UAAU,EACV,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,0BAA0B,EAC1B,SAAS,EACV,MAAM,sBAAsB,CAAC;AAE9B,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,KAAK,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC,cAAc,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,mBAAmB,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,GAAG,IAAI,GAAG,SAAS;IACzB,MAAM,GAAG,IAAI,GAAG,SAAS;IACzB,MAAM,GAAG,IAAI,GAAG,SAAS;IACzB,MAAM;CACP,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACvC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,GAAG,EAAE,OAAO,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM;IACN,MAAM;IACN,MAAM,GAAG,IAAI,GAAG,SAAS;IACzB,MAAM,GAAG,IAAI,GAAG,SAAS;IACzB,MAAM;IACN,MAAM;IACN,MAAM;CACP,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,aAAa,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;CAC3C,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC9C,CAAC;AAEF,eAAO,MAAM,4BAA4B;;CAExC,CAAC;AAEF,eAAO,MAAM,oBAAoB;;;EAG/B,CAAC;AAEH,eAAO,MAAM,sBAAsB;;;;;;EAMjC,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG;IAEzC,UAAU,EAAE,MAAM,CAAC;IAEnB,YAAY,EAAE,MAAM,CAAC;IAErB,WAAW,EAAE,MAAM,CAAC;IAEpB,WAAW,EAAE,MAAM,CAAC;IAEpB,SAAS,EAAE,MAAM,CAAC;IAElB,UAAU,EAAE,SAAS,CAAC;IAEtB,aAAa,EAAE,MAAM,CAAC;IAEtB,0BAA0B,EAAE,OAAO,CAAC;IAEpC,cAAc,EAAE,SAAS,CAAC;IAE1B,OAAO,EAAE,MAAM,CAAC;IAEhB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,OAAO,GAAG;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,SAAS,CAAC;CACvB,CAAC;AACF,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,iBAAiB,EAAE,SAAS,CAAC;CAC9B,CAAC;AACF,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AACF,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,UAAU,EAAE,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;CAC3B,CAAC;AACF,MAAM,MAAM,WAAW,GAAG;IACxB,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;CACpB,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,EAAE,SAAS,CAAC;IAClB,QAAQ,EAAE,WAAW,CAAC;CACvB,CAAC;AACF,eAAO,MAAM,sBAAsB;;;;CAIlC,CAAC;AACF,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAC;AAEvE,MAAM,MAAM,YAAY,GAAG;IACzB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,YAAY,EAAE,KAAK,CAAC;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACJ,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG,iBAAiB,GAAG;IAC5C,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,SAAS,GAAG,IAAI,GAAG,SAAS,CAAC;IACzC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAAC;IAC5C,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,oBAAoB,GAAG;IAClD,MAAM,EAAE,SAAS,CAAC;IAClB,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,OAAO,CAAC;IACb,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IACtC,WAAW,EAAE,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG,uBAAuB,GAAG;IACxD,QAAQ,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACrC,SAAS,EAAE,aAAa,EAAE,GAAG,SAAS,CAAC;IACvC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG;IAC9D,QAAQ,EAAE,eAAe,EAAE,GAAG,SAAS,CAAC;IACxC,SAAS,EAAE,gBAAgB,EAAE,GAAG,SAAS,CAAC;IAC1C,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG;IAAE,gBAAgB,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE9E,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG;IAC3C,gBAAgB,EAAE,mBAAmB,CAAC;CACvC,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AACF,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,iBAAiB,CAAC,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ledgerhq/coin-bitcoin",
3
- "version": "0.29.0-nightly.20260116024452",
3
+ "version": "0.29.0-nightly.20260116124336",
4
4
  "description": "Ledger Bitcoin Coin integration",
5
5
  "keywords": [
6
6
  "Ledger",
@@ -61,15 +61,16 @@
61
61
  "@noble/curves": "^1.9.7",
62
62
  "utility-types": "^3.10.0",
63
63
  "varuint-bitcoin": "1.1.2",
64
- "@ledgerhq/coin-framework": "^6.13.0-nightly.20260116024452",
65
- "@ledgerhq/cryptoassets": "^13.37.0-nightly.20260116024452",
66
- "@ledgerhq/devices": "8.10.0-nightly.20260116024452",
67
- "@ledgerhq/errors": "^6.29.0-nightly.20260116024452",
68
- "@ledgerhq/live-env": "^2.25.0-nightly.20260116024452",
69
- "@ledgerhq/live-network": "^2.2.0-nightly.20260116024452",
70
- "@ledgerhq/logs": "^6.14.0-nightly.20260116024452",
71
- "@ledgerhq/types-cryptoassets": "^7.32.0-nightly.20260116024452",
72
- "@ledgerhq/types-live": "^6.93.0-nightly.20260116024452"
64
+ "@ledgerhq/coin-framework": "^6.13.0-nightly.20260116124336",
65
+ "@ledgerhq/cryptoassets": "^13.37.0-nightly.20260116124336",
66
+ "@ledgerhq/devices": "8.10.0-nightly.20260116124336",
67
+ "@ledgerhq/errors": "^6.29.0-nightly.20260116124336",
68
+ "@ledgerhq/psbtv2": "^0.1.0",
69
+ "@ledgerhq/live-env": "^2.25.0-nightly.20260116124336",
70
+ "@ledgerhq/live-network": "^2.2.0-nightly.20260116124336",
71
+ "@ledgerhq/logs": "^6.14.0-nightly.20260116124336",
72
+ "@ledgerhq/types-cryptoassets": "^7.32.0-nightly.20260116124336",
73
+ "@ledgerhq/types-live": "^6.93.0-nightly.20260116124336"
73
74
  },
74
75
  "devDependencies": {
75
76
  "@types/bchaddrjs": "^0.4.3",
@@ -92,12 +93,13 @@
92
93
  "object-hash": "^2.2.0",
93
94
  "@swc/jest": "0.2.39",
94
95
  "@swc/core": "1.15.8",
95
- "@ledgerhq/disable-network-setup": "^0.2.0-nightly.20260116024452"
96
+ "@ledgerhq/disable-network-setup": "^0.2.0-nightly.20260116124336"
96
97
  },
97
98
  "scripts": {
98
99
  "clean": "rimraf lib lib-es",
99
100
  "build": "tsc && tsc -m esnext --moduleResolution bundler --outDir lib-es",
100
101
  "coverage": "jest --coverage",
102
+ "test-integ": "jest --config=jest.integ.config.js",
101
103
  "prewatch": "pnpm build",
102
104
  "watch": "tsc --watch",
103
105
  "watch:es": "tsc --watch -m esnext --moduleResolution bundler --outDir lib-es",
@@ -106,7 +108,6 @@
106
108
  "lint:fix": "pnpm lint --fix",
107
109
  "test": "jest",
108
110
  "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand",
109
- "test-integ": "jest --config=jest.integ.config.js",
110
111
  "typecheck": "tsc --noEmit",
111
112
  "unimported": "unimported"
112
113
  }
@@ -127,6 +127,9 @@ export const mockSigner: BitcoinSigner = {
127
127
  }),
128
128
  createPaymentTransaction: (_arg: CreateTransaction): Promise<string> =>
129
129
  Promise.resolve("createPaymentTransactionReturn"),
130
+ signPsbtBuffer(_psbtBuffer: Buffer): Promise<{ psbt: Buffer; tx: string }> {
131
+ return Promise.resolve({ psbt: Buffer.from(""), tx: "" });
132
+ },
130
133
  };
131
134
 
132
135
  export const mockSignerContext = <T>(
@@ -172,4 +175,7 @@ export const mockSignerContext = <T>(
172
175
  ],
173
176
  }),
174
177
  createPaymentTransaction: (_arg: CreateTransaction): Promise<string> => Promise.resolve(""),
178
+ signPsbtBuffer(_psbtBuffer: Buffer): Promise<{ psbt: Buffer; tx: string }> {
179
+ return Promise.resolve({ psbt: Buffer.from(""), tx: "" });
180
+ },
175
181
  });
@@ -0,0 +1,31 @@
1
+ import { feeFromPsbt } from "../../psbtFees";
2
+ import { parsePsbt } from "@ledgerhq/psbtv2";
3
+
4
+ /*
5
+ * NOTE: in all psbts below, the fee is 5000 since:
6
+ * The input has a WITNESS_UTXO amount: first 8 bytes of data = 20 4e 00 00 00 00 00 00 (little-endian) → 0x0000000000004e20 = 20,000 sats.
7
+ * The output AMOUNT is 98 3a 00 00 00 00 00 00 (little-endian) → 0x0000000000003a98 = 15,000 sats.
8
+ * Fee = Σinputs − Σoutputs = 20,000 − 15,000 = 5,000 sats.
9
+ * all the psbts where generated from https://learnmeabitcoin.com/technical/transaction/psbt/
10
+ *
11
+ */
12
+
13
+ describe("feeFromPsbt (PSBT v2 via PsbtV2)", () => {
14
+ it("parses the v2 PSBT (signer stage) and returns the correct fee", () => {
15
+ // signer stage, decode it https://learnmeabitcoin.com/technical/transaction/psbt/
16
+ const psbtB64 =
17
+ "cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAQYBAAH7BAIAAAAAAQEfIE4AAAAAAAAWABRtTfPDGS0+/pTZAN6itD4d+v/DdyICAoHczplgGVV4+rXYBtC/VsKfZU8OhrrUST2++hq4Lzy9SDBFAiEAisjYLjV0afIPV8fNtfKDEep5qWE+Q4ykeLRVQFMVhJsCIE9Q+4CcW6Cwmnuox4kYpUocoFIWp8pa2OGcuf801ecvAQEOIBpm0EPKluAy05yTYGzOS3gm/qhPQLDCSWqQpVE2pyVMAQ8EAQAAAAABAwiYOgAAAAAAAAEEFgAUgOCAoBDcwBoMygQ0Q5VYjll5FTgA";
18
+
19
+ const fee = feeFromPsbt(parsePsbt(psbtB64));
20
+ expect(fee!.toNumber()).toBe(5000);
21
+ });
22
+
23
+ it("parses the v2 PSBT (input finalizer stage) and returns the correct fee", () => {
24
+ // input finalizer stage, decode it https://learnmeabitcoin.com/technical/transaction/psbt/
25
+ const psbtB64 =
26
+ "cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAQYBAAH7BAIAAAAAAQEfIE4AAAAAAAAWABRtTfPDGS0+/pTZAN6itD4d+v/DdwEIbAJIMEUCIQCKyNguNXRp8g9Xx8218oMR6nmpYT5DjKR4tFVAUxWEmwIgT1D7gJxboLCae6jHiRilShygUhanylrY4Zy5/zTV5y8BIQKB3M6ZYBlVePq12AbQv1bCn2VPDoa61Ek9vvoauC88vQEOIBpm0EPKluAy05yTYGzOS3gm/qhPQLDCSWqQpVE2pyVMAQ8EAQAAAAABAwiYOgAAAAAAAAEEFgAUgOCAoBDcwBoMygQ0Q5VYjll5FTgA";
27
+
28
+ const fee = feeFromPsbt(parsePsbt(psbtB64));
29
+ expect(fee!.toNumber()).toBe(5000);
30
+ });
31
+ });
@@ -0,0 +1,226 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { firstValueFrom, toArray } from "rxjs";
3
+ import buildSignOperation from "../../signOperation";
4
+ import type { Account, Operation } from "@ledgerhq/types-live";
5
+ import { findCryptoCurrencyById } from "@ledgerhq/cryptoassets";
6
+ import type { Transaction } from "../../types";
7
+
8
+ // ---- Mocks ---------------------------------------------------------------
9
+
10
+ jest.mock("../../cache", () => ({
11
+ calculateFees: jest.fn().mockResolvedValue({
12
+ fees: new BigNumber(1000), // 1000 sats
13
+ txInputs: [
14
+ { address: "bc1qsender1..." },
15
+ { address: "bc1qsender2..." },
16
+ { address: "bc1qsender1..." }, // duplicate to test Set behavior
17
+ ],
18
+ txOutputs: [
19
+ { address: "bc1qrecipient...", isChange: false, value: new BigNumber(5000) },
20
+ { address: "bc1qchange...", isChange: true, value: new BigNumber(15000) },
21
+ { address: null, isChange: false, value: new BigNumber(0) },
22
+ ],
23
+ }),
24
+ }));
25
+
26
+ jest.mock("../../buildTransaction", () => ({
27
+ buildTransaction: jest.fn().mockResolvedValue({
28
+ // shape not relevant for test, passed through to wallet.signAccountTx
29
+ }),
30
+ }));
31
+
32
+ jest.mock("../../networks", () => ({
33
+ getNetworkParameters: jest.fn().mockReturnValue({ sigHash: 1 }),
34
+ }));
35
+
36
+ // Wallet mock to capture parameters and simulate device callbacks
37
+ jest.mock("../../wallet-btc", () => ({
38
+ __esModule: true,
39
+ default: {
40
+ // will be inspected and controlled via jest.requireMock in tests
41
+ signAccountTx: jest.fn(),
42
+ },
43
+ getWalletAccount: jest.fn().mockReturnValue({
44
+ params: { path: "m/84'/0'/0'", index: 0 },
45
+ xpub: {},
46
+ }),
47
+ }));
48
+
49
+ // Keep derivation helpers deterministic
50
+ jest.mock("@ledgerhq/coin-framework/derivation", () => {
51
+ const actual = jest.requireActual("@ledgerhq/coin-framework/derivation");
52
+ return {
53
+ ...actual,
54
+ isSegwitDerivationMode: () => true,
55
+ };
56
+ });
57
+
58
+ // ---- Helpers -------------------------------------------------------------
59
+
60
+ const makeAccount = (over: Partial<Account> = {}): Account => ({
61
+ id: "js:2:bitcoin:dummy",
62
+ type: "Account",
63
+ used: true,
64
+ operationsCount: 0,
65
+ balanceHistoryCache: {
66
+ HOUR: {
67
+ latestDate: null,
68
+ balances: [],
69
+ },
70
+ DAY: {
71
+ latestDate: null,
72
+ balances: [],
73
+ },
74
+ WEEK: {
75
+ latestDate: null,
76
+ balances: [],
77
+ },
78
+ },
79
+ swapHistory: [],
80
+ freshAddress: "bc1q...",
81
+ freshAddressPath: "m/84'/0'/0'/0/0",
82
+ currency: findCryptoCurrencyById("bitcoin")!,
83
+ derivationMode: "native_segwit",
84
+ seedIdentifier: "seed",
85
+ xpub: "xpub...",
86
+ index: 0,
87
+ balance: new BigNumber(0),
88
+ spendableBalance: new BigNumber(0),
89
+ blockHeight: 0,
90
+ operations: [],
91
+ pendingOperations: [],
92
+ lastSyncDate: new Date(0),
93
+ creationDate: new Date(0),
94
+ ...over,
95
+ });
96
+
97
+ import type { BitcoinSigner, SignerContext } from "../../signer";
98
+
99
+ type WalletBtcMock = {
100
+ default: {
101
+ // narrow to the shape we exercise in these tests
102
+ signAccountTx: jest.Mock<
103
+ Promise<string>,
104
+ [
105
+ {
106
+ onDeviceSignatureRequested?: () => void;
107
+ onDeviceSignatureGranted?: () => void;
108
+ onDeviceStreaming?: (arg: { progress: number; total: number; index: number }) => void;
109
+ },
110
+ ]
111
+ >;
112
+ };
113
+ getWalletAccount: jest.Mock;
114
+ };
115
+
116
+ const walletBtcMock: WalletBtcMock = jest.requireMock("../../wallet-btc");
117
+
118
+ const signAccountTx = walletBtcMock.default.signAccountTx;
119
+ const getWalletAccount = walletBtcMock.getWalletAccount;
120
+
121
+ const dummySigner: BitcoinSigner = {
122
+ getWalletXpub: jest.fn(),
123
+ getWalletPublicKey: jest.fn(),
124
+ signMessage: jest.fn(),
125
+ splitTransaction: jest.fn(),
126
+ createPaymentTransaction: jest.fn(),
127
+ signPsbtBuffer: jest.fn(),
128
+ };
129
+
130
+ // SignerContext: (deviceId, currency, fn) => Promise<ReturnType<fn>>
131
+ const makeSignerContext = (): SignerContext => (deviceId, currency, fn) => fn(dummySigner);
132
+
133
+ // -------------------------------------------------------------------------
134
+
135
+ describe("signOperation (bitcoin)", () => {
136
+ beforeEach(() => {
137
+ jest.clearAllMocks();
138
+ });
139
+
140
+ test("emits device events and builds optimistic operation from fee data", async () => {
141
+ const signerContext = makeSignerContext();
142
+ const signOperation = buildSignOperation(signerContext);
143
+
144
+ // Minimal transaction shape for this test
145
+ const transaction: Transaction = {
146
+ family: "bitcoin",
147
+ amount: new BigNumber(20000),
148
+ recipient: "bc1qrecipient...",
149
+ useAllAmount: false,
150
+ feePerByte: new BigNumber(1),
151
+ networkInfo: null,
152
+ utxoStrategy: { strategy: 0, excludeUTXOs: [] },
153
+ rbf: false,
154
+ };
155
+
156
+ // signAccountTx should simulate device callbacks and return a tx hex
157
+ signAccountTx.mockImplementation(
158
+ (params: {
159
+ onDeviceSignatureRequested?: () => void;
160
+ onDeviceSignatureGranted?: () => void;
161
+ onDeviceStreaming?: (arg: { progress: number; index: number; total: number }) => void;
162
+ }) => {
163
+ const { onDeviceSignatureRequested, onDeviceSignatureGranted, onDeviceStreaming } = params;
164
+ if (onDeviceSignatureRequested) {
165
+ onDeviceSignatureRequested();
166
+ }
167
+ if (onDeviceStreaming) {
168
+ onDeviceStreaming({ progress: 50, index: 0, total: 1 });
169
+ }
170
+ if (onDeviceSignatureGranted) {
171
+ onDeviceSignatureGranted();
172
+ }
173
+ return Promise.resolve("01020304");
174
+ },
175
+ );
176
+
177
+ const account = makeAccount();
178
+
179
+ const events = await firstValueFrom(
180
+ signOperation({ account, deviceId: "mock", transaction }).pipe(toArray()),
181
+ );
182
+
183
+ // Events should include requested, streaming and granted
184
+ const types = events.map(e => e.type);
185
+ expect(types).toContain("device-signature-requested");
186
+ expect(types).toContain("device-signature-granted");
187
+ expect(types).toContain("device-streaming");
188
+
189
+ const streamingEvt = events.find(e => e.type === "device-streaming");
190
+ expect(streamingEvt).toMatchObject({
191
+ type: "device-streaming",
192
+ progress: 50,
193
+ index: 0,
194
+ total: 1,
195
+ });
196
+
197
+ const signedEvt = events.find(e => e.type === "signed");
198
+ if (!signedEvt || signedEvt.type !== "signed") {
199
+ throw new Error("No signed event");
200
+ }
201
+ const { signedOperation } = signedEvt;
202
+
203
+ // raw signature checks
204
+ expect(signedOperation.signature).toBe("01020304");
205
+
206
+ const op: Operation = signedOperation.operation;
207
+ // fee/value taken from calculateFees mock
208
+ expect(op.fee.toNumber()).toBe(1000);
209
+ expect(op.value.toNumber()).toBe(21000); // amount + fee
210
+ expect(op.senders).toEqual(["bc1qsender1...", "bc1qsender2..."]);
211
+ expect(op.recipients).toEqual(["bc1qrecipient..."]);
212
+ expect(op.accountId).toBe(account.id);
213
+ expect(op.type).toBe("OUT");
214
+ expect(op.date).toBeInstanceOf(Date);
215
+
216
+ // Wallet helpers and additionals wiring
217
+ expect(getWalletAccount).toHaveBeenCalledWith(account);
218
+ expect(signAccountTx).toHaveBeenCalledTimes(1);
219
+ const [params] = signAccountTx.mock.calls[0];
220
+ expect(params).toMatchObject({
221
+ sigHashType: 1,
222
+ segwit: true,
223
+ additionals: ["bitcoin", "bech32"], // For bitcoin + native_segwit we expect bech32 flag
224
+ });
225
+ });
226
+ });
@@ -0,0 +1,188 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import { firstValueFrom, skip, toArray } from "rxjs";
3
+ import buildSignRawOperation from "../../signRawOperation";
4
+ import type { Account, Operation } from "@ledgerhq/types-live";
5
+ import { findCryptoCurrencyById } from "@ledgerhq/cryptoassets";
6
+
7
+ // ---- Mocks ---------------------------------------------------------------
8
+
9
+ jest.mock("../../cache", () => ({
10
+ // Deterministic fallback fees (used if PSBT parsing fails)
11
+ calculateFees: jest.fn().mockResolvedValue({
12
+ fees: new BigNumber(1000), // 1000 sats
13
+ txInputs: [{ address: "bc1qsender..." }],
14
+ txOutputs: [{ address: "bc1qrecipient...", isChange: false, value: 5000 }],
15
+ }),
16
+ }));
17
+
18
+ jest.mock("../../buildTransaction", () => ({
19
+ buildTransaction: jest.fn().mockResolvedValue({
20
+ /* not used by PSBT path */
21
+ }),
22
+ }));
23
+
24
+ jest.mock("../../networks", () => ({
25
+ getNetworkParameters: jest.fn().mockReturnValue({ sigHash: 1 }),
26
+ }));
27
+
28
+ jest.mock("../../wallet-btc", () => ({
29
+ getWalletAccount: jest.fn().mockReturnValue({
30
+ params: { path: "m/84'/0'/0'", index: 0 },
31
+ }),
32
+ default: {}, // default export not used in PSBT path
33
+ }));
34
+
35
+ // Keep derivation helpers deterministic
36
+ jest.mock("@ledgerhq/coin-framework/derivation", () => {
37
+ const actual = jest.requireActual("@ledgerhq/coin-framework/derivation");
38
+ return {
39
+ ...actual,
40
+ isSegwitDerivationMode: () => true,
41
+ getAddressFormatDerivationMode: jest.fn().mockReturnValue("p2wpkh"),
42
+ };
43
+ });
44
+
45
+ // ---- Helpers -------------------------------------------------------------
46
+
47
+ const makeAccount = (over: Partial<Account> = {}): Account => ({
48
+ id: "js:2:bitcoin:dummy",
49
+ type: "Account",
50
+ used: true,
51
+ operationsCount: 0,
52
+ balanceHistoryCache: {
53
+ HOUR: {
54
+ latestDate: null,
55
+ balances: [],
56
+ },
57
+ DAY: {
58
+ latestDate: null,
59
+ balances: [],
60
+ },
61
+ WEEK: {
62
+ latestDate: null,
63
+ balances: [],
64
+ },
65
+ },
66
+ swapHistory: [],
67
+ freshAddress: "bc1q...",
68
+ freshAddressPath: "m/84'/0'/0'/0/0",
69
+ currency: findCryptoCurrencyById("bitcoin")!,
70
+ derivationMode: "native_segwit",
71
+ seedIdentifier: "seed",
72
+ xpub: "xpub...",
73
+ index: 0,
74
+ balance: new BigNumber(0),
75
+ spendableBalance: new BigNumber(0),
76
+ blockHeight: 0,
77
+ operations: [],
78
+ pendingOperations: [],
79
+ lastSyncDate: new Date(0),
80
+ creationDate: new Date(0),
81
+ ...over,
82
+ });
83
+
84
+ type MockSigner = {
85
+ signPsbtBuffer: jest.Mock<any, any>;
86
+ };
87
+
88
+ const makeSignerContext =
89
+ (signer: MockSigner) =>
90
+ // SignerContext: (deviceId, currency, fn) => Promise<ReturnType<fn>>
91
+ async (_deviceId: string, _currency: any, fn: (s: any) => any) =>
92
+ fn(signer);
93
+
94
+ // A real PSBTv2 (base64) with: input 20_000 sats, output 15_000 sats => fee 5_000 sats
95
+ const PSBT_V2_B64 =
96
+ "cHNidP8BAgQCAAAAAQMEAAAAAAEEAQEBBQEBAQYBAAH7BAIAAAAAAQEfIE4AAAAAAAAWABRtTfPDGS0+/pTZAN6itD4d+v/DdwEIbAJIMEUCIQCKyNguNXRp8g9Xx8218oMR6nmpYT5DjKR4tFVAUxWEmwIgT1D7gJxboLCae6jHiRilShygUhanylrY4Zy5/zTV5y8BIQKB3M6ZYBlVePq12AbQv1bCn2VPDoa61Ek9vvoauC88vQEOIBpm0EPKluAy05yTYGzOS3gm/qhPQLDCSWqQpVE2pyVMAQ8EAQAAAAABAwiYOgAAAAAAAAEEFgAUgOCAoBDcwBoMygQ0Q5VYjll5FTgA";
97
+ const EXPECTED_PSBT_FEE = 5000; // sats
98
+
99
+ // -------------------------------------------------------------------------
100
+
101
+ describe("signRawOperation (PSBT path)", () => {
102
+ test("returns tx hex in signature and psbtSigned in rawData; value/fee from PSBT", async () => {
103
+ const txHex = "01020304";
104
+ const signer: MockSigner = {
105
+ signPsbtBuffer: jest.fn().mockImplementation((_psbtBuffer: Buffer, options?: any) => {
106
+ // Simulate the actual behavior of signPsbtBuffer by calling the callbacks
107
+ if (options?.onDeviceSignatureRequested) {
108
+ options.onDeviceSignatureRequested();
109
+ }
110
+ if (options?.onDeviceSignatureGranted) {
111
+ options.onDeviceSignatureGranted();
112
+ }
113
+ if (options?.onDeviceStreaming) {
114
+ options.onDeviceStreaming({ progress: 0.5, index: 1, total: 2 });
115
+ }
116
+ return Promise.resolve({
117
+ psbt: Buffer.from(PSBT_V2_B64, "base64"),
118
+ tx: txHex,
119
+ });
120
+ }),
121
+ };
122
+ const signerContext = makeSignerContext(signer);
123
+ const signRawOperation = buildSignRawOperation(signerContext);
124
+
125
+ const account = makeAccount();
126
+
127
+ const events = await firstValueFrom(
128
+ signRawOperation({ account, deviceId: "mock", transaction: PSBT_V2_B64 }).pipe(toArray()),
129
+ );
130
+
131
+ // Events should include requested and granted
132
+ const types = events.map(e => e.type);
133
+ expect(types).toContain("device-streaming");
134
+ expect(types).toContain("device-signature-requested");
135
+ expect(types).toContain("device-signature-granted");
136
+
137
+ const streamingEvents = events.filter(e => e.type === "device-streaming");
138
+ expect(streamingEvents).toHaveLength(1);
139
+ expect(streamingEvents[0]).toEqual({
140
+ type: "device-streaming",
141
+ progress: 0.5,
142
+ index: 1,
143
+ total: 2,
144
+ });
145
+
146
+ const signedEvt = events.find(e => e.type === "signed");
147
+ if (!signedEvt || signedEvt.type !== "signed") {
148
+ throw new Error("No signed event");
149
+ }
150
+ const { signedOperation } = signedEvt;
151
+
152
+ // rawData and signature checks
153
+ expect(signedOperation.rawData?.psbtSigned).toBe(PSBT_V2_B64);
154
+ expect(signedOperation.signature).toBe(txHex);
155
+
156
+ // fee/value taken from PSBT
157
+ const op: Operation = signedOperation.operation;
158
+ expect(op.fee.toNumber()).toBe(EXPECTED_PSBT_FEE);
159
+ expect(op.value.toNumber()).toBe(EXPECTED_PSBT_FEE);
160
+ expect(op.senders).toEqual([]);
161
+ expect(op.recipients).toEqual([]);
162
+
163
+ // Options propagated
164
+ const [, opts] = signer.signPsbtBuffer.mock.calls[0];
165
+ expect(opts).toMatchObject({
166
+ accountPath: "m/84'/0'/0'/0'",
167
+ addressFormat: "p2wpkh",
168
+ });
169
+ });
170
+
171
+ test("invalid base64 PSBT errors early", async () => {
172
+ const signer: MockSigner = {
173
+ signPsbtBuffer: jest.fn(),
174
+ };
175
+ const signerContext = makeSignerContext(signer);
176
+ const signRawOperation = buildSignRawOperation(signerContext);
177
+
178
+ const account = makeAccount();
179
+
180
+ await expect(
181
+ firstValueFrom(
182
+ signRawOperation({ account, deviceId: "mock", transaction: "!!!not-base64!!!" }).pipe(
183
+ skip(1),
184
+ ),
185
+ ),
186
+ ).rejects.toThrow(/PSBT signing failed: no result from device for account/);
187
+ });
188
+ });
@@ -0,0 +1,30 @@
1
+ import { createBridges } from "./js";
2
+
3
+ describe("createBridges", () => {
4
+ it("has a currency bridge and an account bridge with required methods", () => {
5
+ expect(createBridges(undefined as any, {} as any)).toEqual({
6
+ accountBridge: {
7
+ assignFromAccountRaw: expect.any(Function),
8
+ assignToAccountRaw: expect.any(Function),
9
+ broadcast: expect.any(Function),
10
+ createTransaction: expect.any(Function),
11
+ estimateMaxSpendable: expect.any(Function),
12
+ formatAccountSpecifics: expect.any(Function),
13
+ getSerializedAddressParameters: expect.any(Function),
14
+ getTransactionStatus: expect.any(Function),
15
+ prepareTransaction: expect.any(Function),
16
+ receive: expect.any(Function),
17
+ signOperation: expect.any(Function),
18
+ signRawOperation: expect.any(Function),
19
+ sync: expect.any(Function),
20
+ updateTransaction: expect.any(Function),
21
+ validateAddress: expect.any(Function),
22
+ },
23
+ currencyBridge: {
24
+ preload: expect.any(Function),
25
+ hydrate: expect.any(Function),
26
+ scanAccounts: expect.any(Function),
27
+ },
28
+ });
29
+ });
30
+ });
package/src/bridge/js.ts CHANGED
@@ -23,6 +23,7 @@ import { broadcast } from "../broadcast";
23
23
  import { perCoinLogic } from "../logic";
24
24
  import resolver from "../hw-getAddress";
25
25
  import { validateAddress } from "../validateAddress";
26
+ import buildSignRawOperation from "../signRawOperation";
26
27
 
27
28
  function buildCurrencyBridge(signerContext: SignerContext) {
28
29
  const getAddress = resolver(signerContext);
@@ -78,9 +79,7 @@ function buildAccountBridge(signerContext: SignerContext) {
78
79
  receive,
79
80
  sync,
80
81
  signOperation: buildSignOperation(signerContext),
81
- signRawOperation: () => {
82
- throw new Error("signRawOperation is not supported");
83
- },
82
+ signRawOperation: buildSignRawOperation(signerContext),
84
83
  broadcast: wrappedBroadcast,
85
84
  assignFromAccountRaw,
86
85
  assignToAccountRaw,
@@ -0,0 +1,34 @@
1
+ import { BigNumber } from "bignumber.js";
2
+ import type { Operation } from "@ledgerhq/types-live";
3
+ import { encodeOperationId } from "@ledgerhq/coin-framework/operation";
4
+
5
+ type BuildOptimisticOperationParams = {
6
+ accountId: string;
7
+ fee: BigNumber;
8
+ value?: BigNumber;
9
+ senders?: string[];
10
+ recipients?: string[];
11
+ extra?: Record<string, unknown>;
12
+ };
13
+
14
+ export const buildOptimisticOperation = ({
15
+ accountId,
16
+ fee,
17
+ value,
18
+ senders = [],
19
+ recipients = [],
20
+ extra = {},
21
+ }: BuildOptimisticOperationParams): Operation => ({
22
+ id: encodeOperationId(accountId, "", "OUT"),
23
+ hash: "",
24
+ type: "OUT",
25
+ value: value ?? fee,
26
+ fee,
27
+ blockHash: null,
28
+ blockHeight: null,
29
+ senders,
30
+ recipients,
31
+ accountId,
32
+ date: new Date(),
33
+ extra,
34
+ });
@@ -15,6 +15,7 @@ describe("signMessage", () => {
15
15
  }),
16
16
  splitTransaction: jest.fn(),
17
17
  createPaymentTransaction: jest.fn(),
18
+ signPsbtBuffer: jest.fn(),
18
19
  };
19
20
  const signerContext = <T>(
20
21
  _deviceId: string,
@@ -0,0 +1,12 @@
1
+ import { Observable } from "rxjs";
2
+ import type { Observer } from "rxjs";
3
+
4
+ export const fromAsyncOperation = <T>(
5
+ main: (observer: Observer<T>) => Promise<void>,
6
+ ): Observable<T> =>
7
+ new Observable<T>(observer => {
8
+ main(observer).then(
9
+ () => observer.complete(),
10
+ error => observer.error(error),
11
+ );
12
+ });
@@ -0,0 +1,27 @@
1
+ import { firstValueFrom, toArray } from "rxjs";
2
+ import { fromAsyncOperation } from "./observable";
3
+
4
+ describe("fromAsyncOperation", () => {
5
+ test("emits values and completes when the async function resolves", async () => {
6
+ const values = await firstValueFrom(
7
+ fromAsyncOperation<number>(async observer => {
8
+ observer.next(1);
9
+ observer.next(2);
10
+ }).pipe(toArray()),
11
+ );
12
+
13
+ expect(values).toEqual([1, 2]);
14
+ });
15
+
16
+ test("propagates errors when the async function rejects", async () => {
17
+ const error = new Error("boom");
18
+
19
+ await expect(
20
+ firstValueFrom(
21
+ fromAsyncOperation(async () => {
22
+ throw error;
23
+ }),
24
+ ),
25
+ ).rejects.toThrow("boom");
26
+ });
27
+ });