docs: added more jsdocs

This commit is contained in:
Richard Moore 2022-12-02 21:23:13 -05:00
parent 01d99a601a
commit a74b9a557c
45 changed files with 763 additions and 81 deletions

@ -81,6 +81,27 @@ function fromBase36(value: string): bigint {
return result;
}
/**
* Returns a normalized and checksumed address for %%address%%.
* This accepts non-checksum addresses, checksum addresses and
* [[getIcapAddress]] formats.
*
* The checksum in Ethereum uses the capitalization (upper-case
* vs lower-case) of the characters within an address to encode
* its checksum, which offers, on average, a checksum of 15-bits.
*
* If %%address%% contains both upper-case and lower-case, it is
* assumed to already be a checksum address and its checksum is
* validated, and if the address fails its expected checksum an
* error is thrown.
*
* If you wish the checksum of %%address%% to be ignore, it should
* be converted to lower-case (i.e. ``.toLowercase()``) before
* being passed in. This should be a very rare situation though,
* that you wish to bypass the safegaurds in place to protect
* against an address that has been incorrectly copied from another
* source.
*/
export function getAddress(address: string): string {
assertArgument(typeof(address) === "string", "invalid address", "address", address);
@ -112,6 +133,13 @@ export function getAddress(address: string): string {
assertArgument(false, "invalid address", "address", address);
}
/**
* The [ICAP Address format](link-icap) format is an early checksum
* format which attempts to be compatible with the banking
* industry [IBAN format](link-wiki-iban] for bank accounts.
*
* It is no longer common or a recommended format.
*/
export function getIcapAddress(address: string): string {
//let base36 = _base16To36(getAddress(address).substring(2)).toUpperCase();
let base36 = BigInt(getAddress(address)).toString(36).toUpperCase();

@ -5,10 +5,17 @@ import { getAddress } from "./address.js";
import type { Addressable, AddressLike, NameResolver } from "./index.js";
/**
* Returns true if %%value%% is an object which implements the
* [[Addressable]] interface.
*/
export function isAddressable(value: any): value is Addressable {
return (value && typeof(value.getAddress) === "function");
}
/**
* Returns true if %%value%% is a valid address.
*/
export function isAddress(value: any): boolean {
try {
getAddress(value);
@ -26,8 +33,14 @@ async function checkAddress(target: any, promise: Promise<null | string>): Promi
return getAddress(result);
}
// Resolves an Ethereum address, ENS name or Addressable object,
// throwing if the result is null.
/**
* Resolves to an address for the %%target%%, which may be any
* supported address type, an [[Addressable]] or a Promise which
* resolves to an address.
*
* If an ENS name is provided, but that name has not been correctly
* configured a [[UnconfiguredNameError]] is thrown.
*/
export function resolveAddress(target: AddressLike, resolver?: null | NameResolver): string | Promise<string> {
if (typeof(target) === "string") {

@ -1,17 +1,51 @@
/**
* Addresses in Ethereum can be of several formats. These functions
* help convert between them, checksum them, etc.
* Addresses are a fundamental part of interacting with Ethereum. They
* represent the gloabal identity of Externally Owned Accounts (accounts
* backed by a private key) and contracts.
*
* The Ethereum Naming Service (ENS) provides an interconnected ecosystem
* of contracts, standards and libraries which enable looking up an
* address for an ENS name.
*
* These functions help convert between various formats, validate
* addresses and safely resolve ENS names.
*
* @_section: api/address:Addresses [addresses]
*/
null;
/**
* An interface for objects which have an address, and can
* resolve it asyncronously.
*
* This allows objects such as [[Signer]] or [[Contract]] to
* be used most places an address can be, for example getting
* the [balance](Provider-getBalance).
*/
export interface Addressable {
/**
* Get the object address.
*/
getAddress(): Promise<string>;
}
/**
* Anything that can be used to return or resolve an address.
*/
export type AddressLike = string | Promise<string> | Addressable;
/**
* An interface for any object which can resolve an ENS name.
*/
export interface NameResolver {
/**
* Resolve to the address for the ENS %%name%%.
*
* Resolves to ``null`` if the name is unconfigued. Use
* [[resolveAddress]] (passing this object as %%resolver%%) to
* throw for names that are unconfigured.
*/
resolveName(name: string): Promise<null | string>;
}

@ -1,3 +1,11 @@
/**
* An **HMAC** enables verification that a given key was used
* to authenticate a payload.
*
* See: [[link-wiki-hmac]]
*
* @_subsection: api/crypto:HMAC [about-hmac]
*/
import { createHmac } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js";
@ -12,6 +20,10 @@ const _computeHmac = function(algorithm: "sha256" | "sha512", key: Uint8Array, d
let __computeHmac = _computeHmac;
/**
* Return the HMAC for %%data%% using the %%key%% key with the underlying
* %%algo%% used for compression.
*/
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
const key = getBytes(_key, "key");
const data = getBytes(_data, "data");

@ -1,9 +1,12 @@
/**
* About Crypto?
* A fundamental building block of Ethereum is the underlying
* cryptographic primitives.
*
* @_section: api/crypto:Cryptographic Functions [crypto]
*/
null
// We import all these so we can export lock()
import { computeHmac } from "./hmac.js";
import { keccak256 } from "./keccak.js";

@ -1,3 +1,9 @@
/**
* Cryptographic hashing functions
*
* @_subsection: api/crypto:Hash Functions [about-crypto-hashing]
*/
import { keccak_256 } from "@noble/hashes/sha3";
import { getBytes, hexlify } from "../utils/index.js";

@ -1,3 +1,11 @@
/**
* A **Password-Based Key-Derivation Function** is designed to create
* a sequence of bytes suitible as a **key** from a human-rememberable
* password.
*
* @_subsection: api/crypto:Passwords [about-pbkdf]
*/
import { pbkdf2Sync } from "./crypto.js";
import { getBytes, hexlify } from "../utils/index.js";
@ -13,6 +21,13 @@ const _pbkdf2 = function(password: Uint8Array, salt: Uint8Array, iterations: num
let __pbkdf2 = _pbkdf2;
/**
* Return the [[link-pbkdf2]] for %%keylen%% bytes for %%password%% using
* the %%salt%% and using %%iterations%% of %%algo%%.
*
* This PBKDF is outdated and should not be used in new projects, but is
* required to decrypt older files.
*/
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
const password = getBytes(_password, "password");
const salt = getBytes(_salt, "salt");

@ -1,3 +1,11 @@
/**
* A **Cryptographically Secure Random Value** is one that has been
* generated with additional care take to prevent side-channels
* from allowing others to detect it and prevent others from through
* coincidence generate the same values.
*
* @_subsection: api/crypto:Random Values [about-crypto-random]
*/
import { randomBytes as crypto_random } from "./crypto.js";
let locked = false;
@ -8,6 +16,9 @@ const _randomBytes = function(length: number): Uint8Array {
let __randomBytes = _randomBytes;
/**
* Return %%length%% bytes of cryptographically secure random data.
*/
export function randomBytes(length: number): Uint8Array {
return __randomBytes(length);
}

@ -16,6 +16,7 @@ let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
/**
* Compute the cryptographic RIPEMD-160 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*/
export function ripemd160(_data: BytesLike): string {

@ -4,7 +4,12 @@ import { getBytes, hexlify as H } from "../utils/index.js";
import type { BytesLike } from "../utils/index.js";
/**
* A callback during long-running operations to update any
* UI or provide programatic access to the progress.
*
* The %%percent%% is a value between ``0`` and ``1``.
*/
export type ProgressCallback = (percent: number) => void;
@ -21,6 +26,30 @@ let __scryptAsync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number,
let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p: number, dkLen: number) => BytesLike = _scryptSync
/**
* The [[link-wiki-scrypt]] uses a memory and cpu hard method of
* derivation to increase the resource cost to brute-force a password
* for a given key.
*
* This means this algorithm is intentionally slow, and can be tuned to
* become slower. As computation and memory speed improve over time,
* increasing the difficulty maintains the cost of an attacker.
*
* For example, if a target time of 5 seconds is used, a legitimate user
* which knows their password requires only 5 seconds to unlock their
* account. A 6 character password has 68 billion possibilities, which
* would require an attacker to invest over 10,000 years of CPU time. This
* is of course a crude example (as password generally aren't random),
* but demonstrates to value of imposing large costs to decryption.
*
* For this reason, if building a UI which involved decrypting or
* encrypting datsa using scrypt, it is recommended to use a
* [[ProgressCallback]] (as event short periods can seem lik an eternity
* if the UI freezes). Including the phrase //"decrypting"// in the UI
* can also help, assuring the user their waiting is for a good reason.
*
* @_docloc: api/crypto:Passwords
*/
export async function scrypt(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number, progress?: ProgressCallback): Promise<string> {
const passwd = getBytes(_passwd, "passwd");
const salt = getBytes(_salt, "salt");
@ -34,6 +63,15 @@ scrypt.register = function(func: (passwd: Uint8Array, salt: Uint8Array, N: numbe
}
Object.freeze(scrypt);
/**
* Provides a synchronous variant of [[scrypt]].
*
* This will completely lock up and freeze the UI in a browser and will
* prevent any event loop from progressing. For this reason, it is
* preferred to use the [async variant](scrypt).
*
* @_docloc: api/crypto:Passwords
*/
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
const passwd = getBytes(_passwd, "passwd");
const salt = getBytes(_salt, "salt");

@ -22,6 +22,7 @@ let locked256 = false, locked512 = false;
/**
* Compute the cryptographic SHA2-256 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*/
export function sha256(_data: BytesLike): string {
@ -40,6 +41,7 @@ Object.freeze(sha256);
/**
* Compute the cryptographic SHA2-512 hash of %%data%%.
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*/
export function sha512(_data: BytesLike): string {

@ -21,18 +21,46 @@ secp256k1.utils.hmacSha256Sync = function(key: Uint8Array, ...messages: Array<Ui
return getBytes(computeHmac("sha256", key, concat(messages)));
}
/**
* A **SigningKey** provides high-level access to the elliptic curve
* cryptography (ECC) operations and key management.
*/
export class SigningKey {
#privateKey: string;
/**
* Creates a new **SigningKey** for %%privateKey%%.
*/
constructor(privateKey: BytesLike) {
assertArgument(dataLength(privateKey) === 32, "invalid private key", "privateKey", "[REDACTED]");
this.#privateKey = hexlify(privateKey);
}
/**
* The private key.
*/
get privateKey(): string { return this.#privateKey; }
/**
* The uncompressed public key.
*
* This will always begin with the prefix ``0x04`` and be 132
* characters long (the ``0x`` prefix and 130 hexadecimal nibbles).
*/
get publicKey(): string { return SigningKey.computePublicKey(this.#privateKey); }
/**
* The compressed public key.
*
* This will always begin with either the prefix ``0x02`` or ``0x03``
* and be 68 characters long (the ``0x`` prefix and 33 hexadecimal
* nibbles)
*/
get compressedPublicKey(): string { return SigningKey.computePublicKey(this.#privateKey, true); }
/**
* Return the signature of the signed %%digest%%.
*/
sign(digest: BytesLike): Signature {
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
@ -49,11 +77,27 @@ export class SigningKey {
});
}
/**
* Returns the [[link-wiki-ecdh]] shared secret between this
* private key and the %%other%% key.
*
* The %%other%% key may be any type of key, a raw public key,
* a compressed/uncompressed pubic key or aprivate key.
*
* Best practice is usually to use a cryptographic hash on the
* returned value before using it as a symetric secret.
*/
computeShardSecret(other: BytesLike): string {
const pubKey = SigningKey.computePublicKey(other);
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), pubKey));
}
/**
* Compute the public key for %%key%%, optionally %%compressed%%.
*
* The %%key%% may be any type of key, a raw public key, a
* compressed/uncompressed public key or private key.
*/
static computePublicKey(key: BytesLike, compressed?: boolean): string {
let bytes = getBytes(key, "key");
@ -73,6 +117,10 @@ export class SigningKey {
return hexlify(point.toRawBytes(compressed));
}
/**
* Returns the public key for the private key which produced the
* %%signature%% for the given %%digest%%.
*/
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
@ -85,7 +133,17 @@ export class SigningKey {
assertArgument(false, "invalid signautre for digest", "signature", signature);
}
static _addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
/**
* Returns the point resulting from adding the ellipic curve points
* %%p0%% and %%p1%%.
*
* This is not a common function most developers should require, but
* can be useful for certain privacy-specific techniques.
*
* For example, it is used by [[HDNodeWallet]] to compute child
* addresses from parent public keys and chain codes.
*/
static addPoints(p0: BytesLike, p1: BytesLike, compressed?: boolean): string {
const pub0 = secp256k1.Point.fromHex(SigningKey.computePublicKey(p0).substring(2));
const pub1 = secp256k1.Point.fromHex(SigningKey.computePublicKey(p1).substring(2));
return "0x" + pub0.add(pub1).toHex(!!compressed)

@ -98,7 +98,7 @@ export {
export {
Mnemonic,
BaseWallet, HDNodeWallet, HDNodeVoidWallet, HDNodeWalletManager,
BaseWallet, HDNodeWallet, HDNodeVoidWallet,
Wallet,
defaultPath,
@ -141,8 +141,8 @@ export type {
} from "./providers/index.js";
export type {
AccessList, AccessListish, AccessListSet,
SignedTransaction, TransactionLike
AccessList, AccessListish, AccessListEntry,
TransactionLike
} from "./transaction/index.js";
export type {

@ -5,12 +5,31 @@
*
* @_section: api/providers/thirdparty: Community Providers [thirdparty]
*/
/**
* Providers which offer community credentials should extend this
* to notify any interested consumers whether community credentials
* are in-use.
*/
export interface CommunityResourcable {
/**
* Returns true of the instance is connected using the community
* credentials.
*/
isCommunityResource(): boolean;
}
// Show the throttle message only once
// Show the throttle message only once per service
const shown: Set<string> = new Set();
/**
* Displays a warning in tht console when the community resource is
* being used too heavily by the app, recommending the developer
* acquire their own credentials instead of using the community
* credentials.
*
* The notification will only occur once per service.
*/
export function showThrottleMessage(service: string): void {
if (shown.has(service)) { return; }
shown.add(service);

@ -424,7 +424,7 @@ export class Block implements BlockParams, Iterable<string> {
get length(): number { return this.#transactions.length; }
/**
* The [date](link-js-data) this block was included at.
* The [[link-js-date]] this block was included at.
*/
get date(): null | Date {
if (this.timestamp == null) { return null; }

@ -14,6 +14,9 @@ function accessSetify(addr: string, storageKeys: Array<string>): { address: stri
};
}
/**
* Returns a [[AccessList]] from any ethers-supported access-list structure.
*/
export function accessListify(value: AccessListish): AccessList {
if (Array.isArray(value)) {
return (<Array<[ string, Array<string>] | { address: string, storageKeys: Array<string>}>>value).map((set, index) => {

@ -4,13 +4,21 @@
* @_section api/transaction:Transactions [transactions]
*/
/**
* Moo
*/
export type AccessListSet = { address: string, storageKeys: Array<string> };
export type AccessList = Array<AccessListSet>;
null;
// Input allows flexibility in describing an access list
/**
* A single [[AccessList]] entry of storage keys (slots) for an address.
*/
export type AccessListEntry = { address: string, storageKeys: Array<string> };
/**
* An ordered collection of [[AccessList]] entries.
*/
export type AccessList = Array<AccessListEntry>;
/**
* Any ethers-supported access list structure.
*/
export type AccessListish = AccessList |
Array<[ string, Array<string> ]> |
Record<string, Array<string>>;
@ -20,4 +28,4 @@ export { accessListify } from "./accesslist.js";
export { computeAddress, recoverAddress } from "./address.js";
export { Transaction } from "./transaction.js";
export type { SignedTransaction, TransactionLike } from "./transaction.js";
export type { TransactionLike } from "./transaction.js";

@ -23,27 +23,74 @@ const BN_35 = BigInt(35);
const BN_MAX_UINT = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
export interface TransactionLike<A = string> {
/**
* The type.
*/
type?: null | number;
/**
* The recipient address or ``null`` for an ``init`` transaction.
*/
to?: null | A;
/**
* The sender.
*/
from?: null | A;
/**
* The nonce.
*/
nonce?: null | number;
/**
* The maximum amount of gas that can be used.
*/
gasLimit?: null | BigNumberish;
/**
* The gas price for legacy and berlin transactions.
*/
gasPrice?: null | BigNumberish;
/**
* The maximum priority fee per gas for london transactions.
*/
maxPriorityFeePerGas?: null | BigNumberish;
/**
* The maximum total fee per gas for london transactions.
*/
maxFeePerGas?: null | BigNumberish;
/**
* The data.
*/
data?: null | string;
/**
* The value (in wei) to send.
*/
value?: null | BigNumberish;
/**
* The chain ID the transaction is valid on.
*/
chainId?: null | BigNumberish;
/**
* The transaction hash.
*/
hash?: null | string;
/**
* The signature provided by the sender.
*/
signature?: null | SignatureLike;
/**
* The access list for berlin and london transactions.
*/
accessList?: null | AccessListish;
}
@ -305,14 +352,24 @@ function _serializeEip2930(tx: TransactionLike, sig?: Signature): string {
return concat([ "0x01", encodeRlp(fields)]);
}
/**
* A transactions which has been signed.
*/
/*
export interface SignedTransaction extends Transaction {
type: number;
typeName: string;
from: string;
signature: Signature;
}
*/
/**
* A **Transaction** describes an operation to be executed on
* Ethereum by an Externally Owned Account (EOA). It includes
* who (the [[to]] address), what (the [[data]]) and how much (the
* [[value]] in ether) the operation should entail.
*/
export class Transaction implements TransactionLike<string> {
#type: null | number;
#to: null | string;
@ -327,17 +384,13 @@ export class Transaction implements TransactionLike<string> {
#sig: null | Signature;
#accessList: null | AccessList;
// A type of null indicates the type will be populated automatically
/**
* The transaction type.
*
* If null, the type will be automatically inferred based on
* explicit properties.
*/
get type(): null | number { return this.#type; }
get typeName(): null | string {
switch (this.type) {
case 0: return "legacy";
case 1: return "eip-2930";
case 2: return "eip-1559";
}
return null;
}
set type(value: null | number | string) {
switch (value) {
case null:
@ -357,17 +410,46 @@ export class Transaction implements TransactionLike<string> {
}
}
/**
* The name of the transaction type.
*/
get typeName(): null | string {
switch (this.type) {
case 0: return "legacy";
case 1: return "eip-2930";
case 2: return "eip-1559";
}
return null;
}
/**
* The ``to`` address for the transaction or ``null`` if the
* transaction is an ``init`` transaction.
*/
get to(): null | string { return this.#to; }
set to(value: null | string) {
this.#to = (value == null) ? null: getAddress(value);
}
/**
* The transaction nonce.
*/
get nonce(): number { return this.#nonce; }
set nonce(value: BigNumberish) { this.#nonce = getNumber(value, "value"); }
/**
* The gas limit.
*/
get gasLimit(): bigint { return this.#gasLimit; }
set gasLimit(value: BigNumberish) { this.#gasLimit = getBigInt(value); }
/**
* The gas price.
*
* On legacy networks this defines the fee that will be paid. On
* EIP-1559 networks, this should be ``null``.
*/
get gasPrice(): null | bigint {
const value = this.#gasPrice;
if (value == null && (this.type === 0 || this.type === 1)) { return BN_0; }
@ -377,6 +459,10 @@ export class Transaction implements TransactionLike<string> {
this.#gasPrice = (value == null) ? null: getBigInt(value, "gasPrice");
}
/**
* The maximum priority fee per unit of gas to pay. On legacy
* networks this should be ``null``.
*/
get maxPriorityFeePerGas(): null | bigint {
const value = this.#maxPriorityFeePerGas;
if (value == null) {
@ -389,6 +475,10 @@ export class Transaction implements TransactionLike<string> {
this.#maxPriorityFeePerGas = (value == null) ? null: getBigInt(value, "maxPriorityFeePerGas");
}
/**
* The maximum total fee per unit of gas to pay. On legacy
* networks this should be ``null``.
*/
get maxFeePerGas(): null | bigint {
const value = this.#maxFeePerGas;
if (value == null) {
@ -401,22 +491,41 @@ export class Transaction implements TransactionLike<string> {
this.#maxFeePerGas = (value == null) ? null: getBigInt(value, "maxFeePerGas");
}
/**
* The transaction data. For ``init`` transactions this is the
* deployment code.
*/
get data(): string { return this.#data; }
set data(value: BytesLike) { this.#data = hexlify(value); }
/**
* The amount of ether to send in this transactions.
*/
get value(): bigint { return this.#value; }
set value(value: BigNumberish) {
this.#value = getBigInt(value, "value");
}
/**
* The chain ID this transaction is valid on.
*/
get chainId(): bigint { return this.#chainId; }
set chainId(value: BigNumberish) { this.#chainId = getBigInt(value); }
/**
* If signed, the signature for this transaction.
*/
get signature(): null | Signature { return this.#sig || null; }
set signature(value: null | SignatureLike) {
this.#sig = (value == null) ? null: Signature.from(value);
}
/**
* The access list.
*
* An access list permits discounted (but pre-paid) access to
* bytecode and state variable access within contract execution.
*/
get accessList(): null | AccessList {
const value = this.#accessList || null;
if (value == null) {
@ -429,6 +538,9 @@ export class Transaction implements TransactionLike<string> {
this.#accessList = (value == null) ? null: accessListify(value);
}
/**
* Creates a new Transaction with default values.
*/
constructor() {
this.#type = null;
this.#to = null;
@ -444,29 +556,57 @@ export class Transaction implements TransactionLike<string> {
this.#accessList = null;
}
/**
* The transaction hash, if signed. Otherwise, ``null``.
*/
get hash(): null | string {
if (this.signature == null) { return null; }
return keccak256(this.serialized);
}
/**
* The pre-image hash of this transaction.
*
* This is the digest that a [[Signer]] must sign to authorize
* this transaction.
*/
get unsignedHash(): string {
return keccak256(this.unsignedSerialized);
}
/**
* The sending address, if signed. Otherwise, ``null``.
*/
get from(): null | string {
if (this.signature == null) { return null; }
return recoverAddress(this.unsignedHash, this.signature);
}
/**
* The public key of the sender, if signed. Otherwise, ``null``.
*/
get fromPublicKey(): null | string {
if (this.signature == null) { return null; }
return SigningKey.recoverPublicKey(this.unsignedHash, this.signature);
}
isSigned(): this is SignedTransaction {
/**
* Returns true if signed.
*
* This provides a Type Guard that properties requiring a signed
* transaction are non-null.
*/
isSigned(): this is (Transaction & { type: number, typeName: string, from: string, signature: Signature }) {
//isSigned(): this is SignedTransaction {
return this.signature != null;
}
/**
* The serialized transaction.
*
* This throws if the transaction is unsigned. For the pre-image,
* use [[unsignedSerialized]].
*/
get serialized(): string {
assert(this.signature != null, "cannot serialize unsigned transaction; maybe you meant .unsignedSerialized", "UNSUPPORTED_OPERATION", { operation: ".serialized"});
@ -482,6 +622,12 @@ export class Transaction implements TransactionLike<string> {
assert(false, "unsupported transaction type", "UNSUPPORTED_OPERATION", { operation: ".serialized" });
}
/**
* The transaction pre-image.
*
* The hash of this is the digest which needs to be signed to
* authorize this transaction.
*/
get unsignedSerialized(): string {
switch (this.inferType()) {
case 0:
@ -497,13 +643,16 @@ export class Transaction implements TransactionLike<string> {
/**
* Return the most "likely" type; currently the highest
* supported transaction type
* supported transaction type.
*/
inferType(): number {
return <number>(this.inferTypes().pop());
}
// Validates properties and lists possible types this transaction adheres to
/**
* Validates the explicit properties and returns a list of compatible
* transaction types.
*/
inferTypes(): Array<number> {
// Checks that there are no conflicting properties set
@ -553,20 +702,49 @@ export class Transaction implements TransactionLike<string> {
return types;
}
/**
* Returns true if this transaction is a legacy transaction (i.e.
* ``type === 0``).
*
* This provides a Type Guard that the related properties are
* non-null.
*/
isLegacy(): this is (Transaction & { type: 0, gasPrice: bigint }) {
return (this.type === 0);
}
/**
* Returns true if this transaction is berlin hardform transaction (i.e.
* ``type === 1``).
*
* This provides a Type Guard that the related properties are
* non-null.
*/
isBerlin(): this is (Transaction & { type: 1, gasPrice: bigint, accessList: AccessList }) {
return (this.type === 1);
}
/**
* Returns true if this transaction is london hardform transaction (i.e.
* ``type === 2``).
*
* This provides a Type Guard that the related properties are
* non-null.
*/
isLondon(): this is (Transaction & { type: 2, accessList: AccessList, maxFeePerGas: bigint, maxPriorityFeePerGas: bigint}) {
return (this.type === 2);
}
/**
* Create a copy of this transaciton.
*/
clone(): Transaction {
return Transaction.from(this);
}
/**
* Return a JSON-friendly object.
*/
toJSON(): any {
const s = (v: null | bigint) => {
if (v == null) { return null; }
@ -590,7 +768,13 @@ export class Transaction implements TransactionLike<string> {
};
}
static from(tx: string | TransactionLike<string>): Transaction {
/**
* Create a **Transaction** from a serialized transaction or a
* Transaction-like object.
*/
static from(tx?: string | TransactionLike<string>): Transaction {
if (tx == null) { return new Transaction(); }
if (typeof(tx) === "string") {
const payload = getBytes(tx);

@ -9,7 +9,7 @@
* issue most schemes that use Base58 choose specific high-order values
* to ensure non-zero prefixes.
*
* @_subsection: api/utils:Base58 Encoding [base58]
* @_subsection: api/utils:Base58 Encoding [about-base58]
*/
import { getBytes } from "./data.js";

@ -1,10 +1,10 @@
/**
* [Base64 encoding](link-wiki-base64) using 6-bit words to encode
* [Base64 encoding](link-base64) using 6-bit words to encode
* arbitrary bytes into a string using 65 printable symbols, the
* upper-case and lower-case alphabet, the digits ``0`` through ``9``,
* ``"+"`` and ``"/"`` with the ``"="`` used for padding.
*
* @_subsection: api/utils:Base64 Encoding [base64]
* @_subsection: api/utils:Base64 Encoding [about-base64]
*/
import { getBytes, getBytesCopy } from "./data.js";

@ -2,7 +2,7 @@
* Some data helpers.
*
*
* @_subsection api/utils:Data Helpers [data]
* @_subsection api/utils:Data Helpers [about-data]
*/
import { assert, assertArgument } from "./errors.js";

@ -1,7 +1,7 @@
/**
* About Errors.
*
* @_section: api/utils/errors:Errors [errors]
* @_section: api/utils/errors:Errors [about-errors]
*/
import { version } from "../_version.js";

@ -1,7 +1,7 @@
/**
* Explain events...
*
* @_section api/utils/events:Events [events]
* @_section api/utils/events:Events [about-events]
*/
import { defineProperties } from "./properties.js";

@ -1,7 +1,7 @@
/**
* Explain fetching here...
*
* @_section api/utils/fetching:Fetching Web Content [fetching]
* @_section api/utils/fetching:Fetching Web Content [about-fetch]
*/
import { decodeBase64, encodeBase64 } from "./base64.js";
import { hexlify } from "./data.js";

@ -1,7 +1,7 @@
/**
* About fixed-point math...
*
* @_section: api/utils/fixed-point-math:Fixed-Point Maths [fixed-point-math]
* @_section: api/utils/fixed-point-math:Fixed-Point Maths [about-fixed-point-math]
*/
import { getBytes } from "./data.js";
import { assert, assertArgument, assertPrivate } from "./errors.js";

@ -1,7 +1,7 @@
/**
* Some mathematic operations.
*
* @_subsection: api/utils:Math Helpers [maths]
* @_subsection: api/utils:Math Helpers [about-maths]
*/
import { hexlify, isBytesLike } from "./data.js";
import { assert, assertArgument } from "./errors.js";

@ -1,22 +1,9 @@
/**
* Property helper functions.
*
* @_subsection api/utils:Properties [properties]
* @_subsection api/utils:Properties [about-properties]
*/
/**
* Resolves to a new object that is a copy of %%value%%, but with all
* values resolved.
*/
export async function resolveProperties<T>(value: { [ P in keyof T ]: T[P] | Promise<T[P]>}): Promise<T> {
const keys = Object.keys(value);
const results = await Promise.all(keys.map((k) => Promise.resolve(value[<keyof T>k])));
return results.reduce((accum: any, v, index) => {
accum[keys[index]] = v;
return accum;
}, <{ [ P in keyof T]: T[P] }>{ });
}
function checkType(value: any, type: string, name: string): void {
const types = type.split("|").map(t => t.trim());
for (let i = 0; i < types.length; i++) {
@ -39,6 +26,19 @@ function checkType(value: any, type: string, name: string): void {
throw error;
}
/**
* Resolves to a new object that is a copy of %%value%%, but with all
* values resolved.
*/
export async function resolveProperties<T>(value: { [ P in keyof T ]: T[P] | Promise<T[P]>}): Promise<T> {
const keys = Object.keys(value);
const results = await Promise.all(keys.map((k) => Promise.resolve(value[<keyof T>k])));
return results.reduce((accum: any, v, index) => {
accum[keys[index]] = v;
return accum;
}, <{ [ P in keyof T]: T[P] }>{ });
}
/**
* Assigns the %%values%% to %%target%% as read-only values.
*

@ -2,7 +2,7 @@
* The [[link-rlp]] (RLP) encoding is used throughout Ethereum
* to serialize nested structures of Arrays and data.
*
* @_subsection api/utils:Recursive-Length Prefix [rlp]
* @_subsection api/utils:Recursive-Length Prefix [about-rlp]
*/
export { decodeRlp } from "./rlp-decode.js";

0
src.ts/utils/test.txt Normal file

@ -17,7 +17,7 @@
* The native unit in Ethereum, //ether// is divisible to 18 decimal places,
* where each individual unit is called a //wei//.
*
* @_subsection api/utils:Unit Conversion [units]
* @_subsection api/utils:Unit Conversion [about-units]
*/
import { assertArgument } from "./errors.js";
import { FixedNumber } from "./fixednumber.js";

@ -4,7 +4,7 @@
* safety issues as well as provide the ability to recover and analyse
* strings.
*
* @_subsection api/utils:Strings and UTF-8 [strings]
* @_subsection api/utils:Strings and UTF-8 [about-strings]
*/
import { getBytes } from "./data.js";
import { assertArgument, assertNormalize } from "./errors.js";

@ -27,7 +27,9 @@ import type { Wordlist } from "../wordlists/index.js";
import type { KeystoreAccount } from "./json-keystore.js";
/**
* The default derivation path for Ethereum HD Nodes. (i.e. ``"m/44'/60'/0'/0/0"``)
*/
export const defaultPath: string = "m/44'/60'/0'/0/0";
@ -111,18 +113,67 @@ function derivePath<T extends HDNodeLike<T>>(node: T, path: string): T {
return result;
}
/**
* An **HDNodeWallet** is a [[Signer]] backed by the private key derived
* from an HD Node using the [[link-bip-32]] stantard.
*
* An HD Node forms a hierarchal structure with each HD Node having a
* private key and the ability to derive child HD Nodes, defined by
* a path indicating the index of each child.
*/
export class HDNodeWallet extends BaseWallet {
/**
* The compressed public key.
*/
readonly publicKey!: string;
/**
* The fingerprint.
*
* A fingerprint allows quick qay to detect parent and child nodes,
* but developers should be prepared to deal with collisions as it
* is only 4 bytes.
*/
readonly fingerprint!: string;
/**
* The parent fingerprint.
*/
readonly parentFingerprint!: string;
/**
* The mnemonic used to create this HD Node, if available.
*
* Sources such as extended keys do not encode the mnemonic, in
* which case this will be ``null``.
*/
readonly mnemonic!: null | Mnemonic;
/**
* The chaincode, which is effectively a public key used
* to derive children.
*/
readonly chainCode!: string;
/**
* The derivation path of this wallet.
*
* Since extended keys do not provider full path details, this
* may be ``null``, if instantiated from a source that does not
* enocde it.
*/
readonly path!: null | string;
/**
* The child index of this wallet. Values over ``2 *\* 31`` indicate
* the node is hardened.
*/
readonly index!: number;
/**
* The depth of this wallet, which is the number of components
* in its path.
*/
readonly depth!: number;
/**
@ -187,6 +238,12 @@ export class HDNodeWallet extends BaseWallet {
return encryptKeystoreJsonSync(this.#account(), password);
}
/**
* The extended key.
*
* This key will begin with the prefix ``xpriv`` and can be used to
* reconstruct this HD Node to derive its children.
*/
get extendedKey(): string {
// We only support the mainnet values for now, but if anyone needs
// testnet values, let me know. I believe current sentiment is that
@ -203,14 +260,28 @@ export class HDNodeWallet extends BaseWallet {
]));
}
/**
* Returns true if this wallet has a path, providing a Type Guard
* that the path is non-null.
*/
hasPath(): this is { path: string } { return (this.path != null); }
/**
* Returns a neutered HD Node, which removes the private details
* of an HD Node.
*
* A neutered node has no private key, but can be used to derive
* child addresses and other public data about the HD Node.
*/
neuter(): HDNodeVoidWallet {
return new HDNodeVoidWallet(_guard, this.address, this.publicKey,
this.parentFingerprint, this.chainCode, this.path, this.index,
this.depth, this.provider);
}
/**
* Return the child for %%index%%.
*/
deriveChild(_index: Numeric): HDNodeWallet {
const index = getNumber(_index, "index");
assertArgument(index <= 0xffffffff, "invalid index", "index", index);
@ -230,6 +301,9 @@ export class HDNodeWallet extends BaseWallet {
}
/**
* Return the HDNode for %%path%% from this node.
*/
derivePath(path: string): HDNodeWallet {
return derivePath<HDNodeWallet>(this, path);
}
@ -247,6 +321,13 @@ export class HDNodeWallet extends BaseWallet {
"m", 0, 0, mnemonic, null);
}
/**
* Creates a new HD Node from %%extendedKey%%.
*
* If the %%extendedKey%% will either have a prefix or ``xpub`` or
* ``xpriv``, returning a neutered HD Node ([[HDNodeVoidWallet]])
* or full HD Node ([[HDNodeWallet) respectively.
*/
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
const bytes = toArray(decodeBase58(extendedKey)); // @TODO: redact
@ -278,6 +359,9 @@ export class HDNodeWallet extends BaseWallet {
assertArgument(false, "invalid extended key prefix", "extendedKey", "[ REDACTED ]");
}
/**
* Creates a new random HDNode.
*/
static createRandom(password?: string, path?: string, wordlist?: Wordlist): HDNodeWallet {
if (password == null) { password = ""; }
if (path == null) { path = defaultPath; }
@ -286,11 +370,17 @@ export class HDNodeWallet extends BaseWallet {
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
}
/**
* Create am HD Node from %%mnemonic%%.
*/
static fromMnemonic(mnemonic: Mnemonic, path?: string): HDNodeWallet {
if (!path) { path = defaultPath; }
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
}
/**
* Creates an HD Node from a mnemonic %%phrase%%.
*/
static fromPhrase(phrase: string, password?: string, path?: string, wordlist?: Wordlist): HDNodeWallet {
if (password == null) { password = ""; }
if (path == null) { path = defaultPath; }
@ -299,21 +389,67 @@ export class HDNodeWallet extends BaseWallet {
return HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
}
/**
* Creates an HD Node from a %%seed%%.
*/
static fromSeed(seed: BytesLike): HDNodeWallet {
return HDNodeWallet.#fromSeed(seed, null);
}
}
/**
* A **HDNodeVoidWallet** cannot sign, but provides access to
* the children nodes of a [[link-bip-32]] HD wallet addresses.
*
* The can be created by using an extended ``xpub`` key to
* [[HDNodeWallet_fromExtendedKey]] or by
* [nuetering](HDNodeWallet-neuter) a [[HDNodeWallet]].
*/
export class HDNodeVoidWallet extends VoidSigner {
/**
* The compressed public key.
*/
readonly publicKey!: string;
/**
* The fingerprint.
*
* A fingerprint allows quick qay to detect parent and child nodes,
* but developers should be prepared to deal with collisions as it
* is only 4 bytes.
*/
readonly fingerprint!: string;
/**
* The parent node fingerprint.
*/
readonly parentFingerprint!: string;
/**
* The chaincode, which is effectively a public key used
* to derive children.
*/
readonly chainCode!: string;
/**
* The derivation path of this wallet.
*
* Since extended keys do not provider full path details, this
* may be ``null``, if instantiated from a source that does not
* enocde it.
*/
readonly path!: null | string;
/**
* The child index of this wallet. Values over ``2 *\* 31`` indicate
* the node is hardened.
*/
readonly index!: number;
/**
* The depth of this wallet, which is the number of components
* in its path.
*/
readonly depth!: number;
/**
@ -336,6 +472,12 @@ export class HDNodeVoidWallet extends VoidSigner {
this.parentFingerprint, this.chainCode, this.path, this.index, this.depth, provider);
}
/**
* The extended key.
*
* This key will begin with the prefix ``xpub`` and can be used to
* reconstruct this neutered key to derive its children addresses.
*/
get extendedKey(): string {
// We only support the mainnet values for now, but if anyone needs
// testnet values, let me know. I believe current sentiment is that
@ -355,8 +497,15 @@ export class HDNodeVoidWallet extends VoidSigner {
]));
}
/**
* Returns true if this wallet has a path, providing a Type Guard
* that the path is non-null.
*/
hasPath(): this is { path: string } { return (this.path != null); }
/**
* Return the child for %%index%%.
*/
deriveChild(_index: Numeric): HDNodeVoidWallet {
const index = getNumber(_index, "index");
assertArgument(index <= 0xffffffff, "invalid index", "index", index);
@ -369,7 +518,7 @@ export class HDNodeVoidWallet extends VoidSigner {
}
const { IR, IL } = ser_I(index, this.chainCode, this.publicKey, null);
const Ki = SigningKey._addPoints(IL, this.publicKey, true);
const Ki = SigningKey.addPoints(IL, this.publicKey, true);
const address = computeAddress(Ki);
@ -378,11 +527,15 @@ export class HDNodeVoidWallet extends VoidSigner {
}
/**
* Return the signer for %%path%% from this node.
*/
derivePath(path: string): HDNodeVoidWallet {
return derivePath<HDNodeVoidWallet>(this, path);
}
}
/*
export class HDNodeWalletManager {
#root: HDNodeWallet;
@ -397,10 +550,34 @@ export class HDNodeWalletManager {
return this.#root.deriveChild((index == null) ? 0: index);
}
}
*/
/**
* Returns the [[link-bip-32]] path for the acount at %%index%%.
*
* This is the pattern used by wallets like Ledger.
*
* There is also an [alternate pattern](getIndexedAccountPath) used by
* some software.
*/
export function getAccountPath(_index: Numeric): string {
const index = getNumber(_index, "index");
assertArgument(index >= 0 && index < HardenedBit, "invalid account index", "index", index);
return `m/44'/60'/${ index }'/0/0`;
}
/**
* Returns the path using an alternative pattern for deriving accounts,
* at %%index%%.
*
* This derivation path uses the //index// component rather than the
* //account// component to derive sequential accounts.
*
* This is the pattern used by wallets like MetaMask.
*/
export function getIndexedAccountPath(_index: Numeric): string {
const index = getNumber(_index, "index");
assertArgument(index >= 0 && index < HardenedBit, "invalid account index", "index", index);
return `m/44'/60'/0'/0/${ index}`;
}

@ -26,7 +26,6 @@ export {
HDNodeWallet,
HDNodeVoidWallet,
HDNodeWalletManager,
} from "./hdwallet.js";
export { isCrowdsaleJson, decryptCrowdsaleJson } from "./json-crowdsale.js";

@ -101,11 +101,32 @@ function entropyToMnemonic(entropy: Uint8Array, wordlist?: null | Wordlist): str
const _guard = { };
/**
* A **Mnemonic** wraps all properties required to compute [[link-bip39]]
* seeds and convert between phrases and entropy.
*/
export class Mnemonic {
/**
* The mnemonic phrase of 12, 15, 18, 21 or 24 words.
*
* Use the [[wordlist]] ``split`` method to get the individual words.
*/
readonly phrase!: string;
/**
* The password used for this mnemonic. If no password is used this
* is the empty string (i.e. ``""``) as per the specification.
*/
readonly password!: string;
/**
* The wordlist for this mnemonic.
*/
readonly wordlist!: Wordlist;
/**
* The underlying entropy which the mnemonic encodes.
*/
readonly entropy!: string;
/**
@ -118,11 +139,20 @@ export class Mnemonic {
defineProperties<Mnemonic>(this, { phrase, password, wordlist, entropy });
}
/**
* Returns the seed for the mnemonic.
*/
computeSeed(): string {
const salt = toUtf8Bytes("mnemonic" + this.password, "NFKD");
return pbkdf2(toUtf8Bytes(this.phrase, "NFKD"), salt, 2048, 64, "sha512");
}
/**
* Creates a new Mnemonic for the %%phrase%%.
*
* The default %%password%% is the empty string and the default
* wordlist is the [English wordlists](LangEn).
*/
static fromPhrase(phrase: string, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
// Normalize the case and space; throws if invalid
const entropy = mnemonicToEntropy(phrase, wordlist);
@ -130,21 +160,39 @@ export class Mnemonic {
return new Mnemonic(_guard, entropy, phrase, password, wordlist);
}
/**
* Create a new **Mnemonic** from the %%entropy%%.
*
* The default %%password%% is the empty string and the default
* wordlist is the [English wordlists](LangEn).
*/
static fromEntropy(_entropy: BytesLike, password?: null | string, wordlist?: null | Wordlist): Mnemonic {
const entropy = getBytes(_entropy, "entropy");
const phrase = entropyToMnemonic(entropy, wordlist);
return new Mnemonic(_guard, hexlify(entropy), phrase, password, wordlist);
}
/**
* Returns the phrase for %%mnemonic%%.
*/
static entropyToPhrase(_entropy: BytesLike, wordlist?: null | Wordlist): string {
const entropy = getBytes(_entropy, "entropy");
return entropyToMnemonic(entropy, wordlist);
}
/**
* Returns the entropy for %%phrase%%.
*/
static phraseToEntropy(phrase: string, wordlist?: null | Wordlist): string {
return mnemonicToEntropy(phrase, wordlist);
}
/**
* Returns true if %%phrase%% is a valid [[link-bip39]] phrase.
*
* This checks all the provided words belong to the %%wordlist%%,
* that the length is valid and the checksum is correct.
*/
static isValidMnemonic(phrase: string, wordlist?: null | Wordlist): boolean {
try {
mnemonicToEntropy(phrase, wordlist);

@ -34,6 +34,10 @@ function stall(duration: number): Promise<void> {
*/
export class Wallet extends BaseWallet {
/**
* Create a new wallet for the %%privateKey%%, optionally connected
* to %%provider%%.
*/
constructor(key: string | SigningKey, provider?: null | Provider) {
let signingKey = (typeof(key) === "string") ? new SigningKey(key): key;
super(signingKey, provider);
@ -90,6 +94,13 @@ export class Wallet extends BaseWallet {
return wallet;
}
/**
* Creates (asynchronously) a **Wallet** by decrypting the %%json%%
* with %%password%%.
*
* If %%progress%% is provided, it is called periodically during
* decryption so that any UI can be updated.
*/
static async fromEncryptedJson(json: string, password: Uint8Array | string, progress?: ProgressCallback): Promise<HDNodeWallet | Wallet> {
let account: null | CrowdsaleAccount | KeystoreAccount = null;
if (isKeystoreJson(json)) {
@ -105,6 +116,13 @@ export class Wallet extends BaseWallet {
return Wallet.#fromAccount(account);
}
/**
* Creates a **Wallet** by decrypting the %%json%% with %%password%%.
*
* The [[fromEncryptedJson]] method is preferred, as this method
* will lock up and freeze the UI during decryption, which may take
* some time.
*/
static fromEncryptedJsonSync(json: string, password: Uint8Array | string): HDNodeWallet | Wallet {
let account: null | CrowdsaleAccount | KeystoreAccount = null;
if (isKeystoreJson(json)) {
@ -118,12 +136,21 @@ export class Wallet extends BaseWallet {
return Wallet.#fromAccount(account);
}
/**
* Creates a new random [[HDNodeWallet]] using the avavilable
* [cryptographic random source](randomBytes).
*
* If there is no crytographic random source, this will throw.
*/
static createRandom(provider?: null | Provider): HDNodeWallet {
const wallet = HDNodeWallet.createRandom();
if (provider) { return wallet.connect(provider); }
return wallet;
}
/**
* Creates a [[HDNodeWallet]] for %%phrase%%.
*/
static fromPhrase(phrase: string, provider?: Provider): HDNodeWallet {
const wallet = HDNodeWallet.fromPhrase(phrase);
if (provider) { return wallet.connect(provider); }

@ -22,3 +22,5 @@ export { LangEn } from "./lang-en.js";
export { WordlistOwl } from "./wordlist-owl.js";
export { WordlistOwlA } from "./wordlist-owla.js";
export { wordlists } from "./wordlists.js";

@ -6,7 +6,7 @@ const checksum = "0x25f44555f4af25b51a711136e1c7d6e50ce9f8917d39d6b1f076b2bb4d2f
let wordlist: null | LangCz = null;
/**
* The [[link-bip-39]] Wordlist for the Czech (cz) language.
* The [[link-bip39-cz]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/
@ -15,8 +15,8 @@ export class LangCz extends WordlistOwl {
/**
* Creates a new instance of the Czech language Wordlist.
*
* This should be unnecessary most of the time as the exported
* [[langCz]] should suffice.
* Using the constructor should be unnecessary, instead use the
* [[wordlist]] singleton method.
*/
constructor() { super("cz", words, checksum); }

@ -6,7 +6,7 @@ const checksum = "0x3c8acc1e7b08d8e76f9fda015ef48dc8c710a73cb7e0f77b2c18a9b5a7ad
let wordlist: null | LangEn = null;
/**
* The [[link-bip-39]] Wordlist for the English (en) language.
* The [[link-bip39-en]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -7,7 +7,7 @@ const checksum = "0xf74fb7092aeacdfbf8959557de22098da512207fb9f109cb526994938cf4
let wordlist: null | LangEs = null;
/**
* The [[link-bip-39]] Wordlist for the Spanish (es) language.
* The [[link-bip39-es]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -7,7 +7,7 @@ const checksum = "0x51deb7ae009149dc61a6bd18a918eb7ac78d2775726c68e598b92d002519
let wordlist: null | LangFr = null;
/**
* The [[link-bip-39]] Wordlist for the French (fr) language.
* The [[link-bip39-fr]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -6,7 +6,7 @@ const checksum = "0x5c1362d88fd4cf614a96f3234941d29f7d37c08c5292fde03bf62c2db6ff
let wordlist: null | LangIt = null;
/**
* The [[link-bip-39]] Wordlist for the Italian (it) language.
* The [[link-bip39-it]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -134,7 +134,7 @@ function loadWords(): Array<string> {
let wordlist: null | LangJa = null;
/**
* The [[link-bip-39]] Wordlist for the Japanese (ja) language.
* The [[link-bip39-ja]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -64,7 +64,7 @@ function loadWords(): Array<string> {
let wordlist: null | LangKo = null;
/**
* The [[link-bip-39]] Wordlist for the Korean (ko) language.
* The [[link-bip39-ko]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -6,7 +6,7 @@ const checksum = "0x2219000926df7b50d8aa0a3d495826b988287df4657fbd100e6fe596c8f7
let wordlist: null | LangPt = null;
/**
* The [[link-bip-39]] Wordlist for the Portuguese (pt) language.
* The [[link-bip39-pt]] for [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/

@ -61,14 +61,8 @@ function loadWords(locale: string): Array<string> {
const wordlists: Record<string, LangZh> = { };
/**
* The [[link-bip-39]] Wordlist for the Chinese language.
*
* This Wordlist supports both simplified and traditional
* character set, depending on which is specified in the
* constructor.
*
* For the ``zh_cn`` language use ``"cn"`` and for the ``zh_tw``
* langauge, use ``"tw"``.
* The [[link-bip39-zh_cn]] and [[link-bip39-zh_tw]] for
* [mnemonic phrases](link-bip-39).
*
* @_docloc: api/wordlists
*/