PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/micro-eth-signer/lib

Просмотр файла: index.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Transaction = exports.Address = exports.numberTo0xHex = exports.hexToBytes = exports.strip0x = exports.add0x = exports.TRANSACTION_TYPES = exports.CHAIN_TYPES = void 0;
/*! micro-eth-signer - MIT License (c) 2021 Paul Miller (paulmillr.com) */
const sha3_1 = require("@noble/hashes/sha3");
const utils_1 = require("@noble/hashes/utils");
const utils_2 = require("@noble/curves/abstract/utils");
const secp256k1_1 = require("@noble/curves/secp256k1");
const RLP = require("@ethereumjs/rlp");
exports.CHAIN_TYPES = { mainnet: 1, ropsten: 3, rinkeby: 4, goerli: 5, kovan: 42 };
exports.TRANSACTION_TYPES = { legacy: 0, eip2930: 1, eip1559: 2 };
// All secp methods are in this object. This makes secp library easily replaceable
const secp = {
    getPublicKey65b: (priv) => secp256k1_1.secp256k1.getPublicKey(priv, false),
    normalizePublicKeyTo65b: (pub) => secp256k1_1.secp256k1.ProjectivePoint.fromHex(pub).toRawBytes(false),
    sign: (msg, priv, opts) => {
        return secp256k1_1.secp256k1.sign(msg, priv, {
            extraEntropy: opts?.extraEntropy === false ? undefined : true,
        });
    },
    signAsync: async (msg, priv, opts) => {
        return secp256k1_1.secp256k1.sign(msg, priv, {
            extraEntropy: opts?.extraEntropy === false ? undefined : true,
        });
    },
    sigRecoverPub: (rsrec, msg, checkHighS = true) => {
        const sig = new secp256k1_1.secp256k1.Signature(rsrec.r, rsrec.s).addRecoveryBit(rsrec.recovery);
        if (checkHighS && sig.hasHighS())
            throw new Error('Invalid signature: s is invalid');
        return sig.recoverPublicKey(msg).toRawBytes();
    },
};
function add0x(hex) {
    return /^0x/i.test(hex) ? hex : `0x${hex}`;
}
exports.add0x = add0x;
function strip0x(hex) {
    return hex.replace(/^0x/i, '');
}
exports.strip0x = strip0x;
function hexToBytes(hex) {
    return (0, utils_1.hexToBytes)(strip0x(hex));
}
exports.hexToBytes = hexToBytes;
function numberTo0xHex(num) {
    const hex = num.toString(16);
    const x2 = hex.length & 1 ? `0${hex}` : hex;
    return add0x(x2);
}
exports.numberTo0xHex = numberTo0xHex;
function hexToNumber(hex) {
    if (typeof hex !== 'string') {
        throw new TypeError('hexToNumber: expected string, got ' + typeof hex);
    }
    return hex ? BigInt(add0x(hex)) : 0n;
}
function isObject(item) {
    return item != null && typeof item === 'object';
}
function cloneDeep(obj) {
    if (Array.isArray(obj)) {
        return obj.map(cloneDeep);
    }
    else if (typeof obj === 'bigint') {
        return BigInt(obj);
    }
    else if (typeof obj === 'object') {
        // should be last, so it won't catch other types
        let res = {};
        for (let key in obj)
            res[key] = cloneDeep(obj[key]);
        return res;
    }
    else
        return obj;
}
// The order is important.
const FIELDS = ['nonce', 'gasPrice', 'gasLimit', 'to', 'value', 'data', 'v', 'r', 's'];
// prettier-ignore
const FIELDS2930 = [
    'chainId', 'nonce', 'gasPrice', 'gasLimit',
    'to', 'value', 'data', 'accessList', 'yParity', 'r', 's'
];
// prettier-ignore
const FIELDS1559 = [
    'chainId', 'nonce', 'maxPriorityFeePerGas', 'maxFeePerGas', 'gasLimit',
    'to', 'value', 'data', 'accessList', 'yParity', 'r', 's'
];
const TypeToFields = {
    legacy: FIELDS,
    eip2930: FIELDS2930,
    eip1559: FIELDS1559,
};
// Normalizes field to format which can easily be serialized by rlp (strings & arrays)
// prettier-ignore
const FIELD_NUMBER = new Set([
    'chainId', 'nonce', 'gasPrice', 'maxPriorityFeePerGas', 'maxFeePerGas',
    'gasLimit', 'value', 'v', 'yParity', 'r', 's'
]);
const FIELD_DATA = new Set(['data', 'to', 'storageKey', 'address']);
function normalizeField(field, value) {
    // can be number, bignumber, decimal number in string (123), hex number in string (0x123)
    if (FIELD_NUMBER.has(field)) {
        // bytes
        if ((0, utils_2.isBytes)(value))
            value = add0x((0, utils_1.bytesToHex)(value));
        if (field === 'yParity' && typeof value === 'boolean')
            value = value ? '0x1' : '0x0';
        // '123' -> 0x7b (handles both hex and non-hex numbers)
        if (typeof value === 'string')
            value = BigInt(value === '0x' ? '0x0' : value);
        // 123 -> '0x7b' && 1 -> 0x01
        if (typeof value === 'number' || typeof value === 'bigint')
            value = numberTo0xHex(value);
        // 21000, default / minimum
        if (field === 'gasLimit' && (!value || BigInt(value) === 0n))
            value = '0x5208';
        if (typeof value !== 'string')
            throw new TypeError(`Invalid type for field ${field}`);
        // should be hex string starting with '0x' at this point.
        if (field === 'gasPrice' && BigInt(value) === 0n)
            throw new TypeError('The gasPrice must have non-zero value');
        // '0x00' and '' serializes differently
        return BigInt(value) === 0n ? '' : value;
    }
    // Can be string or Uint8Array
    if (FIELD_DATA.has(field)) {
        if (!value)
            value = '';
        if ((0, utils_2.isBytes)(value))
            value = (0, utils_1.bytesToHex)(value);
        if (typeof value !== 'string')
            throw new TypeError(`Invalid type for field ${field}`);
        value = add0x(value);
        return value === '0x' ? '' : value;
    }
    if (field === 'accessList') {
        if (!value)
            return [];
        let res = {};
        if (Array.isArray(value)) {
            for (let access of value) {
                if (Array.isArray(access)) {
                    // AccessList
                    if (access.length !== 2 || !Array.isArray(access[1]))
                        throw new TypeError(`Invalid type for field ${field}`);
                    const key = normalizeField('address', access[0]);
                    if (!res[key])
                        res[key] = new Set();
                    for (let i of access[1])
                        res[key].add(normalizeField('storageKey', i));
                }
                else {
                    // {address: string, storageKeys: string[]}[]
                    if (!isObject(access) || !access.address || !Array.isArray(access.storageKeys))
                        throw new TypeError(`Invalid type for field ${field}`);
                    const key = normalizeField('address', access.address);
                    if (!res[key])
                        res[key] = new Set();
                    for (let i of access.storageKeys)
                        res[key].add(normalizeField('storageKey', i));
                }
            }
        }
        else {
            // {[address]: string[]}
            if (!isObject(value) || (0, utils_2.isBytes)(value))
                throw new TypeError(`Invalid type for field ${field}`);
            for (let k in value) {
                const key = normalizeField('address', k);
                // undefined/empty allowed
                if (!value[k])
                    continue;
                if (!Array.isArray(value[k]))
                    throw new TypeError(`Invalid type for field ${field}`);
                res[key] = new Set(value[k].map((i) => normalizeField('storageKey', i)));
            }
        }
        return Object.keys(res).map((i) => [i, Array.from(res[i])]);
    }
    throw new TypeError(`Invalid type for field ${field}`);
}
function possibleTypes(input) {
    let types = new Set(Object.keys(exports.TRANSACTION_TYPES));
    const keys = new Set(Object.keys(input));
    if (keys.has('maxPriorityFeePerGas') || keys.has('maxFeePerGas')) {
        types.delete('legacy');
        types.delete('eip2930');
    }
    if (keys.has('accessList') || keys.has('yParity'))
        types.delete('legacy');
    if (keys.has('gasPrice'))
        types.delete('eip1559');
    return types;
}
const RawTxLength = { 9: 'legacy', 11: 'eip2930', 12: 'eip1559' };
const RawTxLengthRev = { legacy: 9, eip2930: 11, eip1559: 12 };
function rawToSerialized(input, chain, type) {
    let chainId;
    if (chain)
        chainId = exports.CHAIN_TYPES[chain];
    if (Array.isArray(input)) {
        if (!type)
            type = RawTxLength[input.length];
        if (!type || RawTxLengthRev[type] !== input.length)
            throw new Error(`Invalid fields length for ${type}`);
    }
    else {
        const types = possibleTypes(input);
        if (type && !types.has(type)) {
            throw new Error(`Invalid type=${type}. Possible types with current fields: ${Array.from(types)}`);
        }
        if (!type) {
            if (types.has('legacy'))
                type = 'legacy';
            else if (!types.size)
                throw new Error('Impossible fields set');
            else
                type = Array.from(types)[0];
        }
        if (input.chainId) {
            if (chain) {
                const fromChain = normalizeField('chainId', exports.CHAIN_TYPES[chain]);
                const fromInput = normalizeField('chainId', input.chainId);
                if (fromChain !== fromInput) {
                    throw new Error(`Both chain=${chain}(${fromChain}) and chainId=${input.chainId}(${fromInput}) specified at same time`);
                }
            }
            chainId = input.chainId;
        }
        else
            input.chainId = chainId;
        input = TypeToFields[type].map((key) => input[key]);
    }
    if (input) {
        const sign = input.slice(-3);
        // remove signature if any of fields is empty
        if (!sign[0] || !sign[1] || !sign[2]) {
            input = input.slice(0, -3);
            // EIP-155
            if (type === 'legacy' && chainId)
                input.push(normalizeField('chainId', chainId), '', '');
        }
    }
    let normalized = input.map((value, i) => normalizeField(TypeToFields[type][i], value));
    if (chainId)
        chainId = normalizeField('chainId', chainId);
    if (type !== 'legacy' && chainId && normalized[0] !== chainId)
        throw new Error(`ChainId=${normalized[0]} incompatible with Chain=${chainId}`);
    const tNum = exports.TRANSACTION_TYPES[type];
    return (tNum ? `0x0${tNum}` : '0x') + (0, utils_1.bytesToHex)(RLP.encode(normalized));
}
exports.Address = {
    fromPrivateKey(key) {
        if (typeof key === 'string')
            key = hexToBytes(key);
        return exports.Address.fromPublicKey(secp.getPublicKey65b(key));
    },
    fromPublicKey(key) {
        const pub = secp.normalizePublicKeyTo65b(key);
        const addr = (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(pub.subarray(1, 65))).slice(24);
        return exports.Address.checksum(addr);
    },
    // ETH addr checksum is calculated by hashing the string with keccak.
    // NOTE: it hashes *string*, not a bytearray: keccak('beef') not keccak([0xbe, 0xef])
    checksum(nonChecksummedAddress) {
        const addr = strip0x(nonChecksummedAddress.toLowerCase());
        if (addr.length !== 40)
            throw new Error('Invalid address, must have 40 chars');
        const hash = strip0x((0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(addr)));
        let checksummed = '';
        for (let i = 0; i < addr.length; i++) {
            // If ith character is 9 to f then make it uppercase
            const nth = Number.parseInt(hash[i], 16);
            let char = addr[i];
            if (nth > 7)
                char = char.toUpperCase();
            checksummed += char;
        }
        return add0x(checksummed);
    },
    verifyChecksum(address) {
        const addr = strip0x(address);
        if (addr.length !== 40)
            throw new Error('Invalid address, must have 40 chars');
        if (addr === addr.toLowerCase() || addr === addr.toUpperCase())
            return true;
        const hash = (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(addr.toLowerCase()));
        for (let i = 0; i < 40; i++) {
            // the nth letter should be uppercase if the nth digit of casemap is 1
            const char = addr[i];
            const nth = Number.parseInt(hash[i], 16);
            if (nth > 7 && char.toUpperCase() !== char)
                return false;
            if (nth <= 7 && char.toLowerCase() !== char)
                return false;
        }
        return true;
    },
};
class Transaction {
    constructor(data, chain, hardfork = Transaction.DEFAULT_HARDFORK, type) {
        this.hardfork = hardfork;
        let norm;
        if (typeof data === 'string') {
            norm = data;
        }
        else if (data instanceof Uint8Array) {
            norm = (0, utils_1.bytesToHex)(data);
        }
        else if (Array.isArray(data) || (typeof data === 'object' && data != null)) {
            norm = rawToSerialized(data, chain, type);
        }
        else {
            throw new TypeError('Expected valid serialized tx');
        }
        if (norm.length <= 6)
            throw new Error('Invalid tx length');
        this.hex = add0x(norm);
        let txData;
        const prevType = type;
        if (this.hex.startsWith('0x01'))
            [txData, type] = [add0x(this.hex.slice(4)), 'eip2930'];
        else if (this.hex.startsWith('0x02'))
            [txData, type] = [add0x(this.hex.slice(4)), 'eip1559'];
        else
            [txData, type] = [this.hex, 'legacy'];
        if (prevType && prevType !== type)
            throw new Error('Invalid transaction type');
        this.type = type;
        const ui8a = RLP.decode(txData);
        this.raw = ui8a.reduce((res, value, i) => {
            const name = TypeToFields[type][i];
            if (!name)
                return res;
            res[name] = normalizeField(name, value);
            return res;
        }, {});
        if (!this.raw.chainId) {
            // Unsigned transaction with EIP-155
            if (type === 'legacy' && !this.raw.r && !this.raw.s) {
                this.raw.chainId = this.raw.v;
                this.raw.v = '';
            }
        }
        if (!this.raw.chainId) {
            this.raw.chainId = normalizeField('chainId', exports.CHAIN_TYPES[chain || Transaction.DEFAULT_CHAIN]);
        }
        this.isSigned = !!(this.raw.r && this.raw.r !== '0x');
    }
    isNew() {
        return this.type === 'eip1559';
    }
    get bytes() {
        return hexToBytes(this.hex);
    }
    equals(other) {
        return this.getMessageToSign() === other.getMessageToSign();
    }
    get chain() {
        for (let k in exports.CHAIN_TYPES)
            if (exports.CHAIN_TYPES[k] === Number(this.raw.chainId))
                return k;
        return undefined;
    }
    get sender() {
        const sender = this.recoverSenderPublicKey();
        if (!sender)
            throw new Error('Invalid signed transaction');
        return exports.Address.fromPublicKey(sender);
    }
    get gasPrice() {
        if (this.isNew())
            throw new Error('Field only available for "legacy" transactions');
        return BigInt(this.raw.gasPrice);
    }
    // maxFeePerGas: Represents the maximum amount that a user is willing to pay for their tx (inclusive of baseFeePerGas and maxPriorityFeePerGas)
    get maxFeePerGas() {
        if (!this.isNew())
            throw new Error('Field only available for "eip1559" transactions');
        return BigInt(this.raw.maxFeePerGas);
    }
    get maxPriorityFeePerGas() {
        if (!this.isNew())
            throw new Error('Field only available for "eip1559" transactions');
        return BigInt(this.raw.maxPriorityFeePerGas);
    }
    get gasLimit() {
        return BigInt(this.raw.gasLimit);
    }
    // Amount in wei
    get amount() {
        return BigInt(this.raw.value);
    }
    // Total fee in wei
    get fee() {
        const price = this.isNew() ? this.maxFeePerGas : this.gasPrice;
        return price * this.gasLimit;
    }
    // Amount + fee in wei
    get upfrontCost() {
        return this.amount + this.fee;
    }
    // Checksummed address
    get to() {
        return exports.Address.checksum(this.raw.to);
    }
    // Nonce is a counter that represents a number of outgoing transactions on the acct
    get nonce() {
        return Number.parseInt(this.raw.nonce, 16) || 0;
    }
    supportsReplayProtection() {
        const properBlock = !['chainstart', 'homestead', 'dao', 'tangerineWhistle'].includes(this.hardfork);
        if (!this.isSigned)
            return true; // Unsigned, supports EIP155
        const v = Number(hexToNumber(this.raw.v));
        const chainId = Number(this.raw.chainId);
        const meetsConditions = v === chainId * 2 + 35 || v === chainId * 2 + 36;
        return properBlock && meetsConditions;
    }
    getMessageToSign(signed = false) {
        let values = TypeToFields[this.type].map((i) => this.raw[i]);
        if (!signed) {
            // TODO: merge with line #252 somehow? (same strip & EIP-155)
            // Strip signature (last 3 values)
            values = values.slice(0, -3);
            // EIP-155
            if (this.type === 'legacy' && this.supportsReplayProtection())
                values.push(this.raw.chainId, '', '');
        }
        let encoded = RLP.encode(values);
        if (this.type !== 'legacy')
            encoded = new Uint8Array([exports.TRANSACTION_TYPES[this.type], ...Array.from(encoded)]);
        return (0, utils_1.bytesToHex)((0, sha3_1.keccak_256)(encoded));
    }
    // Used in block explorers etc
    get hash() {
        if (!this.isSigned)
            throw new Error('Expected signed transaction');
        return this.getMessageToSign(true);
    }
    sign(privateKey, extraEntropy = false) {
        if (this.isSigned)
            throw new Error('Expected unsigned transaction');
        if (typeof privateKey === 'string')
            privateKey = strip0x(privateKey);
        const sig = secp.sign(this.getMessageToSign(), privateKey, { extraEntropy });
        const rec = sig.recovery;
        const chainId = Number(this.raw.chainId);
        const vv = this.type === 'legacy' ? (chainId ? rec + (chainId * 2 + 35) : rec + 27) : rec;
        const [v, r, s] = [vv, sig.r, sig.s].map(numberTo0xHex);
        const signedRaw = this.type === 'legacy'
            ? { ...this.raw, v, r, s }
            : { ...cloneDeep(this.raw), yParity: v, r, s };
        return new Transaction(signedRaw, this.chain, this.hardfork, this.type);
    }
    recoverSenderPublicKey() {
        if (!this.isSigned)
            throw new Error('Expected signed transaction: cannot recover sender of unsigned tx');
        const v = Number(hexToNumber(this.type === 'legacy' ? this.raw.v : this.raw.yParity));
        const chainId = Number(this.raw.chainId);
        const recovery = this.type === 'legacy' ? (chainId ? v - (chainId * 2 + 35) : v - 27) : v;
        const [r, s] = [this.raw.r, this.raw.s].map(hexToNumber);
        const checkHighS = this.hardfork !== 'chainstart';
        return secp.sigRecoverPub({ r, s, recovery }, this.getMessageToSign(), checkHighS);
    }
}
exports.Transaction = Transaction;
Transaction.DEFAULT_HARDFORK = 'london';
Transaction.DEFAULT_CHAIN = 'mainnet';
Transaction.DEFAULT_TYPE = 'eip1559';

Выполнить команду


Для локальной разработки. Не используйте в интернете!