docs: added examples to jsdocs

This commit is contained in:
Richard Moore 2022-12-09 18:21:45 -05:00
parent 30d2626e0c
commit 724881f34d
37 changed files with 471 additions and 130 deletions

View File

@ -3,7 +3,7 @@ import assert from "assert";
import {
concat, dataLength,
keccak256,
toArray,
toBeArray,
isCallException, isError
} from "../index.js";
@ -15,8 +15,8 @@ describe("Test CCIP execution", function() {
// processed data from the endpoint
const verify = function(sender: string, data: string, result: string): void {
const check = concat([
toArray(dataLength(sender)), sender,
toArray(dataLength(data)), data
toBeArray(dataLength(sender)), sender,
toBeArray(dataLength(data)), data
]);
assert.equal(result, keccak256(check), "response is equal");
}

View File

@ -2,7 +2,7 @@
import assert from "assert";
import {
concat, dataSlice, id, toArray, zeroPadValue,
concat, dataSlice, id, toBeArray, zeroPadValue,
isCallException
} from "../index.js";
@ -60,7 +60,7 @@ describe("Tests Provider Errors", function() {
const data = concat([
dataSlice(id("testPanic(uint256)"), 0, 4),
zeroPadValue(toArray(code), 32)
zeroPadValue(toBeArray(code), 32)
]);
const tx = { to: testAddr, data };

View File

@ -2,7 +2,7 @@ import assert from "assert";
import {
isError,
getBigInt, getNumber, toArray, toHex, toQuantity,
getBigInt, getNumber, toBeArray, toBeHex, toQuantity,
} from "../index.js";
describe("Tests Quantity Functions", function() {
@ -146,7 +146,7 @@ describe("Tests Bad Math Values", function() {
{
name: "negative value",
value: -4,
error: "cannot toHex negative value"
error: "cannot toBeHex negative value"
},
{
name: "width too short",
@ -157,9 +157,9 @@ describe("Tests Bad Math Values", function() {
];
for (const { name, value, error, width } of badHex) {
it(`correctly fails on bad toHex values: ${ name }`, function() {
it(`correctly fails on bad toBeHex values: ${ name }`, function() {
assert.throws(() => {
const result = toHex(value, width);
const result = toBeHex(value, width);
console.log(result);
}, (e: any) => {
return (isError(e, "INVALID_ARGUMENT") &&
@ -168,13 +168,13 @@ describe("Tests Bad Math Values", function() {
});
}
it(`correctly fails on nad toArray values: negative value`, function() {
it(`correctly fails on nad toBeArray values: negative value`, function() {
assert.throws(() => {
const result = toArray(-4);
const result = toBeArray(-4);
console.log(result);
}, (e: any) => {
return (isError(e, "INVALID_ARGUMENT") &&
e.message.startsWith("cannot toArray negative value"));
e.message.startsWith("cannot toBeArray negative value"));
});
});
});

View File

@ -1,7 +1,7 @@
import {
defineProperties, concat, getBytesCopy, getNumber, hexlify,
toArray, toBigInt, toNumber,
toBeArray, toBigInt, toNumber,
assert, assertPrivate, assertArgument
} from "../../utils/index.js";
@ -188,7 +188,7 @@ export function checkResultErrors(result: Result): Array<{ path: Array<string |
}
function getValue(value: BigNumberish): Uint8Array {
let bytes = toArray(value);
let bytes = toBeArray(value);
assert (bytes.length <= WordSize, "value out-of-bounds",
"BUFFER_OVERRUN", { buffer: bytes, length: WordSize, offset: bytes.length });

View File

@ -1,5 +1,5 @@
import { getAddress } from "../../address/index.js";
import { toHex } from "../../utils/maths.js";
import { toBeHex } from "../../utils/maths.js";
import { Typed } from "../typed.js";
import { Coder } from "./abstract-coder.js";
@ -31,6 +31,6 @@ export class AddressCoder extends Coder {
}
decode(reader: Reader): any {
return getAddress(toHex(reader.readValue(), 20));
return getAddress(toBeHex(reader.readValue(), 20));
}
}

View File

@ -8,7 +8,7 @@ import { keccak256 } from "../crypto/index.js"
import { id } from "../hash/index.js"
import {
concat, dataSlice, getBigInt, getBytes, getBytesCopy,
hexlify, zeroPadValue, isHexString, defineProperties, assertArgument, toHex,
hexlify, zeroPadValue, isHexString, defineProperties, assertArgument, toBeHex,
assert
} from "../utils/index.js";
@ -789,7 +789,7 @@ export class Interface {
}
if (param.type.match(/^u?int/)) {
value = toHex(value);
value = toBeHex(value);
}
// Check addresses are valid

View File

@ -101,6 +101,20 @@ function fromBase36(value: string): bigint {
* that you wish to bypass the safegaurds in place to protect
* against an address that has been incorrectly copied from another
* source.
*
* @example:
* // Adds the checksum (via upper-casing specific letters)
* getAddress("0x8ba1f109551bd432803012645ac136ddd64dba72")
* //_result:
*
* // Converts ICAP address and adds checksum
* getAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
* //_result:
*
* // Throws an error if an address contains mixed case,
* // but the checksum fails
* getAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
* //_error:
*/
export function getAddress(address: string): string {
@ -139,6 +153,17 @@ export function getAddress(address: string): string {
* industry [IBAN format](link-wiki-iban] for bank accounts.
*
* It is no longer common or a recommended format.
*
* @example:
* getIcapAddress("0x8ba1f109551bd432803012645ac136ddd64dba72");
* //_result:
*
* getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36");
* //_result:
*
* // Throws an error if the ICAP checksum is wrong
* getIcapAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK37");
* //_error:
*/
export function getIcapAddress(address: string): string {
//let base36 = _base16To36(getAddress(address).substring(2)).toUpperCase();

View File

@ -8,6 +8,16 @@ import type { Addressable, AddressLike, NameResolver } from "./index.js";
/**
* Returns true if %%value%% is an object which implements the
* [[Addressable]] interface.
*
* @example:
* // Wallets and AbstractSigner sub-classes
* isAddressable(Wallet.createRandom())
* //_result:
*
* // Contracts
* contract = new Contract("dai.tokens.ethers.eth", [ ], provider)
* isAddressable(contract)
* //_result:
*/
export function isAddressable(value: any): value is Addressable {
return (value && typeof(value.getAddress) === "function");
@ -15,6 +25,28 @@ export function isAddressable(value: any): value is Addressable {
/**
* Returns true if %%value%% is a valid address.
*
* @example:
* // Valid address
* isAddress("0x8ba1f109551bD432803012645Ac136ddd64DBA72")
* //_result:
*
* // Valid ICAP address
* isAddress("XE65GB6LDNXYOFTX0NSV3FUWKOWIXAMJK36")
* //_result:
*
* // Invalid checksum
* isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBa72")
* //_result:
*
* // Invalid ICAP checksum
* isAddress("0x8Ba1f109551bD432803012645Ac136ddd64DBA72")
* //_result:
*
* // Not an address (an ENS name requires a provided and an
* // asynchronous API to access)
* isAddress("ricmoo.eth")
* //_result:
*/
export function isAddress(value: any): boolean {
try {
@ -40,6 +72,35 @@ async function checkAddress(target: any, promise: Promise<null | string>): Promi
*
* If an ENS name is provided, but that name has not been correctly
* configured a [[UnconfiguredNameError]] is thrown.
*
* @example:
* addr = "0x6B175474E89094C44Da98b954EedeAC495271d0F"
*
* // Addresses are return synchronously
* resolveAddress(addr, provider)
* //_result:
*
* // Address promises are resolved asynchronously
* resolveAddress(Promise.resolve(addr))
* //_result:
*
* // ENS names are resolved asynchronously
* resolveAddress("dai.tokens.ethers.eth", provider)
* //_result:
*
* // Addressable objects are resolved asynchronously
* contract = new Contract(addr, [ ])
* resolveAddress(contract, provider)
* //_result:
*
* // Unconfigured ENS names reject
* resolveAddress("nothing-here.ricmoo.eth", provider)
* //_error:
*
* // ENS names require a NameResolver object passed in
* // (notice the provider was omitted)
* resolveAddress("nothing-here.ricmoo.eth")
* //_error:
*/
export function resolveAddress(target: AddressLike, resolver?: null | NameResolver): string | Promise<string> {

View File

@ -20,6 +20,13 @@ import type { BigNumberish, BytesLike } from "../utils/index.js";
* This can also be used to compute the address a contract will be
* deployed to by a contract, by using the contract's address as the
* ``to`` and the contract's nonce.
*
* @example
* from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72";
* nonce = 5;
*
* getCreateAddress({ from, nonce });
* //_result:
*/
export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): string {
const from = getAddress(tx.from);
@ -43,6 +50,22 @@ export function getCreateAddress(tx: { from: string, nonce: BigNumberish }): str
*
* To compute the %%initCodeHash%% from a contract's init code, use
* the [[keccak256]] function.
*
* For a quick overview and example of ``CREATE2``, see [[link-ricmoo-wisps]].
*
* @example
* // The address of the contract
* from = "0x8ba1f109551bD432803012645Ac136ddd64DBA72"
*
* // The salt
* salt = id("HelloWorld")
*
* // The hash of the initCode
* initCode = "0x6394198df16000526103ff60206004601c335afa6040516060f3";
* initCodeHash = keccak256(initCode)
*
* getCreate2Address(from, salt, initCodeHash)
* //_result:
*/
export function getCreate2Address(_from: string, _salt: BytesLike, _initCodeHash: BytesLike): string {
const from = getAddress(_from);

View File

@ -1,6 +1,8 @@
/**
* A constant for the zero address.
*
* (**i.e.** ``"0x0000000000000000000000000000000000000000"``)
*/
export const ZeroAddress: string = "0x0000000000000000000000000000000000000000";

View File

@ -1,5 +1,7 @@
/**
* A constant for the zero hash.
*
* (**i.e.** ``"0x0000000000000000000000000000000000000000000000000000000000000000"``)
*/
export const ZeroHash: string = "0x0000000000000000000000000000000000000000000000000000000000000000";

View File

@ -1,25 +1,35 @@
/**
* A constant for the order N for the secp256k1 curve.
*
* (**i.e.** ``0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n``)
*/
export const N: bigint = BigInt("0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141");
/**
* A constant for the number of wei in a single ether.
*
* (**i.e.** ``1000000000000000000n``)
*/
export const WeiPerEther: bigint = BigInt("1000000000000000000");
/**
* A constant for the maximum value for a ``uint256``.
*
* (**i.e.** ``0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
*/
export const MaxUint256: bigint = BigInt("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
/**
* A constant for the minimum value for an ``int256``.
*
* (**i.e.** ``-8000000000000000000000000000000000000000000000000000000000000000n``)
*/
export const MinInt256: bigint = BigInt("0x8000000000000000000000000000000000000000000000000000000000000000") * BigInt(-1);
/**
* A constant for the maximum value for an ``int256``.
*
* (**i.e.** ``0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn``)
*/
export const MaxInt256: bigint = BigInt("0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");

View File

@ -2,8 +2,15 @@
/**
* A constant for the ether symbol (normalized using NFKC).
*
* (**i.e.** ``"\\u039e"``)
*/
export const EtherSymbol: string = "\u039e"; // "\uD835\uDF63";
/**
* A constant for the [[link-eip-191]] personal message prefix.
*
* (**i.e.** ``"\\x19Ethereum Signed Message:\\n"``)
*/
export const MessagePrefix: string = "\x19Ethereum Signed Message:\n";

View File

@ -23,6 +23,19 @@ let __computeHmac = _computeHmac;
/**
* Return the HMAC for %%data%% using the %%key%% key with the underlying
* %%algo%% used for compression.
*
* @example:
* key = id("some-secret")
*
* // Compute the HMAC
* computeHmac("sha256", key, "0x1337")
* //_result:
*
* // To compute the HMAC of UTF-8 data, the data must be
* // converted to UTF-8 bytes
* computeHmac("sha256", key, toUtf8Bytes("Hello World"))
* //_result:
*
*/
export function computeHmac(algorithm: "sha256" | "sha512", _key: BytesLike, _data: BytesLike): string {
const key = getBytes(_key, "key");

View File

@ -22,7 +22,20 @@ let __keccak256: (data: Uint8Array) => BytesLike = _keccak256;
/**
* Compute the cryptographic KECCAK256 hash of %%data%%.
*
* The %%data%% **must** be a data representation, to compute the
* hash of UTF-8 data use the [[id]] function.
*
* @returns DataHexstring
* @example:
* keccak256("0x")
* //_result:
*
* keccak256("0x1337")
* //_result:
*
* keccak256(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
*/
export function keccak256(_data: BytesLike): string {
const data = getBytes(_data, "data");

View File

@ -27,6 +27,19 @@ let __pbkdf2 = _pbkdf2;
*
* This PBKDF is outdated and should not be used in new projects, but is
* required to decrypt older files.
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the PBKDF2
* pbkdf2(passwordBytes, salt, 1024, 16, "sha256")
* //_result:
*/
export function pbkdf2(_password: BytesLike, _salt: BytesLike, iterations: number, keylen: number, algo: "sha256" | "sha512"): string {
const password = getBytes(_password, "password");

View File

@ -18,6 +18,10 @@ let __randomBytes = _randomBytes;
/**
* Return %%length%% bytes of cryptographically secure random data.
*
* @example:
* randomBytes(8)
* //_result:
*/
export function randomBytes(length: number): Uint8Array {
return __randomBytes(length);

View File

@ -18,6 +18,17 @@ let __ripemd160: (data: Uint8Array) => BytesLike = _ripemd160;
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* ripemd160("0x")
* //_result:
*
* ripemd160("0x1337")
* //_result:
*
* ripemd160(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
*/
export function ripemd160(_data: BytesLike): string {
const data = getBytes(_data, "data");

View File

@ -49,6 +49,19 @@ let __scryptSync: (passwd: Uint8Array, salt: Uint8Array, N: number, r: number, p
* can also help, assuring the user their waiting is for a good reason.
*
* @_docloc: api/crypto:Passwords
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the scrypt
* scrypt(passwordBytes, salt, 1024, 8, 1, 16)
* //_result:
*/
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");
@ -71,6 +84,19 @@ Object.freeze(scrypt);
* preferred to use the [async variant](scrypt).
*
* @_docloc: api/crypto:Passwords
*
* @example:
* // The password must be converted to bytes, and it is generally
* // best practices to ensure the string has been normalized. Many
* // formats explicitly indicate the normalization form to use.
* password = "hello"
* passwordBytes = toUtf8Bytes(password, "NFKC")
*
* salt = id("some-salt")
*
* // Compute the scrypt
* scryptSync(passwordBytes, salt, 1024, 8, 1, 16)
* //_result:
*/
export function scryptSync(_passwd: BytesLike, _salt: BytesLike, N: number, r: number, p: number, dkLen: number): string {
const passwd = getBytes(_passwd, "passwd");

View File

@ -24,6 +24,17 @@ let locked256 = false, locked512 = false;
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* sha256("0x")
* //_result:
*
* sha256("0x1337")
* //_result:
*
* sha256(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*
*/
export function sha256(_data: BytesLike): string {
const data = getBytes(_data, "data");
@ -43,6 +54,16 @@ Object.freeze(sha256);
*
* @_docloc: api/crypto:Hash Functions
* @returns DataHexstring
*
* @example:
* sha512("0x")
* //_result:
*
* sha512("0x1337")
* //_result:
*
* sha512(new Uint8Array([ 0x13, 0x37 ]))
* //_result:
*/
export function sha512(_data: BytesLike): string {
const data = getBytes(_data, "data");

View File

@ -178,7 +178,14 @@ export class Signature {
}
/**
* Compute the chain ID from an EIP-155 ``v`` for legacy transactions.
* Compute the chain ID from the ``v`` in a legacy EIP-155 transactions.
*
* @example:
* Signature.getChainId(45)
* //_result:
*
* Signature.getChainId(46)
* //_result:
*/
static getChainId(v: BigNumberish): bigint {
const bv = getBigInt(v, "v");
@ -193,20 +200,51 @@ export class Signature {
}
/**
* Compute the EIP-155 ``v`` for a chain ID for legacy transactions.
* Compute the ``v`` for a chain ID for a legacy EIP-155 transactions.
*
* Legacy transactions which use [[link-eip-155]] hijack the ``v``
* property to include the chain ID.
*
* @example:
* Signature.getChainIdV(5, 27)
* //_result:
*
* Signature.getChainIdV(5, 28)
* //_result:
*
*/
static getChainIdV(chainId: BigNumberish, v: 27 | 28): bigint {
return (getBigInt(chainId) * BN_2) + BigInt(35 + v - 27);
}
/**
* Compute the normalized EIP-155 ``v`` for legacy transactions.
* Compute the normalized legacy transaction ``v`` from a ``yParirty``,
* a legacy transaction ``v`` or a legacy [[link-eip-155]] transaction.
*
* @example:
* // The values 0 and 1 imply v is actually yParity
* Signature.getNormalizedV(0)
* //_result:
*
* // Legacy non-EIP-1559 transaction (i.e. 27 or 28)
* Signature.getNormalizedV(27)
* //_result:
*
* // Legacy EIP-155 transaction (i.e. >= 35)
* Signature.getNormalizedV(46)
* //_result:
*
* // Invalid values throw
* Signature.getNormalizedV(5)
* //_error:
*/
static getNormalizedV(v: BigNumberish): 27 | 28 {
const bv = getBigInt(v);
if (bv == BN_0) { return 27; }
if (bv == BN_1) { return 28; }
if (bv === BN_0 || bv === BN_27) { return 27; }
if (bv === BN_1 || bv === BN_28) { return 28; }
assertArgument(bv >= BN_35, "invalid v", "v", v);
// Otherwise, EIP-155 v means odd is 27 and even is 28
return (bv & BN_1) ? 27: 28;

View File

@ -2,7 +2,7 @@
import * as secp256k1 from "@noble/secp256k1";
import {
concat, dataLength, getBytes, getBytesCopy, hexlify, toHex,
concat, dataLength, getBytes, getBytesCopy, hexlify, toBeHex,
assertArgument
} from "../utils/index.js";
@ -71,8 +71,8 @@ export class SigningKey {
const sig = secp256k1.Signature.fromHex(sigDer);
return Signature.from({
r: toHex("0x" + sig.r.toString(16), 32),
s: toHex("0x" + sig.s.toString(16), 32),
r: toBeHex("0x" + sig.r.toString(16), 32),
s: toBeHex("0x" + sig.s.toString(16), 32),
v: (recid ? 0x1c: 0x1b)
});
}
@ -86,10 +86,23 @@ export class SigningKey {
*
* Best practice is usually to use a cryptographic hash on the
* returned value before using it as a symetric secret.
*
* @example:
* sign1 = new SigningKey(id("some-secret-1"))
* sign2 = new SigningKey(id("some-secret-2"))
*
* // Notice that privA.computeSharedSecret(pubB)...
* sign1.computeSharedSecret(sign2.publicKey)
* //_result:
*
* // ...is equal to privB.computeSharedSecret(pubA).
* sign2.computeSharedSecret(sign1.publicKey)
* //_result:
*/
computeShardSecret(other: BytesLike): string {
computeSharedSecret(other: BytesLike): string {
const pubKey = SigningKey.computePublicKey(other);
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), pubKey));
console.log(pubKey);
return hexlify(secp256k1.getSharedSecret(getBytesCopy(this.#privateKey), getBytes(pubKey)));
}
/**
@ -97,6 +110,25 @@ export class SigningKey {
*
* The %%key%% may be any type of key, a raw public key, a
* compressed/uncompressed public key or private key.
*
* @example:
* sign = new SigningKey(id("some-secret"));
*
* // Compute the uncompressed public key for a private key
* SigningKey.computePublicKey(sign.privateKey)
* //_result:
*
* // Compute the compressed public key for a private key
* SigningKey.computePublicKey(sign.privateKey, true)
* //_result:
*
* // Compute the uncompressed public key
* SigningKey.computePublicKey(sign.publicKey, false);
* //_result:
*
* // Compute the Compressed a public key
* SigningKey.computePublicKey(sign.publicKey, true);
* //_result:
*/
static computePublicKey(key: BytesLike, compressed?: boolean): string {
let bytes = getBytes(key, "key");
@ -120,6 +152,20 @@ export class SigningKey {
/**
* Returns the public key for the private key which produced the
* %%signature%% for the given %%digest%%.
*
* @example:
* key = new SigningKey(id("some-secret"))
* digest = id("hello world")
* sig = key.sign(digest)
*
* // Notice the signer public key...
* key.publicKey
* //_result:
*
* // ...is equal to the recovered public key
* SigningKey.recoverPublicKey(digest, sig)
* //_result:
*
*/
static recoverPublicKey(digest: BytesLike, signature: SignatureLike): string {
assertArgument(dataLength(digest) === 32, "invalid digest length", "digest", digest);
@ -150,36 +196,3 @@ export class SigningKey {
}
}
/*
const key = new SigningKey("0x1234567890123456789012345678901234567890123456789012345678901234");
console.log(key);
console.log(key.sign("0x1234567890123456789012345678901234567890123456789012345678901234"));
{
const privKey = "0x1234567812345678123456781234567812345678123456781234567812345678";
const signingKey = new SigningKey(privKey);
console.log("0", signingKey, signingKey.publicKey, signingKey.publicKeyCompressed);
let pubKey = SigningKey.computePublicKey(privKey);
let pubKeyComp = SigningKey.computePublicKey(privKey, true);
let pubKeyRaw = "0x" + SigningKey.computePublicKey(privKey).substring(4);
console.log("A", pubKey, pubKeyComp);
let a = SigningKey.computePublicKey(pubKey);
let b = SigningKey.computePublicKey(pubKey, true);
console.log("B", a, b);
a = SigningKey.computePublicKey(pubKeyComp);
b = SigningKey.computePublicKey(pubKeyComp, true);
console.log("C", a, b);
a = SigningKey.computePublicKey(pubKeyRaw);
b = SigningKey.computePublicKey(pubKeyRaw, true);
console.log("D", a, b);
const digest = "0x1122334411223344112233441122334411223344112233441122334411223344";
const sig = signingKey.sign(digest);
console.log("SS", sig, sig.r, sig.s, sig.yParity);
console.log("R", SigningKey.recoverPublicKey(digest, sig));
}
*/

View File

@ -17,7 +17,8 @@ export {
export {
getAddress, getIcapAddress,
getCreateAddress, getCreate2Address
getCreateAddress, getCreate2Address,
isAddressable, isAddress, resolveAddress
} from "./address/index.js";
export {
@ -92,7 +93,7 @@ export {
isCallException, isError,
FetchRequest, FetchResponse, FetchCancelSignal,
FixedNumber,
getBigInt, getNumber, toArray, toBigInt, toHex, toNumber, toQuantity,
getBigInt, getNumber, getUint, toBeArray, toBigInt, toBeHex, toNumber, toQuantity,
fromTwos, toTwos, mask,
formatEther, parseEther, formatUnits, parseUnits,
toUtf8Bytes, toUtf8CodePoints, toUtf8String,

View File

@ -1,6 +1,17 @@
import { keccak256 } from "../crypto/index.js";
import { toUtf8Bytes } from "../utils/index.js";
/**
* A simple hashing function which operates on UTF-8 strings to
* compute an 32-byte irentifier.
*
* This simply computes the [UTF-8 bytes](toUtf8Bytes) and computes
* the [[keccak256]].
*
* @example:
* id("hello world")
* //_result:
*/
export function id(value: string): string {
return keccak256(toUtf8Bytes(value));
}

View File

@ -2,7 +2,34 @@ import { keccak256 } from "../crypto/index.js";
import { MessagePrefix } from "../constants/index.js";
import { concat, toUtf8Bytes } from "../utils/index.js";
/**
* Computes the [[link-eip-191]] personal-sign message digest to sign.
*
* This prefixes the message with [[MessagePrefix]] and the decimal length
* of %%message%% and computes the [[keccak256]] digest.
*
* If %%message%% is a string, it is converted to its UTF-8 bytes
* first. To compute the digest of a [[DataHexString]], it must be converted
* to [bytes](getBytes).
*
* @example:
* hashMessage("Hello World")
* //_result:
*
* // Hashes the SIX (6) string characters, i.e.
* // [ "0", "x", "4", "2", "4", "3" ]
* hashMessage("0x4243")
* //_result:
*
* // Hashes the TWO (2) bytes [ 0x42, 0x43 ]...
* hashMessage(getBytes("0x4243"))
* //_result:
*
* // ...which is equal to using data
* hashMessage(new Uint8Array([ 0x42, 0x43 ]))
* //_result:
*
*/
export function hashMessage(message: Uint8Array | string): string {
if (typeof(message) === "string") { message = toUtf8Bytes(message); }
return keccak256(concat([

View File

@ -1,8 +1,9 @@
import { getAddress } from "../address/index.js";
import {
keccak256 as _keccak256, sha256 as _sha256
} from "../crypto/index.js";
import {
concat, dataLength, getBytes, hexlify, toArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
concat, dataLength, getBytes, hexlify, toBeArray, toTwos, toUtf8Bytes, zeroPadBytes, zeroPadValue,
assertArgument
} from "../utils/index.js";
@ -16,7 +17,7 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
switch(type) {
case "address":
if (isArray) { return getBytes(zeroPadValue(value, 32)); }
return getBytes(value);
return getBytes(getAddress(value));
case "string":
return toUtf8Bytes(value);
case "bytes":
@ -38,7 +39,7 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
if (signed) { value = toTwos(value, size); }
return getBytes(zeroPadValue(toArray(value), size / 8));
return getBytes(zeroPadValue(toBeArray(value), size / 8));
}
match = type.match(regexBytes);
@ -70,6 +71,15 @@ function _pack(type: string, value: any, isArray?: boolean): Uint8Array {
// @TODO: Array Enum
/**
* Computes the [[link-solc-packed]] representation of %%values%%
* respectively to their %%types%%.
*
* @example:
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
* solidityPacked([ "address", "uint" ], [ addr, 45 ]);
* //_result:
*/
export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
assertArgument(types.length === values.length, "wrong number of values; expected ${ types.length }", "values", values);
@ -81,22 +91,27 @@ export function solidityPacked(types: ReadonlyArray<string>, values: ReadonlyArr
}
/**
* Computes the non-standard packed (tightly packed) keccak256 hash of
* the values given the types.
*
* @param {Array<string>} types - The Solidity types to interpret each value as [default: bar]
* @param {Array<any>} values - The values to pack
* Computes the [[link-solc-packed]] [[keccak256]] hash of %%values%%
* respectively to their %%types%%.
*
* @example:
* solidityPackedKeccak256([ "address", "uint" ], [ "0x1234", 45 ]);
* / /_result:
*
* @see https://docs.soliditylang.org/en/v0.8.14/abi-spec.html#non-standard-packed-mode
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
* solidityPackedKeccak256([ "address", "uint" ], [ addr, 45 ]);
* //_result:
*/
export function solidityPackedKeccak256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
return _keccak256(solidityPacked(types, values));
}
/**
* Computes the [[link-solc-packed]] [[sha256]] hash of %%values%%
* respectively to their %%types%%.
*
* @example:
* addr = "0x8ba1f109551bd432803012645ac136ddd64dba72"
* solidityPackedSha256([ "address", "uint" ], [ addr, 45 ]);
* //_result:
*/
export function solidityPackedSha256(types: ReadonlyArray<string>, values: ReadonlyArray<any>): string {
return _sha256(solidityPacked(types, values));
}

View File

@ -2,7 +2,7 @@
import { getAddress } from "../address/index.js";
import { keccak256 } from "../crypto/index.js";
import {
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toHex, toTwos, zeroPadValue,
concat, defineProperties, getBigInt, getBytes, hexlify, isHexString, mask, toBeHex, toTwos, zeroPadValue,
assertArgument
} from "../utils/index.js";
@ -41,8 +41,8 @@ function hexPadRight(value: BytesLike): string {
return hexlify(bytes);
}
const hexTrue = toHex(BN_1, 32);
const hexFalse = toHex(BN_0, 32);
const hexTrue = toBeHex(BN_1, 32);
const hexFalse = toBeHex(BN_0, 32);
const domainFieldTypes: Record<string, string> = {
name: "string",
@ -100,7 +100,7 @@ function getBaseEncoder(type: string): null | ((value: any) => string) {
assertArgument(value >= boundsLower && value <= boundsUpper, `value out-of-bounds for ${ type }`, "value", value);
return toHex(toTwos(value, 256), 32);
return toBeHex(toTwos(value, 256), 32);
};
}
}

View File

@ -2,7 +2,7 @@
* The Application Programming Interface (API) is the collection of
* functions, classes and types offered by the Ethers library.
*
* @_section: api:API Specification
* @_section: api:API Specification [about-api]
*/
import * as ethers from "./ethers.js";

View File

@ -19,7 +19,7 @@ import {
getBigInt, getBytes, getNumber,
isCallException, makeError, assert, assertArgument,
FetchRequest,
toArray, toQuantity,
toBeArray, toQuantity,
defineProperties, EventPayload, resolveProperties,
toUtf8String
} from "../utils/index.js";
@ -1313,7 +1313,7 @@ function _parseBytes(result: string, start: number): null | string {
}
function numPad(value: number): Uint8Array {
const result = toArray(value);
const result = toBeArray(value);
if (result.length > 32) { throw new Error("internal; should not happen"); }
const padded = new Uint8Array(32);

View File

@ -9,7 +9,7 @@ import { ZeroAddress, ZeroHash } from "../constants/index.js";
import { dnsEncode, namehash } from "../hash/index.js";
import {
concat, dataSlice, getBytes, hexlify, zeroPadValue,
defineProperties, encodeBase58, getBigInt, toArray,
defineProperties, encodeBase58, getBigInt, toBeArray,
toNumber, toUtf8Bytes, toUtf8String,
assert, assertArgument,
FetchRequest
@ -43,7 +43,7 @@ function parseString(result: string, start: number): null | string {
}
function numPad(value: BigNumberish): Uint8Array {
const result = toArray(value);
const result = toBeArray(value);
if (result.length > 32) { throw new Error("internal; should not happen"); }
const padded = new Uint8Array(32);

View File

@ -3,7 +3,7 @@ import { getAddress } from "../address/index.js";
import { keccak256, Signature, SigningKey } from "../crypto/index.js";
import {
concat, decodeRlp, encodeRlp, getBytes, getBigInt, getNumber, hexlify,
assert, assertArgument, toArray, zeroPadValue
assert, assertArgument, toBeArray, zeroPadValue
} from "../utils/index.js";
import { accessListify } from "./accesslist.js";
@ -121,7 +121,7 @@ function handleUint(_value: string, param: string): bigint {
function formatNumber(_value: BigNumberish, name: string): Uint8Array {
const value = getBigInt(_value, "value");
const result = toArray(value);
const result = toBeArray(value);
assertArgument(result.length <= 32, `value too large`, `tx.${ name }`, value);
return result;
}
@ -210,7 +210,7 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
if (!sig) {
// We have an EIP-155 transaction (chainId was specified and non-zero)
if (chainId !== BN_0) {
fields.push(toArray(chainId));
fields.push(toBeArray(chainId));
fields.push("0x");
fields.push("0x");
}
@ -226,9 +226,9 @@ function _serializeLegacy(tx: Transaction, sig?: Signature): string {
assertArgument(false, "tx.chainId/sig.v mismatch", "sig", sig);
}
fields.push(toArray(v));
fields.push(toArray(sig.r));
fields.push(toArray(sig.s));
fields.push(toBeArray(v));
fields.push(toBeArray(sig.r));
fields.push(toBeArray(sig.s));
return encodeRlp(fields);
}
@ -296,8 +296,8 @@ function _serializeEip1559(tx: TransactionLike, sig?: Signature): string {
if (sig) {
fields.push(formatNumber(sig.yParity, "yParity"));
fields.push(toArray(sig.r));
fields.push(toArray(sig.s));
fields.push(toBeArray(sig.r));
fields.push(toBeArray(sig.s));
}
return concat([ "0x02", encodeRlp(fields)]);
@ -345,30 +345,25 @@ function _serializeEip2930(tx: TransactionLike, sig?: Signature): string {
if (sig) {
fields.push(formatNumber(sig.yParity, "recoveryParam"));
fields.push(toArray(sig.r));
fields.push(toArray(sig.s));
fields.push(toBeArray(sig.r));
fields.push(toBeArray(sig.s));
}
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.
*
* @example:
* tx = new Transaction()
* //_result:
*
* tx.data = "0x1234";
* //_result:
*/
export class Transaction implements TransactionLike<string> {
#type: null | number;

View File

@ -435,13 +435,14 @@ export type CodedEthersError<T> =
*
* @See [ErrorCodes](api:ErrorCode)
* @example
* try {
* / / code....
* } catch (e) {
* try {
* // code....
* } catch (e) {
* if (isError(e, "CALL_EXCEPTION")) {
* // The Type Guard has validated this object
* console.log(e.data);
* }
* }
* }
*/
export function isError<K extends ErrorCode, T extends CodedEthersError<K>>(error: any, code: K): error is T {
return (error && (<EthersError>error).code === code);

View File

@ -153,6 +153,12 @@ function checkSignal(signal?: FetchCancelSignal): FetchCancelSignal {
* and ``IPFS:``.
*
* Additional schemes can be added globally using [[registerGateway]].
*
* @example:
* req = new FetchRequest("https://www.ricmoo.com")
* resp = await req.send()
* resp.body.length
* //_result:
*/
export class FetchRequest implements Iterable<[ key: string, value: string ]> {
#allowInsecure: boolean;

View File

@ -6,16 +6,12 @@
import { getBytes } from "./data.js";
import { assert, assertArgument, assertPrivate } from "./errors.js";
import {
getBigInt, fromTwos, mask, toBigInt, toHex, toTwos
getBigInt, fromTwos, mask, toBigInt
} from "./maths.js";
import { defineProperties } from "./properties.js";
import type { BigNumberish, BytesLike } from "./index.js";
if (0) {
console.log(getBytes, toBigInt, toHex, toTwos);
}
const BN_N1 = BigInt(-1);
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);

View File

@ -30,7 +30,7 @@ export { FixedNumber } from "./fixednumber.js"
export {
fromTwos, toTwos, mask,
getBigInt, getNumber, toBigInt, toNumber, toHex, toArray, toQuantity
getBigInt, getNumber, getUint, toBigInt, toNumber, toBeHex, toBeArray, toQuantity
} from "./maths.js";
export { resolveProperties, defineProperties} from "./properties.js";

View File

@ -22,6 +22,9 @@ export type BigNumberish = string | Numeric;
const BN_0 = BigInt(0);
const BN_1 = BigInt(1);
//const BN_Max256 = (BN_1 << BigInt(256)) - BN_1;
// IEEE 754 support 53-bits of mantissa
const maxValue = 0x1fffffffffffff;
@ -32,10 +35,9 @@ const maxValue = 0x1fffffffffffff;
* If the highest bit is ``1``, the result will be negative.
*/
export function fromTwos(_value: BigNumberish, _width: Numeric): bigint {
const value = getBigInt(_value, "value");
const value = getUint(_value, "value");
const width = BigInt(getNumber(_width, "width"));
assertArgument(value >= BN_0, "invalid twos complement value", "value", value);
assert((value >> width) === BN_0, "overflow", "NUMERIC_FAULT", {
operation: "fromTwos", fault: "overflow", value: _value
});
@ -81,7 +83,7 @@ export function toTwos(_value: BigNumberish, _width: Numeric): bigint {
* Mask %%value%% with a bitmask of %%bits%% ones.
*/
export function mask(_value: BigNumberish, _bits: Numeric): bigint {
const value = getBigInt(_value, "value");
const value = getUint(_value, "value");
const bits = BigInt(getNumber(_bits, "bits"));
return value & ((BN_1 << bits) - BN_1);
}
@ -111,6 +113,13 @@ export function getBigInt(value: BigNumberish, name?: string): bigint {
assertArgument(false, "invalid BigNumberish value", name || "value", value);
}
export function getUint(value: BigNumberish, name?: string): bigint {
const result = getBigInt(value, name);
assert(result >= BN_0, "overflow", "NUMERIC_FAULT", {
fault: "overflow", operation: "getUint", value
});
return result;
}
const Nibbles = "0123456789abcdef";
@ -168,9 +177,8 @@ export function toNumber(value: BigNumberish | Uint8Array): number {
* Converts %%value%% to a Big Endian hexstring, optionally padded to
* %%width%% bytes.
*/
export function toHex(_value: BigNumberish, _width?: Numeric): string {
const value = getBigInt(_value, "value");
assertArgument(value >= 0, "cannot toHex negative value", "value", _value);
export function toBeHex(_value: BigNumberish, _width?: Numeric): string {
const value = getUint(_value, "value");
let result = value.toString(16);
@ -192,9 +200,8 @@ export function toHex(_value: BigNumberish, _width?: Numeric): string {
/**
* Converts %%value%% to a Big Endian Uint8Array.
*/
export function toArray(_value: BigNumberish): Uint8Array {
const value = getBigInt(_value, "value");
assertArgument(value >= 0, "cannot toArray negative value", "value", _value);
export function toBeArray(_value: BigNumberish): Uint8Array {
const value = getUint(_value, "value");
if (value === BN_0) { return new Uint8Array([ ]); }
@ -218,7 +225,7 @@ export function toArray(_value: BigNumberish): Uint8Array {
* numeric values.
*/
export function toQuantity(value: BytesLike | BigNumberish): string {
let result = hexlify(isBytesLike(value) ? value: toArray(value)).substring(2);
let result = hexlify(isBytesLike(value) ? value: toBeArray(value)).substring(2);
while (result.substring(0, 1) === "0") { result = result.substring(1); }
if (result === "") { result = "0"; }
return "0x" + result;

View File

@ -9,7 +9,7 @@ import { computeAddress } from "../transaction/index.js";
import {
concat, dataSlice, decodeBase58, defineProperties, encodeBase58,
getBytes, hexlify, isBytesLike,
getNumber, toArray, toBigInt, toHex,
getNumber, toBeArray, toBigInt, toBeHex,
assertPrivate, assert, assertArgument
} from "../utils/index.js";
import { LangEn } from "../wordlists/lang-en.js";
@ -294,7 +294,7 @@ export class HDNodeWallet extends BaseWallet {
}
const { IR, IL } = ser_I(index, this.chainCode, this.publicKey, this.privateKey);
const ki = new SigningKey(toHex((toBigInt(IL) + BigInt(this.privateKey)) % N, 32));
const ki = new SigningKey(toBeHex((toBigInt(IL) + BigInt(this.privateKey)) % N, 32));
return new HDNodeWallet(_guard, ki, this.fingerprint, hexlify(IR),
path, index, this.depth + 1, this.mnemonic, this.provider);
@ -329,7 +329,7 @@ export class HDNodeWallet extends BaseWallet {
* or full HD Node ([[HDNodeWallet) respectively.
*/
static fromExtendedKey(extendedKey: string): HDNodeWallet | HDNodeVoidWallet {
const bytes = toArray(decodeBase58(extendedKey)); // @TODO: redact
const bytes = toBeArray(decodeBase58(extendedKey)); // @TODO: redact
assertArgument(bytes.length === 82 || encodeBase58Check(bytes.slice(0, 78)) === extendedKey,
"invalid extended key", "extendedKey", "[ REDACTED ]");