@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.
- package/README.md +8 -14
- package/bch/package.json +6 -0
- package/cosmos/package.json +6 -0
- package/dist/bch-CK6dKGQA.d.ts +74 -0
- package/dist/bch-CpLACx0j.cjs +139 -0
- package/dist/bch-CpLACx0j.cjs.map +1 -0
- package/dist/bch-DHsIVJqK.d.cts +74 -0
- package/dist/bch-dMESlQfv.js +134 -0
- package/dist/bch-dMESlQfv.js.map +1 -0
- package/dist/bch.cjs +13 -0
- package/dist/bch.d.cts +26 -0
- package/dist/bch.d.ts +26 -0
- package/dist/bch.js +4 -0
- package/dist/{btc-VyJKXq7d.js → btc-BmVgvvBd.js} +17 -8
- package/dist/btc-BmVgvvBd.js.map +1 -0
- package/dist/{btc-Fr6Jz4Fi.cjs → btc-BxNww6kW.cjs} +20 -11
- package/dist/btc-BxNww6kW.cjs.map +1 -0
- package/dist/{btc-DfQ0q79G.d.ts → btc-uzt0uC-Q.d.ts} +15 -4
- package/dist/{btc-Dn6_Y12c.d.cts → btc-wogJ4INA.d.cts} +15 -4
- package/dist/btc.cjs +2 -2
- package/dist/btc.d.cts +1 -1
- package/dist/btc.d.ts +1 -1
- package/dist/btc.js +2 -2
- package/dist/{cardano-yuOygqwp.js → cardano-BCT55gwf.js} +3 -2
- package/dist/{cardano-yuOygqwp.js.map → cardano-BCT55gwf.js.map} +1 -1
- package/dist/{cardano-DP6U_K1J.cjs → cardano-CzYswGzK.cjs} +5 -4
- package/dist/{cardano-DP6U_K1J.cjs.map → cardano-CzYswGzK.cjs.map} +1 -1
- package/dist/cardano.cjs +2 -2
- package/dist/cardano.js +2 -2
- package/dist/cashaddr-BIzawizX.js +134 -0
- package/dist/cashaddr-BIzawizX.js.map +1 -0
- package/dist/cashaddr-Ci0_8ITN.cjs +151 -0
- package/dist/cashaddr-Ci0_8ITN.cjs.map +1 -0
- package/dist/cosmos-BYrhIqRk.d.cts +77 -0
- package/dist/cosmos-DDsgtUki.cjs +113 -0
- package/dist/cosmos-DDsgtUki.cjs.map +1 -0
- package/dist/cosmos-DqyjA6lg.d.ts +77 -0
- package/dist/cosmos-jUHNxgWC.js +102 -0
- package/dist/cosmos-jUHNxgWC.js.map +1 -0
- package/dist/cosmos.cjs +10 -0
- package/dist/cosmos.d.cts +3 -0
- package/dist/cosmos.d.ts +3 -0
- package/dist/cosmos.js +3 -0
- package/dist/{derive-C4JdycUh.js → derive-00JUOkmn.js} +14 -3
- package/dist/derive-00JUOkmn.js.map +1 -0
- package/dist/{derive-CuILJRPT.cjs → derive-BuNsfWlg.cjs} +25 -2
- package/dist/derive-BuNsfWlg.cjs.map +1 -0
- package/dist/{evm-kJb3-oiR.js → evm-CI1cuZsp.js} +3 -2
- package/dist/{evm-kJb3-oiR.js.map → evm-CI1cuZsp.js.map} +1 -1
- package/dist/{evm-BHj_2OTG.cjs → evm-yfKOc2dy.cjs} +6 -5
- package/dist/{evm-BHj_2OTG.cjs.map → evm-yfKOc2dy.cjs.map} +1 -1
- package/dist/evm.cjs +2 -2
- package/dist/evm.js +2 -2
- package/dist/gzip-CLzDX7AZ.cjs +79 -0
- package/dist/gzip-CLzDX7AZ.cjs.map +1 -0
- package/dist/gzip-DyZLtgJJ.js +68 -0
- package/dist/gzip-DyZLtgJJ.js.map +1 -0
- package/dist/index.cjs +120 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -3
- package/dist/index.d.ts +50 -3
- package/dist/index.js +90 -9
- package/dist/index.js.map +1 -1
- package/dist/keypath-Bvv_cfHt.js +75 -0
- package/dist/keypath-Bvv_cfHt.js.map +1 -0
- package/dist/keypath-pzm_YIfN.cjs +116 -0
- package/dist/keypath-pzm_YIfN.cjs.map +1 -0
- package/dist/{messages-17Oup0-Z.js → messages--XbVef_k.js} +39 -3
- package/dist/messages--XbVef_k.js.map +1 -0
- package/dist/{messages-BzcdWlg1.cjs → messages-orAQ52CI.cjs} +44 -2
- package/dist/messages-orAQ52CI.cjs.map +1 -0
- package/dist/{shared-B8Wc7ViU.js → shared-Bbgejrus.js} +2 -73
- package/dist/shared-Bbgejrus.js.map +1 -0
- package/dist/{shared-nISrEktU.cjs → shared-Cu2yynP9.cjs} +13 -114
- package/dist/shared-Cu2yynP9.cjs.map +1 -0
- package/dist/{solana-DdEn24X4.cjs → solana-BoQBy0hu.cjs} +6 -5
- package/dist/{solana-DdEn24X4.cjs.map → solana-BoQBy0hu.cjs.map} +1 -1
- package/dist/{solana-C7JQEAec.js → solana-BukH3AI3.js} +3 -2
- package/dist/{solana-C7JQEAec.js.map → solana-BukH3AI3.js.map} +1 -1
- package/dist/solana.cjs +2 -2
- package/dist/solana.js +2 -2
- package/dist/sui-6WX6VPlW.d.cts +49 -0
- package/dist/sui-BtbPG6Xt.js +71 -0
- package/dist/sui-BtbPG6Xt.js.map +1 -0
- package/dist/sui-CYRn331O.cjs +82 -0
- package/dist/sui-CYRn331O.cjs.map +1 -0
- package/dist/sui-DI0ruW7E.d.ts +49 -0
- package/dist/sui.cjs +10 -0
- package/dist/sui.d.cts +3 -0
- package/dist/sui.d.ts +3 -0
- package/dist/sui.js +3 -0
- package/dist/{ton-5Uvi5ifg.js → ton-BSPKU5B9.js} +3 -2
- package/dist/{ton-5Uvi5ifg.js.map → ton-BSPKU5B9.js.map} +1 -1
- package/dist/{ton-DUJGXdGa.cjs → ton-CI2s9puH.cjs} +6 -5
- package/dist/{ton-DUJGXdGa.cjs.map → ton-CI2s9puH.cjs.map} +1 -1
- package/dist/ton.cjs +2 -2
- package/dist/ton.js +2 -2
- package/dist/{tron-Bo9HnvVE.js → tron-BpUEYTPT.js} +5 -67
- package/dist/tron-BpUEYTPT.js.map +1 -0
- package/dist/{tron-CQIEqjCA.cjs → tron-DYPOg5cm.cjs} +10 -72
- package/dist/{tron-Bo9HnvVE.js.map → tron-DYPOg5cm.cjs.map} +1 -1
- package/dist/tron.cjs +3 -3
- package/dist/tron.js +3 -3
- package/dist/verify.cjs +414 -24
- package/dist/verify.cjs.map +1 -1
- package/dist/verify.d.cts +120 -1
- package/dist/verify.d.ts +120 -1
- package/dist/verify.js +408 -24
- package/dist/verify.js.map +1 -1
- package/dist/xrp-BXAeK4iH.d.cts +32 -0
- package/dist/xrp-BrHXUnX5.cjs +52 -0
- package/dist/xrp-BrHXUnX5.cjs.map +1 -0
- package/dist/xrp-C8LJO5b-.js +47 -0
- package/dist/xrp-C8LJO5b-.js.map +1 -0
- package/dist/xrp-DqCXGYEk.d.ts +32 -0
- package/dist/xrp.cjs +9 -0
- package/dist/xrp.d.cts +3 -0
- package/dist/xrp.d.ts +3 -0
- package/dist/xrp.js +3 -0
- package/package.json +49 -1
- package/sui/package.json +6 -0
- package/xrp/package.json +6 -0
- package/dist/btc-Fr6Jz4Fi.cjs.map +0 -1
- package/dist/btc-VyJKXq7d.js.map +0 -1
- package/dist/derive-C4JdycUh.js.map +0 -1
- package/dist/derive-CuILJRPT.cjs.map +0 -1
- package/dist/messages-17Oup0-Z.js.map +0 -1
- package/dist/messages-BzcdWlg1.cjs.map +0 -1
- package/dist/shared-B8Wc7ViU.js.map +0 -1
- package/dist/shared-nISrEktU.cjs.map +0 -1
- package/dist/tron-CQIEqjCA.cjs.map +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { K as EraSdkError } from "./shared-Bbgejrus.js";
|
|
2
|
+
//#region src/chains/cashaddr.ts
|
|
3
|
+
/**
|
|
4
|
+
* CashAddr codec (the Bitcoin Cash address format).
|
|
5
|
+
*
|
|
6
|
+
* Not bech32: the checksum is a 40-bit BCH code over its own generator set,
|
|
7
|
+
* and there is no separator-position rule — the payload is everything after
|
|
8
|
+
* the optional `prefix:`. The decoder takes every spec-legal spelling
|
|
9
|
+
* (bare, prefixed, all-uppercase; mixed case refused), but the DEVICE's own
|
|
10
|
+
* parser reads only the lowercase form — its prefix rebuild turns an
|
|
11
|
+
* uppercase body into a mixed-case string it then rejects, and the refusal
|
|
12
|
+
* fails open into a zero hash. Anything that goes on the wire must therefore
|
|
13
|
+
* be re-encoded through `encodeCashAddr`, never passed through verbatim;
|
|
14
|
+
* `BchChain.generateSignRequest` does exactly that.
|
|
15
|
+
*/
|
|
16
|
+
const CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
17
|
+
const CHARSET_REV = new Map([...CHARSET].map((c, i) => [c, i]));
|
|
18
|
+
/** The default (mainnet) human-readable prefix. */
|
|
19
|
+
const CASHADDR_PREFIX = "bitcoincash";
|
|
20
|
+
const GENERATOR = [
|
|
21
|
+
656907472481n,
|
|
22
|
+
522768456162n,
|
|
23
|
+
1044723512260n,
|
|
24
|
+
748107326120n,
|
|
25
|
+
130178868336n
|
|
26
|
+
];
|
|
27
|
+
function polymod(values) {
|
|
28
|
+
let c = 1n;
|
|
29
|
+
for (const d of values) {
|
|
30
|
+
const c0 = c >> 35n;
|
|
31
|
+
c = (c & 34359738367n) << 5n ^ BigInt(d);
|
|
32
|
+
for (let i = 0; i < 5; i++) if (c0 >> BigInt(i) & 1n) c ^= GENERATOR[i];
|
|
33
|
+
}
|
|
34
|
+
return c ^ 1n;
|
|
35
|
+
}
|
|
36
|
+
/** Prefix expansion: the low five bits of each character, then a zero. */
|
|
37
|
+
function expandPrefix(prefix) {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (const ch of prefix) out.push(ch.charCodeAt(0) & 31);
|
|
40
|
+
out.push(0);
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function convertBits(data, from, to, pad) {
|
|
44
|
+
let acc = 0;
|
|
45
|
+
let bits = 0;
|
|
46
|
+
const out = [];
|
|
47
|
+
const maxv = (1 << to) - 1;
|
|
48
|
+
for (const value of data) {
|
|
49
|
+
if (value < 0 || value >> from !== 0) throw new EraSdkError("invalid-props", "cashaddr: value out of range");
|
|
50
|
+
acc = acc << from | value;
|
|
51
|
+
bits += from;
|
|
52
|
+
while (bits >= to) {
|
|
53
|
+
bits -= to;
|
|
54
|
+
out.push(acc >> bits & maxv);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (pad) {
|
|
58
|
+
if (bits > 0) out.push(acc << to - bits & maxv);
|
|
59
|
+
} else if (bits >= from || (acc << to - bits & maxv) !== 0) throw new EraSdkError("invalid-props", "cashaddr: invalid padding");
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decode a CashAddr, with or without its `prefix:`. Only 20-byte P2PKH and
|
|
64
|
+
* P2SH payloads are accepted — those are the two script kinds the device
|
|
65
|
+
* builds outputs for.
|
|
66
|
+
*/
|
|
67
|
+
function decodeCashAddr(address, expectedPrefix = CASHADDR_PREFIX) {
|
|
68
|
+
if (!/^[0-9A-Za-z:]*$/.test(address)) throw new EraSdkError("invalid-props", "cashaddr: invalid character");
|
|
69
|
+
const hasUpper = /[A-Z]/.test(address);
|
|
70
|
+
const hasLower = /[a-z]/.test(address);
|
|
71
|
+
if (hasUpper && hasLower) throw new EraSdkError("invalid-props", "cashaddr: mixed-case address refused");
|
|
72
|
+
const lower = address.toLowerCase();
|
|
73
|
+
const colon = lower.lastIndexOf(":");
|
|
74
|
+
const prefix = colon === -1 ? expectedPrefix : lower.slice(0, colon);
|
|
75
|
+
const payload = colon === -1 ? lower : lower.slice(colon + 1);
|
|
76
|
+
if (prefix !== expectedPrefix) throw new EraSdkError("invalid-props", `cashaddr: prefix "${prefix}" does not match expected "${expectedPrefix}"`);
|
|
77
|
+
if (payload.length < 9) throw new EraSdkError("invalid-props", "cashaddr: payload too short");
|
|
78
|
+
const values = [];
|
|
79
|
+
for (const ch of payload) {
|
|
80
|
+
const v = CHARSET_REV.get(ch);
|
|
81
|
+
if (v === void 0) throw new EraSdkError("invalid-props", `cashaddr: invalid character "${ch}"`);
|
|
82
|
+
values.push(v);
|
|
83
|
+
}
|
|
84
|
+
if (polymod([...expandPrefix(prefix), ...values]) !== 0n) throw new EraSdkError("invalid-props", "cashaddr: checksum mismatch");
|
|
85
|
+
const data = convertBits(values.slice(0, -8), 5, 8, false);
|
|
86
|
+
if (data.length === 0) throw new EraSdkError("invalid-props", "cashaddr: empty payload");
|
|
87
|
+
const version = data[0];
|
|
88
|
+
if (version & 128) throw new EraSdkError("invalid-props", "cashaddr: reserved version bit set");
|
|
89
|
+
const typeBits = version >> 3 & 15;
|
|
90
|
+
const hashBits = [
|
|
91
|
+
160,
|
|
92
|
+
192,
|
|
93
|
+
224,
|
|
94
|
+
256,
|
|
95
|
+
320,
|
|
96
|
+
384,
|
|
97
|
+
448,
|
|
98
|
+
512
|
|
99
|
+
][version & 7];
|
|
100
|
+
if (data.length - 1 !== hashBits / 8) throw new EraSdkError("invalid-props", "cashaddr: hash length does not match version byte");
|
|
101
|
+
if (typeBits !== 0 && typeBits !== 1) throw new EraSdkError("invalid-props", `cashaddr: unsupported address type ${typeBits}`);
|
|
102
|
+
if (hashBits !== 160) throw new EraSdkError("invalid-props", "cashaddr: only 20-byte hashes are supported");
|
|
103
|
+
return {
|
|
104
|
+
type: typeBits === 0 ? "p2pkh" : "p2sh",
|
|
105
|
+
hash: Uint8Array.from(data.slice(1)),
|
|
106
|
+
prefix
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Encode a 20-byte hash160 as a CashAddr. Returns the bare form by default. */
|
|
110
|
+
function encodeCashAddr(type, hash, options) {
|
|
111
|
+
if (hash.length !== 20) throw new EraSdkError("invalid-props", "cashaddr: hash must be 20 bytes");
|
|
112
|
+
const prefix = options?.prefix ?? "bitcoincash";
|
|
113
|
+
const payload = convertBits([type === "p2pkh" ? 0 : 8, ...hash], 8, 5, true);
|
|
114
|
+
const checksum = polymod([
|
|
115
|
+
...expandPrefix(prefix),
|
|
116
|
+
...payload,
|
|
117
|
+
0,
|
|
118
|
+
0,
|
|
119
|
+
0,
|
|
120
|
+
0,
|
|
121
|
+
0,
|
|
122
|
+
0,
|
|
123
|
+
0,
|
|
124
|
+
0
|
|
125
|
+
]);
|
|
126
|
+
const suffix = [];
|
|
127
|
+
for (let i = 7; i >= 0; i--) suffix.push(Number(checksum >> BigInt(5 * i) & 31n));
|
|
128
|
+
const body = [...payload, ...suffix].map((v) => CHARSET[v]).join("");
|
|
129
|
+
return options?.withPrefix ? `${prefix}:${body}` : body;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { decodeCashAddr as n, encodeCashAddr as r, CASHADDR_PREFIX as t };
|
|
133
|
+
|
|
134
|
+
//# sourceMappingURL=cashaddr-BIzawizX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cashaddr-BIzawizX.js","names":[],"sources":["../src/chains/cashaddr.ts"],"sourcesContent":["import { EraSdkError } from '../core/errors';\n\n/**\n * CashAddr codec (the Bitcoin Cash address format).\n *\n * Not bech32: the checksum is a 40-bit BCH code over its own generator set,\n * and there is no separator-position rule — the payload is everything after\n * the optional `prefix:`. The decoder takes every spec-legal spelling\n * (bare, prefixed, all-uppercase; mixed case refused), but the DEVICE's own\n * parser reads only the lowercase form — its prefix rebuild turns an\n * uppercase body into a mixed-case string it then rejects, and the refusal\n * fails open into a zero hash. Anything that goes on the wire must therefore\n * be re-encoded through `encodeCashAddr`, never passed through verbatim;\n * `BchChain.generateSignRequest` does exactly that.\n */\n\nconst CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\nconst CHARSET_REV = new Map<string, number>([...CHARSET].map((c, i) => [c, i]));\n\n/** The default (mainnet) human-readable prefix. */\nexport const CASHADDR_PREFIX = 'bitcoincash';\n\nconst GENERATOR = [0x98f2bc8e61n, 0x79b76d99e2n, 0xf33e5fb3c4n, 0xae2eabe2a8n, 0x1e4f43e470n];\n\nfunction polymod(values: readonly number[]): bigint {\n let c = 1n;\n for (const d of values) {\n const c0 = c >> 35n;\n c = ((c & 0x07ffffffffn) << 5n) ^ BigInt(d);\n for (let i = 0; i < 5; i++) {\n if ((c0 >> BigInt(i)) & 1n) c ^= GENERATOR[i]!;\n }\n }\n return c ^ 1n;\n}\n\n/** Prefix expansion: the low five bits of each character, then a zero. */\nfunction expandPrefix(prefix: string): number[] {\n const out: number[] = [];\n for (const ch of prefix) out.push(ch.charCodeAt(0) & 0x1f);\n out.push(0);\n return out;\n}\n\nfunction convertBits(data: readonly number[], from: number, to: number, pad: boolean): number[] {\n let acc = 0;\n let bits = 0;\n const out: number[] = [];\n const maxv = (1 << to) - 1;\n for (const value of data) {\n if (value < 0 || value >> from !== 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: value out of range');\n }\n acc = (acc << from) | value;\n bits += from;\n while (bits >= to) {\n bits -= to;\n out.push((acc >> bits) & maxv);\n }\n }\n if (pad) {\n if (bits > 0) out.push((acc << (to - bits)) & maxv);\n } else if (bits >= from || ((acc << (to - bits)) & maxv) !== 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: invalid padding');\n }\n return out;\n}\n\nexport type CashAddrType = 'p2pkh' | 'p2sh';\n\nexport interface CashAddrPayload {\n readonly type: CashAddrType;\n /** The 20-byte hash160. */\n readonly hash: Uint8Array;\n readonly prefix: string;\n}\n\n/**\n * Decode a CashAddr, with or without its `prefix:`. Only 20-byte P2PKH and\n * P2SH payloads are accepted — those are the two script kinds the device\n * builds outputs for.\n */\nexport function decodeCashAddr(address: string, expectedPrefix = CASHADDR_PREFIX): CashAddrPayload {\n // ASCII only, before any case folding: the case guard below is ASCII-scoped,\n // while String.toLowerCase folds full Unicode — U+212A KELVIN SIGN would\n // otherwise slip past the guard and fold into a charset 'k'.\n if (!/^[0-9A-Za-z:]*$/.test(address)) {\n throw new EraSdkError('invalid-props', 'cashaddr: invalid character');\n }\n const hasUpper = /[A-Z]/.test(address);\n const hasLower = /[a-z]/.test(address);\n if (hasUpper && hasLower) {\n throw new EraSdkError('invalid-props', 'cashaddr: mixed-case address refused');\n }\n const lower = address.toLowerCase();\n const colon = lower.lastIndexOf(':');\n const prefix = colon === -1 ? expectedPrefix : lower.slice(0, colon);\n const payload = colon === -1 ? lower : lower.slice(colon + 1);\n if (prefix !== expectedPrefix) {\n throw new EraSdkError(\n 'invalid-props',\n `cashaddr: prefix \"${prefix}\" does not match expected \"${expectedPrefix}\"`,\n );\n }\n if (payload.length < 8 + 1) {\n throw new EraSdkError('invalid-props', 'cashaddr: payload too short');\n }\n const values: number[] = [];\n for (const ch of payload) {\n const v = CHARSET_REV.get(ch);\n if (v === undefined) {\n throw new EraSdkError('invalid-props', `cashaddr: invalid character \"${ch}\"`);\n }\n values.push(v);\n }\n if (polymod([...expandPrefix(prefix), ...values]) !== 0n) {\n throw new EraSdkError('invalid-props', 'cashaddr: checksum mismatch');\n }\n const data = convertBits(values.slice(0, -8), 5, 8, false);\n if (data.length === 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: empty payload');\n }\n const version = data[0]!;\n if (version & 0x80) {\n throw new EraSdkError('invalid-props', 'cashaddr: reserved version bit set');\n }\n const typeBits = (version >> 3) & 0x0f;\n const sizeBits = version & 0x07;\n const HASH_SIZES = [160, 192, 224, 256, 320, 384, 448, 512];\n const hashBits = HASH_SIZES[sizeBits]!;\n if (data.length - 1 !== hashBits / 8) {\n throw new EraSdkError('invalid-props', 'cashaddr: hash length does not match version byte');\n }\n if (typeBits !== 0 && typeBits !== 1) {\n throw new EraSdkError('invalid-props', `cashaddr: unsupported address type ${typeBits}`);\n }\n if (hashBits !== 160) {\n throw new EraSdkError('invalid-props', 'cashaddr: only 20-byte hashes are supported');\n }\n return {\n type: typeBits === 0 ? 'p2pkh' : 'p2sh',\n hash: Uint8Array.from(data.slice(1)),\n prefix,\n };\n}\n\n/** Encode a 20-byte hash160 as a CashAddr. Returns the bare form by default. */\nexport function encodeCashAddr(\n type: CashAddrType,\n hash: Uint8Array,\n options?: { prefix?: string | undefined; withPrefix?: boolean | undefined },\n): string {\n if (hash.length !== 20) {\n throw new EraSdkError('invalid-props', 'cashaddr: hash must be 20 bytes');\n }\n const prefix = options?.prefix ?? CASHADDR_PREFIX;\n const version = type === 'p2pkh' ? 0 : 8; // typeBits<<3 | sizeBits(160 -> 0)\n const payload = convertBits([version, ...hash], 8, 5, true);\n const checksumInput = [...expandPrefix(prefix), ...payload, 0, 0, 0, 0, 0, 0, 0, 0];\n const checksum = polymod(checksumInput);\n const suffix: number[] = [];\n for (let i = 7; i >= 0; i--) suffix.push(Number((checksum >> BigInt(5 * i)) & 0x1fn));\n const body = [...payload, ...suffix].map((v) => CHARSET[v]!).join('');\n return options?.withPrefix ? `${prefix}:${body}` : body;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
const require_shared = require("./shared-Cu2yynP9.cjs");
|
|
2
|
+
//#region src/chains/cashaddr.ts
|
|
3
|
+
/**
|
|
4
|
+
* CashAddr codec (the Bitcoin Cash address format).
|
|
5
|
+
*
|
|
6
|
+
* Not bech32: the checksum is a 40-bit BCH code over its own generator set,
|
|
7
|
+
* and there is no separator-position rule — the payload is everything after
|
|
8
|
+
* the optional `prefix:`. The decoder takes every spec-legal spelling
|
|
9
|
+
* (bare, prefixed, all-uppercase; mixed case refused), but the DEVICE's own
|
|
10
|
+
* parser reads only the lowercase form — its prefix rebuild turns an
|
|
11
|
+
* uppercase body into a mixed-case string it then rejects, and the refusal
|
|
12
|
+
* fails open into a zero hash. Anything that goes on the wire must therefore
|
|
13
|
+
* be re-encoded through `encodeCashAddr`, never passed through verbatim;
|
|
14
|
+
* `BchChain.generateSignRequest` does exactly that.
|
|
15
|
+
*/
|
|
16
|
+
const CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
17
|
+
const CHARSET_REV = new Map([...CHARSET].map((c, i) => [c, i]));
|
|
18
|
+
/** The default (mainnet) human-readable prefix. */
|
|
19
|
+
const CASHADDR_PREFIX = "bitcoincash";
|
|
20
|
+
const GENERATOR = [
|
|
21
|
+
656907472481n,
|
|
22
|
+
522768456162n,
|
|
23
|
+
1044723512260n,
|
|
24
|
+
748107326120n,
|
|
25
|
+
130178868336n
|
|
26
|
+
];
|
|
27
|
+
function polymod(values) {
|
|
28
|
+
let c = 1n;
|
|
29
|
+
for (const d of values) {
|
|
30
|
+
const c0 = c >> 35n;
|
|
31
|
+
c = (c & 34359738367n) << 5n ^ BigInt(d);
|
|
32
|
+
for (let i = 0; i < 5; i++) if (c0 >> BigInt(i) & 1n) c ^= GENERATOR[i];
|
|
33
|
+
}
|
|
34
|
+
return c ^ 1n;
|
|
35
|
+
}
|
|
36
|
+
/** Prefix expansion: the low five bits of each character, then a zero. */
|
|
37
|
+
function expandPrefix(prefix) {
|
|
38
|
+
const out = [];
|
|
39
|
+
for (const ch of prefix) out.push(ch.charCodeAt(0) & 31);
|
|
40
|
+
out.push(0);
|
|
41
|
+
return out;
|
|
42
|
+
}
|
|
43
|
+
function convertBits(data, from, to, pad) {
|
|
44
|
+
let acc = 0;
|
|
45
|
+
let bits = 0;
|
|
46
|
+
const out = [];
|
|
47
|
+
const maxv = (1 << to) - 1;
|
|
48
|
+
for (const value of data) {
|
|
49
|
+
if (value < 0 || value >> from !== 0) throw new require_shared.EraSdkError("invalid-props", "cashaddr: value out of range");
|
|
50
|
+
acc = acc << from | value;
|
|
51
|
+
bits += from;
|
|
52
|
+
while (bits >= to) {
|
|
53
|
+
bits -= to;
|
|
54
|
+
out.push(acc >> bits & maxv);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (pad) {
|
|
58
|
+
if (bits > 0) out.push(acc << to - bits & maxv);
|
|
59
|
+
} else if (bits >= from || (acc << to - bits & maxv) !== 0) throw new require_shared.EraSdkError("invalid-props", "cashaddr: invalid padding");
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Decode a CashAddr, with or without its `prefix:`. Only 20-byte P2PKH and
|
|
64
|
+
* P2SH payloads are accepted — those are the two script kinds the device
|
|
65
|
+
* builds outputs for.
|
|
66
|
+
*/
|
|
67
|
+
function decodeCashAddr(address, expectedPrefix = CASHADDR_PREFIX) {
|
|
68
|
+
if (!/^[0-9A-Za-z:]*$/.test(address)) throw new require_shared.EraSdkError("invalid-props", "cashaddr: invalid character");
|
|
69
|
+
const hasUpper = /[A-Z]/.test(address);
|
|
70
|
+
const hasLower = /[a-z]/.test(address);
|
|
71
|
+
if (hasUpper && hasLower) throw new require_shared.EraSdkError("invalid-props", "cashaddr: mixed-case address refused");
|
|
72
|
+
const lower = address.toLowerCase();
|
|
73
|
+
const colon = lower.lastIndexOf(":");
|
|
74
|
+
const prefix = colon === -1 ? expectedPrefix : lower.slice(0, colon);
|
|
75
|
+
const payload = colon === -1 ? lower : lower.slice(colon + 1);
|
|
76
|
+
if (prefix !== expectedPrefix) throw new require_shared.EraSdkError("invalid-props", `cashaddr: prefix "${prefix}" does not match expected "${expectedPrefix}"`);
|
|
77
|
+
if (payload.length < 9) throw new require_shared.EraSdkError("invalid-props", "cashaddr: payload too short");
|
|
78
|
+
const values = [];
|
|
79
|
+
for (const ch of payload) {
|
|
80
|
+
const v = CHARSET_REV.get(ch);
|
|
81
|
+
if (v === void 0) throw new require_shared.EraSdkError("invalid-props", `cashaddr: invalid character "${ch}"`);
|
|
82
|
+
values.push(v);
|
|
83
|
+
}
|
|
84
|
+
if (polymod([...expandPrefix(prefix), ...values]) !== 0n) throw new require_shared.EraSdkError("invalid-props", "cashaddr: checksum mismatch");
|
|
85
|
+
const data = convertBits(values.slice(0, -8), 5, 8, false);
|
|
86
|
+
if (data.length === 0) throw new require_shared.EraSdkError("invalid-props", "cashaddr: empty payload");
|
|
87
|
+
const version = data[0];
|
|
88
|
+
if (version & 128) throw new require_shared.EraSdkError("invalid-props", "cashaddr: reserved version bit set");
|
|
89
|
+
const typeBits = version >> 3 & 15;
|
|
90
|
+
const hashBits = [
|
|
91
|
+
160,
|
|
92
|
+
192,
|
|
93
|
+
224,
|
|
94
|
+
256,
|
|
95
|
+
320,
|
|
96
|
+
384,
|
|
97
|
+
448,
|
|
98
|
+
512
|
|
99
|
+
][version & 7];
|
|
100
|
+
if (data.length - 1 !== hashBits / 8) throw new require_shared.EraSdkError("invalid-props", "cashaddr: hash length does not match version byte");
|
|
101
|
+
if (typeBits !== 0 && typeBits !== 1) throw new require_shared.EraSdkError("invalid-props", `cashaddr: unsupported address type ${typeBits}`);
|
|
102
|
+
if (hashBits !== 160) throw new require_shared.EraSdkError("invalid-props", "cashaddr: only 20-byte hashes are supported");
|
|
103
|
+
return {
|
|
104
|
+
type: typeBits === 0 ? "p2pkh" : "p2sh",
|
|
105
|
+
hash: Uint8Array.from(data.slice(1)),
|
|
106
|
+
prefix
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/** Encode a 20-byte hash160 as a CashAddr. Returns the bare form by default. */
|
|
110
|
+
function encodeCashAddr(type, hash, options) {
|
|
111
|
+
if (hash.length !== 20) throw new require_shared.EraSdkError("invalid-props", "cashaddr: hash must be 20 bytes");
|
|
112
|
+
const prefix = options?.prefix ?? "bitcoincash";
|
|
113
|
+
const payload = convertBits([type === "p2pkh" ? 0 : 8, ...hash], 8, 5, true);
|
|
114
|
+
const checksum = polymod([
|
|
115
|
+
...expandPrefix(prefix),
|
|
116
|
+
...payload,
|
|
117
|
+
0,
|
|
118
|
+
0,
|
|
119
|
+
0,
|
|
120
|
+
0,
|
|
121
|
+
0,
|
|
122
|
+
0,
|
|
123
|
+
0,
|
|
124
|
+
0
|
|
125
|
+
]);
|
|
126
|
+
const suffix = [];
|
|
127
|
+
for (let i = 7; i >= 0; i--) suffix.push(Number(checksum >> BigInt(5 * i) & 31n));
|
|
128
|
+
const body = [...payload, ...suffix].map((v) => CHARSET[v]).join("");
|
|
129
|
+
return options?.withPrefix ? `${prefix}:${body}` : body;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
Object.defineProperty(exports, "CASHADDR_PREFIX", {
|
|
133
|
+
enumerable: true,
|
|
134
|
+
get: function() {
|
|
135
|
+
return CASHADDR_PREFIX;
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
Object.defineProperty(exports, "decodeCashAddr", {
|
|
139
|
+
enumerable: true,
|
|
140
|
+
get: function() {
|
|
141
|
+
return decodeCashAddr;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
Object.defineProperty(exports, "encodeCashAddr", {
|
|
145
|
+
enumerable: true,
|
|
146
|
+
get: function() {
|
|
147
|
+
return encodeCashAddr;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=cashaddr-Ci0_8ITN.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cashaddr-Ci0_8ITN.cjs","names":["EraSdkError"],"sources":["../src/chains/cashaddr.ts"],"sourcesContent":["import { EraSdkError } from '../core/errors';\n\n/**\n * CashAddr codec (the Bitcoin Cash address format).\n *\n * Not bech32: the checksum is a 40-bit BCH code over its own generator set,\n * and there is no separator-position rule — the payload is everything after\n * the optional `prefix:`. The decoder takes every spec-legal spelling\n * (bare, prefixed, all-uppercase; mixed case refused), but the DEVICE's own\n * parser reads only the lowercase form — its prefix rebuild turns an\n * uppercase body into a mixed-case string it then rejects, and the refusal\n * fails open into a zero hash. Anything that goes on the wire must therefore\n * be re-encoded through `encodeCashAddr`, never passed through verbatim;\n * `BchChain.generateSignRequest` does exactly that.\n */\n\nconst CHARSET = 'qpzry9x8gf2tvdw0s3jn54khce6mua7l';\n\nconst CHARSET_REV = new Map<string, number>([...CHARSET].map((c, i) => [c, i]));\n\n/** The default (mainnet) human-readable prefix. */\nexport const CASHADDR_PREFIX = 'bitcoincash';\n\nconst GENERATOR = [0x98f2bc8e61n, 0x79b76d99e2n, 0xf33e5fb3c4n, 0xae2eabe2a8n, 0x1e4f43e470n];\n\nfunction polymod(values: readonly number[]): bigint {\n let c = 1n;\n for (const d of values) {\n const c0 = c >> 35n;\n c = ((c & 0x07ffffffffn) << 5n) ^ BigInt(d);\n for (let i = 0; i < 5; i++) {\n if ((c0 >> BigInt(i)) & 1n) c ^= GENERATOR[i]!;\n }\n }\n return c ^ 1n;\n}\n\n/** Prefix expansion: the low five bits of each character, then a zero. */\nfunction expandPrefix(prefix: string): number[] {\n const out: number[] = [];\n for (const ch of prefix) out.push(ch.charCodeAt(0) & 0x1f);\n out.push(0);\n return out;\n}\n\nfunction convertBits(data: readonly number[], from: number, to: number, pad: boolean): number[] {\n let acc = 0;\n let bits = 0;\n const out: number[] = [];\n const maxv = (1 << to) - 1;\n for (const value of data) {\n if (value < 0 || value >> from !== 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: value out of range');\n }\n acc = (acc << from) | value;\n bits += from;\n while (bits >= to) {\n bits -= to;\n out.push((acc >> bits) & maxv);\n }\n }\n if (pad) {\n if (bits > 0) out.push((acc << (to - bits)) & maxv);\n } else if (bits >= from || ((acc << (to - bits)) & maxv) !== 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: invalid padding');\n }\n return out;\n}\n\nexport type CashAddrType = 'p2pkh' | 'p2sh';\n\nexport interface CashAddrPayload {\n readonly type: CashAddrType;\n /** The 20-byte hash160. */\n readonly hash: Uint8Array;\n readonly prefix: string;\n}\n\n/**\n * Decode a CashAddr, with or without its `prefix:`. Only 20-byte P2PKH and\n * P2SH payloads are accepted — those are the two script kinds the device\n * builds outputs for.\n */\nexport function decodeCashAddr(address: string, expectedPrefix = CASHADDR_PREFIX): CashAddrPayload {\n // ASCII only, before any case folding: the case guard below is ASCII-scoped,\n // while String.toLowerCase folds full Unicode — U+212A KELVIN SIGN would\n // otherwise slip past the guard and fold into a charset 'k'.\n if (!/^[0-9A-Za-z:]*$/.test(address)) {\n throw new EraSdkError('invalid-props', 'cashaddr: invalid character');\n }\n const hasUpper = /[A-Z]/.test(address);\n const hasLower = /[a-z]/.test(address);\n if (hasUpper && hasLower) {\n throw new EraSdkError('invalid-props', 'cashaddr: mixed-case address refused');\n }\n const lower = address.toLowerCase();\n const colon = lower.lastIndexOf(':');\n const prefix = colon === -1 ? expectedPrefix : lower.slice(0, colon);\n const payload = colon === -1 ? lower : lower.slice(colon + 1);\n if (prefix !== expectedPrefix) {\n throw new EraSdkError(\n 'invalid-props',\n `cashaddr: prefix \"${prefix}\" does not match expected \"${expectedPrefix}\"`,\n );\n }\n if (payload.length < 8 + 1) {\n throw new EraSdkError('invalid-props', 'cashaddr: payload too short');\n }\n const values: number[] = [];\n for (const ch of payload) {\n const v = CHARSET_REV.get(ch);\n if (v === undefined) {\n throw new EraSdkError('invalid-props', `cashaddr: invalid character \"${ch}\"`);\n }\n values.push(v);\n }\n if (polymod([...expandPrefix(prefix), ...values]) !== 0n) {\n throw new EraSdkError('invalid-props', 'cashaddr: checksum mismatch');\n }\n const data = convertBits(values.slice(0, -8), 5, 8, false);\n if (data.length === 0) {\n throw new EraSdkError('invalid-props', 'cashaddr: empty payload');\n }\n const version = data[0]!;\n if (version & 0x80) {\n throw new EraSdkError('invalid-props', 'cashaddr: reserved version bit set');\n }\n const typeBits = (version >> 3) & 0x0f;\n const sizeBits = version & 0x07;\n const HASH_SIZES = [160, 192, 224, 256, 320, 384, 448, 512];\n const hashBits = HASH_SIZES[sizeBits]!;\n if (data.length - 1 !== hashBits / 8) {\n throw new EraSdkError('invalid-props', 'cashaddr: hash length does not match version byte');\n }\n if (typeBits !== 0 && typeBits !== 1) {\n throw new EraSdkError('invalid-props', `cashaddr: unsupported address type ${typeBits}`);\n }\n if (hashBits !== 160) {\n throw new EraSdkError('invalid-props', 'cashaddr: only 20-byte hashes are supported');\n }\n return {\n type: typeBits === 0 ? 'p2pkh' : 'p2sh',\n hash: Uint8Array.from(data.slice(1)),\n prefix,\n };\n}\n\n/** Encode a 20-byte hash160 as a CashAddr. Returns the bare form by default. */\nexport function encodeCashAddr(\n type: CashAddrType,\n hash: Uint8Array,\n options?: { prefix?: string | undefined; withPrefix?: boolean | undefined },\n): string {\n if (hash.length !== 20) {\n throw new EraSdkError('invalid-props', 'cashaddr: hash must be 20 bytes');\n }\n const prefix = options?.prefix ?? CASHADDR_PREFIX;\n const version = type === 'p2pkh' ? 0 : 8; // typeBits<<3 | sizeBits(160 -> 0)\n const payload = convertBits([version, ...hash], 8, 5, true);\n const checksumInput = [...expandPrefix(prefix), ...payload, 0, 0, 0, 0, 0, 0, 0, 0];\n const checksum = polymod(checksumInput);\n const suffix: number[] = [];\n for (let i = 7; i >= 0; i--) suffix.push(Number((checksum >> BigInt(5 * i)) & 0x1fn));\n const body = [...payload, ...suffix].map((v) => CHARSET[v]!).join('');\n return options?.withPrefix ? `${prefix}:${body}` : body;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { _ as Ur, a as SignRequest, i as ExpectedReply, r as EraConnectConfig } from "./shared-CI8zhQiE.cjs";
|
|
2
|
+
//#region src/chains/cosmos.d.ts
|
|
3
|
+
/** `cosmos-sign-request` dataType (CBOR key 3). */
|
|
4
|
+
declare const CosmosDataType: {
|
|
5
|
+
/** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */
|
|
6
|
+
readonly amino: 1;
|
|
7
|
+
/** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */
|
|
8
|
+
readonly direct: 2;
|
|
9
|
+
/** SIGN_MODE_TEXTUAL (rare). */
|
|
10
|
+
readonly textual: 3;
|
|
11
|
+
/** ADR-036 arbitrary-message signing. */
|
|
12
|
+
readonly message: 4;
|
|
13
|
+
};
|
|
14
|
+
type CosmosDataType = (typeof CosmosDataType)[keyof typeof CosmosDataType];
|
|
15
|
+
interface CosmosSignRequestProps {
|
|
16
|
+
readonly requestId?: Uint8Array | string;
|
|
17
|
+
/** SignDoc bytes: canonical Amino JSON (UTF-8) or protobuf SignDoc. */
|
|
18
|
+
readonly signData: Uint8Array;
|
|
19
|
+
readonly dataType: CosmosDataType;
|
|
20
|
+
/** Full signing path, e.g. `m/44'/118'/0'/0/0`. */
|
|
21
|
+
readonly path: string;
|
|
22
|
+
readonly xfp: string | number;
|
|
23
|
+
/** Bech32 signer address — device display. */
|
|
24
|
+
readonly address?: string;
|
|
25
|
+
readonly origin?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Ethermint-family chains (Injective, Evmos, Dymension, …) sign with
|
|
29
|
+
* keccak-256 over Ethereum-style keys (`m/44'/60'/...`) and travel as an
|
|
30
|
+
* `evm-sign-request` instead.
|
|
31
|
+
*/
|
|
32
|
+
interface EthermintSignRequestProps {
|
|
33
|
+
readonly requestId?: Uint8Array | string;
|
|
34
|
+
readonly signData: Uint8Array;
|
|
35
|
+
/** Amino or Direct — the SignDoc encoding. */
|
|
36
|
+
readonly dataType: typeof CosmosDataType.amino | typeof CosmosDataType.direct;
|
|
37
|
+
/** e.g. `m/44'/60'/0'/0/0`. */
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly xfp: string | number;
|
|
40
|
+
/** The `0x…` signer address string — travels as its ASCII bytes on this wire. */
|
|
41
|
+
readonly address?: string;
|
|
42
|
+
readonly origin?: string;
|
|
43
|
+
}
|
|
44
|
+
interface CosmosSignatureResult {
|
|
45
|
+
readonly requestId: Uint8Array;
|
|
46
|
+
/** 64-byte compact secp256k1 signature (r || s). */
|
|
47
|
+
readonly signature: Uint8Array;
|
|
48
|
+
/** 33-byte compressed public key (absent on the `evm-signature` reply shape). */
|
|
49
|
+
readonly publicKey: Uint8Array | undefined;
|
|
50
|
+
}
|
|
51
|
+
declare class CosmosChain {
|
|
52
|
+
static readonly DataType: {
|
|
53
|
+
/** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */
|
|
54
|
+
readonly amino: 1;
|
|
55
|
+
/** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */
|
|
56
|
+
readonly direct: 2;
|
|
57
|
+
/** SIGN_MODE_TEXTUAL (rare). */
|
|
58
|
+
readonly textual: 3;
|
|
59
|
+
/** ADR-036 arbitrary-message signing. */
|
|
60
|
+
readonly message: 4;
|
|
61
|
+
};
|
|
62
|
+
private readonly context;
|
|
63
|
+
constructor(config?: EraConnectConfig);
|
|
64
|
+
/** Build a `cosmos-sign-request` (4101). Reply: `cosmos-signature` (4102). */
|
|
65
|
+
generateSignRequest(props: CosmosSignRequestProps): SignRequest<CosmosSignatureResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Build an `evm-sign-request` (4101, the Ethermint shape) for
|
|
68
|
+
* Injective/Evmos/Dymension-style chains. Reply: `evm-signature` (4102).
|
|
69
|
+
* The digest on these chains is keccak-256 — see `verifyCosmosSignature`.
|
|
70
|
+
*/
|
|
71
|
+
generateEthermintSignRequest(props: EthermintSignRequestProps): SignRequest<CosmosSignatureResult>;
|
|
72
|
+
/** Parse a `cosmos-signature`/`evm-signature` standalone. */
|
|
73
|
+
parseSignature(input: Ur | string, expect?: ExpectedReply): CosmosSignatureResult;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { EthermintSignRequestProps as a, CosmosSignatureResult as i, CosmosDataType as n, CosmosSignRequestProps as r, CosmosChain as t };
|
|
77
|
+
//# sourceMappingURL=cosmos-BYrhIqRk.d.cts.map
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const require_shared = require("./shared-Cu2yynP9.cjs");
|
|
2
|
+
const require_keypath = require("./keypath-pzm_YIfN.cjs");
|
|
3
|
+
//#region src/chains/cosmos.ts
|
|
4
|
+
/** `cosmos-sign-request` dataType (CBOR key 3). */
|
|
5
|
+
const CosmosDataType = {
|
|
6
|
+
/** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */
|
|
7
|
+
amino: 1,
|
|
8
|
+
/** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */
|
|
9
|
+
direct: 2,
|
|
10
|
+
/** SIGN_MODE_TEXTUAL (rare). */
|
|
11
|
+
textual: 3,
|
|
12
|
+
/** ADR-036 arbitrary-message signing. */
|
|
13
|
+
message: 4
|
|
14
|
+
};
|
|
15
|
+
const COSMOS_REPLY_TYPES = ["cosmos-signature"];
|
|
16
|
+
const ETHERMINT_REPLY_TYPES = ["evm-signature"];
|
|
17
|
+
/** EvmSignDataType on the wire: 2 = Amino SignDoc, 3 = Direct SignDoc. */
|
|
18
|
+
const ETHERMINT_WIRE_TYPE = {
|
|
19
|
+
1: 2,
|
|
20
|
+
2: 3
|
|
21
|
+
};
|
|
22
|
+
var CosmosChain = class {
|
|
23
|
+
constructor(config) {
|
|
24
|
+
this.context = require_shared.resolveContext(config);
|
|
25
|
+
}
|
|
26
|
+
/** Build a `cosmos-sign-request` (4101). Reply: `cosmos-signature` (4102). */
|
|
27
|
+
generateSignRequest(props) {
|
|
28
|
+
const requestId = require_shared.resolveRequestId(this.context, props.requestId);
|
|
29
|
+
const path = require_keypath.parsePath(props.path);
|
|
30
|
+
const xfp = require_keypath.normalizeXfp(props.xfp);
|
|
31
|
+
if (props.signData.length === 0) throw new require_shared.EraSdkError("invalid-props", "signData must not be empty");
|
|
32
|
+
const entries = [
|
|
33
|
+
[1, require_shared.cbTag(37, require_shared.cbBytes(requestId))],
|
|
34
|
+
[2, require_shared.cbBytes(props.signData)],
|
|
35
|
+
[3, require_shared.cbUint(props.dataType)],
|
|
36
|
+
[4, require_shared.cbArray([require_keypath.keypath304(path, xfp)])]
|
|
37
|
+
];
|
|
38
|
+
if (props.address !== void 0) entries.push([5, require_shared.cbArray([require_shared.cbText(props.address)])]);
|
|
39
|
+
entries.push([6, require_shared.cbText(props.origin ?? this.context.origin)]);
|
|
40
|
+
const ur = new require_shared.Ur("cosmos-sign-request", require_shared.cborEncode(require_shared.cbMap(entries)));
|
|
41
|
+
return require_shared.makeSignRequest({
|
|
42
|
+
ur,
|
|
43
|
+
requestId,
|
|
44
|
+
replyTypes: COSMOS_REPLY_TYPES,
|
|
45
|
+
context: this.context,
|
|
46
|
+
parse: (reply) => parseCosmosSignature(reply, requestId, [...COSMOS_REPLY_TYPES])
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build an `evm-sign-request` (4101, the Ethermint shape) for
|
|
51
|
+
* Injective/Evmos/Dymension-style chains. Reply: `evm-signature` (4102).
|
|
52
|
+
* The digest on these chains is keccak-256 — see `verifyCosmosSignature`.
|
|
53
|
+
*/
|
|
54
|
+
generateEthermintSignRequest(props) {
|
|
55
|
+
const requestId = require_shared.resolveRequestId(this.context, props.requestId);
|
|
56
|
+
const path = require_keypath.parsePath(props.path);
|
|
57
|
+
const xfp = require_keypath.normalizeXfp(props.xfp);
|
|
58
|
+
if (props.signData.length === 0) throw new require_shared.EraSdkError("invalid-props", "signData must not be empty");
|
|
59
|
+
const wireType = ETHERMINT_WIRE_TYPE[props.dataType];
|
|
60
|
+
if (wireType === void 0) throw new require_shared.EraSdkError("invalid-props", "Ethermint requests are Amino or Direct only");
|
|
61
|
+
const entries = [
|
|
62
|
+
[1, require_shared.cbTag(37, require_shared.cbBytes(requestId))],
|
|
63
|
+
[2, require_shared.cbBytes(props.signData)],
|
|
64
|
+
[3, require_shared.cbUint(wireType)],
|
|
65
|
+
[4, require_shared.cbUint(0)],
|
|
66
|
+
[5, require_keypath.keypath304(path, xfp)]
|
|
67
|
+
];
|
|
68
|
+
if (props.address !== void 0) entries.push([6, require_shared.cbBytes(require_shared.utf8Encode(props.address))]);
|
|
69
|
+
entries.push([7, require_shared.cbText(props.origin ?? this.context.origin)]);
|
|
70
|
+
const ur = new require_shared.Ur("evm-sign-request", require_shared.cborEncode(require_shared.cbMap(entries)));
|
|
71
|
+
return require_shared.makeSignRequest({
|
|
72
|
+
ur,
|
|
73
|
+
requestId,
|
|
74
|
+
replyTypes: ETHERMINT_REPLY_TYPES,
|
|
75
|
+
context: this.context,
|
|
76
|
+
parse: (reply) => parseCosmosSignature(reply, requestId, [...ETHERMINT_REPLY_TYPES])
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** Parse a `cosmos-signature`/`evm-signature` standalone. */
|
|
80
|
+
parseSignature(input, expect) {
|
|
81
|
+
return parseCosmosSignature(require_shared.toUr(input), expect?.requestId === void 0 ? void 0 : require_shared.normalizeRequestId(expect.requestId), ["cosmos-signature", "evm-signature"]);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
CosmosChain.DataType = CosmosDataType;
|
|
85
|
+
function parseCosmosSignature(ur, expectedRequestId, replyTypes) {
|
|
86
|
+
require_shared.requireUrType(ur, replyTypes, "cosmos-signature");
|
|
87
|
+
const map = require_shared.requireReplyMap(ur, ur.type);
|
|
88
|
+
const requestId = require_shared.requireRequestIdEcho(map, 1, expectedRequestId, ur.type);
|
|
89
|
+
const signature = require_shared.asBytes(require_shared.mapGet(map, 2));
|
|
90
|
+
if (!signature || signature.length !== 64) throw new require_shared.EraSdkError("malformed-reply", `${ur.type} signature is ${signature?.length ?? 0} bytes, expected 64 (compact r||s)`);
|
|
91
|
+
const publicKey = require_shared.asBytes(require_shared.mapGet(map, 3));
|
|
92
|
+
if (publicKey !== void 0 && publicKey.length !== 33) throw new require_shared.EraSdkError("malformed-reply", `${ur.type} public key is not 33 bytes`);
|
|
93
|
+
return {
|
|
94
|
+
requestId,
|
|
95
|
+
signature,
|
|
96
|
+
publicKey
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
//#endregion
|
|
100
|
+
Object.defineProperty(exports, "CosmosChain", {
|
|
101
|
+
enumerable: true,
|
|
102
|
+
get: function() {
|
|
103
|
+
return CosmosChain;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
Object.defineProperty(exports, "CosmosDataType", {
|
|
107
|
+
enumerable: true,
|
|
108
|
+
get: function() {
|
|
109
|
+
return CosmosDataType;
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
//# sourceMappingURL=cosmos-DDsgtUki.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cosmos-DDsgtUki.cjs","names":["resolveContext","resolveRequestId","parsePath","normalizeXfp","EraSdkError","cbTag","cbBytes","cbUint","cbArray","keypath304","cbText","UrValue","cborEncode","cbMap","makeSignRequest","utf8Encode","toUr","normalizeRequestId","requireReplyMap","requireRequestIdEcho","asBytes","mapGet"],"sources":["../src/chains/cosmos.ts"],"sourcesContent":["import { cborEncode } from '../cbor/encode';\nimport type { CborValue } from '../cbor/model';\nimport { asBytes, cbArray, cbBytes, cbMap, cbTag, cbText, cbUint, mapGet } from '../cbor/model';\nimport { utf8Encode } from '../core/bytes';\nimport { EraSdkError } from '../core/errors';\nimport { normalizeRequestId } from '../core/rand';\nimport { keypath304, normalizeXfp, parsePath } from '../registry/keypath';\nimport type { Ur } from '../ur/ur';\nimport { Ur as UrValue } from '../ur/ur';\nimport type { ChainContext, EraConnectConfig, ExpectedReply, SignRequest } from './shared';\nimport {\n makeSignRequest,\n requireReplyMap,\n requireRequestIdEcho,\n requireUrType,\n resolveContext,\n resolveRequestId,\n toUr,\n} from './shared';\n\n/** `cosmos-sign-request` dataType (CBOR key 3). */\nexport const CosmosDataType = {\n /** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */\n amino: 1,\n /** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */\n direct: 2,\n /** SIGN_MODE_TEXTUAL (rare). */\n textual: 3,\n /** ADR-036 arbitrary-message signing. */\n message: 4,\n} as const;\nexport type CosmosDataType = (typeof CosmosDataType)[keyof typeof CosmosDataType];\n\nexport interface CosmosSignRequestProps {\n readonly requestId?: Uint8Array | string;\n /** SignDoc bytes: canonical Amino JSON (UTF-8) or protobuf SignDoc. */\n readonly signData: Uint8Array;\n readonly dataType: CosmosDataType;\n /** Full signing path, e.g. `m/44'/118'/0'/0/0`. */\n readonly path: string;\n readonly xfp: string | number;\n /** Bech32 signer address — device display. */\n readonly address?: string;\n readonly origin?: string;\n}\n\n/**\n * Ethermint-family chains (Injective, Evmos, Dymension, …) sign with\n * keccak-256 over Ethereum-style keys (`m/44'/60'/...`) and travel as an\n * `evm-sign-request` instead.\n */\nexport interface EthermintSignRequestProps {\n readonly requestId?: Uint8Array | string;\n readonly signData: Uint8Array;\n /** Amino or Direct — the SignDoc encoding. */\n readonly dataType: typeof CosmosDataType.amino | typeof CosmosDataType.direct;\n /** e.g. `m/44'/60'/0'/0/0`. */\n readonly path: string;\n readonly xfp: string | number;\n /** The `0x…` signer address string — travels as its ASCII bytes on this wire. */\n readonly address?: string;\n readonly origin?: string;\n}\n\nexport interface CosmosSignatureResult {\n readonly requestId: Uint8Array;\n /** 64-byte compact secp256k1 signature (r || s). */\n readonly signature: Uint8Array;\n /** 33-byte compressed public key (absent on the `evm-signature` reply shape). */\n readonly publicKey: Uint8Array | undefined;\n}\n\nconst COSMOS_REPLY_TYPES = ['cosmos-signature'] as const;\nconst ETHERMINT_REPLY_TYPES = ['evm-signature'] as const;\n\n/** EvmSignDataType on the wire: 2 = Amino SignDoc, 3 = Direct SignDoc. */\nconst ETHERMINT_WIRE_TYPE: Record<number, number> = { 1: 2, 2: 3 };\n\nexport class CosmosChain {\n static readonly DataType = CosmosDataType;\n\n private readonly context: ChainContext;\n\n constructor(config?: EraConnectConfig) {\n this.context = resolveContext(config);\n }\n\n /** Build a `cosmos-sign-request` (4101). Reply: `cosmos-signature` (4102). */\n generateSignRequest(props: CosmosSignRequestProps): SignRequest<CosmosSignatureResult> {\n const requestId = resolveRequestId(this.context, props.requestId);\n const path = parsePath(props.path);\n const xfp = normalizeXfp(props.xfp);\n if (props.signData.length === 0) {\n throw new EraSdkError('invalid-props', 'signData must not be empty');\n }\n\n const entries: [number, CborValue][] = [\n [1, cbTag(37, cbBytes(requestId))],\n [2, cbBytes(props.signData)],\n [3, cbUint(props.dataType)],\n [4, cbArray([keypath304(path, xfp)])],\n ];\n if (props.address !== undefined) entries.push([5, cbArray([cbText(props.address)])]);\n entries.push([6, cbText(props.origin ?? this.context.origin)]);\n\n const ur = new UrValue('cosmos-sign-request', cborEncode(cbMap(entries)));\n return makeSignRequest({\n ur,\n requestId,\n replyTypes: COSMOS_REPLY_TYPES,\n context: this.context,\n parse: (reply) => parseCosmosSignature(reply, requestId, [...COSMOS_REPLY_TYPES]),\n });\n }\n\n /**\n * Build an `evm-sign-request` (4101, the Ethermint shape) for\n * Injective/Evmos/Dymension-style chains. Reply: `evm-signature` (4102).\n * The digest on these chains is keccak-256 — see `verifyCosmosSignature`.\n */\n generateEthermintSignRequest(\n props: EthermintSignRequestProps,\n ): SignRequest<CosmosSignatureResult> {\n const requestId = resolveRequestId(this.context, props.requestId);\n const path = parsePath(props.path);\n const xfp = normalizeXfp(props.xfp);\n if (props.signData.length === 0) {\n throw new EraSdkError('invalid-props', 'signData must not be empty');\n }\n const wireType = ETHERMINT_WIRE_TYPE[props.dataType];\n if (wireType === undefined) {\n throw new EraSdkError('invalid-props', 'Ethermint requests are Amino or Direct only');\n }\n\n const entries: [number, CborValue][] = [\n [1, cbTag(37, cbBytes(requestId))],\n [2, cbBytes(props.signData)],\n [3, cbUint(wireType)],\n [4, cbUint(0)], // customChainId — 0, the chain resolves from the SignDoc\n [5, keypath304(path, xfp)],\n ];\n if (props.address !== undefined) {\n entries.push([6, cbBytes(utf8Encode(props.address))]); // ASCII of the 0x string\n }\n entries.push([7, cbText(props.origin ?? this.context.origin)]);\n\n const ur = new UrValue('evm-sign-request', cborEncode(cbMap(entries)));\n return makeSignRequest({\n ur,\n requestId,\n replyTypes: ETHERMINT_REPLY_TYPES,\n context: this.context,\n parse: (reply) => parseCosmosSignature(reply, requestId, [...ETHERMINT_REPLY_TYPES]),\n });\n }\n\n /** Parse a `cosmos-signature`/`evm-signature` standalone. */\n parseSignature(input: Ur | string, expect?: ExpectedReply): CosmosSignatureResult {\n return parseCosmosSignature(\n toUr(input),\n expect?.requestId === undefined ? undefined : normalizeRequestId(expect.requestId),\n ['cosmos-signature', 'evm-signature'],\n );\n }\n}\n\nfunction parseCosmosSignature(\n ur: Ur,\n expectedRequestId: Uint8Array | undefined,\n replyTypes: string[],\n): CosmosSignatureResult {\n requireUrType(ur, replyTypes, 'cosmos-signature');\n const map = requireReplyMap(ur, ur.type);\n const requestId = requireRequestIdEcho(map, 1, expectedRequestId, ur.type);\n const signature = asBytes(mapGet(map, 2));\n if (!signature || signature.length !== 64) {\n throw new EraSdkError(\n 'malformed-reply',\n `${ur.type} signature is ${signature?.length ?? 0} bytes, expected 64 (compact r||s)`,\n );\n }\n const publicKey = asBytes(mapGet(map, 3));\n if (publicKey !== undefined && publicKey.length !== 33) {\n throw new EraSdkError('malformed-reply', `${ur.type} public key is not 33 bytes`);\n }\n return { requestId, signature, publicKey };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { _ as Ur, a as SignRequest, i as ExpectedReply, r as EraConnectConfig } from "./shared-CI8zhQiE.js";
|
|
2
|
+
//#region src/chains/cosmos.d.ts
|
|
3
|
+
/** `cosmos-sign-request` dataType (CBOR key 3). */
|
|
4
|
+
declare const CosmosDataType: {
|
|
5
|
+
/** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */
|
|
6
|
+
readonly amino: 1;
|
|
7
|
+
/** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */
|
|
8
|
+
readonly direct: 2;
|
|
9
|
+
/** SIGN_MODE_TEXTUAL (rare). */
|
|
10
|
+
readonly textual: 3;
|
|
11
|
+
/** ADR-036 arbitrary-message signing. */
|
|
12
|
+
readonly message: 4;
|
|
13
|
+
};
|
|
14
|
+
type CosmosDataType = (typeof CosmosDataType)[keyof typeof CosmosDataType];
|
|
15
|
+
interface CosmosSignRequestProps {
|
|
16
|
+
readonly requestId?: Uint8Array | string;
|
|
17
|
+
/** SignDoc bytes: canonical Amino JSON (UTF-8) or protobuf SignDoc. */
|
|
18
|
+
readonly signData: Uint8Array;
|
|
19
|
+
readonly dataType: CosmosDataType;
|
|
20
|
+
/** Full signing path, e.g. `m/44'/118'/0'/0/0`. */
|
|
21
|
+
readonly path: string;
|
|
22
|
+
readonly xfp: string | number;
|
|
23
|
+
/** Bech32 signer address — device display. */
|
|
24
|
+
readonly address?: string;
|
|
25
|
+
readonly origin?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Ethermint-family chains (Injective, Evmos, Dymension, …) sign with
|
|
29
|
+
* keccak-256 over Ethereum-style keys (`m/44'/60'/...`) and travel as an
|
|
30
|
+
* `evm-sign-request` instead.
|
|
31
|
+
*/
|
|
32
|
+
interface EthermintSignRequestProps {
|
|
33
|
+
readonly requestId?: Uint8Array | string;
|
|
34
|
+
readonly signData: Uint8Array;
|
|
35
|
+
/** Amino or Direct — the SignDoc encoding. */
|
|
36
|
+
readonly dataType: typeof CosmosDataType.amino | typeof CosmosDataType.direct;
|
|
37
|
+
/** e.g. `m/44'/60'/0'/0/0`. */
|
|
38
|
+
readonly path: string;
|
|
39
|
+
readonly xfp: string | number;
|
|
40
|
+
/** The `0x…` signer address string — travels as its ASCII bytes on this wire. */
|
|
41
|
+
readonly address?: string;
|
|
42
|
+
readonly origin?: string;
|
|
43
|
+
}
|
|
44
|
+
interface CosmosSignatureResult {
|
|
45
|
+
readonly requestId: Uint8Array;
|
|
46
|
+
/** 64-byte compact secp256k1 signature (r || s). */
|
|
47
|
+
readonly signature: Uint8Array;
|
|
48
|
+
/** 33-byte compressed public key (absent on the `evm-signature` reply shape). */
|
|
49
|
+
readonly publicKey: Uint8Array | undefined;
|
|
50
|
+
}
|
|
51
|
+
declare class CosmosChain {
|
|
52
|
+
static readonly DataType: {
|
|
53
|
+
/** SIGN_MODE_LEGACY_AMINO_JSON — `signData` is the canonical JSON (UTF-8 bytes). */
|
|
54
|
+
readonly amino: 1;
|
|
55
|
+
/** SIGN_MODE_DIRECT — `signData` is the protobuf-encoded SignDoc. */
|
|
56
|
+
readonly direct: 2;
|
|
57
|
+
/** SIGN_MODE_TEXTUAL (rare). */
|
|
58
|
+
readonly textual: 3;
|
|
59
|
+
/** ADR-036 arbitrary-message signing. */
|
|
60
|
+
readonly message: 4;
|
|
61
|
+
};
|
|
62
|
+
private readonly context;
|
|
63
|
+
constructor(config?: EraConnectConfig);
|
|
64
|
+
/** Build a `cosmos-sign-request` (4101). Reply: `cosmos-signature` (4102). */
|
|
65
|
+
generateSignRequest(props: CosmosSignRequestProps): SignRequest<CosmosSignatureResult>;
|
|
66
|
+
/**
|
|
67
|
+
* Build an `evm-sign-request` (4101, the Ethermint shape) for
|
|
68
|
+
* Injective/Evmos/Dymension-style chains. Reply: `evm-signature` (4102).
|
|
69
|
+
* The digest on these chains is keccak-256 — see `verifyCosmosSignature`.
|
|
70
|
+
*/
|
|
71
|
+
generateEthermintSignRequest(props: EthermintSignRequestProps): SignRequest<CosmosSignatureResult>;
|
|
72
|
+
/** Parse a `cosmos-signature`/`evm-signature` standalone. */
|
|
73
|
+
parseSignature(input: Ur | string, expect?: ExpectedReply): CosmosSignatureResult;
|
|
74
|
+
}
|
|
75
|
+
//#endregion
|
|
76
|
+
export { EthermintSignRequestProps as a, CosmosSignatureResult as i, CosmosDataType as n, CosmosSignRequestProps as r, CosmosChain as t };
|
|
77
|
+
//# sourceMappingURL=cosmos-DqyjA6lg.d.ts.map
|