/* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ import { FormatterError } from 'web3-errors'; import { Iban } from 'web3-eth-iban'; import { BlockTags, Filter, Numbers, Topic, BlockInput, BlockOutput, LogsInput, LogsOutput, Mutable, PostInput, PostOutput, Proof, ReceiptInput, ReceiptOutput, SyncInput, SyncOutput, TransactionInput, TransactionOutput, } from 'web3-types'; import { fromUtf8, hexToNumber, hexToNumberString, isAddress, isHexStrict, mergeDeep, numberToHex, sha3Raw, toChecksumAddress, toNumber, toUtf8, utf8ToHex, } from 'web3-utils'; import { isBlockTag, isHex, isNullish } from 'web3-validator'; /* eslint-disable deprecation/deprecation */ /** * @deprecated Use format function from web3-utils package instead * Will format the given storage key array values to hex strings. */ export const inputStorageKeysFormatter = (keys: Array) => keys.map(num => numberToHex(num)); /** * @deprecated Use format function from web3-utils package instead * Will format the given proof response from the node. */ export const outputProofFormatter = (proof: Proof): Proof => ({ address: toChecksumAddress(proof.address), nonce: hexToNumberString(proof.nonce), balance: hexToNumberString(proof.balance), }); /** * @deprecated Use format function from web3-utils package instead * Should the format output to a big number */ export const outputBigIntegerFormatter = (number: Numbers) => toNumber(number); /** * @deprecated Use format function from web3-utils package instead * Returns the given block number as hex string or the predefined block number 'latest', 'pending', 'earliest', 'genesis' */ export const inputBlockNumberFormatter = (blockNumber: Numbers | undefined) => { if (isNullish(blockNumber)) { return undefined; } if (typeof blockNumber === 'string' && isBlockTag(blockNumber)) { return blockNumber; } if (blockNumber === 'genesis') { return '0x0'; } if (typeof blockNumber === 'string' && isHexStrict(blockNumber)) { return blockNumber.toLowerCase(); } return numberToHex(blockNumber); }; /** * @deprecated Use format function from web3-utils package instead * Returns the given block number as hex string or does return the defaultBlock property of the current module */ export const inputDefaultBlockNumberFormatter = ( blockNumber: Numbers | undefined, defaultBlock: Numbers, ) => { if (!blockNumber) { return inputBlockNumberFormatter(defaultBlock); } return inputBlockNumberFormatter(blockNumber); }; /** * @deprecated Use format function from web3-utils package instead * @param address */ export const inputAddressFormatter = (address: string): string | never => { if (Iban.isValid(address) && Iban.isDirect(address)) { const iban = new Iban(address); return iban.toAddress().toLowerCase(); } if (isAddress(address)) { return `0x${address.toLowerCase().replace('0x', '')}`; } throw new FormatterError( `Provided address ${address} is invalid, the capitalization checksum test failed, or it's an indirect IBAN address which can't be converted.`, ); }; /** * @deprecated Use format function from web3-utils package instead * Formats the input of a transaction and converts all values to HEX */ export const txInputOptionsFormatter = (options: TransactionInput): Mutable => { const modifiedOptions = { ...options } as unknown as Mutable; if (options.to) { // it might be contract creation modifiedOptions.to = inputAddressFormatter(options.to); } if (options.data && options.input) { throw new FormatterError( 'You can\'t have "data" and "input" as properties of transactions at the same time, please use either "data" or "input" instead.', ); } if (!options.input && options.data) { modifiedOptions.input = options.data; delete modifiedOptions.data; } if (options.input && !options.input.startsWith('0x')) { modifiedOptions.input = `0x${options.input}`; } if (modifiedOptions.input && !isHexStrict(modifiedOptions.input)) { throw new FormatterError('The input field must be HEX encoded data.'); } // allow both if (options.gas || options.gasLimit) { modifiedOptions.gas = toNumber(options.gas ?? options.gasLimit); } if (options.maxPriorityFeePerGas || options.maxFeePerGas) { delete modifiedOptions.gasPrice; } ['gasPrice', 'gas', 'value', 'maxPriorityFeePerGas', 'maxFeePerGas', 'nonce', 'chainId'] .filter(key => !isNullish(modifiedOptions[key])) .forEach(key => { modifiedOptions[key] = numberToHex(modifiedOptions[key] as Numbers); }); return modifiedOptions as TransactionOutput; }; /** * @deprecated Use format function from web3-utils package instead * Formats the input of a transaction and converts all values to HEX */ export const inputCallFormatter = (options: TransactionInput, defaultAccount?: string) => { const opts = txInputOptionsFormatter(options); const from = opts.from ?? defaultAccount; if (from) { opts.from = inputAddressFormatter(from); } return opts; }; /** * @deprecated Use format function from web3-utils package instead * Formats the input of a transaction and converts all values to HEX */ export const inputTransactionFormatter = (options: TransactionInput, defaultAccount?: string) => { const opts = txInputOptionsFormatter(options); // check from, only if not number, or object if (!(typeof opts.from === 'number') && !(!!opts.from && typeof opts.from === 'object')) { opts.from = opts.from ?? defaultAccount; if (!options.from && !(typeof options.from === 'number')) { throw new FormatterError('The send transactions "from" field must be defined!'); } opts.from = inputAddressFormatter(options.from); } return opts; }; /** * @deprecated Use format function from web3-utils package instead * Hex encodes the data passed to eth_sign and personal_sign */ export const inputSignFormatter = (data: string) => (isHexStrict(data) ? data : utf8ToHex(data)); /** * @deprecated Use format function from web3-utils package instead * Formats the output of a transaction to its proper values * @function outputTransactionFormatter */ export const outputTransactionFormatter = (tx: TransactionInput): TransactionOutput => { const modifiedTx = { ...tx } as unknown as Mutable; if (tx.blockNumber) { modifiedTx.blockNumber = hexToNumber(tx.blockNumber); } if (tx.transactionIndex) { modifiedTx.transactionIndex = hexToNumber(tx.transactionIndex); } modifiedTx.nonce = hexToNumber(tx.nonce); modifiedTx.gas = hexToNumber(tx.gas); if (tx.gasPrice) { modifiedTx.gasPrice = outputBigIntegerFormatter(tx.gasPrice); } if (tx.maxFeePerGas) { modifiedTx.maxFeePerGas = outputBigIntegerFormatter(tx.maxFeePerGas); } if (tx.maxPriorityFeePerGas) { modifiedTx.maxPriorityFeePerGas = outputBigIntegerFormatter(tx.maxPriorityFeePerGas); } if (tx.type) { modifiedTx.type = hexToNumber(tx.type); } modifiedTx.value = outputBigIntegerFormatter(tx.value); if (tx.to && isAddress(tx.to)) { // tx.to could be `0x0` or `null` while contract creation modifiedTx.to = toChecksumAddress(tx.to); } else { modifiedTx.to = undefined; // set to `null` if invalid address } if (tx.from) { modifiedTx.from = toChecksumAddress(tx.from); } return modifiedTx; }; /** * @deprecated Use format function from web3-utils package instead * @param topic */ // To align with specification we use the type "null" here // eslint-disable-next-line @typescript-eslint/ban-types export const inputTopicFormatter = (topic: Topic): Topic | null => { // Using "null" value intentionally for validation // eslint-disable-next-line no-null/no-null if (isNullish(topic)) return null; const value = String(topic); return isHex(value) ? value : fromUtf8(value); }; /** * @deprecated Use format function from web3-utils package instead * @param filter */ export const inputLogFormatter = (filter: Filter) => { const val: Mutable = isNullish(filter) ? {} : mergeDeep({}, filter as Record); // If options !== undefined, don't blow out existing data if (isNullish(val.fromBlock)) { val.fromBlock = BlockTags.LATEST; } val.fromBlock = inputBlockNumberFormatter(val.fromBlock); if (!isNullish(val.toBlock)) { val.toBlock = inputBlockNumberFormatter(val.toBlock); } // make sure topics, get converted to hex val.topics = val.topics ?? []; val.topics = val.topics.map(topic => Array.isArray(topic) ? (topic.map(inputTopicFormatter) as Topic[]) : inputTopicFormatter(topic as Topic), ); if (val.address) { val.address = Array.isArray(val.address) ? val.address.map(addr => inputAddressFormatter(addr)) : inputAddressFormatter(val.address); } return val as Filter; }; /** * @deprecated Use format function from web3-utils package instead * Formats the output of a log * @function outputLogFormatter */ export const outputLogFormatter = (log: Partial): LogsOutput => { const modifiedLog = { ...log } as unknown as Mutable; const logIndex = typeof log.logIndex === 'string' ? log.logIndex : numberToHex(log.logIndex as unknown as number); // generate a custom log id if (typeof log.blockHash === 'string' && typeof log.transactionHash === 'string') { const shaId = sha3Raw( `${log.blockHash.replace('0x', '')}${log.transactionHash.replace( '0x', '', )}${logIndex.replace('0x', '')}`, ); modifiedLog.id = `log_${shaId.replace('0x', '').slice(0, 8)}`; } else if (!log.id) { modifiedLog.id = undefined; } if (log.blockNumber && isHexStrict(log.blockNumber)) { modifiedLog.blockNumber = hexToNumber(log.blockNumber); } if (log.transactionIndex && isHexStrict(log.transactionIndex)) { modifiedLog.transactionIndex = hexToNumber(log.transactionIndex); } if (log.logIndex && isHexStrict(log.logIndex)) { modifiedLog.logIndex = hexToNumber(log.logIndex); } if (log.address) { modifiedLog.address = toChecksumAddress(log.address); } return modifiedLog; }; /** * @deprecated Use format function from web3-utils package instead * Formats the output of a transaction receipt to its proper values */ export const outputTransactionReceiptFormatter = (receipt: ReceiptInput): ReceiptOutput => { if (typeof receipt !== 'object') { throw new FormatterError(`Received receipt is invalid: ${String(receipt)}`); } const modifiedReceipt = { ...receipt } as unknown as Mutable; if (receipt.blockNumber) { modifiedReceipt.blockNumber = hexToNumber(receipt.blockNumber); } if (receipt.transactionIndex) { modifiedReceipt.transactionIndex = hexToNumber(receipt.transactionIndex); } modifiedReceipt.cumulativeGasUsed = hexToNumber(receipt.cumulativeGasUsed); modifiedReceipt.gasUsed = hexToNumber(receipt.gasUsed); if (receipt.logs && Array.isArray(receipt.logs)) { modifiedReceipt.logs = receipt.logs.map(outputLogFormatter); } if (receipt.effectiveGasPrice) { modifiedReceipt.effectiveGasPrice = hexToNumber(receipt.effectiveGasPrice); } if (receipt.contractAddress) { modifiedReceipt.contractAddress = toChecksumAddress(receipt.contractAddress); } if (receipt.status) { modifiedReceipt.status = Boolean(parseInt(receipt.status, 10)); } return modifiedReceipt; }; /** * @deprecated Use format function from web3-utils package instead * Formats the output of a block to its proper values * @function outputBlockFormatter */ export const outputBlockFormatter = (block: BlockInput): BlockOutput => { const modifiedBlock = { ...block } as unknown as Mutable; // transform to number modifiedBlock.gasLimit = hexToNumber(block.gasLimit); modifiedBlock.gasUsed = hexToNumber(block.gasUsed); modifiedBlock.size = hexToNumber(block.size); modifiedBlock.timestamp = hexToNumber(block.timestamp); if (block.number) { modifiedBlock.number = hexToNumber(block.number); } if (block.difficulty) { modifiedBlock.difficulty = outputBigIntegerFormatter(block.difficulty); } if (block.totalDifficulty) { modifiedBlock.totalDifficulty = outputBigIntegerFormatter(block.totalDifficulty); } if (block.transactions && Array.isArray(block.transactions)) { modifiedBlock.transactions = block.transactions.map(outputTransactionFormatter); } if (block.miner) { modifiedBlock.miner = toChecksumAddress(block.miner); } if (block.baseFeePerGas) { modifiedBlock.baseFeePerGas = outputBigIntegerFormatter(block.baseFeePerGas); } return modifiedBlock; }; /** * @deprecated Use format function from web3-utils package instead * Formats the input of a whisper post and converts all values to HEX */ export const inputPostFormatter = (post: PostOutput): PostInput => { const modifiedPost = { ...post } as unknown as Mutable; if (post.ttl) { modifiedPost.ttl = numberToHex(post.ttl); } if (post.workToProve) { modifiedPost.workToProve = numberToHex(post.workToProve); } if (post.priority) { modifiedPost.priority = numberToHex(post.priority); } // fallback if (post.topics && !Array.isArray(post.topics)) { modifiedPost.topics = post.topics ? [post.topics] : []; } // format the following options modifiedPost.topics = modifiedPost.topics?.map(topic => topic.startsWith('0x') ? topic : fromUtf8(topic), ); return modifiedPost; }; /** * @deprecated Use format function from web3-utils package instead * Formats the output of a received post message * @function outputPostFormatter */ export const outputPostFormatter = (post: PostInput): PostOutput => { const modifiedPost = { ...post } as unknown as Mutable; if (post.expiry) { modifiedPost.expiry = hexToNumber(post.expiry); } if (post.sent) { modifiedPost.sent = hexToNumber(post.sent); } if (post.ttl) { modifiedPost.ttl = hexToNumber(post.ttl); } if (post.workProved) { modifiedPost.workProved = hexToNumber(post.workProved); } // post.payloadRaw = post.payload; // post.payload = utils.hexToAscii(post.payload); // if (utils.isJson(post.payload)) { // post.payload = JSON.parse(post.payload); // } // format the following options if (!post.topics) { modifiedPost.topics = []; } modifiedPost.topics = modifiedPost.topics?.map(toUtf8); return modifiedPost; }; /** * @deprecated Use format function from web3-utils package instead */ export const outputSyncingFormatter = (result: SyncInput): SyncOutput => { const modifiedResult = { ...result } as unknown as Mutable; modifiedResult.startingBlock = hexToNumber(result.startingBlock); modifiedResult.currentBlock = hexToNumber(result.currentBlock); modifiedResult.highestBlock = hexToNumber(result.highestBlock); if (result.knownStates) { modifiedResult.knownStates = hexToNumber(result.knownStates); } if (result.pulledStates) { modifiedResult.pulledStates = hexToNumber(result.pulledStates); } return modifiedResult; };