@ethereumjs/util
Advanced tools
Comparing version 9.0.3 to 9.1.0
@@ -1,2 +0,2 @@ | ||
import type { BigIntLike, BytesLike } from './types.js'; | ||
import type { BigIntLike, BytesLike, PrefixedHexString } from './types.js'; | ||
export interface AccountData { | ||
@@ -8,10 +8,44 @@ nonce?: BigIntLike; | ||
} | ||
export interface PartialAccountData { | ||
nonce?: BigIntLike | null; | ||
balance?: BigIntLike | null; | ||
storageRoot?: BytesLike | null; | ||
codeHash?: BytesLike | null; | ||
codeSize?: BigIntLike | null; | ||
version?: BigIntLike | null; | ||
} | ||
export declare type AccountBodyBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]; | ||
/** | ||
* Account class to load and maintain the basic account objects. | ||
* Supports partial loading and access required for verkle with null | ||
* as the placeholder. | ||
* | ||
* Note: passing undefined in constructor is different from null | ||
* While undefined leads to default assignment, null is retained | ||
* to track the information not available/loaded because of partial | ||
* witness access | ||
*/ | ||
export declare class Account { | ||
nonce: bigint; | ||
balance: bigint; | ||
storageRoot: Uint8Array; | ||
codeHash: Uint8Array; | ||
_nonce: bigint | null; | ||
_balance: bigint | null; | ||
_storageRoot: Uint8Array | null; | ||
_codeHash: Uint8Array | null; | ||
_codeSize: number | null; | ||
_version: number | null; | ||
get version(): number; | ||
set version(_version: number); | ||
get nonce(): bigint; | ||
set nonce(_nonce: bigint); | ||
get balance(): bigint; | ||
set balance(_balance: bigint); | ||
get storageRoot(): Uint8Array; | ||
set storageRoot(_storageRoot: Uint8Array); | ||
get codeHash(): Uint8Array; | ||
set codeHash(_codeHash: Uint8Array); | ||
get codeSize(): number; | ||
set codeSize(_codeSize: number); | ||
static fromAccountData(accountData: AccountData): Account; | ||
static fromPartialAccountData(partialAccountData: PartialAccountData): Account; | ||
static fromRlpSerializedAccount(serialized: Uint8Array): Account; | ||
static fromRlpSerializedPartialAccount(serialized: Uint8Array): Account; | ||
static fromValuesArray(values: Uint8Array[]): Account; | ||
@@ -21,4 +55,5 @@ /** | ||
* Use the static factory methods to assist in creating an Account from varying data types. | ||
* undefined get assigned with the defaults present, but null args are retained as is | ||
*/ | ||
constructor(nonce?: bigint, balance?: bigint, storageRoot?: Uint8Array, codeHash?: Uint8Array); | ||
constructor(nonce?: bigint | null, balance?: bigint | null, storageRoot?: Uint8Array | null, codeHash?: Uint8Array | null, codeSize?: number | null, version?: number | null); | ||
private _validate; | ||
@@ -33,2 +68,3 @@ /** | ||
serialize(): Uint8Array; | ||
serializeWithPartialInfo(): Uint8Array; | ||
/** | ||
@@ -48,3 +84,3 @@ * Returns a `Boolean` determining if the account is a contract. | ||
*/ | ||
export declare const isValidAddress: (hexAddress: string) => boolean; | ||
export declare const isValidAddress: (hexAddress: string) => hexAddress is `0x${string}`; | ||
/** | ||
@@ -62,3 +98,3 @@ * Returns a checksummed address. | ||
*/ | ||
export declare const toChecksumAddress: (hexAddress: string, eip1191ChainId?: BigIntLike) => string; | ||
export declare const toChecksumAddress: (hexAddress: string, eip1191ChainId?: BigIntLike) => PrefixedHexString; | ||
/** | ||
@@ -65,0 +101,0 @@ * Checks if the address is a valid checksummed address. |
@@ -11,2 +11,12 @@ "use strict"; | ||
const internal_js_1 = require("./internal.js"); | ||
/** | ||
* Account class to load and maintain the basic account objects. | ||
* Supports partial loading and access required for verkle with null | ||
* as the placeholder. | ||
* | ||
* Note: passing undefined in constructor is different from null | ||
* While undefined leads to default assignment, null is retained | ||
* to track the information not available/loaded because of partial | ||
* witness access | ||
*/ | ||
class Account { | ||
@@ -16,14 +26,108 @@ /** | ||
* Use the static factory methods to assist in creating an Account from varying data types. | ||
* undefined get assigned with the defaults present, but null args are retained as is | ||
*/ | ||
constructor(nonce = constants_js_1.BIGINT_0, balance = constants_js_1.BIGINT_0, storageRoot = constants_js_1.KECCAK256_RLP, codeHash = constants_js_1.KECCAK256_NULL) { | ||
this.nonce = nonce; | ||
this.balance = balance; | ||
this.storageRoot = storageRoot; | ||
this.codeHash = codeHash; | ||
constructor(nonce = constants_js_1.BIGINT_0, balance = constants_js_1.BIGINT_0, storageRoot = constants_js_1.KECCAK256_RLP, codeHash = constants_js_1.KECCAK256_NULL, codeSize = null, version = 0) { | ||
this._nonce = null; | ||
this._balance = null; | ||
this._storageRoot = null; | ||
this._codeHash = null; | ||
// codeSize and version is separately stored in VKT | ||
this._codeSize = null; | ||
this._version = null; | ||
this._nonce = nonce; | ||
this._balance = balance; | ||
this._storageRoot = storageRoot; | ||
this._codeHash = codeHash; | ||
if (codeSize === null && codeHash !== null && !this.isContract()) { | ||
codeSize = 0; | ||
} | ||
this._codeSize = codeSize; | ||
this._version = version; | ||
this._validate(); | ||
} | ||
get version() { | ||
if (this._version !== null) { | ||
return this._version; | ||
} | ||
else { | ||
throw Error(`version=${this._version} not loaded`); | ||
} | ||
} | ||
set version(_version) { | ||
this._version = _version; | ||
} | ||
get nonce() { | ||
if (this._nonce !== null) { | ||
return this._nonce; | ||
} | ||
else { | ||
throw Error(`nonce=${this._nonce} not loaded`); | ||
} | ||
} | ||
set nonce(_nonce) { | ||
this._nonce = _nonce; | ||
} | ||
get balance() { | ||
if (this._balance !== null) { | ||
return this._balance; | ||
} | ||
else { | ||
throw Error(`balance=${this._balance} not loaded`); | ||
} | ||
} | ||
set balance(_balance) { | ||
this._balance = _balance; | ||
} | ||
get storageRoot() { | ||
if (this._storageRoot !== null) { | ||
return this._storageRoot; | ||
} | ||
else { | ||
throw Error(`storageRoot=${this._storageRoot} not loaded`); | ||
} | ||
} | ||
set storageRoot(_storageRoot) { | ||
this._storageRoot = _storageRoot; | ||
} | ||
get codeHash() { | ||
if (this._codeHash !== null) { | ||
return this._codeHash; | ||
} | ||
else { | ||
throw Error(`codeHash=${this._codeHash} not loaded`); | ||
} | ||
} | ||
set codeHash(_codeHash) { | ||
this._codeHash = _codeHash; | ||
} | ||
get codeSize() { | ||
if (this._codeSize !== null) { | ||
return this._codeSize; | ||
} | ||
else { | ||
throw Error(`codeHash=${this._codeSize} not loaded`); | ||
} | ||
} | ||
set codeSize(_codeSize) { | ||
this._codeSize = _codeSize; | ||
} | ||
static fromAccountData(accountData) { | ||
const { nonce, balance, storageRoot, codeHash } = accountData; | ||
if (nonce === null || balance === null || storageRoot === null || codeHash === null) { | ||
throw Error(`Partial fields not supported in fromAccountData`); | ||
} | ||
return new Account(nonce !== undefined ? (0, bytes_js_1.bytesToBigInt)((0, bytes_js_1.toBytes)(nonce)) : undefined, balance !== undefined ? (0, bytes_js_1.bytesToBigInt)((0, bytes_js_1.toBytes)(balance)) : undefined, storageRoot !== undefined ? (0, bytes_js_1.toBytes)(storageRoot) : undefined, codeHash !== undefined ? (0, bytes_js_1.toBytes)(codeHash) : undefined); | ||
} | ||
static fromPartialAccountData(partialAccountData) { | ||
const { nonce, balance, storageRoot, codeHash, codeSize, version } = partialAccountData; | ||
if (nonce === null && | ||
balance === null && | ||
storageRoot === null && | ||
codeHash === null && | ||
codeSize === null && | ||
version === null) { | ||
throw Error(`All partial fields null`); | ||
} | ||
return new Account(nonce !== undefined && nonce !== null ? (0, bytes_js_1.bytesToBigInt)((0, bytes_js_1.toBytes)(nonce)) : nonce, balance !== undefined && balance !== null ? (0, bytes_js_1.bytesToBigInt)((0, bytes_js_1.toBytes)(balance)) : balance, storageRoot !== undefined && storageRoot !== null ? (0, bytes_js_1.toBytes)(storageRoot) : storageRoot, codeHash !== undefined && codeHash !== null ? (0, bytes_js_1.toBytes)(codeHash) : codeHash, codeSize !== undefined && codeSize !== null ? (0, bytes_js_1.bytesToInt)((0, bytes_js_1.toBytes)(codeSize)) : codeSize, version !== undefined && version !== null ? (0, bytes_js_1.bytesToInt)((0, bytes_js_1.toBytes)(version)) : version); | ||
} | ||
static fromRlpSerializedAccount(serialized) { | ||
@@ -36,2 +140,87 @@ const values = rlp_1.RLP.decode(serialized); | ||
} | ||
static fromRlpSerializedPartialAccount(serialized) { | ||
const values = rlp_1.RLP.decode(serialized); | ||
if (!Array.isArray(values)) { | ||
throw new Error('Invalid serialized account input. Must be array'); | ||
} | ||
let nonce = null; | ||
if (!Array.isArray(values[0])) { | ||
throw new Error('Invalid partial nonce encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[0][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for nonce`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
nonce = (0, bytes_js_1.bytesToBigInt)(values[0][1]); | ||
} | ||
} | ||
let balance = null; | ||
if (!Array.isArray(values[1])) { | ||
throw new Error('Invalid partial balance encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[1][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for balance`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
balance = (0, bytes_js_1.bytesToBigInt)(values[1][1]); | ||
} | ||
} | ||
let storageRoot = null; | ||
if (!Array.isArray(values[2])) { | ||
throw new Error('Invalid partial storageRoot encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[2][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for storageRoot`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
storageRoot = values[2][1]; | ||
} | ||
} | ||
let codeHash = null; | ||
if (!Array.isArray(values[3])) { | ||
throw new Error('Invalid partial codeHash encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[3][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeHash`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeHash = values[3][1]; | ||
} | ||
} | ||
let codeSize = null; | ||
if (!Array.isArray(values[4])) { | ||
throw new Error('Invalid partial codeSize encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[4][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeSize`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeSize = (0, bytes_js_1.bytesToInt)(values[4][1]); | ||
} | ||
} | ||
let version = null; | ||
if (!Array.isArray(values[5])) { | ||
throw new Error('Invalid partial version encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = (0, bytes_js_1.bytesToInt)(values[5][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for version`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
version = (0, bytes_js_1.bytesToInt)(values[5][1]); | ||
} | ||
} | ||
return this.fromPartialAccountData({ balance, nonce, storageRoot, codeHash, codeSize, version }); | ||
} | ||
static fromValuesArray(values) { | ||
@@ -42,14 +231,17 @@ const [nonce, balance, storageRoot, codeHash] = values; | ||
_validate() { | ||
if (this.nonce < constants_js_1.BIGINT_0) { | ||
if (this._nonce !== null && this._nonce < constants_js_1.BIGINT_0) { | ||
throw new Error('nonce must be greater than zero'); | ||
} | ||
if (this.balance < constants_js_1.BIGINT_0) { | ||
if (this._balance !== null && this._balance < constants_js_1.BIGINT_0) { | ||
throw new Error('balance must be greater than zero'); | ||
} | ||
if (this.storageRoot.length !== 32) { | ||
if (this._storageRoot !== null && this._storageRoot.length !== 32) { | ||
throw new Error('storageRoot must have a length of 32'); | ||
} | ||
if (this.codeHash.length !== 32) { | ||
if (this._codeHash !== null && this._codeHash.length !== 32) { | ||
throw new Error('codeHash must have a length of 32'); | ||
} | ||
if (this._codeSize !== null && this._codeSize < constants_js_1.BIGINT_0) { | ||
throw new Error('codeSize must be greater than zero'); | ||
} | ||
} | ||
@@ -73,2 +265,44 @@ /** | ||
} | ||
serializeWithPartialInfo() { | ||
const partialData = []; | ||
const zeroEncoded = (0, bytes_js_1.intToUnpaddedBytes)(0); | ||
const oneEncoded = (0, bytes_js_1.intToUnpaddedBytes)(1); | ||
if (this._nonce !== null) { | ||
partialData.push([oneEncoded, (0, bytes_js_1.bigIntToUnpaddedBytes)(this._nonce)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._balance !== null) { | ||
partialData.push([oneEncoded, (0, bytes_js_1.bigIntToUnpaddedBytes)(this._balance)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._storageRoot !== null) { | ||
partialData.push([oneEncoded, this._storageRoot]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._codeHash !== null) { | ||
partialData.push([oneEncoded, this._codeHash]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._codeSize !== null) { | ||
partialData.push([oneEncoded, (0, bytes_js_1.intToUnpaddedBytes)(this._codeSize)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._version !== null) { | ||
partialData.push([oneEncoded, (0, bytes_js_1.intToUnpaddedBytes)(this._version)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
return rlp_1.RLP.encode(partialData); | ||
} | ||
/** | ||
@@ -78,3 +312,7 @@ * Returns a `Boolean` determining if the account is a contract. | ||
isContract() { | ||
return !(0, bytes_js_1.equalsBytes)(this.codeHash, constants_js_1.KECCAK256_NULL); | ||
if (this._codeHash === null && this._codeSize === null) { | ||
throw Error(`Insufficient data as codeHash=null and codeSize=null`); | ||
} | ||
return ((this._codeHash !== null && !(0, bytes_js_1.equalsBytes)(this._codeHash, constants_js_1.KECCAK256_NULL)) || | ||
(this._codeSize !== null && this._codeSize !== 0)); | ||
} | ||
@@ -87,2 +325,8 @@ /** | ||
isEmpty() { | ||
// helpful for determination in partial accounts | ||
if ((this._balance !== null && this.balance !== constants_js_1.BIGINT_0) || | ||
(this._nonce === null && this.nonce !== constants_js_1.BIGINT_0) || | ||
(this._codeHash !== null && !(0, bytes_js_1.equalsBytes)(this.codeHash, constants_js_1.KECCAK256_NULL))) { | ||
return false; | ||
} | ||
return (this.balance === constants_js_1.BIGINT_0 && | ||
@@ -129,3 +373,3 @@ this.nonce === constants_js_1.BIGINT_0 && | ||
const hash = (0, bytes_js_1.bytesToHex)((0, keccak_js_1.keccak256)(bytes)).slice(2); | ||
let ret = '0x'; | ||
let ret = ''; | ||
for (let i = 0; i < address.length; i++) { | ||
@@ -139,3 +383,3 @@ if (parseInt(hash[i], 16) >= 8) { | ||
} | ||
return ret; | ||
return `0x${ret}`; | ||
}; | ||
@@ -142,0 +386,0 @@ exports.toChecksumAddress = toChecksumAddress; |
@@ -0,1 +1,2 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
/** | ||
@@ -55,3 +56,3 @@ * Handling and generating Ethereum addresses | ||
*/ | ||
toString(): string; | ||
toString(): PrefixedHexString; | ||
/** | ||
@@ -58,0 +59,0 @@ * Returns a new Uint8Array representation of address. |
@@ -29,5 +29,5 @@ "use strict"; | ||
if (!(0, account_js_1.isValidAddress)(str)) { | ||
throw new Error('Invalid address'); | ||
throw new Error(`Invalid address input=${str}`); | ||
} | ||
return new Address((0, bytes_js_1.toBytes)(str)); | ||
return new Address((0, bytes_js_1.hexToBytes)(str)); | ||
} | ||
@@ -34,0 +34,0 @@ /** |
@@ -11,3 +11,3 @@ import { bytesToHex as _bytesToUnprefixedHex } from 'ethereum-cryptography/utils.js'; | ||
export declare const unprefixedHexToBytes: (inp: string) => Uint8Array; | ||
export declare const bytesToHex: (bytes: Uint8Array) => string; | ||
export declare const bytesToHex: (bytes: Uint8Array) => PrefixedHexString; | ||
/** | ||
@@ -26,3 +26,9 @@ * Converts a {@link Uint8Array} to a {@link bigint} | ||
export declare const bytesToInt: (bytes: Uint8Array) => number; | ||
export declare const hexToBytes: (hex: string) => Uint8Array; | ||
/** | ||
* Converts a {@link PrefixedHexString} to a {@link Uint8Array} | ||
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert | ||
* @returns {Uint8Array} The converted bytes | ||
* @throws If the input is not a valid 0x-prefixed hex string | ||
*/ | ||
export declare const hexToBytes: (hex: PrefixedHexString | string) => Uint8Array; | ||
/******************************************/ | ||
@@ -83,7 +89,7 @@ /** | ||
* Trims leading zeros from a `PrefixedHexString`. | ||
* @param {PrefixedHexString} a | ||
* @param {PrefixedHexString | string} a | ||
* @return {PrefixedHexString} | ||
*/ | ||
export declare const unpadHex: (a: string) => PrefixedHexString; | ||
export declare type ToBytesInputTypes = PrefixedHexString | number | bigint | Uint8Array | number[] | TransformabletoBytes | null | undefined; | ||
export declare const unpadHex: (a: PrefixedHexString | string) => PrefixedHexString; | ||
export declare type ToBytesInputTypes = PrefixedHexString | string | number | bigint | Uint8Array | number[] | TransformabletoBytes | null | undefined; | ||
/** | ||
@@ -166,2 +172,3 @@ * Attempts to turn a value into a `Uint8Array`. | ||
export declare const bigIntToUnpaddedBytes: (value: bigint) => Uint8Array; | ||
export declare const bigIntToAddressBytes: (value: bigint, strict?: boolean) => Uint8Array; | ||
/** | ||
@@ -229,2 +236,3 @@ * Convert value from number to an unpadded Uint8Array | ||
export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/utils.js'; | ||
export declare function hexToBigInt(input: PrefixedHexString | string): bigint; | ||
//# sourceMappingURL=bytes.d.ts.map |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.utf8ToBytes = exports.equalsBytes = exports.bytesToUtf8 = exports.bigInt64ToBytes = exports.int32ToBytes = exports.bytesToBigInt64 = exports.bytesToInt32 = exports.concatBytes = exports.randomBytes = exports.compareBytes = exports.intToUnpaddedBytes = exports.bigIntToUnpaddedBytes = exports.bigIntMin = exports.bigIntMax = exports.bigIntToHex = exports.validateNoLeadingZeroes = exports.short = exports.addHexPrefix = exports.toUnsigned = exports.fromSigned = exports.toBytes = exports.unpadHex = exports.unpadArray = exports.unpadBytes = exports.setLengthRight = exports.setLengthLeft = exports.zeros = exports.bigIntToBytes = exports.intToBytes = exports.intToHex = exports.hexToBytes = exports.bytesToInt = exports.bytesToBigInt = exports.bytesToHex = exports.unprefixedHexToBytes = exports.bytesToUnprefixedHex = void 0; | ||
exports.hexToBigInt = exports.utf8ToBytes = exports.equalsBytes = exports.bytesToUtf8 = exports.bigInt64ToBytes = exports.int32ToBytes = exports.bytesToBigInt64 = exports.bytesToInt32 = exports.concatBytes = exports.randomBytes = exports.compareBytes = exports.intToUnpaddedBytes = exports.bigIntToAddressBytes = exports.bigIntToUnpaddedBytes = exports.bigIntMin = exports.bigIntMax = exports.bigIntToHex = exports.validateNoLeadingZeroes = exports.short = exports.addHexPrefix = exports.toUnsigned = exports.fromSigned = exports.toBytes = exports.unpadHex = exports.unpadArray = exports.unpadBytes = exports.setLengthRight = exports.setLengthLeft = exports.zeros = exports.bigIntToBytes = exports.intToBytes = exports.intToHex = exports.hexToBytes = exports.bytesToInt = exports.bytesToBigInt = exports.bytesToHex = exports.unprefixedHexToBytes = exports.bytesToUnprefixedHex = void 0; | ||
const random_js_1 = require("ethereum-cryptography/random.js"); | ||
@@ -55,7 +55,7 @@ // eslint-disable-next-line no-restricted-imports | ||
const bytesToHex = (bytes) => { | ||
let hex = '0x'; | ||
let hex = `0x`; | ||
if (bytes === undefined || bytes.length === 0) | ||
return hex; | ||
for (const byte of bytes) { | ||
hex += hexByByte[byte]; | ||
hex = `${hex}${hexByByte[byte]}`; | ||
} | ||
@@ -106,2 +106,9 @@ return hex; | ||
exports.bytesToInt = bytesToInt; | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Converts a {@link PrefixedHexString} to a {@link Uint8Array} | ||
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert | ||
* @returns {Uint8Array} The converted bytes | ||
* @throws If the input is not a valid 0x-prefixed hex string | ||
*/ | ||
const hexToBytes = (hex) => { | ||
@@ -114,7 +121,4 @@ if (typeof hex !== 'string') { | ||
} | ||
hex = hex.slice(2); | ||
if (hex.length % 2 !== 0) { | ||
hex = (0, internal_js_1.padToEven)(hex); | ||
} | ||
return _unprefixedHexToBytes(hex); | ||
const unprefixedHex = hex.slice(2); | ||
return _unprefixedHexToBytes(unprefixedHex.length % 2 === 0 ? unprefixedHex : (0, internal_js_1.padToEven)(unprefixedHex)); | ||
}; | ||
@@ -152,3 +156,3 @@ exports.hexToBytes = hexToBytes; | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
const bytes = (0, exports.toBytes)('0x' + (0, internal_js_1.padToEven)(num.toString(16))); | ||
const bytes = (0, exports.toBytes)(`0x${(0, internal_js_1.padToEven)(num.toString(16))}`); | ||
return littleEndian ? bytes.reverse() : bytes; | ||
@@ -213,5 +217,5 @@ }; | ||
/** | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or PrefixedHexString`. | ||
* @param {Uint8Array|number[]|PrefixedHexString} a | ||
* @return {Uint8Array|number[]|PrefixedHexString} | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or `string`. | ||
* @param {Uint8Array|number[]|string} a | ||
* @return {Uint8Array|number[]|string} | ||
*/ | ||
@@ -246,5 +250,6 @@ const stripZeros = (a) => { | ||
exports.unpadArray = unpadArray; | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Trims leading zeros from a `PrefixedHexString`. | ||
* @param {PrefixedHexString} a | ||
* @param {PrefixedHexString | string} a | ||
* @return {PrefixedHexString} | ||
@@ -254,4 +259,3 @@ */ | ||
(0, helpers_js_1.assertIsHexString)(a); | ||
a = (0, internal_js_1.stripHexPrefix)(a); | ||
return '0x' + stripZeros(a); | ||
return `0x${stripZeros((0, internal_js_1.stripHexPrefix)(a))}`; | ||
}; | ||
@@ -325,3 +329,3 @@ exports.unpadHex = unpadHex; | ||
} | ||
return (0, internal_js_1.isHexPrefixed)(str) ? str : '0x' + str; | ||
return (0, internal_js_1.isHexString)(str) ? str : `0x${str}`; | ||
}; | ||
@@ -376,3 +380,3 @@ exports.addHexPrefix = addHexPrefix; | ||
const bigIntToHex = (num) => { | ||
return '0x' + num.toString(16); | ||
return `0x${num.toString(16)}`; | ||
}; | ||
@@ -402,2 +406,11 @@ exports.bigIntToHex = bigIntToHex; | ||
exports.bigIntToUnpaddedBytes = bigIntToUnpaddedBytes; | ||
const bigIntToAddressBytes = (value, strict = true) => { | ||
const addressBytes = (0, exports.bigIntToBytes)(value); | ||
if (strict && addressBytes.length > 20) { | ||
throw Error(`Invalid address bytes length=${addressBytes.length} strict=${strict}`); | ||
} | ||
// setLength already slices if more than requisite length | ||
return (0, exports.setLengthLeft)(addressBytes, 20); | ||
}; | ||
exports.bigIntToAddressBytes = bigIntToAddressBytes; | ||
/** | ||
@@ -518,2 +531,7 @@ * Convert value from number to an unpadded Uint8Array | ||
Object.defineProperty(exports, "utf8ToBytes", { enumerable: true, get: function () { return utils_js_2.utf8ToBytes; } }); | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
function hexToBigInt(input) { | ||
return (0, exports.bytesToBigInt)((0, exports.hexToBytes)((0, internal_js_1.isHexString)(input) ? input : `0x${input}`)); | ||
} | ||
exports.hexToBigInt = hexToBigInt; | ||
//# sourceMappingURL=bytes.js.map |
@@ -34,3 +34,3 @@ import type { PrefixedHexString } from './types.js'; | ||
export interface GenesisState { | ||
[key: PrefixedHexString]: PrefixedHexString | AccountState; | ||
[key: string]: PrefixedHexString | AccountState; | ||
} | ||
@@ -37,0 +37,0 @@ /** |
@@ -12,11 +12,11 @@ "use strict"; | ||
const state = {}; | ||
for (let address of Object.keys(json.alloc)) { | ||
for (const address of Object.keys(json.alloc)) { | ||
let { balance, code, storage, nonce } = json.alloc[address]; | ||
// create a map with lowercase for easy lookups | ||
address = (0, bytes_js_1.addHexPrefix)(address.toLowerCase()); | ||
balance = (0, internal_js_1.isHexPrefixed)(balance) ? balance : (0, bytes_js_1.bigIntToHex)(BigInt(balance)); | ||
const prefixedAddress = (0, bytes_js_1.addHexPrefix)(address.toLowerCase()); | ||
balance = (0, internal_js_1.isHexString)(balance) ? balance : (0, bytes_js_1.bigIntToHex)(BigInt(balance)); | ||
code = code !== undefined ? (0, bytes_js_1.addHexPrefix)(code) : undefined; | ||
storage = storage !== undefined ? Object.entries(storage) : undefined; | ||
nonce = nonce !== undefined ? (0, bytes_js_1.addHexPrefix)(nonce) : undefined; | ||
state[address] = [balance, code, storage, nonce]; | ||
state[prefixedAddress] = [balance, code, storage, nonce]; | ||
} | ||
@@ -23,0 +23,0 @@ return state; |
@@ -43,3 +43,3 @@ /** | ||
export * from './genesis.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexPrefixed, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export * from './kzg.js'; | ||
@@ -49,2 +49,4 @@ export * from './lock.js'; | ||
export * from './provider.js'; | ||
export * from './requests.js'; | ||
export * from './verkle.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -17,3 +17,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.toAscii = exports.stripHexPrefix = exports.padToEven = exports.isHexString = exports.isHexPrefixed = exports.getKeys = exports.getBinarySize = exports.fromUtf8 = exports.fromAscii = exports.arrayContainsArray = void 0; | ||
exports.toAscii = exports.stripHexPrefix = exports.padToEven = exports.isHexString = exports.getKeys = exports.getBinarySize = exports.fromUtf8 = exports.fromAscii = exports.arrayContainsArray = void 0; | ||
/** | ||
@@ -67,3 +67,2 @@ * Constants | ||
Object.defineProperty(exports, "getKeys", { enumerable: true, get: function () { return internal_js_1.getKeys; } }); | ||
Object.defineProperty(exports, "isHexPrefixed", { enumerable: true, get: function () { return internal_js_1.isHexPrefixed; } }); | ||
Object.defineProperty(exports, "isHexString", { enumerable: true, get: function () { return internal_js_1.isHexString; } }); | ||
@@ -77,2 +76,4 @@ Object.defineProperty(exports, "padToEven", { enumerable: true, get: function () { return internal_js_1.padToEven; } }); | ||
__exportStar(require("./provider.js"), exports); | ||
__exportStar(require("./requests.js"), exports); | ||
__exportStar(require("./verkle.js"), exports); | ||
//# sourceMappingURL=index.js.map |
@@ -0,8 +1,9 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
/** | ||
* Returns a `Boolean` on whether or not the a `String` starts with '0x' | ||
* @param str the string input value | ||
* @return a boolean if it is or is not hex prefixed | ||
* @throws if the str input is not a string | ||
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length | ||
* @param {string} value the string input value | ||
* @param {number|undefined} length the optional length of the hex string in bytes | ||
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length | ||
*/ | ||
export declare function isHexPrefixed(str: string): boolean; | ||
export declare function isHexString(value: string, length?: number): value is PrefixedHexString; | ||
/** | ||
@@ -71,10 +72,2 @@ * Removes '0x' from a given `String` if present | ||
export declare function getKeys(params: Record<string, string>[], key: string, allowEmpty?: boolean): string[]; | ||
/** | ||
* Is the string a hex string. | ||
* | ||
* @param value | ||
* @param length | ||
* @returns output the string is a hex string | ||
*/ | ||
export declare function isHexString(value: string, length?: number): boolean; | ||
//# sourceMappingURL=internal.d.ts.map |
@@ -26,17 +26,18 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isHexString = exports.getKeys = exports.fromAscii = exports.fromUtf8 = exports.toAscii = exports.arrayContainsArray = exports.getBinarySize = exports.padToEven = exports.stripHexPrefix = exports.isHexPrefixed = void 0; | ||
exports.getKeys = exports.fromAscii = exports.fromUtf8 = exports.toAscii = exports.arrayContainsArray = exports.getBinarySize = exports.padToEven = exports.stripHexPrefix = exports.isHexString = void 0; | ||
const bytes_js_1 = require("./bytes.js"); | ||
/** | ||
* Returns a `Boolean` on whether or not the a `String` starts with '0x' | ||
* @param str the string input value | ||
* @return a boolean if it is or is not hex prefixed | ||
* @throws if the str input is not a string | ||
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length | ||
* @param {string} value the string input value | ||
* @param {number|undefined} length the optional length of the hex string in bytes | ||
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length | ||
*/ | ||
function isHexPrefixed(str) { | ||
if (typeof str !== 'string') { | ||
throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`); | ||
} | ||
return str[0] === '0' && str[1] === 'x'; | ||
function isHexString(value, length) { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) | ||
return false; | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) | ||
return false; | ||
return true; | ||
} | ||
exports.isHexPrefixed = isHexPrefixed; | ||
exports.isHexString = isHexString; | ||
/** | ||
@@ -50,3 +51,3 @@ * Removes '0x' from a given `String` if present | ||
throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`); | ||
return isHexPrefixed(str) ? str.slice(2) : str; | ||
return isHexString(str) ? str.slice(2) : str; | ||
}; | ||
@@ -180,17 +181,2 @@ exports.stripHexPrefix = stripHexPrefix; | ||
exports.getKeys = getKeys; | ||
/** | ||
* Is the string a hex string. | ||
* | ||
* @param value | ||
* @param length | ||
* @returns output the string is a hex string | ||
*/ | ||
function isHexString(value, length) { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) | ||
return false; | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) | ||
return false; | ||
return true; | ||
} | ||
exports.isHexString = isHexString; | ||
//# sourceMappingURL=internal.js.map |
@@ -20,3 +20,4 @@ declare type rpcParams = { | ||
* } | ||
* const block = await fetchFromProvider(provider, params) | ||
* const block = await fetchFromProvider(provider, params) | ||
* ``` | ||
*/ | ||
@@ -23,0 +24,0 @@ export declare const fetchFromProvider: (url: string, params: rpcParams) => Promise<any>; |
@@ -19,3 +19,4 @@ "use strict"; | ||
* } | ||
* const block = await fetchFromProvider(provider, params) | ||
* const block = await fetchFromProvider(provider, params) | ||
* ``` | ||
*/ | ||
@@ -22,0 +23,0 @@ const fetchFromProvider = async (url, params) => { |
@@ -0,1 +1,2 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
export interface ECDSASignature { | ||
@@ -40,3 +41,3 @@ v: bigint; | ||
*/ | ||
export declare const fromRpcSig: (sig: string) => ECDSASignature; | ||
export declare const fromRpcSig: (sig: PrefixedHexString) => ECDSASignature; | ||
/** | ||
@@ -43,0 +44,0 @@ * Validate a ECDSA signature. |
@@ -5,3 +5,3 @@ import type { Address } from './address.js'; | ||
export declare type BytesLike = Uint8Array | number[] | number | bigint | TransformabletoBytes | PrefixedHexString; | ||
export declare type PrefixedHexString = string; | ||
export declare type PrefixedHexString = `0x${string}`; | ||
/** | ||
@@ -15,2 +15,3 @@ * A type that represents an input that can be converted to an Address. | ||
export declare type NestedUint8Array = Array<Uint8Array | NestedUint8Array>; | ||
export declare function isNestedUint8Array(value: unknown): value is NestedUint8Array; | ||
/** | ||
@@ -17,0 +18,0 @@ * Type output options |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.toType = exports.TypeOutput = void 0; | ||
exports.toType = exports.TypeOutput = exports.isNestedUint8Array = void 0; | ||
const bytes_js_1 = require("./bytes.js"); | ||
const internal_js_1 = require("./internal.js"); | ||
function isNestedUint8Array(value) { | ||
if (!Array.isArray(value)) { | ||
return false; | ||
} | ||
for (const item of value) { | ||
if (Array.isArray(item)) { | ||
if (!isNestedUint8Array(item)) { | ||
return false; | ||
} | ||
} | ||
else if (!(item instanceof Uint8Array)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
exports.isNestedUint8Array = isNestedUint8Array; | ||
/** | ||
@@ -7,0 +24,0 @@ * Type output options |
import { Address } from './address.js'; | ||
import type { AddressLike, BigIntLike } from './types.js'; | ||
import type { AddressLike, BigIntLike, PrefixedHexString } from './types.js'; | ||
/** | ||
@@ -18,6 +18,6 @@ * Flexible input data type for EIP-4895 withdrawal data with amount in Gwei to | ||
export interface JsonRpcWithdrawal { | ||
index: string; | ||
validatorIndex: string; | ||
address: string; | ||
amount: string; | ||
index: PrefixedHexString; | ||
validatorIndex: PrefixedHexString; | ||
address: PrefixedHexString; | ||
amount: PrefixedHexString; | ||
} | ||
@@ -62,8 +62,8 @@ export declare type WithdrawalBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]; | ||
toJSON(): { | ||
index: string; | ||
validatorIndex: string; | ||
address: string; | ||
amount: string; | ||
index: `0x${string}`; | ||
validatorIndex: `0x${string}`; | ||
address: `0x${string}`; | ||
amount: `0x${string}`; | ||
}; | ||
} | ||
//# sourceMappingURL=withdrawal.d.ts.map |
@@ -1,2 +0,2 @@ | ||
import type { BigIntLike, BytesLike } from './types.js'; | ||
import type { BigIntLike, BytesLike, PrefixedHexString } from './types.js'; | ||
export interface AccountData { | ||
@@ -8,10 +8,44 @@ nonce?: BigIntLike; | ||
} | ||
export interface PartialAccountData { | ||
nonce?: BigIntLike | null; | ||
balance?: BigIntLike | null; | ||
storageRoot?: BytesLike | null; | ||
codeHash?: BytesLike | null; | ||
codeSize?: BigIntLike | null; | ||
version?: BigIntLike | null; | ||
} | ||
export declare type AccountBodyBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]; | ||
/** | ||
* Account class to load and maintain the basic account objects. | ||
* Supports partial loading and access required for verkle with null | ||
* as the placeholder. | ||
* | ||
* Note: passing undefined in constructor is different from null | ||
* While undefined leads to default assignment, null is retained | ||
* to track the information not available/loaded because of partial | ||
* witness access | ||
*/ | ||
export declare class Account { | ||
nonce: bigint; | ||
balance: bigint; | ||
storageRoot: Uint8Array; | ||
codeHash: Uint8Array; | ||
_nonce: bigint | null; | ||
_balance: bigint | null; | ||
_storageRoot: Uint8Array | null; | ||
_codeHash: Uint8Array | null; | ||
_codeSize: number | null; | ||
_version: number | null; | ||
get version(): number; | ||
set version(_version: number); | ||
get nonce(): bigint; | ||
set nonce(_nonce: bigint); | ||
get balance(): bigint; | ||
set balance(_balance: bigint); | ||
get storageRoot(): Uint8Array; | ||
set storageRoot(_storageRoot: Uint8Array); | ||
get codeHash(): Uint8Array; | ||
set codeHash(_codeHash: Uint8Array); | ||
get codeSize(): number; | ||
set codeSize(_codeSize: number); | ||
static fromAccountData(accountData: AccountData): Account; | ||
static fromPartialAccountData(partialAccountData: PartialAccountData): Account; | ||
static fromRlpSerializedAccount(serialized: Uint8Array): Account; | ||
static fromRlpSerializedPartialAccount(serialized: Uint8Array): Account; | ||
static fromValuesArray(values: Uint8Array[]): Account; | ||
@@ -21,4 +55,5 @@ /** | ||
* Use the static factory methods to assist in creating an Account from varying data types. | ||
* undefined get assigned with the defaults present, but null args are retained as is | ||
*/ | ||
constructor(nonce?: bigint, balance?: bigint, storageRoot?: Uint8Array, codeHash?: Uint8Array); | ||
constructor(nonce?: bigint | null, balance?: bigint | null, storageRoot?: Uint8Array | null, codeHash?: Uint8Array | null, codeSize?: number | null, version?: number | null); | ||
private _validate; | ||
@@ -33,2 +68,3 @@ /** | ||
serialize(): Uint8Array; | ||
serializeWithPartialInfo(): Uint8Array; | ||
/** | ||
@@ -48,3 +84,3 @@ * Returns a `Boolean` determining if the account is a contract. | ||
*/ | ||
export declare const isValidAddress: (hexAddress: string) => boolean; | ||
export declare const isValidAddress: (hexAddress: string) => hexAddress is `0x${string}`; | ||
/** | ||
@@ -62,3 +98,3 @@ * Returns a checksummed address. | ||
*/ | ||
export declare const toChecksumAddress: (hexAddress: string, eip1191ChainId?: BigIntLike) => string; | ||
export declare const toChecksumAddress: (hexAddress: string, eip1191ChainId?: BigIntLike) => PrefixedHexString; | ||
/** | ||
@@ -65,0 +101,0 @@ * Checks if the address is a valid checksummed address. |
import { RLP } from '@ethereumjs/rlp'; | ||
import { keccak256 } from 'ethereum-cryptography/keccak.js'; | ||
import { secp256k1 } from 'ethereum-cryptography/secp256k1.js'; | ||
import { bigIntToUnpaddedBytes, bytesToBigInt, bytesToHex, concatBytes, equalsBytes, hexToBytes, toBytes, utf8ToBytes, zeros, } from './bytes.js'; | ||
import { bigIntToUnpaddedBytes, bytesToBigInt, bytesToHex, bytesToInt, concatBytes, equalsBytes, hexToBytes, intToUnpaddedBytes, toBytes, utf8ToBytes, zeros, } from './bytes.js'; | ||
import { BIGINT_0, KECCAK256_NULL, KECCAK256_RLP } from './constants.js'; | ||
import { assertIsBytes, assertIsHexString, assertIsString } from './helpers.js'; | ||
import { stripHexPrefix } from './internal.js'; | ||
/** | ||
* Account class to load and maintain the basic account objects. | ||
* Supports partial loading and access required for verkle with null | ||
* as the placeholder. | ||
* | ||
* Note: passing undefined in constructor is different from null | ||
* While undefined leads to default assignment, null is retained | ||
* to track the information not available/loaded because of partial | ||
* witness access | ||
*/ | ||
export class Account { | ||
@@ -12,14 +22,108 @@ /** | ||
* Use the static factory methods to assist in creating an Account from varying data types. | ||
* undefined get assigned with the defaults present, but null args are retained as is | ||
*/ | ||
constructor(nonce = BIGINT_0, balance = BIGINT_0, storageRoot = KECCAK256_RLP, codeHash = KECCAK256_NULL) { | ||
this.nonce = nonce; | ||
this.balance = balance; | ||
this.storageRoot = storageRoot; | ||
this.codeHash = codeHash; | ||
constructor(nonce = BIGINT_0, balance = BIGINT_0, storageRoot = KECCAK256_RLP, codeHash = KECCAK256_NULL, codeSize = null, version = 0) { | ||
this._nonce = null; | ||
this._balance = null; | ||
this._storageRoot = null; | ||
this._codeHash = null; | ||
// codeSize and version is separately stored in VKT | ||
this._codeSize = null; | ||
this._version = null; | ||
this._nonce = nonce; | ||
this._balance = balance; | ||
this._storageRoot = storageRoot; | ||
this._codeHash = codeHash; | ||
if (codeSize === null && codeHash !== null && !this.isContract()) { | ||
codeSize = 0; | ||
} | ||
this._codeSize = codeSize; | ||
this._version = version; | ||
this._validate(); | ||
} | ||
get version() { | ||
if (this._version !== null) { | ||
return this._version; | ||
} | ||
else { | ||
throw Error(`version=${this._version} not loaded`); | ||
} | ||
} | ||
set version(_version) { | ||
this._version = _version; | ||
} | ||
get nonce() { | ||
if (this._nonce !== null) { | ||
return this._nonce; | ||
} | ||
else { | ||
throw Error(`nonce=${this._nonce} not loaded`); | ||
} | ||
} | ||
set nonce(_nonce) { | ||
this._nonce = _nonce; | ||
} | ||
get balance() { | ||
if (this._balance !== null) { | ||
return this._balance; | ||
} | ||
else { | ||
throw Error(`balance=${this._balance} not loaded`); | ||
} | ||
} | ||
set balance(_balance) { | ||
this._balance = _balance; | ||
} | ||
get storageRoot() { | ||
if (this._storageRoot !== null) { | ||
return this._storageRoot; | ||
} | ||
else { | ||
throw Error(`storageRoot=${this._storageRoot} not loaded`); | ||
} | ||
} | ||
set storageRoot(_storageRoot) { | ||
this._storageRoot = _storageRoot; | ||
} | ||
get codeHash() { | ||
if (this._codeHash !== null) { | ||
return this._codeHash; | ||
} | ||
else { | ||
throw Error(`codeHash=${this._codeHash} not loaded`); | ||
} | ||
} | ||
set codeHash(_codeHash) { | ||
this._codeHash = _codeHash; | ||
} | ||
get codeSize() { | ||
if (this._codeSize !== null) { | ||
return this._codeSize; | ||
} | ||
else { | ||
throw Error(`codeHash=${this._codeSize} not loaded`); | ||
} | ||
} | ||
set codeSize(_codeSize) { | ||
this._codeSize = _codeSize; | ||
} | ||
static fromAccountData(accountData) { | ||
const { nonce, balance, storageRoot, codeHash } = accountData; | ||
if (nonce === null || balance === null || storageRoot === null || codeHash === null) { | ||
throw Error(`Partial fields not supported in fromAccountData`); | ||
} | ||
return new Account(nonce !== undefined ? bytesToBigInt(toBytes(nonce)) : undefined, balance !== undefined ? bytesToBigInt(toBytes(balance)) : undefined, storageRoot !== undefined ? toBytes(storageRoot) : undefined, codeHash !== undefined ? toBytes(codeHash) : undefined); | ||
} | ||
static fromPartialAccountData(partialAccountData) { | ||
const { nonce, balance, storageRoot, codeHash, codeSize, version } = partialAccountData; | ||
if (nonce === null && | ||
balance === null && | ||
storageRoot === null && | ||
codeHash === null && | ||
codeSize === null && | ||
version === null) { | ||
throw Error(`All partial fields null`); | ||
} | ||
return new Account(nonce !== undefined && nonce !== null ? bytesToBigInt(toBytes(nonce)) : nonce, balance !== undefined && balance !== null ? bytesToBigInt(toBytes(balance)) : balance, storageRoot !== undefined && storageRoot !== null ? toBytes(storageRoot) : storageRoot, codeHash !== undefined && codeHash !== null ? toBytes(codeHash) : codeHash, codeSize !== undefined && codeSize !== null ? bytesToInt(toBytes(codeSize)) : codeSize, version !== undefined && version !== null ? bytesToInt(toBytes(version)) : version); | ||
} | ||
static fromRlpSerializedAccount(serialized) { | ||
@@ -32,2 +136,87 @@ const values = RLP.decode(serialized); | ||
} | ||
static fromRlpSerializedPartialAccount(serialized) { | ||
const values = RLP.decode(serialized); | ||
if (!Array.isArray(values)) { | ||
throw new Error('Invalid serialized account input. Must be array'); | ||
} | ||
let nonce = null; | ||
if (!Array.isArray(values[0])) { | ||
throw new Error('Invalid partial nonce encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[0][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for nonce`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
nonce = bytesToBigInt(values[0][1]); | ||
} | ||
} | ||
let balance = null; | ||
if (!Array.isArray(values[1])) { | ||
throw new Error('Invalid partial balance encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[1][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for balance`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
balance = bytesToBigInt(values[1][1]); | ||
} | ||
} | ||
let storageRoot = null; | ||
if (!Array.isArray(values[2])) { | ||
throw new Error('Invalid partial storageRoot encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[2][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for storageRoot`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
storageRoot = values[2][1]; | ||
} | ||
} | ||
let codeHash = null; | ||
if (!Array.isArray(values[3])) { | ||
throw new Error('Invalid partial codeHash encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[3][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeHash`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeHash = values[3][1]; | ||
} | ||
} | ||
let codeSize = null; | ||
if (!Array.isArray(values[4])) { | ||
throw new Error('Invalid partial codeSize encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[4][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeSize`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeSize = bytesToInt(values[4][1]); | ||
} | ||
} | ||
let version = null; | ||
if (!Array.isArray(values[5])) { | ||
throw new Error('Invalid partial version encoding. Must be array'); | ||
} | ||
else { | ||
const isNotNullIndicator = bytesToInt(values[5][0]); | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for version`); | ||
} | ||
if (isNotNullIndicator === 1) { | ||
version = bytesToInt(values[5][1]); | ||
} | ||
} | ||
return this.fromPartialAccountData({ balance, nonce, storageRoot, codeHash, codeSize, version }); | ||
} | ||
static fromValuesArray(values) { | ||
@@ -38,14 +227,17 @@ const [nonce, balance, storageRoot, codeHash] = values; | ||
_validate() { | ||
if (this.nonce < BIGINT_0) { | ||
if (this._nonce !== null && this._nonce < BIGINT_0) { | ||
throw new Error('nonce must be greater than zero'); | ||
} | ||
if (this.balance < BIGINT_0) { | ||
if (this._balance !== null && this._balance < BIGINT_0) { | ||
throw new Error('balance must be greater than zero'); | ||
} | ||
if (this.storageRoot.length !== 32) { | ||
if (this._storageRoot !== null && this._storageRoot.length !== 32) { | ||
throw new Error('storageRoot must have a length of 32'); | ||
} | ||
if (this.codeHash.length !== 32) { | ||
if (this._codeHash !== null && this._codeHash.length !== 32) { | ||
throw new Error('codeHash must have a length of 32'); | ||
} | ||
if (this._codeSize !== null && this._codeSize < BIGINT_0) { | ||
throw new Error('codeSize must be greater than zero'); | ||
} | ||
} | ||
@@ -69,2 +261,44 @@ /** | ||
} | ||
serializeWithPartialInfo() { | ||
const partialData = []; | ||
const zeroEncoded = intToUnpaddedBytes(0); | ||
const oneEncoded = intToUnpaddedBytes(1); | ||
if (this._nonce !== null) { | ||
partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._nonce)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._balance !== null) { | ||
partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._balance)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._storageRoot !== null) { | ||
partialData.push([oneEncoded, this._storageRoot]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._codeHash !== null) { | ||
partialData.push([oneEncoded, this._codeHash]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._codeSize !== null) { | ||
partialData.push([oneEncoded, intToUnpaddedBytes(this._codeSize)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
if (this._version !== null) { | ||
partialData.push([oneEncoded, intToUnpaddedBytes(this._version)]); | ||
} | ||
else { | ||
partialData.push([zeroEncoded]); | ||
} | ||
return RLP.encode(partialData); | ||
} | ||
/** | ||
@@ -74,3 +308,7 @@ * Returns a `Boolean` determining if the account is a contract. | ||
isContract() { | ||
return !equalsBytes(this.codeHash, KECCAK256_NULL); | ||
if (this._codeHash === null && this._codeSize === null) { | ||
throw Error(`Insufficient data as codeHash=null and codeSize=null`); | ||
} | ||
return ((this._codeHash !== null && !equalsBytes(this._codeHash, KECCAK256_NULL)) || | ||
(this._codeSize !== null && this._codeSize !== 0)); | ||
} | ||
@@ -83,2 +321,8 @@ /** | ||
isEmpty() { | ||
// helpful for determination in partial accounts | ||
if ((this._balance !== null && this.balance !== BIGINT_0) || | ||
(this._nonce === null && this.nonce !== BIGINT_0) || | ||
(this._codeHash !== null && !equalsBytes(this.codeHash, KECCAK256_NULL))) { | ||
return false; | ||
} | ||
return (this.balance === BIGINT_0 && | ||
@@ -123,3 +367,3 @@ this.nonce === BIGINT_0 && | ||
const hash = bytesToHex(keccak256(bytes)).slice(2); | ||
let ret = '0x'; | ||
let ret = ''; | ||
for (let i = 0; i < address.length; i++) { | ||
@@ -133,3 +377,3 @@ if (parseInt(hash[i], 16) >= 8) { | ||
} | ||
return ret; | ||
return `0x${ret}`; | ||
}; | ||
@@ -136,0 +380,0 @@ /** |
@@ -0,1 +1,2 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
/** | ||
@@ -55,3 +56,3 @@ * Handling and generating Ethereum addresses | ||
*/ | ||
toString(): string; | ||
toString(): PrefixedHexString; | ||
/** | ||
@@ -58,0 +59,0 @@ * Returns a new Uint8Array representation of address. |
import { generateAddress, generateAddress2, isValidAddress, privateToAddress, pubToAddress, } from './account.js'; | ||
import { bigIntToBytes, bytesToBigInt, bytesToHex, equalsBytes, toBytes, zeros } from './bytes.js'; | ||
import { bigIntToBytes, bytesToBigInt, bytesToHex, equalsBytes, hexToBytes, zeros, } from './bytes.js'; | ||
import { BIGINT_0 } from './constants.js'; | ||
@@ -26,5 +26,5 @@ /** | ||
if (!isValidAddress(str)) { | ||
throw new Error('Invalid address'); | ||
throw new Error(`Invalid address input=${str}`); | ||
} | ||
return new Address(toBytes(str)); | ||
return new Address(hexToBytes(str)); | ||
} | ||
@@ -31,0 +31,0 @@ /** |
@@ -11,3 +11,3 @@ import { bytesToHex as _bytesToUnprefixedHex } from 'ethereum-cryptography/utils.js'; | ||
export declare const unprefixedHexToBytes: (inp: string) => Uint8Array; | ||
export declare const bytesToHex: (bytes: Uint8Array) => string; | ||
export declare const bytesToHex: (bytes: Uint8Array) => PrefixedHexString; | ||
/** | ||
@@ -26,3 +26,9 @@ * Converts a {@link Uint8Array} to a {@link bigint} | ||
export declare const bytesToInt: (bytes: Uint8Array) => number; | ||
export declare const hexToBytes: (hex: string) => Uint8Array; | ||
/** | ||
* Converts a {@link PrefixedHexString} to a {@link Uint8Array} | ||
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert | ||
* @returns {Uint8Array} The converted bytes | ||
* @throws If the input is not a valid 0x-prefixed hex string | ||
*/ | ||
export declare const hexToBytes: (hex: PrefixedHexString | string) => Uint8Array; | ||
/******************************************/ | ||
@@ -83,7 +89,7 @@ /** | ||
* Trims leading zeros from a `PrefixedHexString`. | ||
* @param {PrefixedHexString} a | ||
* @param {PrefixedHexString | string} a | ||
* @return {PrefixedHexString} | ||
*/ | ||
export declare const unpadHex: (a: string) => PrefixedHexString; | ||
export declare type ToBytesInputTypes = PrefixedHexString | number | bigint | Uint8Array | number[] | TransformabletoBytes | null | undefined; | ||
export declare const unpadHex: (a: PrefixedHexString | string) => PrefixedHexString; | ||
export declare type ToBytesInputTypes = PrefixedHexString | string | number | bigint | Uint8Array | number[] | TransformabletoBytes | null | undefined; | ||
/** | ||
@@ -166,2 +172,3 @@ * Attempts to turn a value into a `Uint8Array`. | ||
export declare const bigIntToUnpaddedBytes: (value: bigint) => Uint8Array; | ||
export declare const bigIntToAddressBytes: (value: bigint, strict?: boolean) => Uint8Array; | ||
/** | ||
@@ -229,2 +236,3 @@ * Convert value from number to an unpadded Uint8Array | ||
export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/utils.js'; | ||
export declare function hexToBigInt(input: PrefixedHexString | string): bigint; | ||
//# sourceMappingURL=bytes.d.ts.map |
@@ -5,3 +5,3 @@ import { getRandomBytesSync } from 'ethereum-cryptography/random.js'; | ||
import { assertIsArray, assertIsBytes, assertIsHexString } from './helpers.js'; | ||
import { isHexPrefixed, isHexString, padToEven, stripHexPrefix } from './internal.js'; | ||
import { isHexString, padToEven, stripHexPrefix } from './internal.js'; | ||
const BIGINT_0 = BigInt(0); | ||
@@ -52,7 +52,7 @@ /** | ||
export const bytesToHex = (bytes) => { | ||
let hex = '0x'; | ||
let hex = `0x`; | ||
if (bytes === undefined || bytes.length === 0) | ||
return hex; | ||
for (const byte of bytes) { | ||
hex += hexByByte[byte]; | ||
hex = `${hex}${hexByByte[byte]}`; | ||
} | ||
@@ -100,2 +100,9 @@ return hex; | ||
}; | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Converts a {@link PrefixedHexString} to a {@link Uint8Array} | ||
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert | ||
* @returns {Uint8Array} The converted bytes | ||
* @throws If the input is not a valid 0x-prefixed hex string | ||
*/ | ||
export const hexToBytes = (hex) => { | ||
@@ -108,7 +115,4 @@ if (typeof hex !== 'string') { | ||
} | ||
hex = hex.slice(2); | ||
if (hex.length % 2 !== 0) { | ||
hex = padToEven(hex); | ||
} | ||
return _unprefixedHexToBytes(hex); | ||
const unprefixedHex = hex.slice(2); | ||
return _unprefixedHexToBytes(unprefixedHex.length % 2 === 0 ? unprefixedHex : padToEven(unprefixedHex)); | ||
}; | ||
@@ -143,3 +147,3 @@ /******************************************/ | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
const bytes = toBytes('0x' + padToEven(num.toString(16))); | ||
const bytes = toBytes(`0x${padToEven(num.toString(16))}`); | ||
return littleEndian ? bytes.reverse() : bytes; | ||
@@ -200,5 +204,5 @@ }; | ||
/** | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or PrefixedHexString`. | ||
* @param {Uint8Array|number[]|PrefixedHexString} a | ||
* @return {Uint8Array|number[]|PrefixedHexString} | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or `string`. | ||
* @param {Uint8Array|number[]|string} a | ||
* @return {Uint8Array|number[]|string} | ||
*/ | ||
@@ -231,5 +235,6 @@ const stripZeros = (a) => { | ||
}; | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Trims leading zeros from a `PrefixedHexString`. | ||
* @param {PrefixedHexString} a | ||
* @param {PrefixedHexString | string} a | ||
* @return {PrefixedHexString} | ||
@@ -239,4 +244,3 @@ */ | ||
assertIsHexString(a); | ||
a = stripHexPrefix(a); | ||
return '0x' + stripZeros(a); | ||
return `0x${stripZeros(stripHexPrefix(a))}`; | ||
}; | ||
@@ -306,3 +310,3 @@ /** | ||
} | ||
return isHexPrefixed(str) ? str : '0x' + str; | ||
return isHexString(str) ? str : `0x${str}`; | ||
}; | ||
@@ -354,3 +358,3 @@ /** | ||
export const bigIntToHex = (num) => { | ||
return '0x' + num.toString(16); | ||
return `0x${num.toString(16)}`; | ||
}; | ||
@@ -376,2 +380,10 @@ /** | ||
}; | ||
export const bigIntToAddressBytes = (value, strict = true) => { | ||
const addressBytes = bigIntToBytes(value); | ||
if (strict && addressBytes.length > 20) { | ||
throw Error(`Invalid address bytes length=${addressBytes.length} strict=${strict}`); | ||
} | ||
// setLength already slices if more than requisite length | ||
return setLengthLeft(addressBytes, 20); | ||
}; | ||
/** | ||
@@ -481,2 +493,6 @@ * Convert value from number to an unpadded Uint8Array | ||
export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/utils.js'; | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
export function hexToBigInt(input) { | ||
return bytesToBigInt(hexToBytes(isHexString(input) ? input : `0x${input}`)); | ||
} | ||
//# sourceMappingURL=bytes.js.map |
@@ -34,3 +34,3 @@ import type { PrefixedHexString } from './types.js'; | ||
export interface GenesisState { | ||
[key: PrefixedHexString]: PrefixedHexString | AccountState; | ||
[key: string]: PrefixedHexString | AccountState; | ||
} | ||
@@ -37,0 +37,0 @@ /** |
import { addHexPrefix, bigIntToHex } from './bytes.js'; | ||
import { isHexPrefixed } from './internal.js'; | ||
import { isHexString } from './internal.js'; | ||
/** | ||
@@ -9,11 +9,11 @@ * Parses the geth genesis state into Blockchain {@link GenesisState} | ||
const state = {}; | ||
for (let address of Object.keys(json.alloc)) { | ||
for (const address of Object.keys(json.alloc)) { | ||
let { balance, code, storage, nonce } = json.alloc[address]; | ||
// create a map with lowercase for easy lookups | ||
address = addHexPrefix(address.toLowerCase()); | ||
balance = isHexPrefixed(balance) ? balance : bigIntToHex(BigInt(balance)); | ||
const prefixedAddress = addHexPrefix(address.toLowerCase()); | ||
balance = isHexString(balance) ? balance : bigIntToHex(BigInt(balance)); | ||
code = code !== undefined ? addHexPrefix(code) : undefined; | ||
storage = storage !== undefined ? Object.entries(storage) : undefined; | ||
nonce = nonce !== undefined ? addHexPrefix(nonce) : undefined; | ||
state[address] = [balance, code, storage, nonce]; | ||
state[prefixedAddress] = [balance, code, storage, nonce]; | ||
} | ||
@@ -20,0 +20,0 @@ return state; |
@@ -43,3 +43,3 @@ /** | ||
export * from './genesis.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexPrefixed, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export * from './kzg.js'; | ||
@@ -49,2 +49,4 @@ export * from './lock.js'; | ||
export * from './provider.js'; | ||
export * from './requests.js'; | ||
export * from './verkle.js'; | ||
//# sourceMappingURL=index.d.ts.map |
@@ -43,3 +43,3 @@ /** | ||
export * from './genesis.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexPrefixed, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export { arrayContainsArray, fromAscii, fromUtf8, getBinarySize, getKeys, isHexString, padToEven, stripHexPrefix, toAscii, } from './internal.js'; | ||
export * from './kzg.js'; | ||
@@ -49,2 +49,4 @@ export * from './lock.js'; | ||
export * from './provider.js'; | ||
export * from './requests.js'; | ||
export * from './verkle.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -0,8 +1,9 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
/** | ||
* Returns a `Boolean` on whether or not the a `String` starts with '0x' | ||
* @param str the string input value | ||
* @return a boolean if it is or is not hex prefixed | ||
* @throws if the str input is not a string | ||
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length | ||
* @param {string} value the string input value | ||
* @param {number|undefined} length the optional length of the hex string in bytes | ||
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length | ||
*/ | ||
export declare function isHexPrefixed(str: string): boolean; | ||
export declare function isHexString(value: string, length?: number): value is PrefixedHexString; | ||
/** | ||
@@ -71,10 +72,2 @@ * Removes '0x' from a given `String` if present | ||
export declare function getKeys(params: Record<string, string>[], key: string, allowEmpty?: boolean): string[]; | ||
/** | ||
* Is the string a hex string. | ||
* | ||
* @param value | ||
* @param length | ||
* @returns output the string is a hex string | ||
*/ | ||
export declare function isHexString(value: string, length?: number): boolean; | ||
//# sourceMappingURL=internal.d.ts.map |
@@ -26,12 +26,13 @@ /* | ||
/** | ||
* Returns a `Boolean` on whether or not the a `String` starts with '0x' | ||
* @param str the string input value | ||
* @return a boolean if it is or is not hex prefixed | ||
* @throws if the str input is not a string | ||
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length | ||
* @param {string} value the string input value | ||
* @param {number|undefined} length the optional length of the hex string in bytes | ||
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length | ||
*/ | ||
export function isHexPrefixed(str) { | ||
if (typeof str !== 'string') { | ||
throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`); | ||
} | ||
return str[0] === '0' && str[1] === 'x'; | ||
export function isHexString(value, length) { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) | ||
return false; | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) | ||
return false; | ||
return true; | ||
} | ||
@@ -46,3 +47,3 @@ /** | ||
throw new Error(`[stripHexPrefix] input must be type 'string', received ${typeof str}`); | ||
return isHexPrefixed(str) ? str.slice(2) : str; | ||
return isHexString(str) ? str.slice(2) : str; | ||
}; | ||
@@ -168,16 +169,2 @@ /** | ||
} | ||
/** | ||
* Is the string a hex string. | ||
* | ||
* @param value | ||
* @param length | ||
* @returns output the string is a hex string | ||
*/ | ||
export function isHexString(value, length) { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) | ||
return false; | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) | ||
return false; | ||
return true; | ||
} | ||
//# sourceMappingURL=internal.js.map |
@@ -20,3 +20,4 @@ declare type rpcParams = { | ||
* } | ||
* const block = await fetchFromProvider(provider, params) | ||
* const block = await fetchFromProvider(provider, params) | ||
* ``` | ||
*/ | ||
@@ -23,0 +24,0 @@ export declare const fetchFromProvider: (url: string, params: rpcParams) => Promise<any>; |
@@ -16,3 +16,4 @@ /** | ||
* } | ||
* const block = await fetchFromProvider(provider, params) | ||
* const block = await fetchFromProvider(provider, params) | ||
* ``` | ||
*/ | ||
@@ -19,0 +20,0 @@ export const fetchFromProvider = async (url, params) => { |
@@ -0,1 +1,2 @@ | ||
import type { PrefixedHexString } from './types.js'; | ||
export interface ECDSASignature { | ||
@@ -40,3 +41,3 @@ v: bigint; | ||
*/ | ||
export declare const fromRpcSig: (sig: string) => ECDSASignature; | ||
export declare const fromRpcSig: (sig: PrefixedHexString) => ECDSASignature; | ||
/** | ||
@@ -43,0 +44,0 @@ * Validate a ECDSA signature. |
@@ -5,3 +5,3 @@ import type { Address } from './address.js'; | ||
export declare type BytesLike = Uint8Array | number[] | number | bigint | TransformabletoBytes | PrefixedHexString; | ||
export declare type PrefixedHexString = string; | ||
export declare type PrefixedHexString = `0x${string}`; | ||
/** | ||
@@ -15,2 +15,3 @@ * A type that represents an input that can be converted to an Address. | ||
export declare type NestedUint8Array = Array<Uint8Array | NestedUint8Array>; | ||
export declare function isNestedUint8Array(value: unknown): value is NestedUint8Array; | ||
/** | ||
@@ -17,0 +18,0 @@ * Type output options |
import { bytesToBigInt, bytesToHex, toBytes } from './bytes.js'; | ||
import { isHexString } from './internal.js'; | ||
export function isNestedUint8Array(value) { | ||
if (!Array.isArray(value)) { | ||
return false; | ||
} | ||
for (const item of value) { | ||
if (Array.isArray(item)) { | ||
if (!isNestedUint8Array(item)) { | ||
return false; | ||
} | ||
} | ||
else if (!(item instanceof Uint8Array)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
/** | ||
@@ -4,0 +20,0 @@ * Type output options |
import { Address } from './address.js'; | ||
import type { AddressLike, BigIntLike } from './types.js'; | ||
import type { AddressLike, BigIntLike, PrefixedHexString } from './types.js'; | ||
/** | ||
@@ -18,6 +18,6 @@ * Flexible input data type for EIP-4895 withdrawal data with amount in Gwei to | ||
export interface JsonRpcWithdrawal { | ||
index: string; | ||
validatorIndex: string; | ||
address: string; | ||
amount: string; | ||
index: PrefixedHexString; | ||
validatorIndex: PrefixedHexString; | ||
address: PrefixedHexString; | ||
amount: PrefixedHexString; | ||
} | ||
@@ -62,8 +62,8 @@ export declare type WithdrawalBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array]; | ||
toJSON(): { | ||
index: string; | ||
validatorIndex: string; | ||
address: string; | ||
amount: string; | ||
index: `0x${string}`; | ||
validatorIndex: `0x${string}`; | ||
address: `0x${string}`; | ||
amount: `0x${string}`; | ||
}; | ||
} | ||
//# sourceMappingURL=withdrawal.d.ts.map |
{ | ||
"name": "@ethereumjs/util", | ||
"version": "9.0.3", | ||
"version": "9.1.0", | ||
"description": "A collection of utility functions for Ethereum", | ||
@@ -88,4 +88,4 @@ "keywords": [ | ||
"prepublishOnly": "../../config/cli/prepublish.sh", | ||
"test": "npm run test:node && npm run test:browser", | ||
"test:browser": "npx vitest run --config=./vitest.config.browser.ts --browser.name=chrome --browser.headless", | ||
"test": "npm run test:node", | ||
"test:browser": "npx vitest run --config=../../config/vitest.config.browser.mts", | ||
"test:node": "npx vitest run", | ||
@@ -96,6 +96,6 @@ "tsc": "../../config/cli/ts-compile.sh" | ||
"@ethereumjs/rlp": "^5.0.2", | ||
"ethereum-cryptography": "^2.1.3" | ||
"ethereum-cryptography": "^2.2.1" | ||
}, | ||
"devDependencies": { | ||
"kzg-wasm": "^0.3.1" | ||
"kzg-wasm": "^0.4.0" | ||
}, | ||
@@ -102,0 +102,0 @@ "engines": { |
@@ -48,2 +48,16 @@ # @ethereumjs/util | ||
For Verkle or other contexts it can be useful to create partial accounts not containing all the account parameters. This is supported starting with v9.1.0: | ||
```ts | ||
// ./examples/accountPartial.ts | ||
import { Account } from '@ethereumjs/util' | ||
const account = Account.fromPartialAccountData({ | ||
nonce: '0x02', | ||
balance: '0x0384', | ||
}) | ||
console.log(`Partial account with nonce=${account.nonce} and balance=${account.balance} created`) | ||
``` | ||
### Module: [address](src/address.ts) | ||
@@ -121,3 +135,3 @@ | ||
Internalized simple helper methods like `isHexPrefixed`. Note that methods from this module might get deprectared in the future. | ||
Internalized simple helper methods like `isHexString`. Note that methods from this module might get deprecated in the future. | ||
@@ -132,2 +146,12 @@ ### Module: [kzg](src/kzg.ts) | ||
### Module: [requests](src/requests.ts) | ||
Module with various type and an abstract base class for [EIP-7685](https://eips.ethereum.org/EIPS/eip-7685) general purpose execution layer requests to the CL (Prague hardfork) as well as concrete implementations for the currently supported request types: | ||
- [EIP-6110](https://eips.ethereum.org/EIPS/eip-6110): `DepositRequest` (Prague Harfork) | ||
- [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002): `WithdrawawlRequest` (Prague Hardfork) | ||
- [EIP-7251](https://eips.ethereum.org/EIPS/eip-7251): `ConsolidationRequest` (Prague Hardfork) | ||
These request types are mainly used within the [@ethereumjs/block](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/block) library where applied usage instructions are provided in the README. | ||
### Module: [signature](src/signature.ts) | ||
@@ -263,4 +287,4 @@ | ||
- stripHexPrefix | ||
- isHexPrefixed | ||
- isHexString | ||
- isHexString | ||
- padToEven | ||
@@ -267,0 +291,0 @@ - fromAscii |
@@ -9,5 +9,7 @@ import { RLP } from '@ethereumjs/rlp' | ||
bytesToHex, | ||
bytesToInt, | ||
concatBytes, | ||
equalsBytes, | ||
hexToBytes, | ||
intToUnpaddedBytes, | ||
toBytes, | ||
@@ -21,3 +23,3 @@ utf8ToBytes, | ||
import type { BigIntLike, BytesLike } from './types.js' | ||
import type { BigIntLike, BytesLike, PrefixedHexString } from './types.js' | ||
@@ -31,12 +33,103 @@ export interface AccountData { | ||
export interface PartialAccountData { | ||
nonce?: BigIntLike | null | ||
balance?: BigIntLike | null | ||
storageRoot?: BytesLike | null | ||
codeHash?: BytesLike | null | ||
codeSize?: BigIntLike | null | ||
version?: BigIntLike | null | ||
} | ||
export type AccountBodyBytes = [Uint8Array, Uint8Array, Uint8Array, Uint8Array] | ||
/** | ||
* Account class to load and maintain the basic account objects. | ||
* Supports partial loading and access required for verkle with null | ||
* as the placeholder. | ||
* | ||
* Note: passing undefined in constructor is different from null | ||
* While undefined leads to default assignment, null is retained | ||
* to track the information not available/loaded because of partial | ||
* witness access | ||
*/ | ||
export class Account { | ||
nonce: bigint | ||
balance: bigint | ||
storageRoot: Uint8Array | ||
codeHash: Uint8Array | ||
_nonce: bigint | null = null | ||
_balance: bigint | null = null | ||
_storageRoot: Uint8Array | null = null | ||
_codeHash: Uint8Array | null = null | ||
// codeSize and version is separately stored in VKT | ||
_codeSize: number | null = null | ||
_version: number | null = null | ||
get version() { | ||
if (this._version !== null) { | ||
return this._version | ||
} else { | ||
throw Error(`version=${this._version} not loaded`) | ||
} | ||
} | ||
set version(_version: number) { | ||
this._version = _version | ||
} | ||
get nonce() { | ||
if (this._nonce !== null) { | ||
return this._nonce | ||
} else { | ||
throw Error(`nonce=${this._nonce} not loaded`) | ||
} | ||
} | ||
set nonce(_nonce: bigint) { | ||
this._nonce = _nonce | ||
} | ||
get balance() { | ||
if (this._balance !== null) { | ||
return this._balance | ||
} else { | ||
throw Error(`balance=${this._balance} not loaded`) | ||
} | ||
} | ||
set balance(_balance: bigint) { | ||
this._balance = _balance | ||
} | ||
get storageRoot() { | ||
if (this._storageRoot !== null) { | ||
return this._storageRoot | ||
} else { | ||
throw Error(`storageRoot=${this._storageRoot} not loaded`) | ||
} | ||
} | ||
set storageRoot(_storageRoot: Uint8Array) { | ||
this._storageRoot = _storageRoot | ||
} | ||
get codeHash() { | ||
if (this._codeHash !== null) { | ||
return this._codeHash | ||
} else { | ||
throw Error(`codeHash=${this._codeHash} not loaded`) | ||
} | ||
} | ||
set codeHash(_codeHash: Uint8Array) { | ||
this._codeHash = _codeHash | ||
} | ||
get codeSize() { | ||
if (this._codeSize !== null) { | ||
return this._codeSize | ||
} else { | ||
throw Error(`codeHash=${this._codeSize} not loaded`) | ||
} | ||
} | ||
set codeSize(_codeSize: number) { | ||
this._codeSize = _codeSize | ||
} | ||
static fromAccountData(accountData: AccountData) { | ||
const { nonce, balance, storageRoot, codeHash } = accountData | ||
if (nonce === null || balance === null || storageRoot === null || codeHash === null) { | ||
throw Error(`Partial fields not supported in fromAccountData`) | ||
} | ||
@@ -51,2 +144,26 @@ return new Account( | ||
static fromPartialAccountData(partialAccountData: PartialAccountData) { | ||
const { nonce, balance, storageRoot, codeHash, codeSize, version } = partialAccountData | ||
if ( | ||
nonce === null && | ||
balance === null && | ||
storageRoot === null && | ||
codeHash === null && | ||
codeSize === null && | ||
version === null | ||
) { | ||
throw Error(`All partial fields null`) | ||
} | ||
return new Account( | ||
nonce !== undefined && nonce !== null ? bytesToBigInt(toBytes(nonce)) : nonce, | ||
balance !== undefined && balance !== null ? bytesToBigInt(toBytes(balance)) : balance, | ||
storageRoot !== undefined && storageRoot !== null ? toBytes(storageRoot) : storageRoot, | ||
codeHash !== undefined && codeHash !== null ? toBytes(codeHash) : codeHash, | ||
codeSize !== undefined && codeSize !== null ? bytesToInt(toBytes(codeSize)) : codeSize, | ||
version !== undefined && version !== null ? bytesToInt(toBytes(version)) : version | ||
) | ||
} | ||
public static fromRlpSerializedAccount(serialized: Uint8Array) { | ||
@@ -62,2 +179,90 @@ const values = RLP.decode(serialized) as Uint8Array[] | ||
public static fromRlpSerializedPartialAccount(serialized: Uint8Array) { | ||
const values = RLP.decode(serialized) as Uint8Array[][] | ||
if (!Array.isArray(values)) { | ||
throw new Error('Invalid serialized account input. Must be array') | ||
} | ||
let nonce = null | ||
if (!Array.isArray(values[0])) { | ||
throw new Error('Invalid partial nonce encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[0][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for nonce`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
nonce = bytesToBigInt(values[0][1]) | ||
} | ||
} | ||
let balance = null | ||
if (!Array.isArray(values[1])) { | ||
throw new Error('Invalid partial balance encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[1][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for balance`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
balance = bytesToBigInt(values[1][1]) | ||
} | ||
} | ||
let storageRoot = null | ||
if (!Array.isArray(values[2])) { | ||
throw new Error('Invalid partial storageRoot encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[2][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for storageRoot`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
storageRoot = values[2][1] | ||
} | ||
} | ||
let codeHash = null | ||
if (!Array.isArray(values[3])) { | ||
throw new Error('Invalid partial codeHash encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[3][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeHash`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeHash = values[3][1] | ||
} | ||
} | ||
let codeSize = null | ||
if (!Array.isArray(values[4])) { | ||
throw new Error('Invalid partial codeSize encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[4][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for codeSize`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
codeSize = bytesToInt(values[4][1]) | ||
} | ||
} | ||
let version = null | ||
if (!Array.isArray(values[5])) { | ||
throw new Error('Invalid partial version encoding. Must be array') | ||
} else { | ||
const isNotNullIndicator = bytesToInt(values[5][0]) | ||
if (isNotNullIndicator !== 0 && isNotNullIndicator !== 1) { | ||
throw new Error(`Invalid isNullIndicator=${isNotNullIndicator} for version`) | ||
} | ||
if (isNotNullIndicator === 1) { | ||
version = bytesToInt(values[5][1]) | ||
} | ||
} | ||
return this.fromPartialAccountData({ balance, nonce, storageRoot, codeHash, codeSize, version }) | ||
} | ||
public static fromValuesArray(values: Uint8Array[]) { | ||
@@ -72,14 +277,23 @@ const [nonce, balance, storageRoot, codeHash] = values | ||
* Use the static factory methods to assist in creating an Account from varying data types. | ||
* undefined get assigned with the defaults present, but null args are retained as is | ||
*/ | ||
constructor( | ||
nonce = BIGINT_0, | ||
balance = BIGINT_0, | ||
storageRoot = KECCAK256_RLP, | ||
codeHash = KECCAK256_NULL | ||
nonce: bigint | null = BIGINT_0, | ||
balance: bigint | null = BIGINT_0, | ||
storageRoot: Uint8Array | null = KECCAK256_RLP, | ||
codeHash: Uint8Array | null = KECCAK256_NULL, | ||
codeSize: number | null = null, | ||
version: number | null = 0 | ||
) { | ||
this.nonce = nonce | ||
this.balance = balance | ||
this.storageRoot = storageRoot | ||
this.codeHash = codeHash | ||
this._nonce = nonce | ||
this._balance = balance | ||
this._storageRoot = storageRoot | ||
this._codeHash = codeHash | ||
if (codeSize === null && codeHash !== null && !this.isContract()) { | ||
codeSize = 0 | ||
} | ||
this._codeSize = codeSize | ||
this._version = version | ||
this._validate() | ||
@@ -89,14 +303,17 @@ } | ||
private _validate() { | ||
if (this.nonce < BIGINT_0) { | ||
if (this._nonce !== null && this._nonce < BIGINT_0) { | ||
throw new Error('nonce must be greater than zero') | ||
} | ||
if (this.balance < BIGINT_0) { | ||
if (this._balance !== null && this._balance < BIGINT_0) { | ||
throw new Error('balance must be greater than zero') | ||
} | ||
if (this.storageRoot.length !== 32) { | ||
if (this._storageRoot !== null && this._storageRoot.length !== 32) { | ||
throw new Error('storageRoot must have a length of 32') | ||
} | ||
if (this.codeHash.length !== 32) { | ||
if (this._codeHash !== null && this._codeHash.length !== 32) { | ||
throw new Error('codeHash must have a length of 32') | ||
} | ||
if (this._codeSize !== null && this._codeSize < BIGINT_0) { | ||
throw new Error('codeSize must be greater than zero') | ||
} | ||
} | ||
@@ -123,2 +340,46 @@ | ||
serializeWithPartialInfo(): Uint8Array { | ||
const partialData = [] | ||
const zeroEncoded = intToUnpaddedBytes(0) | ||
const oneEncoded = intToUnpaddedBytes(1) | ||
if (this._nonce !== null) { | ||
partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._nonce)]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
if (this._balance !== null) { | ||
partialData.push([oneEncoded, bigIntToUnpaddedBytes(this._balance)]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
if (this._storageRoot !== null) { | ||
partialData.push([oneEncoded, this._storageRoot]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
if (this._codeHash !== null) { | ||
partialData.push([oneEncoded, this._codeHash]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
if (this._codeSize !== null) { | ||
partialData.push([oneEncoded, intToUnpaddedBytes(this._codeSize)]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
if (this._version !== null) { | ||
partialData.push([oneEncoded, intToUnpaddedBytes(this._version)]) | ||
} else { | ||
partialData.push([zeroEncoded]) | ||
} | ||
return RLP.encode(partialData) | ||
} | ||
/** | ||
@@ -128,3 +389,9 @@ * Returns a `Boolean` determining if the account is a contract. | ||
isContract(): boolean { | ||
return !equalsBytes(this.codeHash, KECCAK256_NULL) | ||
if (this._codeHash === null && this._codeSize === null) { | ||
throw Error(`Insufficient data as codeHash=null and codeSize=null`) | ||
} | ||
return ( | ||
(this._codeHash !== null && !equalsBytes(this._codeHash, KECCAK256_NULL)) || | ||
(this._codeSize !== null && this._codeSize !== 0) | ||
) | ||
} | ||
@@ -138,2 +405,11 @@ | ||
isEmpty(): boolean { | ||
// helpful for determination in partial accounts | ||
if ( | ||
(this._balance !== null && this.balance !== BIGINT_0) || | ||
(this._nonce === null && this.nonce !== BIGINT_0) || | ||
(this._codeHash !== null && !equalsBytes(this.codeHash, KECCAK256_NULL)) | ||
) { | ||
return false | ||
} | ||
return ( | ||
@@ -150,3 +426,3 @@ this.balance === BIGINT_0 && | ||
*/ | ||
export const isValidAddress = function (hexAddress: string): boolean { | ||
export const isValidAddress = function (hexAddress: string): hexAddress is PrefixedHexString { | ||
try { | ||
@@ -176,3 +452,3 @@ assertIsString(hexAddress) | ||
eip1191ChainId?: BigIntLike | ||
): string { | ||
): PrefixedHexString { | ||
assertIsHexString(hexAddress) | ||
@@ -189,3 +465,3 @@ const address = stripHexPrefix(hexAddress).toLowerCase() | ||
const hash = bytesToHex(keccak256(bytes)).slice(2) | ||
let ret = '0x' | ||
let ret = '' | ||
@@ -200,3 +476,3 @@ for (let i = 0; i < address.length; i++) { | ||
return ret | ||
return `0x${ret}` | ||
} | ||
@@ -203,0 +479,0 @@ |
@@ -8,5 +8,14 @@ import { | ||
} from './account.js' | ||
import { bigIntToBytes, bytesToBigInt, bytesToHex, equalsBytes, toBytes, zeros } from './bytes.js' | ||
import { | ||
bigIntToBytes, | ||
bytesToBigInt, | ||
bytesToHex, | ||
equalsBytes, | ||
hexToBytes, | ||
zeros, | ||
} from './bytes.js' | ||
import { BIGINT_0 } from './constants.js' | ||
import type { PrefixedHexString } from './types.js' | ||
/** | ||
@@ -38,5 +47,5 @@ * Handling and generating Ethereum addresses | ||
if (!isValidAddress(str)) { | ||
throw new Error('Invalid address') | ||
throw new Error(`Invalid address input=${str}`) | ||
} | ||
return new Address(toBytes(str)) | ||
return new Address(hexToBytes(str)) | ||
} | ||
@@ -124,3 +133,3 @@ | ||
*/ | ||
toString(): string { | ||
toString(): PrefixedHexString { | ||
return bytesToHex(this.bytes) | ||
@@ -127,0 +136,0 @@ } |
@@ -6,3 +6,3 @@ import { getRandomBytesSync } from 'ethereum-cryptography/random.js' | ||
import { assertIsArray, assertIsBytes, assertIsHexString } from './helpers.js' | ||
import { isHexPrefixed, isHexString, padToEven, stripHexPrefix } from './internal.js' | ||
import { isHexString, padToEven, stripHexPrefix } from './internal.js' | ||
@@ -61,7 +61,7 @@ import type { PrefixedHexString, TransformabletoBytes } from './types.js' | ||
export const bytesToHex = (bytes: Uint8Array): string => { | ||
let hex = '0x' | ||
export const bytesToHex = (bytes: Uint8Array): PrefixedHexString => { | ||
let hex: PrefixedHexString = `0x` | ||
if (bytes === undefined || bytes.length === 0) return hex | ||
for (const byte of bytes) { | ||
hex += hexByByte[byte] | ||
hex = `${hex}${hexByByte[byte]}` | ||
} | ||
@@ -112,3 +112,10 @@ return hex | ||
export const hexToBytes = (hex: string): Uint8Array => { | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Converts a {@link PrefixedHexString} to a {@link Uint8Array} | ||
* @param {PrefixedHexString | string} hex The 0x-prefixed hex string to convert | ||
* @returns {Uint8Array} The converted bytes | ||
* @throws If the input is not a valid 0x-prefixed hex string | ||
*/ | ||
export const hexToBytes = (hex: PrefixedHexString | string): Uint8Array => { | ||
if (typeof hex !== 'string') { | ||
@@ -122,8 +129,7 @@ throw new Error(`hex argument type ${typeof hex} must be of type string`) | ||
hex = hex.slice(2) | ||
const unprefixedHex = hex.slice(2) | ||
if (hex.length % 2 !== 0) { | ||
hex = padToEven(hex) | ||
} | ||
return _unprefixedHexToBytes(hex) | ||
return _unprefixedHexToBytes( | ||
unprefixedHex.length % 2 === 0 ? unprefixedHex : padToEven(unprefixedHex) | ||
) | ||
} | ||
@@ -162,3 +168,3 @@ | ||
// eslint-disable-next-line @typescript-eslint/no-use-before-define | ||
const bytes = toBytes('0x' + padToEven(num.toString(16))) | ||
const bytes = toBytes(`0x${padToEven(num.toString(16))}`) | ||
@@ -224,9 +230,7 @@ return littleEndian ? bytes.reverse() : bytes | ||
/** | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or PrefixedHexString`. | ||
* @param {Uint8Array|number[]|PrefixedHexString} a | ||
* @return {Uint8Array|number[]|PrefixedHexString} | ||
* Trims leading zeros from a `Uint8Array`, `number[]` or `string`. | ||
* @param {Uint8Array|number[]|string} a | ||
* @return {Uint8Array|number[]|string} | ||
*/ | ||
const stripZeros = < | ||
T extends Uint8Array | number[] | PrefixedHexString = Uint8Array | number[] | PrefixedHexString | ||
>( | ||
const stripZeros = <T extends Uint8Array | number[] | string = Uint8Array | number[] | string>( | ||
a: T | ||
@@ -262,15 +266,17 @@ ): T => { | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
/** | ||
* Trims leading zeros from a `PrefixedHexString`. | ||
* @param {PrefixedHexString} a | ||
* @param {PrefixedHexString | string} a | ||
* @return {PrefixedHexString} | ||
*/ | ||
export const unpadHex = (a: string): PrefixedHexString => { | ||
export const unpadHex = (a: PrefixedHexString | string): PrefixedHexString => { | ||
assertIsHexString(a) | ||
a = stripHexPrefix(a) | ||
return '0x' + stripZeros(a) | ||
return `0x${stripZeros(stripHexPrefix(a))}` | ||
} | ||
// TODO: remove the string type from this function (only keep PrefixedHexString) | ||
export type ToBytesInputTypes = | ||
| PrefixedHexString | ||
| string | ||
| number | ||
@@ -359,3 +365,3 @@ | bigint | ||
return isHexPrefixed(str) ? str : '0x' + str | ||
return isHexString(str) ? str : `0x${str}` | ||
} | ||
@@ -410,3 +416,3 @@ | ||
export const bigIntToHex = (num: bigint): PrefixedHexString => { | ||
return '0x' + num.toString(16) | ||
return `0x${num.toString(16)}` | ||
} | ||
@@ -436,2 +442,12 @@ | ||
export const bigIntToAddressBytes = (value: bigint, strict: boolean = true): Uint8Array => { | ||
const addressBytes = bigIntToBytes(value) | ||
if (strict && addressBytes.length > 20) { | ||
throw Error(`Invalid address bytes length=${addressBytes.length} strict=${strict}`) | ||
} | ||
// setLength already slices if more than requisite length | ||
return setLengthLeft(addressBytes, 20) | ||
} | ||
/** | ||
@@ -548,1 +564,6 @@ * Convert value from number to an unpadded Uint8Array | ||
export { bytesToUtf8, equalsBytes, utf8ToBytes } from 'ethereum-cryptography/utils.js' | ||
// TODO: Restrict the input type to only PrefixedHexString | ||
export function hexToBigInt(input: PrefixedHexString | string): bigint { | ||
return bytesToBigInt(hexToBytes(isHexString(input) ? input : `0x${input}`)) | ||
} |
import { addHexPrefix, bigIntToHex } from './bytes.js' | ||
import { isHexPrefixed } from './internal.js' | ||
import { isHexString } from './internal.js' | ||
@@ -40,3 +40,3 @@ import type { PrefixedHexString } from './types.js' | ||
export interface GenesisState { | ||
[key: PrefixedHexString]: PrefixedHexString | AccountState | ||
[key: string]: PrefixedHexString | AccountState | ||
} | ||
@@ -50,13 +50,13 @@ | ||
const state: GenesisState = {} | ||
for (let address of Object.keys(json.alloc)) { | ||
for (const address of Object.keys(json.alloc)) { | ||
let { balance, code, storage, nonce } = json.alloc[address] | ||
// create a map with lowercase for easy lookups | ||
address = addHexPrefix(address.toLowerCase()) | ||
balance = isHexPrefixed(balance) ? balance : bigIntToHex(BigInt(balance)) | ||
const prefixedAddress = addHexPrefix(address.toLowerCase()) | ||
balance = isHexString(balance) ? balance : bigIntToHex(BigInt(balance)) | ||
code = code !== undefined ? addHexPrefix(code) : undefined | ||
storage = storage !== undefined ? Object.entries(storage) : undefined | ||
nonce = nonce !== undefined ? addHexPrefix(nonce) : undefined | ||
state[address] = [balance, code, storage, nonce] | ||
state[prefixedAddress] = [balance, code, storage, nonce] | ||
} | ||
return state | ||
} |
@@ -58,3 +58,2 @@ /** | ||
getKeys, | ||
isHexPrefixed, | ||
isHexString, | ||
@@ -69,1 +68,3 @@ padToEven, | ||
export * from './provider.js' | ||
export * from './requests.js' | ||
export * from './verkle.js' |
@@ -27,14 +27,16 @@ /* | ||
import type { PrefixedHexString } from './types.js' | ||
/** | ||
* Returns a `Boolean` on whether or not the a `String` starts with '0x' | ||
* @param str the string input value | ||
* @return a boolean if it is or is not hex prefixed | ||
* @throws if the str input is not a string | ||
* Returns a boolean on whether or not the the input starts with '0x' and matches the optional length | ||
* @param {string} value the string input value | ||
* @param {number|undefined} length the optional length of the hex string in bytes | ||
* @returns {boolean} Whether or not the string is a valid PrefixedHexString matching the optional length | ||
*/ | ||
export function isHexPrefixed(str: string): boolean { | ||
if (typeof str !== 'string') { | ||
throw new Error(`[isHexPrefixed] input must be type 'string', received type ${typeof str}`) | ||
} | ||
export function isHexString(value: string, length?: number): value is PrefixedHexString { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) return false | ||
return str[0] === '0' && str[1] === 'x' | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) return false | ||
return true | ||
} | ||
@@ -51,3 +53,3 @@ | ||
return isHexPrefixed(str) ? str.slice(2) : str | ||
return isHexString(str) ? str.slice(2) : str | ||
} | ||
@@ -200,16 +202,1 @@ | ||
} | ||
/** | ||
* Is the string a hex string. | ||
* | ||
* @param value | ||
* @param length | ||
* @returns output the string is a hex string | ||
*/ | ||
export function isHexString(value: string, length?: number): boolean { | ||
if (typeof value !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) return false | ||
if (typeof length !== 'undefined' && length > 0 && value.length !== 2 + 2 * length) return false | ||
return true | ||
} |
@@ -21,3 +21,4 @@ type rpcParams = { | ||
* } | ||
* const block = await fetchFromProvider(provider, params) | ||
* const block = await fetchFromProvider(provider, params) | ||
* ``` | ||
*/ | ||
@@ -24,0 +25,0 @@ export const fetchFromProvider = async (url: string, params: rpcParams) => { |
@@ -23,2 +23,4 @@ import { keccak256 } from 'ethereum-cryptography/keccak.js' | ||
import type { PrefixedHexString } from './types.js' | ||
export interface ECDSASignature { | ||
@@ -143,3 +145,3 @@ v: bigint | ||
*/ | ||
export const fromRpcSig = function (sig: string): ECDSASignature { | ||
export const fromRpcSig = function (sig: PrefixedHexString): ECDSASignature { | ||
const bytes: Uint8Array = toBytes(sig) | ||
@@ -146,0 +148,0 @@ |
@@ -26,3 +26,3 @@ import { bytesToBigInt, bytesToHex, toBytes } from './bytes.js' | ||
*/ | ||
export type PrefixedHexString = string | ||
export type PrefixedHexString = `0x${string}` | ||
@@ -40,2 +40,18 @@ /** | ||
export function isNestedUint8Array(value: unknown): value is NestedUint8Array { | ||
if (!Array.isArray(value)) { | ||
return false | ||
} | ||
for (const item of value) { | ||
if (Array.isArray(item)) { | ||
if (!isNestedUint8Array(item)) { | ||
return false | ||
} | ||
} else if (!(item instanceof Uint8Array)) { | ||
return false | ||
} | ||
} | ||
return true | ||
} | ||
/** | ||
@@ -42,0 +58,0 @@ * Type output options |
@@ -6,3 +6,3 @@ import { Address } from './address.js' | ||
import type { AddressLike, BigIntLike } from './types.js' | ||
import type { AddressLike, BigIntLike, PrefixedHexString } from './types.js' | ||
@@ -25,6 +25,6 @@ /** | ||
export interface JsonRpcWithdrawal { | ||
index: string // QUANTITY - bigint 8 bytes | ||
validatorIndex: string // QUANTITY - bigint 8 bytes | ||
address: string // DATA, 20 Bytes address to withdraw to | ||
amount: string // QUANTITY - bigint amount in Gwei 8 bytes | ||
index: PrefixedHexString // QUANTITY - bigint 8 bytes | ||
validatorIndex: PrefixedHexString // QUANTITY - bigint 8 bytes | ||
address: PrefixedHexString // DATA, 20 Bytes address to withdraw to | ||
amount: PrefixedHexString // QUANTITY - bigint amount in Gwei 8 bytes | ||
} | ||
@@ -31,0 +31,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
702417
196
10691
317
Updatedethereum-cryptography@^2.2.1