dcr-ts 0.2.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/CHANGELOG.md +563 -0
- package/LICENSE +15 -0
- package/README.md +259 -0
- package/SECURITY.md +106 -0
- package/dist/index.cjs +2424 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +955 -0
- package/dist/index.d.ts +955 -0
- package/dist/index.js +2328 -0
- package/dist/index.js.map +1 -0
- package/package.json +76 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,955 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors.
|
|
3
|
+
*
|
|
4
|
+
* Everything this library throws is a {@link DcrError} carrying a stable
|
|
5
|
+
* {@link DcrErrorCode}. Without one, the only way to tell a mistyped address from
|
|
6
|
+
* a right-address-wrong-network paste is to match on prose — which is not part of
|
|
7
|
+
* any API, breaks the moment a message is reworded, and cannot express the cases
|
|
8
|
+
* that share wording. The tests in this repository had exactly that problem.
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* try {
|
|
12
|
+
* addressToScript(pasted, mainnet);
|
|
13
|
+
* } catch (e) {
|
|
14
|
+
* if (hasErrorCode(e, "bad-checksum")) showTypoHelp();
|
|
15
|
+
* else if (hasErrorCode(e, "wrong-network")) showWrongNetworkHelp();
|
|
16
|
+
* else throw e;
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Codes are the stable part; messages are for humans and may be reworded.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* What went wrong, as a value rather than a sentence.
|
|
24
|
+
*
|
|
25
|
+
* Grouped by concern. New codes may be added in a minor release, so treat an
|
|
26
|
+
* unrecognised one as a generic failure rather than assuming the set is closed.
|
|
27
|
+
*/
|
|
28
|
+
type DcrErrorCode =
|
|
29
|
+
/** A character outside the base58 alphabet. */
|
|
30
|
+
"invalid-base58"
|
|
31
|
+
/** base58check or WIF checksum did not match. Usually a typo. */
|
|
32
|
+
| "bad-checksum"
|
|
33
|
+
/** Input longer than the format allows; rejected before the quadratic decode. */
|
|
34
|
+
| "input-too-long"
|
|
35
|
+
/** A field or payload was not the required size. */
|
|
36
|
+
| "bad-length"
|
|
37
|
+
/** A varint that could have been encoded in fewer bytes (dcrd's ErrNonCanonicalVarInt). */
|
|
38
|
+
| "non-canonical-varint"
|
|
39
|
+
/** Ran off the end of the input while reading. */
|
|
40
|
+
| "unexpected-end"
|
|
41
|
+
/** Input parsed, but bytes remained after it. */
|
|
42
|
+
| "trailing-bytes"
|
|
43
|
+
/** Not a valid private scalar (zero, or out of range for the suite's group order). */
|
|
44
|
+
| "invalid-private-key"
|
|
45
|
+
/** Wrong length or prefix, or not a point on the curve. */
|
|
46
|
+
| "invalid-public-key"
|
|
47
|
+
/** The two-byte version prefix belongs to no known network and kind. */
|
|
48
|
+
| "unknown-prefix"
|
|
49
|
+
/** Well-formed, but for a different network than the one required. */
|
|
50
|
+
| "wrong-network"
|
|
51
|
+
/** A signature-suite identifier this library does not support. */
|
|
52
|
+
| "unsupported-signature-type"
|
|
53
|
+
/** Cannot derive a hardened child from a public key. */
|
|
54
|
+
| "hardened-from-public"
|
|
55
|
+
/** The derived child is invalid; retry the next index (BIP32 says this is ~2^-127). */
|
|
56
|
+
| "invalid-child"
|
|
57
|
+
/** Refused to derive past the depth a single byte can serialize. */
|
|
58
|
+
| "max-depth"
|
|
59
|
+
/** A derivation path that does not parse. */
|
|
60
|
+
| "invalid-path"
|
|
61
|
+
/** A private-key operation was asked of a public (neutered) key. */
|
|
62
|
+
| "not-a-private-key"
|
|
63
|
+
/** Extended-key version bytes matching no known network. */
|
|
64
|
+
| "unknown-version"
|
|
65
|
+
/** Mnemonic failed its checksum, or used a word outside the wordlist. */
|
|
66
|
+
| "invalid-mnemonic"
|
|
67
|
+
/** A script whose data pushes do not tokenize (dcrd's checkScriptParses). */
|
|
68
|
+
| "malformed-script"
|
|
69
|
+
/** A signature hash type dcrd would not accept, or one wider than a byte. */
|
|
70
|
+
| "invalid-hash-type"
|
|
71
|
+
/** A push above MaxScriptElementSize, which dcrd can never execute. */
|
|
72
|
+
| "element-too-large"
|
|
73
|
+
/** A numeric argument outside its permitted range. */
|
|
74
|
+
| "out-of-range"
|
|
75
|
+
/** A numeric argument that was not an integer (includes NaN and Infinity). */
|
|
76
|
+
| "not-an-integer"
|
|
77
|
+
/** A malformed or unrepresentable amount. */
|
|
78
|
+
| "invalid-amount"
|
|
79
|
+
/** A required argument was missing or of the wrong shape. */
|
|
80
|
+
| "invalid-argument";
|
|
81
|
+
/** Every error this library throws. */
|
|
82
|
+
declare class DcrError extends Error {
|
|
83
|
+
/** Stable, machine-readable. Branch on this, not on {@link message}. */
|
|
84
|
+
readonly code: DcrErrorCode;
|
|
85
|
+
readonly name = "DcrError";
|
|
86
|
+
constructor(
|
|
87
|
+
/** Stable, machine-readable. Branch on this, not on {@link message}. */
|
|
88
|
+
code: DcrErrorCode, message: string, options?: {
|
|
89
|
+
cause?: unknown;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* True when `e` is a {@link DcrError}, including one thrown by another copy of
|
|
94
|
+
* this package loaded into the same process.
|
|
95
|
+
*/
|
|
96
|
+
declare function isDcrError(e: unknown): e is DcrError;
|
|
97
|
+
/**
|
|
98
|
+
* True when `e` is a {@link DcrError} with this code.
|
|
99
|
+
*
|
|
100
|
+
* Safe on an `unknown` from a `catch`, so it needs no type guard at the call site.
|
|
101
|
+
*/
|
|
102
|
+
declare function hasErrorCode(e: unknown, code: DcrErrorCode): boolean;
|
|
103
|
+
|
|
104
|
+
/** The BLAKE-256 digest length in bytes. */
|
|
105
|
+
declare const BLAKE256_DIGEST_LENGTH = 32;
|
|
106
|
+
/** The BLAKE-256 block length in bytes. */
|
|
107
|
+
declare const BLAKE256_BLOCK_LENGTH = 64;
|
|
108
|
+
/** Incremental BLAKE-256 hasher. */
|
|
109
|
+
declare class Blake256 {
|
|
110
|
+
private readonly h;
|
|
111
|
+
private readonly buf;
|
|
112
|
+
private buflen;
|
|
113
|
+
/** Total message bytes fed in (used for the final length encoding). */
|
|
114
|
+
private total;
|
|
115
|
+
/** Message bytes already absorbed by the compression function. */
|
|
116
|
+
private compressed;
|
|
117
|
+
private finished;
|
|
118
|
+
update(data: Uint8Array): this;
|
|
119
|
+
digest(): Uint8Array;
|
|
120
|
+
}
|
|
121
|
+
/** One-shot BLAKE-256. Returns the 32-byte digest. */
|
|
122
|
+
declare function blake256(data: Uint8Array): Uint8Array;
|
|
123
|
+
|
|
124
|
+
/** Double BLAKE-256: `blake256(blake256(data))`. */
|
|
125
|
+
declare function hash256(data: Uint8Array): Uint8Array;
|
|
126
|
+
/** RIPEMD-160 of BLAKE-256: `ripemd160(blake256(data))`. The address hash. */
|
|
127
|
+
declare function hash160(data: Uint8Array): Uint8Array;
|
|
128
|
+
|
|
129
|
+
/** Encode raw bytes as base58 (no checksum). */
|
|
130
|
+
declare function base58Encode(bytes: Uint8Array): string;
|
|
131
|
+
/**
|
|
132
|
+
* Longest base58 string that can decode to `decodedLen` bytes.
|
|
133
|
+
*
|
|
134
|
+
* base58 expands by at most log_58(256) ≈ 1.37 bytes of output per input byte,
|
|
135
|
+
* which is how dcrd derives its own bounds (`stdaddr.DecodeAddressV0`'s
|
|
136
|
+
* `maxV0AddrLen`, `hdkeychain.NewKeyFromString`'s `maxKeyLen`). Callers must cap
|
|
137
|
+
* untrusted input *before* decoding: {@link base58Decode} accumulates one BigInt
|
|
138
|
+
* digit at a time and is therefore quadratic, so an unbounded string is a cheap
|
|
139
|
+
* way to stall the event loop.
|
|
140
|
+
*/
|
|
141
|
+
declare function maxBase58Length(decodedLen: number): number;
|
|
142
|
+
/**
|
|
143
|
+
* Decode a base58 string to raw bytes. Throws on invalid characters.
|
|
144
|
+
*
|
|
145
|
+
* Cost is **quadratic** in the length of `str`. There is deliberately no length
|
|
146
|
+
* cap here, because the function is general-purpose; every decoder in this
|
|
147
|
+
* library bounds its input first via {@link maxBase58Length}, and anything
|
|
148
|
+
* calling this directly on untrusted input must do the same.
|
|
149
|
+
*/
|
|
150
|
+
declare function base58Decode(str: string): Uint8Array;
|
|
151
|
+
/** base58check-encode: append the 4-byte double-BLAKE-256 checksum. */
|
|
152
|
+
declare function checkEncode(data: Uint8Array): string;
|
|
153
|
+
/**
|
|
154
|
+
* base58check-decode and verify the checksum, returning the payload without the
|
|
155
|
+
* trailing 4 checksum bytes. Throws if the checksum does not match.
|
|
156
|
+
*
|
|
157
|
+
* Inherits {@link base58Decode}'s **quadratic** cost and its lack of a length
|
|
158
|
+
* cap, and the checksum does not change that: the whole string is decoded before
|
|
159
|
+
* there is anything to check. Cap untrusted input with {@link maxBase58Length}
|
|
160
|
+
* first, exactly as `decodeAddress`, `decodeWif` and `ExtendedKey.fromString`
|
|
161
|
+
* do before they call this — the bound is in each of those callers, not in here.
|
|
162
|
+
*/
|
|
163
|
+
declare function checkDecode(str: string): Uint8Array;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Copy `n` bytes out of `src` starting at `off`, always into a fresh buffer.
|
|
167
|
+
*
|
|
168
|
+
* Deliberately not `src.slice(off, off + n)`. `Uint8Array.prototype.slice`
|
|
169
|
+
* copies, but Node's `Buffer` overrides it to return a *view* over the same
|
|
170
|
+
* memory (deprecated, still the behaviour). Since `Buffer` is what
|
|
171
|
+
* `fs.readFileSync`, `Buffer.from(hex, "hex")`, sockets and database drivers all
|
|
172
|
+
* hand back, a `slice()` here would silently alias the caller's memory for the
|
|
173
|
+
* most common input type: reusing or zeroing that buffer afterwards would mutate
|
|
174
|
+
* an already-parsed transaction or key.
|
|
175
|
+
*/
|
|
176
|
+
declare function copyOf(src: Uint8Array, off: number, n: number): Uint8Array;
|
|
177
|
+
/** Growable little-endian byte writer. */
|
|
178
|
+
declare class Writer {
|
|
179
|
+
private buf;
|
|
180
|
+
private view;
|
|
181
|
+
private len;
|
|
182
|
+
private ensure;
|
|
183
|
+
u8(v: number): this;
|
|
184
|
+
u16(v: number): this;
|
|
185
|
+
u32(v: number): this;
|
|
186
|
+
u64(v: bigint): this;
|
|
187
|
+
/** Signed 64-bit little-endian (two's complement). Used for atom amounts. */
|
|
188
|
+
i64(v: bigint): this;
|
|
189
|
+
bytes(b: Uint8Array): this;
|
|
190
|
+
/** Compact-size varint. */
|
|
191
|
+
varInt(v: number | bigint): this;
|
|
192
|
+
/** A varint length prefix followed by the bytes themselves. */
|
|
193
|
+
varBytes(b: Uint8Array): this;
|
|
194
|
+
finish(): Uint8Array;
|
|
195
|
+
}
|
|
196
|
+
/** Little-endian byte reader. */
|
|
197
|
+
declare class Reader {
|
|
198
|
+
private readonly data;
|
|
199
|
+
private off;
|
|
200
|
+
private readonly view;
|
|
201
|
+
constructor(data: Uint8Array);
|
|
202
|
+
get offset(): number;
|
|
203
|
+
get remaining(): number;
|
|
204
|
+
private need;
|
|
205
|
+
u8(): number;
|
|
206
|
+
u16(): number;
|
|
207
|
+
u32(): number;
|
|
208
|
+
u64(): bigint;
|
|
209
|
+
/** Signed 64-bit little-endian (two's complement). */
|
|
210
|
+
i64(): bigint;
|
|
211
|
+
bytes(n: number): Uint8Array;
|
|
212
|
+
/**
|
|
213
|
+
* Compact-size varint. Rejects non-canonical encodings (a value that could
|
|
214
|
+
* have been encoded in fewer bytes), matching dcrd's `ErrNonCanonicalVarInt`.
|
|
215
|
+
* Without this check two distinct byte strings could parse to the same
|
|
216
|
+
* transaction while hashing to different ids.
|
|
217
|
+
*/
|
|
218
|
+
varInt(): number;
|
|
219
|
+
varBytes(): Uint8Array;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Decred network parameters.
|
|
224
|
+
*
|
|
225
|
+
* The magic prefix bytes, private-key IDs, extended-key version bytes and coin
|
|
226
|
+
* types are taken verbatim from dcrd's `chaincfg` package for the four
|
|
227
|
+
* networks. They are what make an address human-readable as `Ds…`/`Ts…`/`Ss…`
|
|
228
|
+
* and what bind a key to a specific network.
|
|
229
|
+
*/
|
|
230
|
+
/** Two-byte address version prefixes and related per-network identifiers. */
|
|
231
|
+
interface Network {
|
|
232
|
+
/** Human name, e.g. "mainnet". */
|
|
233
|
+
readonly name: string;
|
|
234
|
+
/** Network magic (wire protocol identifier). */
|
|
235
|
+
readonly net: number;
|
|
236
|
+
/** Leading character(s) of every address on this network (informational). */
|
|
237
|
+
readonly addressPrefix: string;
|
|
238
|
+
/** Version prefix for pay-to-pubkey (secp256k1 ECDSA) addresses. */
|
|
239
|
+
readonly pubKeyAddrId: readonly [number, number];
|
|
240
|
+
/** Version prefix for pay-to-pubkey-hash (secp256k1 ECDSA) addresses. */
|
|
241
|
+
readonly pubKeyHashAddrId: readonly [number, number];
|
|
242
|
+
/** Version prefix for pay-to-pubkey-hash (Ed25519) addresses. */
|
|
243
|
+
readonly pubKeyHashEdwardsAddrId: readonly [number, number];
|
|
244
|
+
/** Version prefix for pay-to-pubkey-hash (secp256k1 Schnorr) addresses. */
|
|
245
|
+
readonly pubKeyHashSchnorrAddrId: readonly [number, number];
|
|
246
|
+
/** Version prefix for pay-to-script-hash addresses. */
|
|
247
|
+
readonly scriptHashAddrId: readonly [number, number];
|
|
248
|
+
/** Version prefix for WIF private keys. */
|
|
249
|
+
readonly privateKeyId: readonly [number, number];
|
|
250
|
+
/** BIP32 extended private key version bytes (`dprv`/`tprv`/…). */
|
|
251
|
+
readonly hdPrivateKeyId: readonly [number, number, number, number];
|
|
252
|
+
/** BIP32 extended public key version bytes (`dpub`/`tpub`/…). */
|
|
253
|
+
readonly hdPublicKeyId: readonly [number, number, number, number];
|
|
254
|
+
/** SLIP-0044 registered coin type used in BIP44 derivation paths. */
|
|
255
|
+
readonly slip44: number;
|
|
256
|
+
}
|
|
257
|
+
declare const mainnet: Network;
|
|
258
|
+
declare const testnet3: Network;
|
|
259
|
+
declare const simnet: Network;
|
|
260
|
+
declare const regnet: Network;
|
|
261
|
+
/** All networks keyed by name. */
|
|
262
|
+
declare const networks: {
|
|
263
|
+
readonly mainnet: Network;
|
|
264
|
+
readonly testnet3: Network;
|
|
265
|
+
readonly simnet: Network;
|
|
266
|
+
readonly regnet: Network;
|
|
267
|
+
};
|
|
268
|
+
type NetworkName = keyof typeof networks;
|
|
269
|
+
|
|
270
|
+
/** The secp256k1 group order. */
|
|
271
|
+
declare const CURVE_ORDER: bigint;
|
|
272
|
+
/** True when `key` is a valid secp256k1 private scalar (0 < key < n). */
|
|
273
|
+
declare function isValidPrivateKey(key: Uint8Array): boolean;
|
|
274
|
+
/**
|
|
275
|
+
* Throw unless `key` is a usable secp256k1 private scalar.
|
|
276
|
+
*
|
|
277
|
+
* Everything that signs, or turns a private key into a public one, goes through
|
|
278
|
+
* this. `@noble` checks the same two conditions itself but throws its own plain
|
|
279
|
+
* `Error`, which escapes the typed-error contract — a caller branching on
|
|
280
|
+
* `hasErrorCode` cannot classify a zeroed or wrong-length key buffer, which is
|
|
281
|
+
* exactly the mistake worth classifying.
|
|
282
|
+
*
|
|
283
|
+
* Deliberately stricter than dcrd, which cannot express this failure at all:
|
|
284
|
+
* `secp256k1.PrivKeyFromBytes` reduces mod n and left-pads a short slice, so a
|
|
285
|
+
* zero key there signs under an all-zero-X public key and a 31-byte key is
|
|
286
|
+
* silently padded. Rejecting is the safer contract for a signing API.
|
|
287
|
+
*/
|
|
288
|
+
declare function assertPrivateKey(key: Uint8Array, who: string): void;
|
|
289
|
+
/** Compressed (33-byte) public key for a private key. */
|
|
290
|
+
declare function publicKeyFromPrivate(privateKey: Uint8Array, compressed?: boolean): Uint8Array;
|
|
291
|
+
/** True when `key` is a valid serialized secp256k1 point (compressed or not). */
|
|
292
|
+
declare function isValidPublicKey(key: Uint8Array): boolean;
|
|
293
|
+
/**
|
|
294
|
+
* True when `key` is a valid 32-byte Ed25519 public key.
|
|
295
|
+
*
|
|
296
|
+
* Decred's alternative signature suites are recognised on decode even though this
|
|
297
|
+
* library cannot sign for them, and an address whose key is not on the curve is
|
|
298
|
+
* unspendable — so it should not decode as valid. Ed25519 comes from the same
|
|
299
|
+
* `@noble/curves` package already in use, so this adds no dependency.
|
|
300
|
+
*/
|
|
301
|
+
declare function isValidEd25519PublicKey(key: Uint8Array): boolean;
|
|
302
|
+
/**
|
|
303
|
+
* Throw unless `key` is a 33-byte compressed secp256k1 point.
|
|
304
|
+
*
|
|
305
|
+
* Anything that turns a public key into an address or an output script must go
|
|
306
|
+
* through this. Length alone is not enough, and length is not even checked in the
|
|
307
|
+
* common mistake: passing a 32-byte private key where the public key was meant
|
|
308
|
+
* type-checks fine, since both are `Uint8Array`. The resulting address or script
|
|
309
|
+
* is well-formed and permanently unspendable, because no key hashes to it.
|
|
310
|
+
*/
|
|
311
|
+
declare function assertCompressedPubKey(key: Uint8Array, who: string): void;
|
|
312
|
+
/**
|
|
313
|
+
* Throw unless `key` is a serialized secp256k1 point — 33-byte compressed or
|
|
314
|
+
* 65-byte uncompressed.
|
|
315
|
+
*
|
|
316
|
+
* For hashing a key into a P2PKH address, where both serializations are
|
|
317
|
+
* legitimate and produce *different* addresses (dcrd hashes whichever form the
|
|
318
|
+
* caller holds; see `dcrutil/util.go`). Use {@link assertCompressedPubKey}
|
|
319
|
+
* wherever the format itself requires 33 bytes, such as the pay-to-pubkey address
|
|
320
|
+
* payload or a bare-P2PK script.
|
|
321
|
+
*/
|
|
322
|
+
declare function assertPubKey(key: Uint8Array, who: string): void;
|
|
323
|
+
|
|
324
|
+
type AddressKind = "pubkeyhash-ecdsa" | "pubkeyhash-ed25519" | "pubkeyhash-schnorr" | "scripthash" | "pubkey-ecdsa" | "pubkey-ed25519" | "pubkey-schnorr";
|
|
325
|
+
/** The hash-based address kinds, which carry a 20-byte `hash`. */
|
|
326
|
+
type HashAddressKind = "pubkeyhash-ecdsa" | "pubkeyhash-ed25519" | "pubkeyhash-schnorr" | "scripthash";
|
|
327
|
+
/** The pay-to-pubkey kinds, which carry a serialized `pubKey`. */
|
|
328
|
+
type PubKeyAddressKind = "pubkey-ecdsa" | "pubkey-ed25519" | "pubkey-schnorr";
|
|
329
|
+
/**
|
|
330
|
+
* A decoded address.
|
|
331
|
+
*
|
|
332
|
+
* A discriminated union on `kind`, so `hash` and `pubKey` are present exactly
|
|
333
|
+
* where they exist — narrowing on `kind` (or on `"hash" in decoded`) replaces
|
|
334
|
+
* what would otherwise be a non-null assertion at every use.
|
|
335
|
+
*/
|
|
336
|
+
type DecodedAddress = {
|
|
337
|
+
readonly network: Network;
|
|
338
|
+
readonly kind: HashAddressKind;
|
|
339
|
+
/** 20-byte hash. */
|
|
340
|
+
readonly hash: Uint8Array;
|
|
341
|
+
/** The original address string. */
|
|
342
|
+
readonly address: string;
|
|
343
|
+
} | {
|
|
344
|
+
readonly network: Network;
|
|
345
|
+
readonly kind: PubKeyAddressKind;
|
|
346
|
+
/**
|
|
347
|
+
* The serialized public key: 33-byte compressed secp256k1 for
|
|
348
|
+
* `pubkey-ecdsa` and `pubkey-schnorr`, 32-byte Ed25519 for
|
|
349
|
+
* `pubkey-ed25519`.
|
|
350
|
+
*/
|
|
351
|
+
readonly pubKey: Uint8Array;
|
|
352
|
+
readonly address: string;
|
|
353
|
+
};
|
|
354
|
+
/**
|
|
355
|
+
* Longest a version-0 address can be: a 33-byte payload (the pay-to-pubkey kind)
|
|
356
|
+
* plus a 2-byte version prefix and a 4-byte checksum. Matches dcrd's
|
|
357
|
+
* `maxV0AddrLen`.
|
|
358
|
+
*/
|
|
359
|
+
declare const MAX_ADDRESS_LENGTH: number;
|
|
360
|
+
/** Encode a 20-byte pubkey hash as a P2PKH (secp256k1 ECDSA) address. */
|
|
361
|
+
declare function pubKeyHashAddress(hash: Uint8Array, network: Network): string;
|
|
362
|
+
/** Encode a 20-byte script hash as a P2SH address. */
|
|
363
|
+
declare function scriptHashAddress(hash: Uint8Array, network: Network): string;
|
|
364
|
+
/** Encode a 20-byte pubkey hash as a P2PKH (Ed25519) address. */
|
|
365
|
+
declare function pubKeyHashEd25519Address(hash: Uint8Array, network: Network): string;
|
|
366
|
+
/** Encode a 20-byte pubkey hash as a P2PKH (secp256k1 Schnorr) address. */
|
|
367
|
+
declare function pubKeyHashSchnorrAddress(hash: Uint8Array, network: Network): string;
|
|
368
|
+
/** Encode a compressed public key as a pay-to-pubkey (secp256k1 ECDSA) address. */
|
|
369
|
+
declare function pubKeyAddress(compressedPubKey: Uint8Array, network: Network): string;
|
|
370
|
+
/** Encode a 32-byte Ed25519 public key as a pay-to-pubkey address. */
|
|
371
|
+
declare function pubKeyEd25519Address(pubKey: Uint8Array, network: Network): string;
|
|
372
|
+
/** Encode a compressed public key as a pay-to-pubkey (secp256k1 Schnorr) address. */
|
|
373
|
+
declare function pubKeySchnorrAddress(compressedPubKey: Uint8Array, network: Network): string;
|
|
374
|
+
/**
|
|
375
|
+
* Derive the standard P2PKH address for a public key (`hash160` of the key).
|
|
376
|
+
*
|
|
377
|
+
* Accepts **either** serialization: 33-byte compressed or 65-byte uncompressed.
|
|
378
|
+
* They hash to different addresses, and both are legitimate — dcrd hashes
|
|
379
|
+
* whichever form the caller holds — so refusing the uncompressed form would break
|
|
380
|
+
* the only address a signature script built with
|
|
381
|
+
* `signatureScript(..., compressed = false)` can ever satisfy.
|
|
382
|
+
*
|
|
383
|
+
* The key is validated as a real curve point. Without that, any byte string
|
|
384
|
+
* hashes to something and produces a well-formed, valid-checksum address that no
|
|
385
|
+
* key can ever spend from — and the way to hit it is mundane: passing
|
|
386
|
+
* `privateKeyBytes()` where `publicKey()` was meant type-checks silently, because
|
|
387
|
+
* both are `Uint8Array`, and 32 vs 33 bytes is invisible at the call site.
|
|
388
|
+
*/
|
|
389
|
+
declare function addressFromPubKey(pubKey: Uint8Array, network: Network): string;
|
|
390
|
+
/** Derive the P2SH address that pays to `redeemScript`. */
|
|
391
|
+
declare function addressFromScript(redeemScript: Uint8Array, network: Network): string;
|
|
392
|
+
/**
|
|
393
|
+
* Decode and validate an address. When `network` is given the address must
|
|
394
|
+
* belong to it; otherwise the network is inferred from the version prefix.
|
|
395
|
+
*/
|
|
396
|
+
declare function decodeAddress(address: string, network?: Network): DecodedAddress;
|
|
397
|
+
/** True when `address` is a well-formed address (optionally for `network`). */
|
|
398
|
+
declare function isValidAddress(address: string, network?: Network): boolean;
|
|
399
|
+
/**
|
|
400
|
+
* Build the pkScript that pays to `address`.
|
|
401
|
+
*
|
|
402
|
+
* `network` is **required**, and deliberately so. A payment script commits only
|
|
403
|
+
* to the 20-byte hash, not to the network, so `addressToScript` on a testnet
|
|
404
|
+
* address produces bytes byte-identical to the mainnet address for the same hash
|
|
405
|
+
* — a pasted testnet address would quietly pay whoever controls that hash on
|
|
406
|
+
* mainnet. Naming the expected network here is the only thing that catches it.
|
|
407
|
+
*
|
|
408
|
+
* Use {@link decodeAddress} without a network when you genuinely want to inspect
|
|
409
|
+
* an address of unknown origin; it returns the network it found.
|
|
410
|
+
*/
|
|
411
|
+
declare function addressToScript(address: string, network: Network): Uint8Array;
|
|
412
|
+
|
|
413
|
+
/** Decred signature suites, matching dcrd's `dcrec.SignatureType`. */
|
|
414
|
+
declare enum SignatureType {
|
|
415
|
+
Ecdsa = 0,
|
|
416
|
+
Ed25519 = 1,
|
|
417
|
+
SchnorrSecp256k1 = 2
|
|
418
|
+
}
|
|
419
|
+
interface DecodedWif {
|
|
420
|
+
readonly privateKey: Uint8Array;
|
|
421
|
+
readonly network: Network;
|
|
422
|
+
readonly signatureType: SignatureType;
|
|
423
|
+
}
|
|
424
|
+
/** Encode a 32-byte private key as WIF. */
|
|
425
|
+
declare function encodeWif(privateKey: Uint8Array, network: Network, signatureType?: SignatureType): string;
|
|
426
|
+
/**
|
|
427
|
+
* Longest a WIF string can be: 2 prefix + 1 suite + 32 key + 4 checksum bytes.
|
|
428
|
+
*/
|
|
429
|
+
declare const MAX_WIF_LENGTH: number;
|
|
430
|
+
/** Decode and validate a WIF string. */
|
|
431
|
+
declare function decodeWif(wif: string): DecodedWif;
|
|
432
|
+
|
|
433
|
+
declare const OP: {
|
|
434
|
+
readonly OP_0: 0;
|
|
435
|
+
readonly DATA_20: 20;
|
|
436
|
+
readonly DATA_32: 32;
|
|
437
|
+
readonly DATA_33: 33;
|
|
438
|
+
readonly PUSHDATA1: 76;
|
|
439
|
+
readonly PUSHDATA2: 77;
|
|
440
|
+
readonly PUSHDATA4: 78;
|
|
441
|
+
readonly OP_1NEGATE: 79;
|
|
442
|
+
readonly OP_1: 81;
|
|
443
|
+
readonly OP_2: 82;
|
|
444
|
+
readonly OP_16: 96;
|
|
445
|
+
readonly DUP: 118;
|
|
446
|
+
readonly EQUAL: 135;
|
|
447
|
+
readonly EQUALVERIFY: 136;
|
|
448
|
+
readonly HASH160: 169;
|
|
449
|
+
readonly CHECKSIG: 172;
|
|
450
|
+
readonly CHECKSIGALT: 190;
|
|
451
|
+
};
|
|
452
|
+
/**
|
|
453
|
+
* Largest a single stack element may be (dcrd `txscript.MaxScriptElementSize`).
|
|
454
|
+
* dcrd rejects a bigger push both when building and at execution, so anything
|
|
455
|
+
* over this can never run.
|
|
456
|
+
*/
|
|
457
|
+
declare const MAX_SCRIPT_ELEMENT_SIZE = 2048;
|
|
458
|
+
/**
|
|
459
|
+
* Encode a canonical data push — the smallest valid encoding for `data`.
|
|
460
|
+
*
|
|
461
|
+
* "Smallest" includes the small-integer opcodes, which is a consensus rule and
|
|
462
|
+
* not a policy one: dcrd's script engine applies `checkMinimalDataPush` to every
|
|
463
|
+
* executed push with no verification flag gating it, so `OP_DATA_1 0x05` fails
|
|
464
|
+
* where `OP_5` succeeds. A script built with a non-minimal push is unspendable.
|
|
465
|
+
*/
|
|
466
|
+
declare function pushData(data: Uint8Array): Uint8Array;
|
|
467
|
+
/**
|
|
468
|
+
* True when `script` tokenizes cleanly as a version-0 script — i.e. every data
|
|
469
|
+
* push declares a length that actually fits.
|
|
470
|
+
*
|
|
471
|
+
* The equivalent of dcrd's `checkScriptParses`, which its exported
|
|
472
|
+
* `CalcSignatureHash` runs before hashing. Signing against a script that does
|
|
473
|
+
* not parse produces a signature over a message dcrd would refuse to compute,
|
|
474
|
+
* so the resulting transaction can never be spent.
|
|
475
|
+
*
|
|
476
|
+
* This is a structural check only, not an execution one: it says nothing about
|
|
477
|
+
* whether the opcodes are valid or the script would succeed.
|
|
478
|
+
*/
|
|
479
|
+
declare function scriptParses(script: Uint8Array): boolean;
|
|
480
|
+
/** Build a P2PKH script: `OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY OP_CHECKSIG`. */
|
|
481
|
+
declare function payToPubKeyHashScript(hash160: Uint8Array): Uint8Array;
|
|
482
|
+
/**
|
|
483
|
+
* Build a P2PKH script for an alternative signature suite (Ed25519 = 1,
|
|
484
|
+
* secp256k1 Schnorr = 2): `OP_DUP OP_HASH160 <20-byte hash> OP_EQUALVERIFY
|
|
485
|
+
* <OP_1|OP_2> OP_CHECKSIGALT`. The signature type is pushed as a small integer.
|
|
486
|
+
*/
|
|
487
|
+
declare function payToPubKeyHashAltScript(hash160: Uint8Array, sigType: 1 | 2): Uint8Array;
|
|
488
|
+
/** Build a P2SH script: `OP_HASH160 <20-byte hash> OP_EQUAL`. */
|
|
489
|
+
declare function payToScriptHashScript(hash160: Uint8Array): Uint8Array;
|
|
490
|
+
/**
|
|
491
|
+
* Build a bare P2PK script: `<33-byte compressed pubkey> OP_CHECKSIG`.
|
|
492
|
+
*
|
|
493
|
+
* The key is validated as an actual curve point, not just measured. This is an
|
|
494
|
+
* *output* script: paying to one built around arbitrary 33 bytes burns the coins,
|
|
495
|
+
* because no signature can ever satisfy an `OP_CHECKSIG` whose key does not
|
|
496
|
+
* parse. dcrd cannot express this — its constructor takes a parsed public key.
|
|
497
|
+
*/
|
|
498
|
+
declare function payToPubKeyScript(compressedPubKey: Uint8Array): Uint8Array;
|
|
499
|
+
/**
|
|
500
|
+
* Build a pay-to-pubkey script for an alternative signature suite.
|
|
501
|
+
*
|
|
502
|
+
* Ed25519 takes a 32-byte key: `<32-byte pubkey> OP_1 OP_CHECKSIGALT`.
|
|
503
|
+
* secp256k1 Schnorr takes a 33-byte compressed key:
|
|
504
|
+
* `<33-byte pubkey> OP_2 OP_CHECKSIGALT`.
|
|
505
|
+
*
|
|
506
|
+
* The suite is pushed as a small integer, exactly as in
|
|
507
|
+
* {@link payToPubKeyHashAltScript}.
|
|
508
|
+
*/
|
|
509
|
+
declare function payToPubKeyAltScript(pubKey: Uint8Array, sigType: 1 | 2): Uint8Array;
|
|
510
|
+
/** True when `script` is a canonical version-0 P2PKH template. */
|
|
511
|
+
declare function isPayToPubKeyHash(script: Uint8Array): boolean;
|
|
512
|
+
/** True when `script` is a canonical version-0 P2SH template. */
|
|
513
|
+
declare function isPayToScriptHash(script: Uint8Array): boolean;
|
|
514
|
+
/**
|
|
515
|
+
* Extract the 20-byte hash from a P2PKH or P2SH script, or `null`.
|
|
516
|
+
*
|
|
517
|
+
* Note this deliberately loses *which* template matched, and the two need
|
|
518
|
+
* different addresses — use {@link classifyScript} when that matters, or the
|
|
519
|
+
* hash will be encoded as the wrong address kind.
|
|
520
|
+
*/
|
|
521
|
+
declare function extractHash160(script: Uint8Array): Uint8Array | null;
|
|
522
|
+
/** What {@link classifyScript} recognises. */
|
|
523
|
+
type ScriptKind = "pubkeyhash-ecdsa" | "pubkeyhash-ed25519" | "pubkeyhash-schnorr" | "scripthash";
|
|
524
|
+
/**
|
|
525
|
+
* Classify a version-0 payment script and return its 20-byte hash.
|
|
526
|
+
*
|
|
527
|
+
* {@link extractHash160} returns a bare hash for either the P2PKH or the P2SH
|
|
528
|
+
* template, so a caller labelling outputs by address has no way to tell which
|
|
529
|
+
* encoder to use — and picking wrong produces a completely different, valid
|
|
530
|
+
* address for the same script. This keeps the kind attached. Also recognises the
|
|
531
|
+
* two `OP_CHECKSIGALT` templates the library can build, which nothing could
|
|
532
|
+
* classify before.
|
|
533
|
+
*/
|
|
534
|
+
declare function classifyScript(script: Uint8Array): {
|
|
535
|
+
kind: ScriptKind;
|
|
536
|
+
hash: Uint8Array;
|
|
537
|
+
} | null;
|
|
538
|
+
|
|
539
|
+
/** Index of the first hardened child (2^31). */
|
|
540
|
+
declare const HARDENED_OFFSET = 2147483648;
|
|
541
|
+
/**
|
|
542
|
+
* Longest a `dprv`/`dpub` string can be: the 78-byte serialization plus a 4-byte
|
|
543
|
+
* checksum. Matches dcrd's `maxKeyLen` in `NewKeyFromString`.
|
|
544
|
+
*/
|
|
545
|
+
declare const MAX_EXTENDED_KEY_LENGTH: number;
|
|
546
|
+
/**
|
|
547
|
+
* Mark a BIP44 child index as hardened.
|
|
548
|
+
*
|
|
549
|
+
* Rejects anything outside `0..2^31-1`: adding the offset to an already-hardened
|
|
550
|
+
* or out-of-range index wraps, and the result would be a *non*-hardened index
|
|
551
|
+
* silently derived from the wrong branch.
|
|
552
|
+
*/
|
|
553
|
+
declare function hardened(index: number): number;
|
|
554
|
+
/** A BIP32 extended key with Decred version bytes. */
|
|
555
|
+
declare class ExtendedKey {
|
|
556
|
+
readonly network: Network;
|
|
557
|
+
readonly isPrivate: boolean;
|
|
558
|
+
/** 32-byte private scalar, or `null` for a public (neutered) key. */
|
|
559
|
+
private readonly privateKey;
|
|
560
|
+
/** 33-byte compressed public key. */
|
|
561
|
+
private readonly compressedPublicKey;
|
|
562
|
+
private readonly chainCodeBytes;
|
|
563
|
+
readonly depth: number;
|
|
564
|
+
private readonly parentFingerprintBytes;
|
|
565
|
+
readonly childNumber: number;
|
|
566
|
+
/**
|
|
567
|
+
* Whether dcrd would be holding this scalar with its leading zero bytes
|
|
568
|
+
* stripped, which changes the hardened HMAC input of its children (see the
|
|
569
|
+
* module docs). True only for keys produced by {@link derive} — dcrd strips
|
|
570
|
+
* in `child` alone, so a master key from `fromSeed` and a key parsed by
|
|
571
|
+
* `fromSerialized` are both held at full width, exactly as `NewMaster` and
|
|
572
|
+
* `NewKeyFromString` do. The scalar itself is always stored padded to 32
|
|
573
|
+
* bytes here; only the HMAC input is narrowed.
|
|
574
|
+
*/
|
|
575
|
+
private readonly scalarStripped;
|
|
576
|
+
private constructor();
|
|
577
|
+
/** Memoized hash160 of the public key; see {@link identifier}. */
|
|
578
|
+
private cachedIdentifier;
|
|
579
|
+
/**
|
|
580
|
+
* Memoized decompression of {@link compressedPublicKey}, so deriving a chain of
|
|
581
|
+
* public children does the modular square root once instead of per step. Only
|
|
582
|
+
* populated on the public-derivation path.
|
|
583
|
+
*/
|
|
584
|
+
private cachedPoint;
|
|
585
|
+
/** Derive a master key from a BIP32 seed (16–64 bytes). */
|
|
586
|
+
static fromSeed(seed: Uint8Array, network: Network): ExtendedKey;
|
|
587
|
+
/** The compressed public key (33 bytes). */
|
|
588
|
+
publicKey(): Uint8Array;
|
|
589
|
+
/** The 32-byte private scalar. Throws for a public key. */
|
|
590
|
+
privateKeyBytes(): Uint8Array;
|
|
591
|
+
/**
|
|
592
|
+
* The 32-byte chain code. A copy: the key's own derivation reads the internal
|
|
593
|
+
* bytes, so handing out a live view would let a caller change what this key
|
|
594
|
+
* derives.
|
|
595
|
+
*/
|
|
596
|
+
get chainCode(): Uint8Array;
|
|
597
|
+
/** The parent's 4-byte fingerprint, or four zero bytes for a master key. A copy. */
|
|
598
|
+
get parentFingerprint(): Uint8Array;
|
|
599
|
+
/**
|
|
600
|
+
* Identifier = hash160(compressed pubkey); the fingerprint is its first 4 bytes.
|
|
601
|
+
*
|
|
602
|
+
* Memoized, because `derive` needs the parent fingerprint for every child and
|
|
603
|
+
* would otherwise recompute a BLAKE-256 plus a RIPEMD-160 of the same key at
|
|
604
|
+
* every step. Both accessors return copies: the memo turned what used to be a
|
|
605
|
+
* per-call throwaway digest into long-lived shared state, so handing out a view
|
|
606
|
+
* would let one caller's write corrupt the cache, this key's own fingerprint,
|
|
607
|
+
* every sibling's `parentFingerprint` and every child derived afterwards.
|
|
608
|
+
*/
|
|
609
|
+
identifier(): Uint8Array;
|
|
610
|
+
fingerprint(): Uint8Array;
|
|
611
|
+
/** The memoized digest itself. Never escapes this class. */
|
|
612
|
+
private identifierBytes;
|
|
613
|
+
/**
|
|
614
|
+
* Derive a child key by index, the **Decred way** — the equivalent of dcrd
|
|
615
|
+
* `hdkeychain.Child`, and what dcrwallet and Decrediton derive with for the
|
|
616
|
+
* whole wallet path. Use {@link hardened} for hardened indices.
|
|
617
|
+
*
|
|
618
|
+
* This is the default because it is what the Decred ecosystem derives; see
|
|
619
|
+
* {@link deriveBip32Std} for the strict form and the module docs for why they
|
|
620
|
+
* differ.
|
|
621
|
+
*/
|
|
622
|
+
derive(index: number): ExtendedKey;
|
|
623
|
+
/**
|
|
624
|
+
* Derive a child key by **strict BIP32** — the equivalent of dcrd
|
|
625
|
+
* `hdkeychain.ChildBIP32Std`, retaining the leading zero bytes of the parent
|
|
626
|
+
* private key that {@link derive} strips.
|
|
627
|
+
*
|
|
628
|
+
* Produces different hardened children from {@link derive} for any parent
|
|
629
|
+
* scalar with a leading zero byte, which is about 1 key in 256 at each
|
|
630
|
+
* hardened step. Use it only when strict BIP32 is what you want; anything that
|
|
631
|
+
* has to agree with a dcrwallet or Decrediton seed must not.
|
|
632
|
+
*/
|
|
633
|
+
deriveBip32Std(index: number): ExtendedKey;
|
|
634
|
+
private deriveInner;
|
|
635
|
+
/**
|
|
636
|
+
* Derive along a path like `m/44'/42'/0'/0/0`, the **Decred way** (see
|
|
637
|
+
* {@link derive}). An apostrophe or `h` marks a hardened index.
|
|
638
|
+
*/
|
|
639
|
+
derivePath(path: string): ExtendedKey;
|
|
640
|
+
/**
|
|
641
|
+
* Derive along a path using **strict BIP32** (see {@link deriveBip32Std}).
|
|
642
|
+
* Diverges from {@link derivePath} below any hardened step whose parent scalar
|
|
643
|
+
* has a leading zero byte, so do not use it to reproduce a wallet seed.
|
|
644
|
+
*/
|
|
645
|
+
derivePathBip32Std(path: string): ExtendedKey;
|
|
646
|
+
private derivePathInner;
|
|
647
|
+
/** Return the public (watch-only) version of this key. */
|
|
648
|
+
neuter(): ExtendedKey;
|
|
649
|
+
/** The standard P2PKH address for this key on its network. */
|
|
650
|
+
address(network?: Network): string;
|
|
651
|
+
/** Serialize to the 78-byte BIP32 form (without the base58check checksum). */
|
|
652
|
+
serialize(): Uint8Array;
|
|
653
|
+
/** Encode as a `dprv`/`dpub` (or per-network) base58check string. */
|
|
654
|
+
toString(): string;
|
|
655
|
+
/** Parse an extended key string, validating the checksum and version. */
|
|
656
|
+
static fromString(str: string): ExtendedKey;
|
|
657
|
+
/**
|
|
658
|
+
* Parse a raw 78-byte serialization (checksum already verified/absent).
|
|
659
|
+
*
|
|
660
|
+
* Every field is copied out of `data`, so the returned key does not alias the
|
|
661
|
+
* caller's buffer — which matters most here, because a caller doing the right
|
|
662
|
+
* thing and wiping the serialization after parsing would otherwise destroy the
|
|
663
|
+
* key it just parsed. See {@link copyOf}.
|
|
664
|
+
*/
|
|
665
|
+
static fromSerialized(data: Uint8Array): ExtendedKey;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** A BIP39 wordlist: 2048 words. Defaults to English throughout this module. */
|
|
669
|
+
type Wordlist = readonly string[];
|
|
670
|
+
/** The English BIP39 wordlist, used wherever `wordlist` is omitted. */
|
|
671
|
+
declare const englishWordlist: Wordlist;
|
|
672
|
+
/** Generate a new mnemonic. `strength` is entropy bits (128–256, default 128). */
|
|
673
|
+
declare function generateMnemonic(strength?: number, wordlist?: Wordlist): string;
|
|
674
|
+
/** Validate a mnemonic's checksum and wordlist membership. */
|
|
675
|
+
declare function validateMnemonic(mnemonic: string, wordlist?: Wordlist): boolean;
|
|
676
|
+
/** Recover the raw entropy behind a mnemonic. */
|
|
677
|
+
declare function mnemonicToEntropy(mnemonic: string, wordlist?: Wordlist): Uint8Array;
|
|
678
|
+
/** Encode entropy (16–32 bytes, multiple of 4) as a mnemonic. */
|
|
679
|
+
declare function entropyToMnemonic(entropy: Uint8Array, wordlist?: Wordlist): string;
|
|
680
|
+
/**
|
|
681
|
+
* Expand a mnemonic (with optional passphrase) into the 64-byte BIP39 seed.
|
|
682
|
+
*
|
|
683
|
+
* Checksum-unchecked, by design: derivation does not consult a wordlist, so any
|
|
684
|
+
* phrase of a legal length expands whether or not its words are in a list and
|
|
685
|
+
* whether or not its checksum holds. Use {@link mnemonicToMasterKey} to get the
|
|
686
|
+
* checksum verified first. The word count *is* enforced: BIP39 is defined only
|
|
687
|
+
* for 12, 15, 18, 21 or 24 words.
|
|
688
|
+
*
|
|
689
|
+
* Both failures are checked here rather than caught from `@scure`, and the two
|
|
690
|
+
* checks are exhaustive: `mnemonicToSeedSync` reaches the caller's input only
|
|
691
|
+
* through `nfkd`, which rejects a non-string, and `normalize`, which rejects a
|
|
692
|
+
* word count outside the five. Its salt is `"mnemonic" + passphrase`, a
|
|
693
|
+
* concatenation that always yields a string, and its PBKDF2 parameters are
|
|
694
|
+
* constants — so nothing else in it can throw. Catching instead would report
|
|
695
|
+
* `invalid-mnemonic` for a future `@scure` failure that has nothing to do with
|
|
696
|
+
* the mnemonic, which is the one direction that wastes the most debugging time.
|
|
697
|
+
*/
|
|
698
|
+
declare function mnemonicToSeed(mnemonic: string, passphrase?: string): Uint8Array;
|
|
699
|
+
/**
|
|
700
|
+
* Expand a mnemonic straight into a Decred master {@link ExtendedKey}.
|
|
701
|
+
*
|
|
702
|
+
* The mnemonic's checksum is verified first, against `wordlist` (English by
|
|
703
|
+
* default). Because seed derivation consults no wordlist, a typo'd or
|
|
704
|
+
* mis-transcribed phrase of the right length would otherwise expand happily into
|
|
705
|
+
* a different, valid-looking wallet — one of the classic ways to lose funds while
|
|
706
|
+
* every operation appears to succeed.
|
|
707
|
+
*
|
|
708
|
+
* Pass the matching `wordlist` for a non-English phrase; validating a Spanish
|
|
709
|
+
* mnemonic against the English list would reject a perfectly good one. Use
|
|
710
|
+
* {@link mnemonicToSeed} directly if you specifically want the unchecked
|
|
711
|
+
* primitive.
|
|
712
|
+
*/
|
|
713
|
+
declare function mnemonicToMasterKey(mnemonic: string, network: Network, passphrase?: string, wordlist?: Wordlist): ExtendedKey;
|
|
714
|
+
|
|
715
|
+
/** Transaction serialization selectors (encoded in the version word). */
|
|
716
|
+
declare enum TxSerializeType {
|
|
717
|
+
Full = 0,
|
|
718
|
+
NoWitness = 1,
|
|
719
|
+
OnlyWitness = 2
|
|
720
|
+
}
|
|
721
|
+
/** Output tree: regular spends vs. the stake tree. */
|
|
722
|
+
declare enum TxTree {
|
|
723
|
+
Regular = 0,
|
|
724
|
+
Stake = 1
|
|
725
|
+
}
|
|
726
|
+
declare const DEFAULT_TX_VERSION = 1;
|
|
727
|
+
declare const MAX_SEQUENCE = 4294967295;
|
|
728
|
+
/**
|
|
729
|
+
* Sentinel "unknown" input amount / block position used for unsigned inputs,
|
|
730
|
+
* matching dcrd's `wire.NullValueIn` / `NullBlockHeight` / `NullBlockIndex`.
|
|
731
|
+
*
|
|
732
|
+
* Note the asymmetry, which is dcrd's and not a typo here: the null block
|
|
733
|
+
* *height* is `0` ("it references the genesis block") while the null block
|
|
734
|
+
* *index* is `0xffffffff`.
|
|
735
|
+
*/
|
|
736
|
+
declare const NULL_VALUE_IN = -1n;
|
|
737
|
+
declare const NULL_BLOCK_HEIGHT = 0;
|
|
738
|
+
declare const NULL_BLOCK_INDEX = 4294967295;
|
|
739
|
+
interface OutPoint {
|
|
740
|
+
/** 32-byte transaction hash in internal (serialized) byte order. */
|
|
741
|
+
hash: Uint8Array;
|
|
742
|
+
index: number;
|
|
743
|
+
tree: number;
|
|
744
|
+
}
|
|
745
|
+
interface TxInput {
|
|
746
|
+
previousOutPoint: OutPoint;
|
|
747
|
+
sequence: number;
|
|
748
|
+
valueIn: bigint;
|
|
749
|
+
blockHeight: number;
|
|
750
|
+
blockIndex: number;
|
|
751
|
+
signatureScript: Uint8Array;
|
|
752
|
+
}
|
|
753
|
+
interface TxOutput {
|
|
754
|
+
value: bigint;
|
|
755
|
+
version: number;
|
|
756
|
+
pkScript: Uint8Array;
|
|
757
|
+
}
|
|
758
|
+
/** A mutable Decred transaction. */
|
|
759
|
+
declare class Transaction {
|
|
760
|
+
version: number;
|
|
761
|
+
inputs: TxInput[];
|
|
762
|
+
outputs: TxOutput[];
|
|
763
|
+
lockTime: number;
|
|
764
|
+
expiry: number;
|
|
765
|
+
/**
|
|
766
|
+
* Add an input. Witness fields default to the "unsigned/unknown" sentinels.
|
|
767
|
+
*
|
|
768
|
+
* The outpoint and signature script are copied, so a caller that reuses or
|
|
769
|
+
* scrubs its own buffers afterwards cannot silently rewrite this transaction's
|
|
770
|
+
* bytes — which would change its txid and invalidate every signature already
|
|
771
|
+
* computed over it, with nothing to detect the change.
|
|
772
|
+
*/
|
|
773
|
+
addInput(previousOutPoint: OutPoint, opts?: Partial<Omit<TxInput, "previousOutPoint">>): this;
|
|
774
|
+
/** Add an output. The script is copied; see {@link addInput}. */
|
|
775
|
+
addOutput(value: bigint, pkScript: Uint8Array, version?: number): this;
|
|
776
|
+
private writeVersion;
|
|
777
|
+
private writePrefixBody;
|
|
778
|
+
private writeWitnessBody;
|
|
779
|
+
/** Serialize as prefix ‖ witness (the full form). */
|
|
780
|
+
serialize(): Uint8Array;
|
|
781
|
+
/** Serialize the prefix only (no witness). This is what the txid hashes. */
|
|
782
|
+
serializePrefix(): Uint8Array;
|
|
783
|
+
/** Serialize the witness only. */
|
|
784
|
+
serializeWitness(): Uint8Array;
|
|
785
|
+
/** Raw 32-byte prefix hash (internal byte order). */
|
|
786
|
+
hash(): Uint8Array;
|
|
787
|
+
/** The transaction id (reversed-hex display form of the prefix hash). */
|
|
788
|
+
txid(): string;
|
|
789
|
+
/** The witness hash id (display form). */
|
|
790
|
+
witnessTxid(): string;
|
|
791
|
+
/** The full hash id: `blake256(prefixHash ‖ witnessHash)`, display form. */
|
|
792
|
+
fullTxid(): string;
|
|
793
|
+
/**
|
|
794
|
+
* Parse a full (prefix ‖ witness) serialization.
|
|
795
|
+
*
|
|
796
|
+
* The declared input and output counts are deliberately **not** capped, where
|
|
797
|
+
* dcrd's `decodePrefix` and `decodeWitness` reject anything above
|
|
798
|
+
* `maxTxInPerMessage` (780336) or `maxTxOutPerMessage` (3728271) — the counts
|
|
799
|
+
* that could fit a 32 MiB `MaxMessagePayload`. Those bounds exist because dcrd
|
|
800
|
+
* decodes from an `io.Reader` of unknown length and sizes `make([]TxIn, count)`
|
|
801
|
+
* from the count *before* reading an input; here the argument is a `Uint8Array`
|
|
802
|
+
* whose length is already the bound, and nothing is sized from a count —
|
|
803
|
+
* `Reader` checks every read against the bytes that remain, so an inflated
|
|
804
|
+
* count fails at the first short read having allocated nothing. The only
|
|
805
|
+
* observable difference is that a blob of ~43 MiB or larger declaring more than
|
|
806
|
+
* 780336 inputs parses here and does not in dcrd; such a transaction is neither
|
|
807
|
+
* relayable (over `MaxMessagePayload`) nor valid (mainnet `MaxTxSize` is 393216
|
|
808
|
+
* bytes, 115x smaller). On a *truncated* blob both reject, only with different
|
|
809
|
+
* errors: dcrd's `ErrTooManyTxs` against this library's `unexpected-end`.
|
|
810
|
+
*
|
|
811
|
+
* Cost is still linear in `bytes.length`, so cap the size of untrusted input at
|
|
812
|
+
* the call site. dcrd's count limits would not help with that: 32 MiB holds
|
|
813
|
+
* 818400 minimal prefix inputs and the cap is 780336, so a buffer at the wire
|
|
814
|
+
* maximum stays under it.
|
|
815
|
+
*/
|
|
816
|
+
static fromBytes(bytes: Uint8Array): Transaction;
|
|
817
|
+
}
|
|
818
|
+
/** Build an OutPoint from a txid *string* (reverses to internal byte order). */
|
|
819
|
+
declare function outPointFromTxid(txid: string, index: number, tree?: TxTree): OutPoint;
|
|
820
|
+
|
|
821
|
+
declare enum SigHashType {
|
|
822
|
+
All = 1,
|
|
823
|
+
None = 2,
|
|
824
|
+
Single = 3,
|
|
825
|
+
AnyOneCanPay = 128
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* True when `hashType` is one dcrd's script engine will accept, i.e. the six
|
|
829
|
+
* values `CheckHashTypeEncoding` permits: All/None/Single, each optionally
|
|
830
|
+
* OR'ed with AnyOneCanPay.
|
|
831
|
+
*
|
|
832
|
+
* Note {@link calcSignatureHash} deliberately still computes a hash for other
|
|
833
|
+
* byte values, because dcrd's `calcSignatureHash` does — undefined types hash as
|
|
834
|
+
* if they were All. Validation belongs at the point a signature is *produced*,
|
|
835
|
+
* which is where {@link assertSignableSigHashType} is applied.
|
|
836
|
+
*/
|
|
837
|
+
declare function isSignableSigHashType(hashType: number): boolean;
|
|
838
|
+
/** Throw unless `hashType` is one dcrd's engine accepts. */
|
|
839
|
+
declare function assertSignableSigHashType(hashType: number): void;
|
|
840
|
+
/**
|
|
841
|
+
* The reusable prefix hash for `SigHashAll` without `AnyOneCanPay`.
|
|
842
|
+
*
|
|
843
|
+
* Under that hash type the prefix half of the signature hash does not depend on
|
|
844
|
+
* which input is being signed, and its serialization is byte-identical to the
|
|
845
|
+
* transaction's own prefix serialization — `SigHashSerializePrefix` and
|
|
846
|
+
* `TxSerializeNoWitness` are both `1`, and the bodies are the same. So this is
|
|
847
|
+
* exactly `tx.hash()`, and passing it to {@link calcSignatureHash} as
|
|
848
|
+
* `cachedPrefix` removes the dominant per-input cost when signing.
|
|
849
|
+
*
|
|
850
|
+
* It does **not** make signing linear. The witness half still walks every input
|
|
851
|
+
* on each call (one varint apiece), so signing N inputs stays O(N²) — but the
|
|
852
|
+
* prefix half is the expensive one, since it re-serializes every outpoint and
|
|
853
|
+
* every output script, so the constant drops by more than an order of magnitude.
|
|
854
|
+
* Measured on the hashing alone: 12x at 50 inputs, 26x at 500.
|
|
855
|
+
*
|
|
856
|
+
* This is what dcrd's `cachedPrefix` parameter exists for.
|
|
857
|
+
*/
|
|
858
|
+
declare function sigHashPrefixAll(tx: Transaction): Uint8Array;
|
|
859
|
+
/**
|
|
860
|
+
* Compute the signature hash for input `idx` of `tx` under `hashType`, with
|
|
861
|
+
* `subScript` as the script being satisfied (the prevout pkScript for P2PKH, or
|
|
862
|
+
* the redeem script for P2SH). Returns the 32-byte hash to be signed.
|
|
863
|
+
*
|
|
864
|
+
* `cachedPrefix` is an optional pre-computed prefix hash from
|
|
865
|
+
* {@link sigHashPrefixAll}, honoured only for `SigHashAll` without
|
|
866
|
+
* `AnyOneCanPay` — the one case where the prefix half is input-independent. It is
|
|
867
|
+
* ignored for every other hash type rather than trusted, so it is safe to pass
|
|
868
|
+
* for *any hash type*.
|
|
869
|
+
*
|
|
870
|
+
* It is **not** checked against `tx`, because a 32-byte hash carries nothing to
|
|
871
|
+
* check it with: it must be this transaction's current prefix hash. Passing a
|
|
872
|
+
* stale one — taken before the prefix was changed, or from a different
|
|
873
|
+
* transaction — silently produces a signature over the wrong message. Take it
|
|
874
|
+
* from the transaction you are about to sign, after the prefix is final, or use
|
|
875
|
+
* {@link signP2PKHInputs}, which does that for you.
|
|
876
|
+
*/
|
|
877
|
+
declare function calcSignatureHash(subScript: Uint8Array, hashType: SigHashType | number, tx: Transaction, idx: number, cachedPrefix?: Uint8Array): Uint8Array;
|
|
878
|
+
|
|
879
|
+
/** DER-encode a deterministic low-S ECDSA signature over a 32-byte hash. */
|
|
880
|
+
declare function signHash(hash: Uint8Array, privateKey: Uint8Array): Uint8Array;
|
|
881
|
+
/**
|
|
882
|
+
* Verify a **DER** signature over a 32-byte hash against a public key.
|
|
883
|
+
*
|
|
884
|
+
* Strictly DER, and low-S. `@noble`'s `verify` falls back to the 64-byte compact
|
|
885
|
+
* `r ‖ s` encoding when DER parsing fails, so without parsing the DER ourselves
|
|
886
|
+
* first this would accept a signature encoding dcrd's script engine rejects — a
|
|
887
|
+
* co-signer or hardware device emitting compact signatures would pass local
|
|
888
|
+
* validation and then fail consensus.
|
|
889
|
+
*/
|
|
890
|
+
declare function verifyHash(hash: Uint8Array, derSignature: Uint8Array, publicKey: Uint8Array): boolean;
|
|
891
|
+
/**
|
|
892
|
+
* Produce the raw signature for input `idx`: the DER signature over the Decred
|
|
893
|
+
* signature hash with the one-byte hash type appended (as it appears in a
|
|
894
|
+
* signature script and in a signature stack element).
|
|
895
|
+
*/
|
|
896
|
+
declare function rawTxInSignature(tx: Transaction, idx: number, subScript: Uint8Array, hashType: SigHashType | number, privateKey: Uint8Array, cachedPrefix?: Uint8Array): Uint8Array;
|
|
897
|
+
/**
|
|
898
|
+
* Build the full P2PKH signature script for input `idx`:
|
|
899
|
+
* `push(<DER-sig ‖ hashType>) push(<pubkey>)`.
|
|
900
|
+
*/
|
|
901
|
+
declare function signatureScript(tx: Transaction, idx: number, subScript: Uint8Array, hashType: SigHashType | number, privateKey: Uint8Array, compressed?: boolean, cachedPrefix?: Uint8Array): Uint8Array;
|
|
902
|
+
/**
|
|
903
|
+
* Sign input `idx` in place: compute and assign its P2PKH signature script.
|
|
904
|
+
* Returns the signed transaction for chaining.
|
|
905
|
+
*
|
|
906
|
+
* For a transaction with several inputs prefer {@link signP2PKHInputs}, which
|
|
907
|
+
* reuses one prefix hash instead of recomputing it per input.
|
|
908
|
+
*/
|
|
909
|
+
declare function signP2PKHInput(tx: Transaction, idx: number, subScript: Uint8Array, privateKey: Uint8Array, hashType?: SigHashType | number, compressed?: boolean): Transaction;
|
|
910
|
+
/** One input to sign, for {@link signP2PKHInputs}. */
|
|
911
|
+
interface P2PKHInputToSign {
|
|
912
|
+
/** Index into `tx.inputs`. */
|
|
913
|
+
idx: number;
|
|
914
|
+
/** The script being satisfied — the prevout pkScript for P2PKH. */
|
|
915
|
+
subScript: Uint8Array;
|
|
916
|
+
privateKey: Uint8Array;
|
|
917
|
+
/** Serialize the public key compressed (the default). */
|
|
918
|
+
compressed?: boolean;
|
|
919
|
+
}
|
|
920
|
+
/**
|
|
921
|
+
* Sign several P2PKH inputs in place, reusing one prefix hash.
|
|
922
|
+
*
|
|
923
|
+
* `calcSignatureHash` re-serializes and re-hashes the whole transaction prefix on
|
|
924
|
+
* every call — every outpoint and every output script — which is the dominant
|
|
925
|
+
* cost for a transaction with many inputs. Under `SigHashAll` without
|
|
926
|
+
* `AnyOneCanPay` that half is input-independent, so it is computed once here and
|
|
927
|
+
* reused, which is what dcrd's `cachedPrefix` parameter is for.
|
|
928
|
+
*
|
|
929
|
+
* This lowers the constant, not the exponent: the witness half still walks every
|
|
930
|
+
* input per call, so signing stays O(N²). On the hashing alone it measured 12x at
|
|
931
|
+
* 50 inputs and 26x at 500; end to end the gain is smaller (1.7x at 250) because
|
|
932
|
+
* ECDSA dominates.
|
|
933
|
+
*
|
|
934
|
+
* The prefix hash is taken **before** any signature script is assigned, which is
|
|
935
|
+
* also why this is correct: the prefix commits to no witness data, so writing
|
|
936
|
+
* signature scripts cannot invalidate it. For other hash types the cache is
|
|
937
|
+
* ignored and each input is hashed independently, so passing one is always safe.
|
|
938
|
+
*/
|
|
939
|
+
declare function signP2PKHInputs(tx: Transaction, toSign: readonly P2PKHInputToSign[], hashType?: SigHashType | number): Transaction;
|
|
940
|
+
|
|
941
|
+
/** Atoms in one DCR. */
|
|
942
|
+
declare const ATOMS_PER_COIN = 100000000n;
|
|
943
|
+
/** Decimal places in a DCR amount. */
|
|
944
|
+
declare const COIN_DECIMALS = 8;
|
|
945
|
+
/**
|
|
946
|
+
* Parse a decimal DCR string (e.g. "1.5", "-0.00000001") into atoms.
|
|
947
|
+
* Accepts up to 8 fractional digits; more is an error.
|
|
948
|
+
*/
|
|
949
|
+
declare function dcrToAtoms(dcr: string): bigint;
|
|
950
|
+
/**
|
|
951
|
+
* Format atoms as a fixed 8-decimal DCR string (e.g. 150000000n → "1.50000000").
|
|
952
|
+
*/
|
|
953
|
+
declare function atomsToDcr(atoms: bigint): string;
|
|
954
|
+
|
|
955
|
+
export { ATOMS_PER_COIN, type AddressKind, BLAKE256_BLOCK_LENGTH, BLAKE256_DIGEST_LENGTH, Blake256, COIN_DECIMALS, CURVE_ORDER, DEFAULT_TX_VERSION, DcrError, type DcrErrorCode, type DecodedAddress, type DecodedWif, ExtendedKey, HARDENED_OFFSET, type HashAddressKind, MAX_ADDRESS_LENGTH, MAX_EXTENDED_KEY_LENGTH, MAX_SCRIPT_ELEMENT_SIZE, MAX_SEQUENCE, MAX_WIF_LENGTH, NULL_BLOCK_HEIGHT, NULL_BLOCK_INDEX, NULL_VALUE_IN, type Network, type NetworkName, OP, type OutPoint, type P2PKHInputToSign, type PubKeyAddressKind, Reader, type ScriptKind, SigHashType, SignatureType, Transaction, type TxInput, type TxOutput, TxSerializeType, TxTree, type Wordlist, Writer, addressFromPubKey, addressFromScript, addressToScript, assertCompressedPubKey, assertPrivateKey, assertPubKey, assertSignableSigHashType, atomsToDcr, base58Decode, base58Encode, blake256, calcSignatureHash, checkDecode, checkEncode, classifyScript, copyOf, dcrToAtoms, decodeAddress, decodeWif, encodeWif, englishWordlist, entropyToMnemonic, extractHash160, generateMnemonic, hardened, hasErrorCode, hash160, hash256, isDcrError, isPayToPubKeyHash, isPayToScriptHash, isSignableSigHashType, isValidAddress, isValidEd25519PublicKey, isValidPrivateKey, isValidPublicKey, mainnet, maxBase58Length, mnemonicToEntropy, mnemonicToMasterKey, mnemonicToSeed, networks, outPointFromTxid, payToPubKeyAltScript, payToPubKeyHashAltScript, payToPubKeyHashScript, payToPubKeyScript, payToScriptHashScript, pubKeyAddress, pubKeyEd25519Address, pubKeyHashAddress, pubKeyHashEd25519Address, pubKeyHashSchnorrAddress, pubKeySchnorrAddress, publicKeyFromPrivate, pushData, rawTxInSignature, regnet, scriptHashAddress, scriptParses, sigHashPrefixAll, signHash, signP2PKHInput, signP2PKHInputs, signatureScript, simnet, testnet3, validateMnemonic, verifyHash };
|