@hwlt/era-connect 0.3.0 → 0.5.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.
Files changed (131) hide show
  1. package/README.md +8 -14
  2. package/bch/package.json +6 -0
  3. package/cosmos/package.json +6 -0
  4. package/dist/bch-CK6dKGQA.d.ts +74 -0
  5. package/dist/bch-CpLACx0j.cjs +139 -0
  6. package/dist/bch-CpLACx0j.cjs.map +1 -0
  7. package/dist/bch-DHsIVJqK.d.cts +74 -0
  8. package/dist/bch-dMESlQfv.js +134 -0
  9. package/dist/bch-dMESlQfv.js.map +1 -0
  10. package/dist/bch.cjs +13 -0
  11. package/dist/bch.d.cts +26 -0
  12. package/dist/bch.d.ts +26 -0
  13. package/dist/bch.js +4 -0
  14. package/dist/{btc-VyJKXq7d.js → btc-BmVgvvBd.js} +17 -8
  15. package/dist/btc-BmVgvvBd.js.map +1 -0
  16. package/dist/{btc-Fr6Jz4Fi.cjs → btc-BxNww6kW.cjs} +20 -11
  17. package/dist/btc-BxNww6kW.cjs.map +1 -0
  18. package/dist/{btc-DfQ0q79G.d.ts → btc-uzt0uC-Q.d.ts} +15 -4
  19. package/dist/{btc-Dn6_Y12c.d.cts → btc-wogJ4INA.d.cts} +15 -4
  20. package/dist/btc.cjs +2 -2
  21. package/dist/btc.d.cts +1 -1
  22. package/dist/btc.d.ts +1 -1
  23. package/dist/btc.js +2 -2
  24. package/dist/{cardano-yuOygqwp.js → cardano-BCT55gwf.js} +3 -2
  25. package/dist/{cardano-yuOygqwp.js.map → cardano-BCT55gwf.js.map} +1 -1
  26. package/dist/{cardano-DP6U_K1J.cjs → cardano-CzYswGzK.cjs} +5 -4
  27. package/dist/{cardano-DP6U_K1J.cjs.map → cardano-CzYswGzK.cjs.map} +1 -1
  28. package/dist/cardano.cjs +2 -2
  29. package/dist/cardano.js +2 -2
  30. package/dist/cashaddr-BIzawizX.js +134 -0
  31. package/dist/cashaddr-BIzawizX.js.map +1 -0
  32. package/dist/cashaddr-Ci0_8ITN.cjs +151 -0
  33. package/dist/cashaddr-Ci0_8ITN.cjs.map +1 -0
  34. package/dist/cosmos-BYrhIqRk.d.cts +77 -0
  35. package/dist/cosmos-DDsgtUki.cjs +113 -0
  36. package/dist/cosmos-DDsgtUki.cjs.map +1 -0
  37. package/dist/cosmos-DqyjA6lg.d.ts +77 -0
  38. package/dist/cosmos-jUHNxgWC.js +102 -0
  39. package/dist/cosmos-jUHNxgWC.js.map +1 -0
  40. package/dist/cosmos.cjs +10 -0
  41. package/dist/cosmos.d.cts +3 -0
  42. package/dist/cosmos.d.ts +3 -0
  43. package/dist/cosmos.js +3 -0
  44. package/dist/{derive-C4JdycUh.js → derive-00JUOkmn.js} +14 -3
  45. package/dist/derive-00JUOkmn.js.map +1 -0
  46. package/dist/{derive-CuILJRPT.cjs → derive-BuNsfWlg.cjs} +25 -2
  47. package/dist/derive-BuNsfWlg.cjs.map +1 -0
  48. package/dist/{evm-kJb3-oiR.js → evm-CI1cuZsp.js} +3 -2
  49. package/dist/{evm-kJb3-oiR.js.map → evm-CI1cuZsp.js.map} +1 -1
  50. package/dist/{evm-BHj_2OTG.cjs → evm-yfKOc2dy.cjs} +6 -5
  51. package/dist/{evm-BHj_2OTG.cjs.map → evm-yfKOc2dy.cjs.map} +1 -1
  52. package/dist/evm.cjs +2 -2
  53. package/dist/evm.js +2 -2
  54. package/dist/gzip-CLzDX7AZ.cjs +79 -0
  55. package/dist/gzip-CLzDX7AZ.cjs.map +1 -0
  56. package/dist/gzip-DyZLtgJJ.js +68 -0
  57. package/dist/gzip-DyZLtgJJ.js.map +1 -0
  58. package/dist/index.cjs +120 -31
  59. package/dist/index.cjs.map +1 -1
  60. package/dist/index.d.cts +50 -3
  61. package/dist/index.d.ts +50 -3
  62. package/dist/index.js +90 -9
  63. package/dist/index.js.map +1 -1
  64. package/dist/keypath-Bvv_cfHt.js +75 -0
  65. package/dist/keypath-Bvv_cfHt.js.map +1 -0
  66. package/dist/keypath-pzm_YIfN.cjs +116 -0
  67. package/dist/keypath-pzm_YIfN.cjs.map +1 -0
  68. package/dist/{messages-17Oup0-Z.js → messages--XbVef_k.js} +39 -3
  69. package/dist/messages--XbVef_k.js.map +1 -0
  70. package/dist/{messages-BzcdWlg1.cjs → messages-orAQ52CI.cjs} +44 -2
  71. package/dist/messages-orAQ52CI.cjs.map +1 -0
  72. package/dist/{shared-B8Wc7ViU.js → shared-Bbgejrus.js} +2 -73
  73. package/dist/shared-Bbgejrus.js.map +1 -0
  74. package/dist/{shared-nISrEktU.cjs → shared-Cu2yynP9.cjs} +13 -114
  75. package/dist/shared-Cu2yynP9.cjs.map +1 -0
  76. package/dist/{solana-DdEn24X4.cjs → solana-BoQBy0hu.cjs} +6 -5
  77. package/dist/{solana-DdEn24X4.cjs.map → solana-BoQBy0hu.cjs.map} +1 -1
  78. package/dist/{solana-C7JQEAec.js → solana-BukH3AI3.js} +3 -2
  79. package/dist/{solana-C7JQEAec.js.map → solana-BukH3AI3.js.map} +1 -1
  80. package/dist/solana.cjs +2 -2
  81. package/dist/solana.js +2 -2
  82. package/dist/sui-6WX6VPlW.d.cts +49 -0
  83. package/dist/sui-BtbPG6Xt.js +71 -0
  84. package/dist/sui-BtbPG6Xt.js.map +1 -0
  85. package/dist/sui-CYRn331O.cjs +82 -0
  86. package/dist/sui-CYRn331O.cjs.map +1 -0
  87. package/dist/sui-DI0ruW7E.d.ts +49 -0
  88. package/dist/sui.cjs +10 -0
  89. package/dist/sui.d.cts +3 -0
  90. package/dist/sui.d.ts +3 -0
  91. package/dist/sui.js +3 -0
  92. package/dist/{ton-5Uvi5ifg.js → ton-BSPKU5B9.js} +3 -2
  93. package/dist/{ton-5Uvi5ifg.js.map → ton-BSPKU5B9.js.map} +1 -1
  94. package/dist/{ton-DUJGXdGa.cjs → ton-CI2s9puH.cjs} +6 -5
  95. package/dist/{ton-DUJGXdGa.cjs.map → ton-CI2s9puH.cjs.map} +1 -1
  96. package/dist/ton.cjs +2 -2
  97. package/dist/ton.js +2 -2
  98. package/dist/{tron-Bo9HnvVE.js → tron-BpUEYTPT.js} +5 -67
  99. package/dist/tron-BpUEYTPT.js.map +1 -0
  100. package/dist/{tron-CQIEqjCA.cjs → tron-DYPOg5cm.cjs} +10 -72
  101. package/dist/{tron-Bo9HnvVE.js.map → tron-DYPOg5cm.cjs.map} +1 -1
  102. package/dist/tron.cjs +3 -3
  103. package/dist/tron.js +3 -3
  104. package/dist/verify.cjs +414 -24
  105. package/dist/verify.cjs.map +1 -1
  106. package/dist/verify.d.cts +120 -1
  107. package/dist/verify.d.ts +120 -1
  108. package/dist/verify.js +408 -24
  109. package/dist/verify.js.map +1 -1
  110. package/dist/xrp-BXAeK4iH.d.cts +32 -0
  111. package/dist/xrp-BrHXUnX5.cjs +52 -0
  112. package/dist/xrp-BrHXUnX5.cjs.map +1 -0
  113. package/dist/xrp-C8LJO5b-.js +47 -0
  114. package/dist/xrp-C8LJO5b-.js.map +1 -0
  115. package/dist/xrp-DqCXGYEk.d.ts +32 -0
  116. package/dist/xrp.cjs +9 -0
  117. package/dist/xrp.d.cts +3 -0
  118. package/dist/xrp.d.ts +3 -0
  119. package/dist/xrp.js +3 -0
  120. package/package.json +49 -1
  121. package/sui/package.json +6 -0
  122. package/xrp/package.json +6 -0
  123. package/dist/btc-Fr6Jz4Fi.cjs.map +0 -1
  124. package/dist/btc-VyJKXq7d.js.map +0 -1
  125. package/dist/derive-C4JdycUh.js.map +0 -1
  126. package/dist/derive-CuILJRPT.cjs.map +0 -1
  127. package/dist/messages-17Oup0-Z.js.map +0 -1
  128. package/dist/messages-BzcdWlg1.cjs.map +0 -1
  129. package/dist/shared-B8Wc7ViU.js.map +0 -1
  130. package/dist/shared-nISrEktU.cjs.map +0 -1
  131. package/dist/tron-CQIEqjCA.cjs.map +0 -1
@@ -0,0 +1,68 @@
1
+ import { K as EraSdkError, T as concatBytes, y as crc32 } from "./shared-Bbgejrus.js";
2
+ import { Gunzip, gzipSync } from "fflate";
3
+ //#region src/tron-proto/gzip.ts
4
+ /** Smallest possible gzip stream: 10-byte header + 8-byte trailer. */
5
+ const MIN_GZIP_BYTES = 18;
6
+ /** Bytes fed to the inflater per step; bounds the overshoot past the cap. */
7
+ const SLICE_BYTES = 1024;
8
+ /** Deterministic gzip (fixed level, zeroed mtime) for reproducible request bytes. */
9
+ function gzipCompress(data) {
10
+ return gzipSync(data, {
11
+ level: 9,
12
+ mtime: 0
13
+ });
14
+ }
15
+ /**
16
+ * Inflate with a hard output ceiling.
17
+ *
18
+ * A one-shot gunzip allocates the entire output before anyone can refuse it —
19
+ * gzip reaches ~1000:1 in practice, so a few hundred scanned bytes could ask
20
+ * for an arbitrary allocation. The decoder is therefore driven in slices and
21
+ * the output counted as it arrives; the moment the total would pass the cap,
22
+ * feeding stops and the reply is refused.
23
+ *
24
+ * The trailer's ISIZE (declared inflated length) is used twice: as a cheap
25
+ * refusal of honest bombs before any work, and as a truncation check at the
26
+ * end — an inflater hands back a partial buffer for a truncated stream
27
+ * without erroring, and a genuine device reply always declares honestly.
28
+ */
29
+ function gunzipCapped(data, maxOutputBytes) {
30
+ if (data.length < MIN_GZIP_BYTES) throw new EraSdkError("gzip-error", "compressed payload is too short to be a gzip stream");
31
+ if (data[0] !== 31 || data[1] !== 139) throw new EraSdkError("gzip-error", "compressed payload is not a gzip stream");
32
+ const n = data.length;
33
+ const isize = (data[n - 4] | data[n - 3] << 8 | data[n - 2] << 16 | data[n - 1] << 24) >>> 0;
34
+ if (isize > maxOutputBytes) throw new EraSdkError("gzip-error", `compressed payload declares ${isize} bytes, over the ${maxOutputBytes} byte ceiling`);
35
+ const chunks = [];
36
+ let total = 0;
37
+ let overflowed = false;
38
+ let malformed = null;
39
+ const gunzip = new Gunzip((chunk) => {
40
+ if (overflowed) return;
41
+ if (total + chunk.length > maxOutputBytes) {
42
+ overflowed = true;
43
+ return;
44
+ }
45
+ chunks.push(chunk);
46
+ total += chunk.length;
47
+ });
48
+ try {
49
+ for (let offset = 0; offset < n && !overflowed; offset += SLICE_BYTES) {
50
+ const end = Math.min(offset + SLICE_BYTES, n);
51
+ const isLast = end === n;
52
+ gunzip.push(data.slice(offset, end), isLast);
53
+ }
54
+ } catch (e) {
55
+ malformed = e.message ?? "inflate error";
56
+ }
57
+ if (overflowed) throw new EraSdkError("gzip-error", `compressed payload inflates past the ${maxOutputBytes} byte ceiling`);
58
+ if (malformed !== null) throw new EraSdkError("gzip-error", `compressed payload is malformed: ${malformed}`);
59
+ const out = concatBytes(...chunks);
60
+ if (out.length !== isize) throw new EraSdkError("gzip-error", `compressed payload inflated to ${out.length} bytes but declares ${isize} — truncated or malformed`);
61
+ const declaredCrc = (data[n - 8] | data[n - 7] << 8 | data[n - 6] << 16 | data[n - 5] << 24) >>> 0;
62
+ if (crc32(out) !== declaredCrc) throw new EraSdkError("gzip-error", "compressed payload is malformed: CRC mismatch");
63
+ return out;
64
+ }
65
+ //#endregion
66
+ export { gzipCompress as n, gunzipCapped as t };
67
+
68
+ //# sourceMappingURL=gzip-DyZLtgJJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gzip-DyZLtgJJ.js","names":[],"sources":["../src/tron-proto/gzip.ts"],"sourcesContent":["import { Gunzip, gzipSync } from 'fflate';\nimport { concatBytes } from '../core/bytes';\nimport { EraSdkError } from '../core/errors';\nimport { crc32 } from '../ur/crc32';\n\n/** Smallest possible gzip stream: 10-byte header + 8-byte trailer. */\nconst MIN_GZIP_BYTES = 18;\n\n/** Bytes fed to the inflater per step; bounds the overshoot past the cap. */\nconst SLICE_BYTES = 1024;\n\n/** Deterministic gzip (fixed level, zeroed mtime) for reproducible request bytes. */\nexport function gzipCompress(data: Uint8Array): Uint8Array {\n return gzipSync(data, { level: 9, mtime: 0 });\n}\n\n/**\n * Inflate with a hard output ceiling.\n *\n * A one-shot gunzip allocates the entire output before anyone can refuse it —\n * gzip reaches ~1000:1 in practice, so a few hundred scanned bytes could ask\n * for an arbitrary allocation. The decoder is therefore driven in slices and\n * the output counted as it arrives; the moment the total would pass the cap,\n * feeding stops and the reply is refused.\n *\n * The trailer's ISIZE (declared inflated length) is used twice: as a cheap\n * refusal of honest bombs before any work, and as a truncation check at the\n * end — an inflater hands back a partial buffer for a truncated stream\n * without erroring, and a genuine device reply always declares honestly.\n */\nexport function gunzipCapped(data: Uint8Array, maxOutputBytes: number): Uint8Array {\n if (data.length < MIN_GZIP_BYTES) {\n throw new EraSdkError('gzip-error', 'compressed payload is too short to be a gzip stream');\n }\n if (data[0] !== 0x1f || data[1] !== 0x8b) {\n throw new EraSdkError('gzip-error', 'compressed payload is not a gzip stream');\n }\n const n = data.length;\n const isize =\n (data[n - 4]! | (data[n - 3]! << 8) | (data[n - 2]! << 16) | (data[n - 1]! << 24)) >>> 0;\n if (isize > maxOutputBytes) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload declares ${isize} bytes, over the ${maxOutputBytes} byte ceiling`,\n );\n }\n\n const chunks: Uint8Array[] = [];\n let total = 0;\n let overflowed = false;\n let malformed: string | null = null;\n\n const gunzip = new Gunzip((chunk) => {\n if (overflowed) return;\n if (total + chunk.length > maxOutputBytes) {\n overflowed = true;\n return;\n }\n chunks.push(chunk);\n total += chunk.length;\n });\n\n try {\n for (let offset = 0; offset < n && !overflowed; offset += SLICE_BYTES) {\n const end = Math.min(offset + SLICE_BYTES, n);\n const isLast = end === n;\n gunzip.push(data.slice(offset, end), isLast);\n }\n } catch (e) {\n malformed = (e as Error).message ?? 'inflate error';\n }\n\n if (overflowed) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload inflates past the ${maxOutputBytes} byte ceiling`,\n );\n }\n if (malformed !== null) {\n throw new EraSdkError('gzip-error', `compressed payload is malformed: ${malformed}`);\n }\n const out = concatBytes(...chunks);\n if (out.length !== isize) {\n throw new EraSdkError(\n 'gzip-error',\n `compressed payload inflated to ${out.length} bytes but declares ${isize} — truncated or malformed`,\n );\n }\n // The trailer CRC32 (little-endian, bytes n-8..n-5) must cover the inflated\n // output. The streaming inflater does not verify it, and the reference\n // implementation's native decoder does — without this check a corrupted\n // stream, or a CONCATENATED multi-member stream (whose final member's CRC\n // cannot cover the whole output), would be accepted here and refused there.\n const declaredCrc =\n (data[n - 8]! | (data[n - 7]! << 8) | (data[n - 6]! << 16) | (data[n - 5]! << 24)) >>> 0;\n if (crc32(out) !== declaredCrc) {\n throw new EraSdkError('gzip-error', 'compressed payload is malformed: CRC mismatch');\n }\n return out;\n}\n"],"mappings":";;;;AAMA,MAAM,iBAAiB;;AAGvB,MAAM,cAAc;;AAGpB,SAAgB,aAAa,MAA8B;CACzD,OAAO,SAAS,MAAM;EAAE,OAAO;EAAG,OAAO;CAAE,CAAC;AAC9C;;;;;;;;;;;;;;;AAgBA,SAAgB,aAAa,MAAkB,gBAAoC;CACjF,IAAI,KAAK,SAAS,gBAChB,MAAM,IAAI,YAAY,cAAc,qDAAqD;CAE3F,IAAI,KAAK,OAAO,MAAQ,KAAK,OAAO,KAClC,MAAM,IAAI,YAAY,cAAc,yCAAyC;CAE/E,MAAM,IAAI,KAAK;CACf,MAAM,SACH,KAAK,IAAI,KAAO,KAAK,IAAI,MAAO,IAAM,KAAK,IAAI,MAAO,KAAO,KAAK,IAAI,MAAO,QAAS;CACzF,IAAI,QAAQ,gBACV,MAAM,IAAI,YACR,cACA,+BAA+B,MAAM,mBAAmB,eAAe,cACzE;CAGF,MAAM,SAAuB,CAAC;CAC9B,IAAI,QAAQ;CACZ,IAAI,aAAa;CACjB,IAAI,YAA2B;CAE/B,MAAM,SAAS,IAAI,QAAQ,UAAU;EACnC,IAAI,YAAY;EAChB,IAAI,QAAQ,MAAM,SAAS,gBAAgB;GACzC,aAAa;GACb;EACF;EACA,OAAO,KAAK,KAAK;EACjB,SAAS,MAAM;CACjB,CAAC;CAED,IAAI;EACF,KAAK,IAAI,SAAS,GAAG,SAAS,KAAK,CAAC,YAAY,UAAU,aAAa;GACrE,MAAM,MAAM,KAAK,IAAI,SAAS,aAAa,CAAC;GAC5C,MAAM,SAAS,QAAQ;GACvB,OAAO,KAAK,KAAK,MAAM,QAAQ,GAAG,GAAG,MAAM;EAC7C;CACF,SAAS,GAAG;EACV,YAAa,EAAY,WAAW;CACtC;CAEA,IAAI,YACF,MAAM,IAAI,YACR,cACA,wCAAwC,eAAe,cACzD;CAEF,IAAI,cAAc,MAChB,MAAM,IAAI,YAAY,cAAc,oCAAoC,WAAW;CAErF,MAAM,MAAM,YAAY,GAAG,MAAM;CACjC,IAAI,IAAI,WAAW,OACjB,MAAM,IAAI,YACR,cACA,kCAAkC,IAAI,OAAO,sBAAsB,MAAM,0BAC3E;CAOF,MAAM,eACH,KAAK,IAAI,KAAO,KAAK,IAAI,MAAO,IAAM,KAAK,IAAI,MAAO,KAAO,KAAK,IAAI,MAAO,QAAS;CACzF,IAAI,MAAM,GAAG,MAAM,aACjB,MAAM,IAAI,YAAY,cAAc,+CAA+C;CAErF,OAAO;AACT"}
package/dist/index.cjs CHANGED
@@ -1,12 +1,17 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_shared = require("./shared-nISrEktU.cjs");
3
- const require_derive = require("./derive-CuILJRPT.cjs");
4
- const require_btc = require("./btc-Fr6Jz4Fi.cjs");
5
- const require_cardano = require("./cardano-DP6U_K1J.cjs");
6
- const require_evm = require("./evm-BHj_2OTG.cjs");
7
- const require_solana = require("./solana-DdEn24X4.cjs");
8
- const require_ton = require("./ton-DUJGXdGa.cjs");
9
- const require_tron = require("./tron-CQIEqjCA.cjs");
2
+ const require_shared = require("./shared-Cu2yynP9.cjs");
3
+ const require_keypath = require("./keypath-pzm_YIfN.cjs");
4
+ const require_derive = require("./derive-BuNsfWlg.cjs");
5
+ const require_btc = require("./btc-BxNww6kW.cjs");
6
+ const require_cardano = require("./cardano-CzYswGzK.cjs");
7
+ const require_bch = require("./bch-CpLACx0j.cjs");
8
+ const require_cosmos = require("./cosmos-DDsgtUki.cjs");
9
+ const require_evm = require("./evm-yfKOc2dy.cjs");
10
+ const require_solana = require("./solana-BoQBy0hu.cjs");
11
+ const require_sui = require("./sui-CYRn331O.cjs");
12
+ const require_ton = require("./ton-CI2s9puH.cjs");
13
+ const require_tron = require("./tron-DYPOg5cm.cjs");
14
+ const require_xrp = require("./xrp-BrHXUnX5.cjs");
10
15
  //#region src/registry/multi-accounts.ts
11
16
  /** UR types a device links a watch-only wallet with. */
12
17
  const WALLET_UR_TYPES = /* @__PURE__ */ new Set([
@@ -79,7 +84,7 @@ function tryParseEntry(item) {
79
84
  if (!map) return null;
80
85
  const origin = require_shared.asMap(require_shared.mapGet(map, 6));
81
86
  if (!origin) return null;
82
- const path = require_shared.parsePathComponents(require_shared.mapGet(origin, 1));
87
+ const path = require_keypath.parsePathComponents(require_shared.mapGet(origin, 1));
83
88
  if (!path || path.length === 0) return null;
84
89
  const xfpValue = require_shared.asUint(require_shared.mapGet(origin, 2));
85
90
  const xfp = xfpValue !== void 0 && xfpValue <= 4294967295n ? Number(xfpValue) : null;
@@ -102,19 +107,22 @@ function classify(path) {
102
107
  if (!p0 || !p1 || !p0.hardened || !p1.hardened) return "unknown";
103
108
  if (p0.index === 44 && p1.index === 60) return "evm";
104
109
  if (p1.index === 0 && (p0.index === 84 || p0.index === 49 || p0.index === 44 || p0.index === 86)) return "btc";
110
+ if (p0.index === 44 && p1.index === 145) return "bch";
105
111
  if (p0.index === 44 && p1.index === 501) return "solana";
106
112
  if (p0.index === 44 && p1.index === 195) return "tron";
107
113
  if (p0.index === 44 && p1.index === 607) return "ton";
108
114
  if (p0.index === 1852 && p1.index === 1815) return "cardano";
115
+ if (p0.index === 44 && p1.index === 784) return "sui";
116
+ if (p0.index === 44 && p1.index === 118) return "cosmos";
109
117
  return "unknown";
110
118
  }
111
119
  function withChainCode(entry) {
112
- if (!entry.chainCode) throw new require_shared.EraSdkError("account-not-found", `account ${require_shared.formatPath([...entry.path])} carries no chain code; cannot derive children`);
120
+ if (!entry.chainCode) throw new require_shared.EraSdkError("account-not-found", `account ${require_keypath.formatPath([...entry.path])} carries no chain code; cannot derive children`);
113
121
  return entry.chainCode;
114
122
  }
115
123
  /** The entry's key at the required length, or a typed refusal (derivation only). */
116
124
  function requireKey(entry, length) {
117
- if (!entry.publicKey || entry.publicKey.length !== length) throw new require_shared.EraSdkError("invalid-props", `account ${require_shared.formatPath([...entry.path])} carries no ${length}-byte public key; xfp lookup still works, address derivation does not`);
125
+ if (!entry.publicKey || entry.publicKey.length !== length) throw new require_shared.EraSdkError("invalid-props", `account ${require_keypath.formatPath([...entry.path])} carries no ${length}-byte public key; xfp lookup still works, address derivation does not`);
118
126
  return entry.publicKey;
119
127
  }
120
128
  /** EVM view over the linked wallet: one account xpub, addresses derived at `0/index`. */
@@ -124,10 +132,10 @@ var EvmAccountView = class {
124
132
  this.resolvedXfp = resolvedXfp;
125
133
  }
126
134
  get xfp() {
127
- return require_shared.xfpToHex(this.resolvedXfp);
135
+ return require_keypath.xfpToHex(this.resolvedXfp);
128
136
  }
129
137
  get accountPath() {
130
- return require_shared.formatPath([...this.entry.path]);
138
+ return require_keypath.formatPath([...this.entry.path]);
131
139
  }
132
140
  /** Signing path for address `index`: `<account>/0/<index>`. */
133
141
  pathFor(index) {
@@ -154,10 +162,10 @@ var BtcAccountView = class {
154
162
  this.resolvedXfp = resolvedXfp;
155
163
  }
156
164
  get xfp() {
157
- return require_shared.xfpToHex(this.resolvedXfp);
165
+ return require_keypath.xfpToHex(this.resolvedXfp);
158
166
  }
159
167
  get accountPath() {
160
- return require_shared.formatPath([...this.entry.path]);
168
+ return require_keypath.formatPath([...this.entry.path]);
161
169
  }
162
170
  receivePath(index) {
163
171
  return `${this.accountPath}/0/${index}`;
@@ -191,10 +199,10 @@ var TronAccountView = class {
191
199
  this.resolvedXfp = resolvedXfp;
192
200
  }
193
201
  get xfp() {
194
- return require_shared.xfpToHex(this.resolvedXfp);
202
+ return require_keypath.xfpToHex(this.resolvedXfp);
195
203
  }
196
204
  get accountPath() {
197
- return require_shared.formatPath([...this.entry.path]);
205
+ return require_keypath.formatPath([...this.entry.path]);
198
206
  }
199
207
  pathFor(index) {
200
208
  return `${this.accountPath}/0/${index}`;
@@ -203,6 +211,33 @@ var TronAccountView = class {
203
211
  return require_derive.tronAddressFromPublicKey(require_derive.derivePublicKey(requireKey(this.entry, 33), withChainCode(this.entry), 0, index));
204
212
  }
205
213
  };
214
+ /** Bitcoin Cash view: `m/44'/145'/0'`, CashAddr P2PKH addresses. */
215
+ var BchAccountView = class {
216
+ constructor(entry, resolvedXfp) {
217
+ this.entry = entry;
218
+ this.resolvedXfp = resolvedXfp;
219
+ }
220
+ get xfp() {
221
+ return require_keypath.xfpToHex(this.resolvedXfp);
222
+ }
223
+ get accountPath() {
224
+ return require_keypath.formatPath([...this.entry.path]);
225
+ }
226
+ receivePath(index) {
227
+ return `${this.accountPath}/0/${index}`;
228
+ }
229
+ changePath(index) {
230
+ return `${this.accountPath}/1/${index}`;
231
+ }
232
+ /** The compressed public key at receive/change `index` — what a sign request's input names. */
233
+ derivePublicKey(index, options) {
234
+ return require_derive.derivePublicKey(requireKey(this.entry, 33), withChainCode(this.entry), options?.change ? 1 : 0, index);
235
+ }
236
+ /** Bare CashAddr by default; `{ withPrefix: true }` for `bitcoincash:...`. */
237
+ deriveAddress(index, options) {
238
+ return require_derive.bchAddressFromPublicKey(this.derivePublicKey(index, options), { withPrefix: options?.withPrefix ?? false });
239
+ }
240
+ };
206
241
  /**
207
242
  * TON view: one Ed25519 key per account (`m/44'/607'/0'`), shared by the
208
243
  * V4R2 and V5R1 wallet contracts — the contract version affects only the
@@ -215,10 +250,10 @@ var TonAccountView = class {
215
250
  this.resolvedXfp = resolvedXfp;
216
251
  }
217
252
  get xfp() {
218
- return require_shared.xfpToHex(this.resolvedXfp);
253
+ return require_keypath.xfpToHex(this.resolvedXfp);
219
254
  }
220
255
  get accountPath() {
221
- return require_shared.formatPath([...this.entry.path]);
256
+ return require_keypath.formatPath([...this.entry.path]);
222
257
  }
223
258
  /** 32-byte Ed25519 public key — the signer for both wallet-contract versions. */
224
259
  get publicKey() {
@@ -240,10 +275,10 @@ var CardanoAccountView = class {
240
275
  this.resolvedXfp = resolvedXfp;
241
276
  }
242
277
  get xfp() {
243
- return require_shared.xfpToHex(this.resolvedXfp);
278
+ return require_keypath.xfpToHex(this.resolvedXfp);
244
279
  }
245
280
  get accountPath() {
246
- return require_shared.formatPath([...this.entry.path]);
281
+ return require_keypath.formatPath([...this.entry.path]);
247
282
  }
248
283
  /** The account-level extended public key material. */
249
284
  get publicKey() {
@@ -261,6 +296,26 @@ var CardanoAccountView = class {
261
296
  return require_derive.cardanoSoftDerivePath(requireKey(this.entry, 32), withChainCode(this.entry), [role, index]);
262
297
  }
263
298
  };
299
+ /** Sui view: like Solana, each fully-hardened exported entry IS a signer. */
300
+ var SuiAccountView = class {
301
+ constructor(entry, resolvedXfp) {
302
+ this.entry = entry;
303
+ this.resolvedXfp = resolvedXfp;
304
+ }
305
+ get xfp() {
306
+ return require_keypath.xfpToHex(this.resolvedXfp);
307
+ }
308
+ get path() {
309
+ return require_keypath.formatPath([...this.entry.path]);
310
+ }
311
+ get publicKey() {
312
+ return requireKey(this.entry, 32);
313
+ }
314
+ /** `0x` Sui address: BLAKE2b-256 of `0x00 || publicKey`. */
315
+ get address() {
316
+ return require_derive.suiAddressFromPublicKey(requireKey(this.entry, 32));
317
+ }
318
+ };
264
319
  /**
265
320
  * Solana view: Ed25519 has no public child derivation, so the device
266
321
  * pre-derives hardened accounts (`m/44'/501'/idx'`) and each entry IS a
@@ -272,10 +327,10 @@ var SolanaAccountView = class {
272
327
  this.resolvedXfp = resolvedXfp;
273
328
  }
274
329
  get xfp() {
275
- return require_shared.xfpToHex(this.resolvedXfp);
330
+ return require_keypath.xfpToHex(this.resolvedXfp);
276
331
  }
277
332
  get path() {
278
- return require_shared.formatPath([...this.entry.path]);
333
+ return require_keypath.formatPath([...this.entry.path]);
279
334
  }
280
335
  /** The hardened account index (third path level). */
281
336
  get index() {
@@ -320,7 +375,7 @@ var EraAccounts = class EraAccounts {
320
375
  }
321
376
  /** Master fingerprint, lowercase 8-hex. */
322
377
  get masterFingerprint() {
323
- return require_shared.xfpToHex(this.raw.masterFingerprint);
378
+ return require_keypath.xfpToHex(this.raw.masterFingerprint);
324
379
  }
325
380
  get device() {
326
381
  return {
@@ -332,8 +387,8 @@ var EraAccounts = class EraAccounts {
332
387
  get keys() {
333
388
  return this.raw.entries.map((entry) => ({
334
389
  chain: classify(entry.path),
335
- path: require_shared.formatPath([...entry.path]),
336
- xfp: require_shared.xfpToHex(entry.xfp ?? this.raw.masterFingerprint),
390
+ path: require_keypath.formatPath([...entry.path]),
391
+ xfp: require_keypath.xfpToHex(entry.xfp ?? this.raw.masterFingerprint),
337
392
  publicKey: entry.publicKey ?? void 0,
338
393
  chainCode: entry.chainCode ?? void 0,
339
394
  name: entry.name ?? void 0,
@@ -345,7 +400,7 @@ var EraAccounts = class EraAccounts {
345
400
  * equals `accountPath`. Throws `account-not-found` — never a silent zero.
346
401
  */
347
402
  xfpFor(accountPath) {
348
- return require_shared.xfpToHex(this.resolveXfp(this.entryFor(accountPath)));
403
+ return require_keypath.xfpToHex(this.resolveXfp(this.entryFor(accountPath)));
349
404
  }
350
405
  /** Entry xfp, falling back to the wrapper's master fingerprint (Cardano-style path-only origins). */
351
406
  resolveXfp(entry) {
@@ -370,11 +425,20 @@ var EraAccounts = class EraAccounts {
370
425
  const entry = this.raw.entries.find((e) => classify(e.path) === "tron");
371
426
  return entry ? new TronAccountView(entry, this.resolveXfp(entry)) : void 0;
372
427
  }
428
+ /** The Bitcoin Cash account (`m/44'/145'/0'`), if the export carries one. */
429
+ bch() {
430
+ const entry = this.raw.entries.find((e) => classify(e.path) === "bch");
431
+ return entry ? new BchAccountView(entry, this.resolveXfp(entry)) : void 0;
432
+ }
373
433
  /** The TON account (linked via the Tonkeeper-style `crypto-hdkey` export). */
374
434
  ton() {
375
435
  const entry = this.raw.entries.find((e) => classify(e.path) === "ton" && e.publicKey?.length === 32);
376
436
  return entry ? new TonAccountView(entry, this.resolveXfp(entry)) : void 0;
377
437
  }
438
+ /** All exported Sui signers (fully hardened SLIP-10 entries). */
439
+ sui() {
440
+ return this.raw.entries.filter((e) => classify(e.path) === "sui" && e.publicKey?.length === 32).map((e) => new SuiAccountView(e, this.resolveXfp(e)));
441
+ }
378
442
  /** The Cardano account (CIP-1852 Icarus export), if the export carries one. */
379
443
  cardano() {
380
444
  const entry = this.raw.entries.find((e) => classify(e.path) === "cardano" && e.publicKey?.length === 32);
@@ -385,8 +449,8 @@ var EraAccounts = class EraAccounts {
385
449
  return this.raw.entries.filter((e) => classify(e.path) === "solana" && e.publicKey?.length === 32).map((e) => new SolanaAccountView(e, this.resolveXfp(e)));
386
450
  }
387
451
  entryFor(accountPath) {
388
- const levels = require_shared.parsePath(accountPath);
389
- const entry = this.raw.entries.find((e) => require_shared.pathEquals(e.path, levels));
452
+ const levels = require_keypath.parsePath(accountPath);
453
+ const entry = this.raw.entries.find((e) => require_keypath.pathEquals(e.path, levels));
390
454
  if (!entry) throw new require_shared.EraSdkError("account-not-found", `the linked wallet carries no account at ${accountPath}`, { path: accountPath });
391
455
  return entry;
392
456
  }
@@ -414,9 +478,9 @@ const ALGOS = {
414
478
  function generateKeyDerivationCall(context, props) {
415
479
  if (props.schemas.length === 0) throw new require_shared.EraSdkError("invalid-props", "at least one derivation schema is required");
416
480
  const schemas = props.schemas.map((schema) => {
417
- const levels = require_shared.parsePath(schema.path);
481
+ const levels = require_keypath.parsePath(schema.path);
418
482
  const entries = [
419
- [1, require_shared.keypath304(levels)],
483
+ [1, require_keypath.keypath304(levels)],
420
484
  [2, require_shared.cbUint(CURVES[schema.curve ?? "secp256k1"])],
421
485
  [3, require_shared.cbUint(ALGOS[schema.algo ?? "slip10"])]
422
486
  ];
@@ -503,6 +567,11 @@ var EraConnect = class {
503
567
  this._tron ?? (this._tron = new require_tron.TronChain(this.context));
504
568
  return this._tron;
505
569
  }
570
+ /** Bitcoin Cash — the structured keystone envelope (see `@hwlt/era-connect/bch`). */
571
+ get bch() {
572
+ this._bch ?? (this._bch = new require_bch.BchChain(this.context));
573
+ return this._bch;
574
+ }
506
575
  get ton() {
507
576
  this._ton ?? (this._ton = new require_ton.TonChain(this.context));
508
577
  return this._ton;
@@ -511,6 +580,18 @@ var EraConnect = class {
511
580
  this._cardano ?? (this._cardano = new require_cardano.CardanoChain(this.context));
512
581
  return this._cardano;
513
582
  }
583
+ get sui() {
584
+ this._sui ?? (this._sui = new require_sui.SuiChain(this.context));
585
+ return this._sui;
586
+ }
587
+ get cosmos() {
588
+ this._cosmos ?? (this._cosmos = new require_cosmos.CosmosChain(this.context));
589
+ return this._cosmos;
590
+ }
591
+ get xrp() {
592
+ this._xrp ?? (this._xrp = new require_xrp.XrpChain(this.context));
593
+ return this._xrp;
594
+ }
514
595
  /** Escape hatch for UR types without a dedicated module. */
515
596
  get raw() {
516
597
  this._raw ?? (this._raw = new RawModule(this.context));
@@ -538,10 +619,14 @@ var EraConnect = class {
538
619
  };
539
620
  //#endregion
540
621
  exports.AnimatedUr = require_shared.AnimatedUr;
622
+ exports.BchAccountView = BchAccountView;
623
+ exports.BchChain = require_bch.BchChain;
541
624
  exports.BtcAccountView = BtcAccountView;
542
625
  exports.BtcChain = require_btc.BtcChain;
543
626
  exports.CardanoAccountView = CardanoAccountView;
544
627
  exports.CardanoChain = require_cardano.CardanoChain;
628
+ exports.CosmosChain = require_cosmos.CosmosChain;
629
+ exports.CosmosDataType = require_cosmos.CosmosDataType;
545
630
  exports.DEFAULT_FRAGMENT_LENGTH = require_shared.DEFAULT_FRAGMENT_LENGTH;
546
631
  exports.DEFAULT_ORIGIN = require_shared.DEFAULT_ORIGIN;
547
632
  exports.DeviceProfile = DeviceProfile;
@@ -555,6 +640,8 @@ exports.RawModule = RawModule;
555
640
  exports.SolSignType = require_solana.SolSignType;
556
641
  exports.SolanaAccountView = SolanaAccountView;
557
642
  exports.SolanaChain = require_solana.SolanaChain;
643
+ exports.SuiAccountView = SuiAccountView;
644
+ exports.SuiChain = require_sui.SuiChain;
558
645
  exports.TonAccountView = TonAccountView;
559
646
  exports.TonChain = require_ton.TonChain;
560
647
  exports.TonDataType = require_ton.TonDataType;
@@ -564,7 +651,9 @@ exports.TypedUrScanner = require_shared.TypedUrScanner;
564
651
  exports.Ur = require_shared.Ur;
565
652
  exports.UrLimits = require_shared.UrLimits;
566
653
  exports.UrScanner = require_shared.UrScanner;
654
+ exports.XrpChain = require_xrp.XrpChain;
567
655
  exports.parseWitnessSet = require_cardano.parseWitnessSet;
656
+ exports.suiIntentDigest = require_sui.suiIntentDigest;
568
657
  exports.utf8Decode = require_shared.utf8Decode;
569
658
  exports.utf8Encode = require_shared.utf8Encode;
570
659