import { bytesToHex, hexToBytes, setLengthLeft, validateNoLeadingZeroes, } from '@ethereumjs/util'; import { isAccessList, isAuthorizationList } from './types.js'; export function checkMaxInitCodeSize(common, length) { const maxInitCodeSize = common.param('vm', 'maxInitCodeSize'); if (maxInitCodeSize && BigInt(length) > maxInitCodeSize) { throw new Error(`the initcode size of this transaction is too large: it is ${length} while the max is ${common.param('vm', 'maxInitCodeSize')}`); } } export class AccessLists { static getAccessListData(accessList) { let AccessListJSON; let bufferAccessList; if (isAccessList(accessList)) { AccessListJSON = accessList; const newAccessList = []; for (let i = 0; i < accessList.length; i++) { const item = accessList[i]; const addressBytes = hexToBytes(item.address); const storageItems = []; for (let index = 0; index < item.storageKeys.length; index++) { storageItems.push(hexToBytes(item.storageKeys[index])); } newAccessList.push([addressBytes, storageItems]); } bufferAccessList = newAccessList; } else { bufferAccessList = accessList ?? []; // build the JSON const json = []; for (let i = 0; i < bufferAccessList.length; i++) { const data = bufferAccessList[i]; const address = bytesToHex(data[0]); const storageKeys = []; for (let item = 0; item < data[1].length; item++) { storageKeys.push(bytesToHex(data[1][item])); } const jsonItem = { address, storageKeys, }; json.push(jsonItem); } AccessListJSON = json; } return { AccessListJSON, accessList: bufferAccessList, }; } static verifyAccessList(accessList) { for (let key = 0; key < accessList.length; key++) { const accessListItem = accessList[key]; const address = accessListItem[0]; const storageSlots = accessListItem[1]; if (accessListItem[2] !== undefined) { throw new Error('Access list item cannot have 3 elements. It can only have an address, and an array of storage slots.'); } if (address.length !== 20) { throw new Error('Invalid EIP-2930 transaction: address length should be 20 bytes'); } for (let storageSlot = 0; storageSlot < storageSlots.length; storageSlot++) { if (storageSlots[storageSlot].length !== 32) { throw new Error('Invalid EIP-2930 transaction: storage slot length should be 32 bytes'); } } } } static getAccessListJSON(accessList) { const accessListJSON = []; for (let index = 0; index < accessList.length; index++) { const item = accessList[index]; const JSONItem = { address: bytesToHex(setLengthLeft(item[0], 20)), storageKeys: [], }; const storageSlots = item[1]; for (let slot = 0; slot < storageSlots.length; slot++) { const storageSlot = storageSlots[slot]; JSONItem.storageKeys.push(bytesToHex(setLengthLeft(storageSlot, 32))); } accessListJSON.push(JSONItem); } return accessListJSON; } static getDataFeeEIP2930(accessList, common) { const accessListStorageKeyCost = common.param('gasPrices', 'accessListStorageKeyCost'); const accessListAddressCost = common.param('gasPrices', 'accessListAddressCost'); let slots = 0; for (let index = 0; index < accessList.length; index++) { const item = accessList[index]; const storageSlots = item[1]; slots += storageSlots.length; } const addresses = accessList.length; return addresses * Number(accessListAddressCost) + slots * Number(accessListStorageKeyCost); } } export class AuthorizationLists { static getAuthorizationListData(authorizationList) { let AuthorizationListJSON; let bufferAuthorizationList; if (isAuthorizationList(authorizationList)) { AuthorizationListJSON = authorizationList; const newAuthorizationList = []; const jsonItems = ['chainId', 'address', 'nonce', 'yParity', 'r', 's']; for (let i = 0; i < authorizationList.length; i++) { const item = authorizationList[i]; for (const key of jsonItems) { // @ts-ignore TODO why does TsScript fail here? if (item[key] === undefined) { throw new Error(`EIP-7702 authorization list invalid: ${key} is not defined`); } } const chainId = hexToBytes(item.chainId); const addressBytes = hexToBytes(item.address); const nonceList = []; for (let j = 0; j < item.nonce.length; j++) { nonceList.push(hexToBytes(item.nonce[j])); } const yParity = hexToBytes(item.yParity); const r = hexToBytes(item.r); const s = hexToBytes(item.s); newAuthorizationList.push([chainId, addressBytes, nonceList, yParity, r, s]); } bufferAuthorizationList = newAuthorizationList; } else { bufferAuthorizationList = authorizationList ?? []; // build the JSON const json = []; for (let i = 0; i < bufferAuthorizationList.length; i++) { const data = bufferAuthorizationList[i]; const chainId = bytesToHex(data[0]); const address = bytesToHex(data[1]); const nonces = data[2]; const nonceList = []; for (let j = 0; j < nonces.length; j++) { nonceList.push(bytesToHex(nonces[j])); } const yParity = bytesToHex(data[3]); const r = bytesToHex(data[4]); const s = bytesToHex(data[5]); const jsonItem = { chainId, address, nonce: nonceList, yParity, r, s, }; json.push(jsonItem); } AuthorizationListJSON = json; } return { AuthorizationListJSON, authorizationList: bufferAuthorizationList, }; } static verifyAuthorizationList(authorizationList) { for (let key = 0; key < authorizationList.length; key++) { const authorizationListItem = authorizationList[key]; const address = authorizationListItem[1]; const nonceList = authorizationListItem[2]; const yParity = authorizationListItem[3]; const r = authorizationListItem[4]; const s = authorizationListItem[5]; validateNoLeadingZeroes({ yParity, r, s }); if (address.length !== 20) { throw new Error('Invalid EIP-7702 transaction: address length should be 20 bytes'); } if (nonceList.length > 1) { throw new Error('Invalid EIP-7702 transaction: nonce list should consist of at most 1 item'); } else if (nonceList.length === 1) { validateNoLeadingZeroes({ nonce: nonceList[0] }); } } } static getDataFeeEIP7702(authorityList, common) { const perAuthBaseCost = common.param('gasPrices', 'perAuthBaseCost'); return authorityList.length * Number(perAuthBaseCost); } } export function txTypeBytes(txType) { return hexToBytes(`0x${txType.toString(16).padStart(2, '0')}`); } //# sourceMappingURL=util.js.map