@tevm/utils
Version:
A custom implementation of ethereumjs blockchain
268 lines (264 loc) • 9.77 kB
JavaScript
import { DefensiveNullCheckError, InvalidBytesSizeError, UnreachableCodeError } from '@tevm/errors';
export { formatAbi, parseAbi } from 'abitype';
import { privateKeyToAccount } from 'viem/accounts';
export { mnemonicToAccount } from 'viem/accounts';
import { hexToBytes, keccak256, toBytes, toHex, getAddress, bytesToHex } from 'viem/utils';
export { boolToBytes, boolToHex, bytesToBigInt, bytesToBigint, bytesToBool, bytesToHex, bytesToNumber, decodeAbiParameters, decodeErrorResult, decodeEventLog, decodeFunctionData, decodeFunctionResult, encodeAbiParameters, encodeDeployData, encodeErrorResult, encodeEventTopics, encodeFunctionData, encodeFunctionResult, encodePacked, formatEther, formatGwei, formatLog, fromBytes, fromHex, fromRlp, getAddress, hexToBigInt, hexToBool, hexToBytes, hexToNumber, hexToString, isAddress, isBytes, isHex, keccak256, numberToHex, parseEther, parseGwei, serializeTransaction, stringToHex, toBytes, toHex, toRlp } from 'viem/utils';
import { ecrecover } from '@ethereumjs/util';
export { Account as EthjsAccount, Address as EthjsAddress, GWEI_TO_WEI, KECCAK256_RLP, KECCAK256_RLP_ARRAY, KeyEncoding, TypeOutput, ValueEncoding, Withdrawal, bytesToUnprefixedHex, bytesToUtf8, concatBytes, createAccount, createAddressFromString, createWithdrawal, ecrecover, equalsBytes, fetchFromProvider, getProvider, randomBytes, setLengthLeft, toType } from '@ethereumjs/util';
// src/Bloom.ts
// src/Bloom.ts
var zeros = (bytes) => {
return new Uint8Array(bytes);
};
var BYTE_SIZE = 256;
var Bloom = class {
bitvector;
/**
* Represents a Bloom filter.
* @throws {InvalidBytesSizeError} If the byte size of the bitvector is not 256.
*/
constructor(bitvector) {
if (!bitvector) {
this.bitvector = zeros(BYTE_SIZE);
} else {
if (bitvector.length !== BYTE_SIZE) throw new InvalidBytesSizeError(BYTE_SIZE, bitvector.length);
this.bitvector = bitvector;
}
}
/**
* Adds an element to a bit vector of a 64 byte bloom filter.
* @param e - The element to add
* @throws {never}
*/
add(e) {
const eBytes = hexToBytes(keccak256(e));
const mask = 2047;
for (let i = 0; i < 3; i++) {
const first2bytes = new DataView(eBytes.buffer).getUint16(i * 2);
const loc = mask & first2bytes;
const byteLoc = loc >> 3;
const bitLoc = 1 << loc % 8;
let item = this.bitvector[BYTE_SIZE - byteLoc - 1];
if (item === void 0) {
throw new DefensiveNullCheckError("item is not defined. There is a bug in the implementation");
}
item |= bitLoc;
this.bitvector[BYTE_SIZE - byteLoc - 1] = item;
}
}
/**
* Checks if an element is in the bloom.
* @param e - The element to check
* @throws {never}
*/
check(e) {
const eBytes = hexToBytes(keccak256(e));
const mask = 2047;
let match = true;
for (let i = 0; i < 3 && match; i++) {
const first2bytes = new DataView(eBytes.buffer).getUint16(i * 2);
const loc = mask & first2bytes;
const byteLoc = loc >> 3;
const bitLoc = 1 << loc % 8;
const item = this.bitvector[BYTE_SIZE - byteLoc - 1];
if (item === void 0) {
throw new DefensiveNullCheckError("item is not defined. There is a bug in the implementation");
}
match = (item & bitLoc) !== 0;
}
return Boolean(match);
}
/**
* Checks if multiple topics are in a bloom.
* @returns `true` if every topic is in the bloom
* @throws {never}
*/
multiCheck(topics) {
return topics.every((t) => this.check(t));
}
/**
* Bitwise or blooms together.
* @throws {never}
*/
or(bloom) {
for (let i = 0; i <= BYTE_SIZE; i++) {
const a = this.bitvector[i];
const b = bloom.bitvector[i];
if (a === void 0) {
throw new DefensiveNullCheckError("a is not defined. Please open an issue in the tevm github repo");
}
if (b === void 0) {
throw new DefensiveNullCheckError("b is not defined. Please open an issue in the tevm github repo");
}
this.bitvector[i] = a | b;
}
}
};
var encodeKey = (bytes) => {
if (bytes instanceof Uint8Array) {
return bytesToHex(bytes);
}
return bytes;
};
var createMemoryDb = (initialDb) => {
const db = initialDb ?? /* @__PURE__ */ new Map();
return {
get: (key) => {
return Promise.resolve(db.get(encodeKey(key)));
},
put: (key, value) => {
db.set(encodeKey(key), value);
return Promise.resolve();
},
del: (key) => {
db.delete(encodeKey(key));
return Promise.resolve();
},
shallowCopy: () => {
return createMemoryDb(new Map(db));
},
// For compatability
open: () => Promise.resolve(),
batch: (stack) => {
for (const item of stack) {
if (item.type === "del") {
db.delete(encodeKey(item.key));
} else if (item.type === "put") {
db.set(encodeKey(item.key), item.value);
} else {
return Promise.reject(new UnreachableCodeError(item));
}
}
return Promise.resolve();
}
};
};
var PREFUNDED_PRIVATE_KEYS = [
"0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80",
// 0
"0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d",
// 1
"0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a",
// 2
"0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6",
// 3
"0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a",
// 4
"0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba",
// 5
"0x92db14e403b83dfe3df233f83dfa3a0d7096f21ca9b0d6d6b8d88b2b4ec1564e",
// 6
"0x4bbbf85ce3377467afe5d46f804f221813b2bb87f24d81f60f1fcdbf7cbf4356",
// 7
"0xdbda1821b80551c9d65939329250298aa3472ba22feea921c0cf5d620ea67b97",
// 8
"0x2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6"
// 9
];
var PREFUNDED_PUBLIC_KEYS = [
"0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
// 0
"0x70997970C51812dc3A010C7d01b50e0d17dc79C8",
// 1
"0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC",
// 2
"0x90F79bf6EB2c4f870365E785982E1f101E93b906",
// 3
"0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65",
// 4
"0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc",
// 5
"0x976EA74026E726554dB657fA54763abd0C3a0aa9",
// 6
"0x14dC79964da2C08b23698B3D3cc7Ca32193d9955",
// 7
"0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f",
// 8
"0xa0Ee7A142d267C1f36714E4a8F75612F20a79720"
// 9
];
var PREFUNDED_ACCOUNTS = [
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[0]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[1]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[2]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[3]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[4]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[5]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[6]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[7]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[8]),
privateKeyToAccount(PREFUNDED_PRIVATE_KEYS[9])
];
var PREFUNDED_SEED = Object.freeze({
mnemonic: "test test test test test test test test test test test junk",
derivationPath: "m/44'/60'/0'/0/"
});
// src/signature.js
function recoverPublicKey({ hash, signature }) {
const v = signature.yParity !== void 0 ? signature.yParity : signature.v !== void 0 ? signature.v - 27 : (() => {
throw new Error("Either v or yParity must be provided in signature");
})();
const rBytes = new Uint8Array(32);
const sBytes = new Uint8Array(32);
const rBigInt = typeof signature.r === "string" ? BigInt(signature.r) : signature.r;
const sBigInt = typeof signature.s === "string" ? BigInt(signature.s) : signature.s;
for (let i = 0; i < 32; i++) {
rBytes[31 - i] = Number(rBigInt >> BigInt(8 * i) & 0xffn);
sBytes[31 - i] = Number(sBigInt >> BigInt(8 * i) & 0xffn);
}
const publicKey = ecrecover(toBytes(hash), BigInt(v), rBytes, sBytes);
if (!publicKey) {
throw new Error("Failed to recover public key");
}
return `0x04${toHex(publicKey).slice(2)}`;
}
function recoverAddress({ hash, signature }) {
const publicKey = recoverPublicKey({ hash, signature });
const publicKeyBytes = toBytes(publicKey).slice(1);
const addressHash = keccak256(publicKeyBytes);
return getAddress(`0x${addressHash.slice(-40)}`);
}
function hashMessage(message) {
const prefix = `Ethereum Signed Message:
${message.length}`;
return keccak256(toBytes(prefix + message));
}
function recoverMessageAddress({ message, signature }) {
const hash = hashMessage(message);
return recoverAddress({ hash, signature });
}
function verifyMessage({ address, message, signature }) {
try {
const recoveredAddress = recoverMessageAddress({ message, signature });
return recoveredAddress.toLowerCase() === address.toLowerCase();
} catch {
return false;
}
}
async function signMessage({ privateKey, message }) {
const { signMessage: viemSignMessage } = await import('viem/accounts');
const signature = await viemSignMessage({ privateKey, message });
const v = Number.parseInt(signature.slice(130, 132), 16);
const yParity = (
/** @type {0 | 1} */
v - 27
);
return {
r: BigInt(signature.slice(0, 66)),
// First 32 bytes as hex
s: BigInt(`0x${signature.slice(66, 130)}`),
// Next 32 bytes as hex
v,
// Already 27/28
yParity
};
}
function invariant(condition, error = new DefensiveNullCheckError()) {
if (!condition) {
throw error;
}
}
export { Bloom, PREFUNDED_ACCOUNTS, PREFUNDED_PRIVATE_KEYS, PREFUNDED_PUBLIC_KEYS, PREFUNDED_SEED, createMemoryDb, hashMessage, invariant, recoverAddress, recoverMessageAddress, recoverPublicKey, signMessage, verifyMessage };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map