PHP WebShell
Текущая директория: /opt/BitGoJS/node_modules/micro-eth-signer/lib/esm
Просмотр файла: tx-validator.js
import { Address, add0x } from './index.js';
import { parseDecimal } from './formatters.js';
const GWEI_PRECISION = 9;
const ETHER_PRECISION = 18;
const GWEI = 10n ** BigInt(GWEI_PRECISION);
const ETHER = 10n ** BigInt(ETHER_PRECISION);
// const MICROETH = 10n ** 12n;
const MAX_AMOUNT = ETHER * 100000000n; // 100m ether
const MAX_GAS_PRICE = Number(GWEI * 10000n); // 10,000 gwei. Arbitrage HFT bots can use more.
// etherscan.io/chart/gasprice
const MIN_GAS_LIMIT = 21000;
const MAX_GAS_LIMIT = 20000000; // 20m wei. It's dynamic; a block limit in 2021 is 12m.
const MAX_NONCE = 10000000; // 10M
const MAX_DATA_SIZE = 10000000;
function minmax(val, min, max, err) {
if (!err)
err = `>= ${min} and <= ${max}`;
if (Number.isNaN(val) || val < min || val > max)
throw new Error(`Must be ${err}`);
return true;
}
function ensureNot16x(val, isBig = false) {
if (typeof val === 'string' && val.startsWith('0x')) {
return isBig ? BigInt(val) : Number.parseInt(val, 16);
}
return val;
}
const checks = {
nonce(num) {
return minmax(num, 0, MAX_NONCE);
},
maxFeePerGas(num) {
return minmax(num, 1, MAX_GAS_PRICE, '>= 1 wei and < 10000 gwei');
},
maxPriorityFeePerGas(num) {
return minmax(num, 0, MAX_GAS_PRICE, '>= 1 wei and < 10000 gwei');
},
gasLimit(num) {
return minmax(num, MIN_GAS_LIMIT, MAX_GAS_LIMIT);
},
to(addr) {
if (addr.length !== 40 && addr.length !== 42)
throw new Error('Address length must be 40 or 42 symbols');
addr = add0x(addr);
if (!/^0x[0-9a-f]+$/i.test(addr))
throw new Error('Address must be hex');
if (!Address.verifyChecksum(addr))
throw new Error('Address checksum does not match');
return true;
},
value(num) {
return minmax(num, 0n, MAX_AMOUNT, '>= 0 and < 100M eth');
},
data(val) {
if (typeof val === 'string' && val.length > MAX_DATA_SIZE)
throw new Error('Data is too big');
return true;
},
chainId(num) {
if (!num)
return true;
return minmax(num, 1, 2 ** 32 - 1, '>= 1 and <= 2**32-1');
},
};
function parseHex(val) {
if (val === '0x')
val = '0x00';
return Number.parseInt(val, 16);
}
export function parseUnit(val, unit) {
const str = ensureNot16x(val, true).toString();
if (unit === 'wei')
return BigInt(str);
let precision;
if (unit === 'gwei')
precision = GWEI_PRECISION;
else if (unit === 'eth')
precision = ETHER_PRECISION;
else
throw new Error(`Wrong unit name: ${unit}`);
return parseDecimal(str, precision);
}
// Raw transaction to humanized
const r2h = {
nonce: parseHex,
maxFeePerGas: parseHex,
gasLimit: parseHex,
to: (val) => Address.checksum(val),
value: (val) => BigInt(val),
data: (val) => val,
chainId: (val) => (val ? parseHex(val) : 1),
};
// Humanized to raw.
const h2r = {
nonce(val) {
return Number.parseInt(ensureNot16x(val).toString());
},
maxFeePerGas(val, opts) {
return parseUnit(val, (opts && opts.maxFeePerGasUnit) || 'gwei');
},
maxPriorityFeePerGas(val, opts) {
return parseUnit(val, (opts && opts.maxPriorityFeePerGasUnit) || 'gwei');
},
gasLimit(val) {
return Number.parseInt(ensureNot16x(val).toString()) || MIN_GAS_LIMIT;
},
to(val, opts) {
if (opts && opts.from && opts.from === val)
throw new Error('Must differ from sender address');
return val;
},
value(val, opts) {
return parseUnit(val, (opts && opts.amountUnit) || 'eth');
},
data(val) {
return val || '';
},
chainId(val) {
return Number.parseInt(val) || 1;
},
};
function hasOwnProperty(obj, prop) {
return obj.hasOwnProperty(prop);
}
function numberToHexUnpadded(num) {
let hex = num.toString(16);
hex = hex.length & 1 ? `0${hex}` : hex;
return hex;
}
function dataToString(snb) {
if (snb == null)
return '';
if (typeof snb === 'string')
return snb;
if (typeof snb === 'number' || typeof snb === 'bigint')
return numberToHexUnpadded(snb);
throw new Error('Invalid type');
}
class TransactionFieldError extends Error {
constructor(message, errors) {
super(message + '. ' + JSON.stringify(errors));
this.errors = errors;
}
}
const requiredFields = ['maxFeePerGas', 'maxPriorityFeePerGas', 'to', 'value', 'nonce'];
const optionFields = {
value: ['amountUnit'],
to: ['from'],
maxFeePerGas: ['maxFeePerGasUnit'],
maxPriorityFeePerGas: ['maxPriorityFeePerGasUnit'],
chainId: [],
};
const allOptionFields = Object.values(optionFields).flat();
export function createTxMapFromFields(fields) {
// prettier-ignore
const normalized = {};
const errors = {};
requiredFields.forEach((f) => {
if (fields[f] == null)
errors[f] = 'Cannot be empty';
});
Object.keys(fields).forEach((f) => {
if (allOptionFields.includes(f))
return;
const field = f;
const opts = {};
if (hasOwnProperty(optionFields, field)) {
const list = optionFields[field];
for (const optionalField of list) {
const ofVal = fields[optionalField];
if (ofVal != null)
opts[optionalField] = ofVal;
}
}
const val = fields[field];
try {
const normVal = h2r[field](val, opts);
// @ts-ignore
checks[field](normVal);
normalized[field] = dataToString(normVal);
}
catch (error) {
errors[field] = error.messages || error.message;
}
});
if (Object.keys(errors).length)
throw new TransactionFieldError('Invalid transaction', errors);
Object.keys(normalized).forEach((f) => {
const field = f;
if (field === 'accessList')
return;
normalized[field] = add0x(normalized[field]);
});
const raw = Object.assign({
nonce: '0x',
to: '0x',
value: '0x',
gasLimit: '0x5208',
maxFeePerGas: '0x',
data: '0x',
v: '0x',
r: '0x',
s: '0x',
chainId: 1,
}, normalized);
return raw;
}
export function validateField(field, val, opts) {
const normVal = h2r[field](val, opts);
// @ts-ignore
checks[field](normVal);
return dataToString(normVal);
}
export function validateFields(raw) {
Object.keys(raw).forEach((f) => {
const field = f;
if (field === 'accessList')
return;
const fn = r2h[field];
if (typeof fn === 'function') {
const value = raw[field];
const normVal = fn(value || '');
checks[field](normVal);
}
});
}
Выполнить команду
Для локальной разработки. Не используйте в интернете!