diff --git a/app/tray/Account/Requests/TransactionRequest/TxFee/index.js b/app/tray/Account/Requests/TransactionRequest/TxFee/index.js index 8ae3adbc5..bbcbb8214 100644 --- a/app/tray/Account/Requests/TransactionRequest/TxFee/index.js +++ b/app/tray/Account/Requests/TransactionRequest/TxFee/index.js @@ -1,12 +1,11 @@ import React from 'react' import Restore from 'react-restore' import BigNumber from 'bignumber.js' -import { utils } from 'ethers' import { DisplayCoinBalance, DisplayValue } from '../../../../../../resources/Components/DisplayValue' import { GasFeesSource, usesBaseFee } from '../../../../../../resources/domain/transaction' import { displayValueData } from '../../../../../../resources/utils/displayValue' -import { chainUsesOptimismFees, calculateOptimismL1DataFee } from '../../../../../../resources/utils/chains' +import { chainUsesOptimismFees } from '../../../../../../resources/utils/chains' import link from '../../../../../../resources/link' import { ClusterBox, @@ -66,20 +65,8 @@ class TxFee extends React.Component { super(props, context) } - getOptimismFee = (l2Price, l2Limit, rawTx) => { - const { maxFeePerGas, maxPriorityFeePerGas, gasPrice, data, gasLimit, nonce, to, value } = rawTx - const chainId = parseInt(rawTx.chainId, 16) - const txData = { chainId, data, gasLimit, nonce, to, value } - - const tx = !!maxFeePerGas - ? { ...txData, maxFeePerGas, maxPriorityFeePerGas, type: 2 } - : { ...txData, gasPrice, type: 0 } - - const serializedTransaction = utils.serializeTransaction(tx) - - // Get current Ethereum gas price - const ethBaseFee = this.store('main.networksMeta.ethereum', 1, 'gas.price.fees.nextBaseFee') - const l1DataFee = calculateOptimismL1DataFee(serializedTransaction, ethBaseFee) + getOptimismFee = (l2Price, l2Limit, chainData) => { + const l1DataFee = BigNumber(chainData?.l1Fees).toNumber() // Compute the L2 execution fee const l2ExecutionFee = l2Price * l2Limit @@ -100,8 +87,9 @@ class TxFee extends React.Component { const maxGas = BigNumber(req.data.gasLimit, 16) const maxFeePerGas = BigNumber(req.data[usesBaseFee(req.data) ? 'maxFeePerGas' : 'gasPrice']) const maxFeeSourceValue = chainUsesOptimismFees(chain.id) - ? this.getOptimismFee(maxFeePerGas, maxGas, req.data) + ? this.getOptimismFee(maxFeePerGas, maxGas, req.chainData?.optimism) : maxFeePerGas.multipliedBy(maxGas) + const maxFee = displayValueData(maxFeeSourceValue, { currencyRate: nativeCurrency.usd, isTestnet @@ -114,7 +102,7 @@ class TxFee extends React.Component { // accounts for the 50% padding in the gas estimate in the provider const minGas = maxGas.dividedBy(BigNumber(1.5)) const minFeeSourceValue = chainUsesOptimismFees(chain.id) - ? this.getOptimismFee(minFeePerGas, minGas, req.data) + ? this.getOptimismFee(minFeePerGas, minGas, req.chainData?.optimism) : minFeePerGas.multipliedBy(minGas) const minFee = displayValueData(minFeeSourceValue, { currencyRate: nativeCurrency.usd, @@ -137,7 +125,11 @@ class TxFee extends React.Component {
- + {!maxFee.bn || maxFee.bn.isNaN() ? ( + `? ${nativeCurrency.symbol}` + ) : ( + + )}
diff --git a/main/accounts/index.ts b/main/accounts/index.ts index 4498413d8..91dfd6ad3 100644 --- a/main/accounts/index.ts +++ b/main/accounts/index.ts @@ -33,6 +33,7 @@ import { ActionType } from '../transaction/actions' import { openBlockExplorer } from '../windows/window' import { ApprovalType } from '../../resources/constants' import { accountNS } from '../../resources/domain/account' +import { chainUsesOptimismFees } from '../../resources/utils/chains' function notify(title: string, body: string, action: (event: Electron.Event) => void) { const notification = new Notification({ title, body }) @@ -41,6 +42,31 @@ function notify(title: string, body: string, action: (event: Electron.Event) => setTimeout(() => notification.show(), 1000) } +function toTransactionsByLayer(requests: Record, chainId?: number) { + return Object.entries(requests) + .filter(([_, req]) => req.type === 'transaction') + .reduce( + ({ l1Transactions, l2Transactions }, [id, req]) => { + const txRequest = req as TransactionRequest + if ( + !txRequest.locked && + !txRequest.feesUpdatedByUser && + txRequest.data.gasFeesSource === GasFeesSource.Frame && + (!chainId || parseInt(txRequest.data.chainId, 16) === chainId) + ) { + l1Transactions.push([id, txRequest]) + } + + if (chainUsesOptimismFees(parseInt(txRequest.data.chainId, 16))) { + l2Transactions.push([id, txRequest]) + } + + return { l1Transactions, l2Transactions } + }, + { l1Transactions: [] as RequestWithId[], l2Transactions: [] as RequestWithId[] } + ) +} + const frameOriginId = uuidv5('frame-internal', uuidv5.DNS) const storeApi = { @@ -65,6 +91,8 @@ export { AddTokenRequest } from './types' +type RequestWithId = [string, TransactionRequest] + export class Accounts extends EventEmitter { _current: string accounts: Record @@ -532,18 +560,9 @@ export class Accounts extends EventEmitter { if (currentAccount) { // If chainId, update pending tx requests from that chain, otherwise update all pending tx requests - const transactions = Object.entries(currentAccount.requests) - .filter(([_, req]) => req.type === 'transaction') - .map(([_, req]) => [_, req] as [string, TransactionRequest]) - .filter( - ([_, req]) => - !req.locked && - !req.feesUpdatedByUser && - req.data.gasFeesSource === GasFeesSource.Frame && - (!chainId || parseInt(req.data.chainId, 16) === chainId) - ) + const { l1Transactions, l2Transactions } = toTransactionsByLayer(currentAccount.requests, chainId) - transactions.forEach(([id, req]) => { + l1Transactions.forEach(([id, req]) => { try { const tx = req.data const chain = { type: 'ethereum', id: parseInt(tx.chainId, 16) } @@ -561,6 +580,26 @@ export class Accounts extends EventEmitter { log.error('Could not update gas fees for transaction', e) } }) + + if (chainId === 1) { + l2Transactions.forEach(async ([_id, req]) => { + let estimate = '' + try { + estimate = (await provider.getL1GasCost(req.data)).toHexString() + } catch (e) { + log.error('Error estimating L1 gas cost', e) + } + + req.chainData = { + ...req.chainData, + optimism: { + l1Fees: estimate + } + } + + currentAccount.update() + }) + } } } diff --git a/main/accounts/types.ts b/main/accounts/types.ts index 7bd4368cf..f3c11d4b3 100644 --- a/main/accounts/types.ts +++ b/main/accounts/types.ts @@ -101,6 +101,11 @@ export interface TransactionRequest extends AccountRequest<'transaction'> { payload: RPC.SendTransaction.Request data: TransactionData decodedData?: DecodedCallData + chainData?: { + optimism?: { + l1Fees: string + } + } tx?: { receipt?: TransactionReceipt hash?: string diff --git a/main/chains/index.js b/main/chains/index.js index a1b09b0f6..c79aa70f8 100644 --- a/main/chains/index.js +++ b/main/chains/index.js @@ -3,6 +3,9 @@ const { powerMonitor } = require('electron') const EventEmitter = require('events') const { addHexPrefix } = require('@ethereumjs/util') const { Hardfork } = require('@ethereumjs/common') +const { estimateL1GasCost } = require('@eth-optimism/sdk') +const { Web3Provider } = require('@ethersproject/providers') +const BigNumber = require('bignumber.js') const provider = require('eth-provider') const log = require('electron-log') @@ -12,6 +15,7 @@ const { default: chainConfig } = require('./config') const { default: GasMonitor } = require('../transaction/gasMonitor') const { createGasCalculator } = require('./gas') const { NETWORK_PRESETS } = require('../../resources/constants') +const { chainUsesOptimismFees } = require('../../resources/utils/chains') // These chain IDs are known to not support EIP-1559 and will be forced // not to use that mechanism @@ -28,6 +32,17 @@ const resError = (error, payload, res) => error: typeof error === 'string' ? { message: error, code: -1 } : error }) +function txEstimate(gasCost, nativeUSD) { + const usd = gasCost.shiftedBy(-18).multipliedBy(nativeUSD).toNumber() + + return { + gasEstimate: addHexPrefix(gasCost.toString(16)), + cost: { + usd + } + } +} + class ChainConnection extends EventEmitter { constructor(type, chainId) { super() @@ -81,6 +96,91 @@ class ChainConnection extends EventEmitter { this.emit('connect') } + async txEstimates(type, id, gasPrice, currentSymbol, provider) { + const sampleEstimates = [ + { + label: `Send ${currentSymbol}`, + txExample: { + value: '0x8e1bc9bf04000', + data: '0x00', + gasLimit: addHexPrefix((21000).toString(16)) + } + }, + { + label: 'Send Tokens', + txExample: { + value: '0x00', + data: '0xa9059cbb000000000000000000000000c1af8ca40dfe1cb43b9c7a8c93df762c2d6ecfd90000000000000000000000000000000000000000000000008ac7230489e80000', + gasLimit: addHexPrefix((65000).toString(16)) + } + }, + { + label: 'Dex Swap', + txExample: { + value: '0x13e1e16b2a10c9', + data: '0x049639fb0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee00000000000000000000000042000000000000000000000000000000000000420000000000000000000000000000000000000000000000000013e1e16b2a10c900000000000000000000000000000000000000000000000045575639011cb45400000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000038812aa3caf000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba00000000000000000000000042000000000000000000000000000000000000060000000000000000000000004200000000000000000000000000000000000042000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba000000000000000000000000a7ca2c8673bcfa5a26d8ceec2887f2cc2b0db22a0000000000000000000000000000000000000000000000000013e1e16b2a10c900000000000000000000000000000000000000000000000045575639011cb455000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f50000000000000000000000000000000000000000000000000000000001d700a007e5c0d20000000000000000000000000000000000000000000000000001b30001505126a132dab612db5cb9fc9ac426a0cc215a3423f9c942000000000000000000000000000000000000060004f41766d8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011edea400000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba0000000000000000000000000000000000000000000000000000000065e75a70000000000000000000000000000000000000000000000000000000000000000100000000000000000000000042000000000000000000000000000000000000060000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607000000000000000000000000000000000000000000000000000000000000000102a000000000000000000000000000000000000000000000000045575639011cb455ee63c1e5801d751bc1a723accf1942122ca9aa82d49d08d2ae7f5c764cbc14f9669b88837ca1490cca17c316071111111254eeb25477b68fb85ed929f73a96058200000000000000000000000bd34b36000000000000000000000000000000000000000000000000', + gasLimit: addHexPrefix((200000).toString(16)) + } + } + ] + + const isTestnet = store('main.networks', type, id, 'isTestnet') + const nativeCurrency = store('main.networksMeta', type, id, 'nativeCurrency') + const nativeUSD = BigNumber( + nativeCurrency && nativeCurrency.usd && !isTestnet ? nativeCurrency.usd.price : 0 + ) + + let estimates + + if (chainUsesOptimismFees(id) && !isTestnet) { + estimates = await Promise.all( + sampleEstimates.map(async ({ label, txExample }) => { + const tx = { + ...txExample, + type: 2, + chainId: id + } + + try { + const l1GasCost = BigNumber((await estimateL1GasCost(provider, tx)).toHexString()) + const l2GasCost = BigNumber(tx.gasLimit).multipliedBy(gasPrice) + const estimatedGas = l1GasCost.plus(l2GasCost) + + return { + label, + gasCost: estimatedGas + } + } catch (e) { + return { + label, + gasCost: BigNumber('') + } + } + }) + ) + } else { + estimates = sampleEstimates.map(({ label, txExample }) => ({ + label, + gasCost: BigNumber(txExample.gasLimit).multipliedBy(gasPrice) + })) + } + + return estimates.map(({ label, gasCost }) => ({ + estimates: { + low: txEstimate(gasCost, nativeUSD), + high: txEstimate(gasCost, nativeUSD) + }, + label + })) + } + + async feeEstimatesUSD(chainId, gasPrice, provider) { + const type = 'ethereum' + const currentSymbol = store('main.networksMeta', type, chainId, 'nativeCurrency', 'symbol') || 'ETH' + + return this.txEstimates(type, chainId, gasPrice, currentSymbol, provider) + } + _createBlockMonitor(provider) { const monitor = new BlockMonitor(provider) const allowEip1559 = !legacyChains.includes(parseInt(this.chainId)) @@ -127,6 +227,19 @@ class ChainConnection extends EventEmitter { }) } + if (provider.connected) { + const gasPrice = store('main.networksMeta', this.type, this.chainId, 'gas.price.levels.slow') + const estimatedGasPrice = feeMarket + ? BigNumber(feeMarket.nextBaseFee).plus(BigNumber(feeMarket.maxPriorityFeePerGas)) + : BigNumber(gasPrice) + + this.feeEstimatesUSD(parseInt(this.chainId), estimatedGasPrice, new Web3Provider(provider)).then( + (samples) => { + store.addSampleGasCosts(this.type, this.chainId, samples) + } + ) + } + store.setGasFees(this.type, this.chainId, feeMarket) store.setBlockHeight(this.chainId, parseInt(block.number, 16)) diff --git a/main/provider/index.ts b/main/provider/index.ts index 0356b03d7..9037f53ed 100644 --- a/main/provider/index.ts +++ b/main/provider/index.ts @@ -1,9 +1,12 @@ -import { v4 as uuid } from 'uuid' import EventEmitter from 'events' +import crypto from 'crypto' import log from 'electron-log' +import { v4 as uuid } from 'uuid' +import { Web3Provider } from '@ethersproject/providers' +import { BigNumber } from 'ethers' +import { estimateL1GasCost } from '@eth-optimism/sdk' import { recoverTypedSignature, SignTypedDataVersion } from '@metamask/eth-sig-util' import { isAddress } from '@ethersproject/address' -import crypto from 'crypto' import { addHexPrefix, intToHex, isHexString, isHexPrefixed, fromUtf8 } from '@ethereumjs/util' import store from '../store' @@ -299,6 +302,27 @@ export class Provider extends EventEmitter { }) } + async getL1GasCost(txData: TransactionData) { + const { chainId, type, ...tx } = txData + + const txRequest = { + ...tx, + type: parseInt(type, 16), + chainId: parseInt(chainId, 16) + } + + const connection = this.connection.connections['ethereum'][txRequest.chainId] as any + const connectedProvider = connection?.primary?.connected + ? connection.primary?.provider + : connection.secondary?.provider + + if (!connectedProvider) { + return BigNumber.from(0) + } + + return estimateL1GasCost(new Web3Provider(connectedProvider), txRequest) + } + signAndSend(req: TransactionRequest, cb: Callback) { const rawTx = req.data const res = (data: any) => { @@ -413,6 +437,7 @@ export class Provider extends EventEmitter { jsonrpc: '2.0', id: 1 } + const targetChain: Chain = { type: 'ethereum', id: parseInt(rawTx.chainId, 16) diff --git a/main/store/actions/index.js b/main/store/actions/index.js index 35b2ce03f..8803d4f00 100644 --- a/main/store/actions/index.js +++ b/main/store/actions/index.js @@ -254,6 +254,11 @@ module.exports = { u('main.networksMeta', netType, netId, 'gas.price.lastLevel', () => level) } }, + addSampleGasCosts: (u, netType, netId, samples) => { + u('main.networksMeta', netType, netId, 'gas.samples', () => { + return samples + }) + }, setNativeCurrencyData: (u, netType, netId, currency) => { u('main.networksMeta', netType, netId, 'nativeCurrency', (existing) => ({ ...existing, ...currency })) }, diff --git a/main/store/state/types/gas.ts b/main/store/state/types/gas.ts index b9c478795..8d4bb2f81 100644 --- a/main/store/state/types/gas.ts +++ b/main/store/state/types/gas.ts @@ -8,6 +8,23 @@ const GasLevelsSchema = z.object({ custom: z.string().optional() }) +const GasEstimateSchema = z.object({ + gasEstimate: z.string(), + cost: z.object({ + usd: z.number().nullish() + }) +}) + +const GasSampleSchema = z.object({ + label: z.string(), + estimates: z + .object({ + low: GasEstimateSchema, + high: GasEstimateSchema + }) + .partial() +}) + // TODO: validate these fields as hex amount values export const GasFeesSchema = z .object({ @@ -19,6 +36,7 @@ export const GasFeesSchema = z .partial() export const GasSchema = z.object({ + samples: z.array(GasSampleSchema).default([]), price: z.object({ selected: GasLevelsSchema.keyof(), levels: GasLevelsSchema, diff --git a/package-lock.json b/package-lock.json index 3b4d14220..b0cadb87a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "GPL-3.0", "dependencies": { + "@eth-optimism/sdk": "3.2.0", "@ethereumjs/common": "3.1.1", "@ethereumjs/tx": "4.1.1", "@ethereumjs/util": "8.0.3", @@ -2741,6 +2742,129 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@eth-optimism/contracts": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/contracts/-/contracts-0.6.0.tgz", + "integrity": "sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==", + "dependencies": { + "@eth-optimism/core-utils": "0.12.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0" + }, + "peerDependencies": { + "ethers": "^5" + } + }, + "node_modules/@eth-optimism/contracts-bedrock": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eth-optimism/contracts-bedrock/-/contracts-bedrock-0.17.1.tgz", + "integrity": "sha512-Hc5peN5PM8kzl9dzqSD5jv6ED3QliO1DF0dXLRJxfrXR7/rmEeyuAYESUwUM0gdJZjkwRYiS5m230BI6bQmnlw==", + "hasInstallScript": true + }, + "node_modules/@eth-optimism/contracts/node_modules/@eth-optimism/core-utils": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz", + "integrity": "sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw==", + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/providers": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bufio": "^1.0.7", + "chai": "^4.3.4" + } + }, + "node_modules/@eth-optimism/core-utils": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", + "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", + "hasInstallScript": true, + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/web": "^5.7.1", + "chai": "^4.3.9", + "ethers": "^5.7.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@eth-optimism/sdk": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.0.tgz", + "integrity": "sha512-+ZEO/mDWz3WLzaPVHvgOAK4iN723HmI6sLLr2tmO1/RUoCHVfWMUDwuiikrA49cAsdsjMxCV9+0XNZ8btD2JUg==", + "hasInstallScript": true, + "dependencies": { + "@eth-optimism/contracts": "0.6.0", + "@eth-optimism/contracts-bedrock": "0.17.1", + "@eth-optimism/core-utils": "0.13.1", + "lodash": "^4.17.21", + "merkletreejs": "^0.3.11", + "rlp": "^2.2.7", + "semver": "^7.5.4" + }, + "peerDependencies": { + "ethers": "^5" + } + }, + "node_modules/@eth-optimism/sdk/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@eth-optimism/sdk/node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/@eth-optimism/sdk/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@eth-optimism/sdk/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, "node_modules/@ethereumjs/common": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.1.1.tgz", @@ -8249,15 +8373,12 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "node_modules/@scure/base": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", - "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==", - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ] + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "funding": { + "url": "https://paulmillr.com/funding/" + } }, "node_modules/@scure/bip32": { "version": "1.1.5", @@ -10196,6 +10317,14 @@ "node": ">=0.8" } }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "engines": { + "node": "*" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -11383,11 +11512,24 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "node_modules/buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==" + }, "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, + "node_modules/bufio": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bufio/-/bufio-1.2.1.tgz", + "integrity": "sha512-9oR3zNdupcg/Ge2sSHQF3GX+kmvL/fTPvD0nd5AGLq8SjUYnTz+SlFjK/GXidndbZtIj+pVKXiWeR9w6e9wKCA==", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/builder-util": { "version": "23.6.0", "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-23.6.0.tgz", @@ -11828,6 +11970,23 @@ "cborg": "cli.js" } }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -11850,6 +12009,17 @@ "node": ">=10" } }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, "node_modules/cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -12542,9 +12712,9 @@ } }, "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/css": { "version": "3.0.0", @@ -12826,6 +12996,17 @@ "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-equal": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", @@ -14449,6 +14630,14 @@ } } }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dependencies": { + "js-sha3": "^0.8.0" + } + }, "node_modules/ethereum-cryptography": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", @@ -14756,6 +14945,24 @@ "@ethersproject/wordlists": "5.7.0" } }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + }, "node_modules/ethjs-util": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", @@ -15291,6 +15498,14 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "engines": { + "node": "*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -20961,6 +21176,14 @@ "loose-envify": "cli.js" } }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, "node_modules/lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -21180,6 +21403,21 @@ "node": ">= 8" } }, + "node_modules/merkletreejs": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.3.11.tgz", + "integrity": "sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ==", + "dependencies": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^4.2.0", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + }, + "engines": { + "node": ">= 7.6.0" + } + }, "node_modules/micro-ftch": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", @@ -22308,6 +22546,24 @@ "node": ">=0.10.0" } }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + }, "node_modules/nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -22893,6 +23149,14 @@ "node": ">=8" } }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "engines": { + "node": "*" + } + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -26004,6 +26268,14 @@ "tree-kill": "cli.js" } }, + "node_modules/treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -26149,7 +26421,6 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, "engines": { "node": ">=4" } @@ -26675,6 +26946,95 @@ "@zxing/text-encoding": "0.9.0" } }, + "node_modules/web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "dependencies": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "dependencies": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/web3-utils/node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/web3-utils/node_modules/ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "dependencies": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -28955,6 +29315,112 @@ "integrity": "sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==", "dev": true }, + "@eth-optimism/contracts": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/contracts/-/contracts-0.6.0.tgz", + "integrity": "sha512-vQ04wfG9kMf1Fwy3FEMqH2QZbgS0gldKhcBeBUPfO8zu68L61VI97UDXmsMQXzTsEAxK8HnokW3/gosl4/NW3w==", + "requires": { + "@eth-optimism/core-utils": "0.12.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0" + }, + "dependencies": { + "@eth-optimism/core-utils": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/core-utils/-/core-utils-0.12.0.tgz", + "integrity": "sha512-qW+7LZYCz7i8dRa7SRlUKIo1VBU8lvN0HeXCxJR+z+xtMzMQpPds20XJNCMclszxYQHkXY00fOT6GvFw9ZL6nw==", + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/providers": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bufio": "^1.0.7", + "chai": "^4.3.4" + } + } + } + }, + "@eth-optimism/contracts-bedrock": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/@eth-optimism/contracts-bedrock/-/contracts-bedrock-0.17.1.tgz", + "integrity": "sha512-Hc5peN5PM8kzl9dzqSD5jv6ED3QliO1DF0dXLRJxfrXR7/rmEeyuAYESUwUM0gdJZjkwRYiS5m230BI6bQmnlw==" + }, + "@eth-optimism/core-utils": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/@eth-optimism/core-utils/-/core-utils-0.13.1.tgz", + "integrity": "sha512-1FvzbUmCEy9zSKPG1QWg2VfA2Cy90xBA9Wkp11lXXrz91zUPCNCNSRTujXWYIC86ketNsZp7p4njSf6lTycHCw==", + "requires": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/contracts": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/web": "^5.7.1", + "chai": "^4.3.9", + "ethers": "^5.7.2", + "node-fetch": "^2.6.7" + } + }, + "@eth-optimism/sdk": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@eth-optimism/sdk/-/sdk-3.2.0.tgz", + "integrity": "sha512-+ZEO/mDWz3WLzaPVHvgOAK4iN723HmI6sLLr2tmO1/RUoCHVfWMUDwuiikrA49cAsdsjMxCV9+0XNZ8btD2JUg==", + "requires": { + "@eth-optimism/contracts": "0.6.0", + "@eth-optimism/contracts-bedrock": "0.17.1", + "@eth-optimism/core-utils": "0.13.1", + "lodash": "^4.17.21", + "merkletreejs": "^0.3.11", + "rlp": "^2.2.7", + "semver": "^7.5.4" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "requires": { + "bn.js": "^5.2.0" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, "@ethereumjs/common": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-3.1.1.tgz", @@ -32873,9 +33339,9 @@ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, "@scure/base": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.1.tgz", - "integrity": "sha512-ZxOhsSyxYwLJj3pLZCefNitxsj093tb2vq90mp2txoYeBqbcjDjqFhyM8eUjq/uFm6zJ+mUuqxlS2FkuSY1MTA==" + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==" }, "@scure/bip32": { "version": "1.1.5", @@ -34465,6 +34931,11 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==" }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==" + }, "astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -35441,11 +35912,21 @@ "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", "dev": true }, + "buffer-reverse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-reverse/-/buffer-reverse-1.0.1.tgz", + "integrity": "sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==" + }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" }, + "bufio": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bufio/-/bufio-1.2.1.tgz", + "integrity": "sha512-9oR3zNdupcg/Ge2sSHQF3GX+kmvL/fTPvD0nd5AGLq8SjUYnTz+SlFjK/GXidndbZtIj+pVKXiWeR9w6e9wKCA==" + }, "builder-util": { "version": "23.6.0", "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-23.6.0.tgz", @@ -35775,6 +36256,20 @@ "resolved": "https://registry.npmjs.org/cborg/-/cborg-1.10.2.tgz", "integrity": "sha512-b3tFPA9pUr2zCUiCfRd2+wok2/LBSNUMKOuRRok+WlvvAgEt/PlbgPTsZUcwCOs53IJvLgTp0eotwtosE6njug==" }, + "chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -35791,6 +36286,14 @@ "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true }, + "check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "requires": { + "get-func-name": "^2.0.2" + } + }, "cheerio": { "version": "1.0.0-rc.12", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", @@ -36327,9 +36830,9 @@ } }, "crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "css": { "version": "3.0.0", @@ -36552,6 +37055,14 @@ "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", "dev": true }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "requires": { + "type-detect": "^4.0.0" + } + }, "deep-equal": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.0.tgz", @@ -37786,6 +38297,14 @@ } } }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "requires": { + "js-sha3": "^0.8.0" + } + }, "ethereum-cryptography": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-1.2.0.tgz", @@ -38075,6 +38594,22 @@ "@ethersproject/wordlists": "5.7.0" } }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha512-/Sn9Y0oKl0uqQuvgFk/zQgR7aw1g36qX/jzSQ5lSwlO0GigPymk4eGQfeNTD03w1dPOqfz8V77Cy43jH56pagw==", + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + } + } + }, "ethjs-util": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", @@ -38486,6 +39021,11 @@ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, + "get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==" + }, "get-intrinsic": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", @@ -42651,6 +43191,14 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "requires": { + "get-func-name": "^2.0.1" + } + }, "lowercase-keys": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", @@ -42831,6 +43379,18 @@ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true }, + "merkletreejs": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/merkletreejs/-/merkletreejs-0.3.11.tgz", + "integrity": "sha512-LJKTl4iVNTndhL+3Uz/tfkjD0klIWsHlUzgtuNnNrsf7bAlXR30m+xYB7lHr5Z/l6e/yAIsr26Dabx6Buo4VGQ==", + "requires": { + "bignumber.js": "^9.0.1", + "buffer-reverse": "^1.0.1", + "crypto-js": "^4.2.0", + "treeify": "^1.1.0", + "web3-utils": "^1.3.4" + } + }, "micro-ftch": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", @@ -43685,6 +44245,22 @@ "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha512-wsJ9gfSz1/s4ZsJN01lyonwuxA1tml6X1yBDnfpMglypcBRFZZkus26EdPSlqS5GJfYddVZa22p3VNb3z5m5Ig==", + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-XWwnNNFCuuSQ0m3r3C4LE3EiORltHd9M05pq6FOlVeiophzRbMo50Sbz1ehl8K3Z+jw9+vmgnXefY1hz8X+2wA==" + } + } + }, "nwsapi": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", @@ -44107,6 +44683,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==" + }, "pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -46447,6 +47028,11 @@ "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true }, + "treeify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.1.0.tgz", + "integrity": "sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==" + }, "trim-right": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", @@ -46547,8 +47133,7 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" }, "type-fest": { "version": "0.20.2", @@ -46945,6 +47530,76 @@ "util": "^0.12.3" } }, + "web3-utils": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.10.4.tgz", + "integrity": "sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==", + "requires": { + "@ethereumjs/util": "^8.1.0", + "bn.js": "^5.2.1", + "ethereum-bloom-filters": "^1.0.6", + "ethereum-cryptography": "^2.1.2", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "dependencies": { + "@ethereumjs/util": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-8.1.0.tgz", + "integrity": "sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==", + "requires": { + "@ethereumjs/rlp": "^4.0.1", + "ethereum-cryptography": "^2.0.0", + "micro-ftch": "^0.3.1" + } + }, + "@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "requires": { + "@noble/hashes": "1.3.3" + } + }, + "@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==" + }, + "@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "requires": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + } + }, + "@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "requires": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + } + }, + "ethereum-cryptography": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.3.tgz", + "integrity": "sha512-BlwbIL7/P45W8FGW2r7LGuvoEZ+7PWsniMvQ4p5s2xCyw9tmaDlpfsN9HjAucbF+t/qpVHwZUisgfK24TCW8aA==", + "requires": { + "@noble/curves": "1.3.0", + "@noble/hashes": "1.3.3", + "@scure/bip32": "1.3.3", + "@scure/bip39": "1.2.2" + } + } + } + }, "webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index a9e3a877d..df973ff29 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ }, "license": "GPL-3.0", "dependencies": { + "@eth-optimism/sdk": "3.2.0", "@ethereumjs/common": "3.1.1", "@ethereumjs/tx": "4.1.1", "@ethereumjs/util": "8.0.3", @@ -245,6 +246,9 @@ "allowScripts": { "$root$": false, "@babel/node>core-js": true, + "@eth-optimism/sdk": false, + "@eth-optimism/sdk>@eth-optimism/contracts-bedrock": false, + "@eth-optimism/sdk>@eth-optimism/core-utils": false, "@lavamoat/preinstall-always-fail": false, "@ledgerhq/hw-transport-node-hid-noevents>node-hid": false, "@ledgerhq/hw-transport-node-hid-singleton>usb": false, diff --git a/resources/Components/Monitor/index.js b/resources/Components/Monitor/index.js index 497671e2a..92147f3cb 100644 --- a/resources/Components/Monitor/index.js +++ b/resources/Components/Monitor/index.js @@ -7,45 +7,18 @@ import link from '../../link' import { ClusterRow, ClusterValue } from '../Cluster' import svg from '../../svg' -import { weiToGwei, hexToInt } from '../../utils' -import { chainUsesOptimismFees, calculateOptimismL1DataFee } from '../../utils/chains' - -// estimated gas to perform various common tasks -const gasToSendEth = 21 * 1000 -const gasToSendToken = 65 * 1000 -const gasForDexSwap = 200 * 1000 - -function roundGwei(gwei) { - return parseFloat( - gwei >= 10 - ? Math.round(gwei) - : gwei >= 5 - ? Math.round(gwei * 10) / 10 - : gwei >= 1 - ? Math.round(gwei * 100) / 100 - : Math.round(gwei * 1000) / 1000 - ) -} +import { weiToGwei, hexToInt, roundGwei } from '../../utils' function levelDisplay(level) { const gwei = weiToGwei(hexToInt(level)) return roundGwei(gwei) || 0 } -function toDisplayUSD(bn) { - if (bn.toNumber() === 0) return '?' +function toDisplayUSD(num) { + const bn = BigNumber(num) + if (num === 0) return '?' return parseFloat( - bn.toNumber() >= 1 - ? bn.toFixed(0, BigNumber.ROUND_UP).toString() - : bn.toFixed(2, BigNumber.ROUND_UP).toString() - ) -} - -function txEstimate(value, gasLimit, nativeUSD) { - return toDisplayUSD( - BigNumber(value * gasLimit) - .shiftedBy(-9) - .multipliedBy(nativeUSD) + num >= 1 ? bn.toFixed(0, BigNumber.ROUND_UP).toString() : bn.toFixed(2, BigNumber.ROUND_UP).toString() ) } @@ -129,88 +102,6 @@ class ChainSummaryComponent extends Component { } } - txEstimates(type, id, gasPrice, calculatedFees, currentSymbol) { - const estimates = [ - { - label: `Send ${currentSymbol}`, - estimatedGas: gasToSendEth, - serializedTxExample: - '0x02ed0a80832463478324670d827b0c94b120c885f1527394c78d50e7c7da57defb24f6128802c68af0bb14000080c0' - }, - { - label: 'Send Tokens', - estimatedGas: gasToSendToken, - serializedTxExample: - '0x02f86d0a808403b35e108403b35e6d8302137894420000000000000000000000000000000000004280b844a9059cbb000000000000000000000000b120c885f1527394c78d50e7c7da57defb24f6120000000000000000000000000000000000000000000000c23cb3bdafde405080c0' - }, - { - label: 'Dex Swap', - estimatedGas: gasForDexSwap, - serializedTxExample: - '0x02f903f60a808402bbcd0b8402bbcd638304b057943fc91a3afd70395cd496c647d5a6cc9d4b2b7fad8806e1a38167665296b903c43593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000064cb05c500000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000006e1a38167665296000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000420fbb40ad6fe5a000000000000000000000000000000000000000000000011ac6ccb6849433fc000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b4200000000000000000000000000000000000006000bb842000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000002c0a7cd5c8f543c00000000000000000000000000000000000000000000000bc9f7effabef331c200000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b42000000000000000000000000000000000000060001f44200000000000000000000000000000000000042000000000000000000000000000000000000000000c0' - } - ] - - const isTestnet = this.store('main.networks', type, id, 'isTestnet') - const nativeCurrency = this.store('main.networksMeta', type, id, 'nativeCurrency') - const nativeUSD = BigNumber( - nativeCurrency && nativeCurrency.usd && !isTestnet ? nativeCurrency.usd.price : 0 - ) - - if (chainUsesOptimismFees(id)) { - // Optimism specific calculations - const price = calculatedFees?.actualFee || gasPrice - - const feeMarket = this.store('main.networksMeta.ethereum', 1, 'gas.price.fees') || {} - const { nextBaseFee: ethBaseFee } = feeMarket - - const optimismEstimate = (serializedTx, l2Limit) => { - const l1Estimate = BigNumber(calculateOptimismL1DataFee(serializedTx, ethBaseFee)).shiftedBy(-9) - const l2Estimate = BigNumber(price * l2Limit) - - return toDisplayUSD(l1Estimate.plus(l2Estimate).shiftedBy(-9).multipliedBy(nativeUSD)) - } - - return estimates.map(({ label, estimatedGas, serializedTxExample }, i) => ({ - low: optimismEstimate(serializedTxExample, estimatedGas), - high: optimismEstimate(serializedTxExample, estimatedGas), - label - })) - } - - const low = calculatedFees - ? roundGwei(calculatedFees.actualBaseFee + calculatedFees.priorityFee) - : gasPrice - - return estimates.map(({ label, estimatedGas }) => ({ - low: txEstimate(low, estimatedGas, nativeUSD), - high: txEstimate(gasPrice, estimatedGas, nativeUSD), - label - })) - } - - feeEstimatesUSD({ chainId, displayFeeMarket, gasPrice }) { - const type = 'ethereum' - const currentSymbol = this.store('main.networksMeta', type, chainId, 'nativeCurrency', 'symbol') || 'ETH' - - if (!displayFeeMarket) { - return this.txEstimates(type, chainId, gasPrice, null, currentSymbol) - } - - const { nextBaseFee, maxPriorityFeePerGas } = this.store( - 'main.networksMeta', - type, - chainId, - 'gas.price.fees' - ) - const calculatedFees = { - actualBaseFee: roundGwei(weiToGwei(hexToInt(nextBaseFee))), - priorityFee: levelDisplay(maxPriorityFeePerGas) - } - - return this.txEstimates(type, chainId, gasPrice, calculatedFees, currentSymbol) - } - render() { const { address, chainId } = this.props const type = 'ethereum' @@ -220,6 +111,7 @@ class ChainSummaryComponent extends Component { const gasPrice = levelDisplay(levels.fast) const explorer = this.store('main.networks', type, chainId, 'explorer') + const sampleOperations = this.store('main.networksMeta', type, chainId, 'gas.samples') || [] // fees is either a populated object (EIP-1559 compatible) or falsy const displayFeeMarket = !!fees @@ -279,26 +171,19 @@ class ChainSummaryComponent extends Component { )} - {this.feeEstimatesUSD({ chainId, displayFeeMarket, gasPrice }).map((estimate, i) => { + {sampleOperations.map(({ label, estimates }, i) => { + const cost = estimates.low?.cost.usd return (
- {!estimate.low || estimate.low >= 0.01 || estimate.low === '?' ? `$` : '<$'} + {!cost || cost >= 0.01 || cost === '?' ? `$` : '<$'} - {`${ - !estimate.low - ? 0 - : estimate.low < 0.01 - ? 0.01 - : estimate.low < 1 - ? estimate.low.toFixed(2) - : estimate.low - }`} + {(cost && `${toDisplayUSD(cost)}`) || '?'}
- {estimate.label} + {label}
diff --git a/resources/utils/chains.ts b/resources/utils/chains.ts index abf68bf91..d0c58c643 100644 --- a/resources/utils/chains.ts +++ b/resources/utils/chains.ts @@ -16,19 +16,5 @@ export function isNetworkEnabled(network: Chain) { } export function chainUsesOptimismFees(chainId: number) { - return [10, 420, 8453, 84531, 7777777].includes(chainId) -} - -export function calculateOptimismL1DataFee(serializedTx: string, baseFeeL1: string) { - const FIXED_OVERHEAD = 188 - const DYNAMIC_OVERHEAD = 0.684 - - const bytes = utils.arrayify(serializedTx) - const baseFee = hexToInt(baseFeeL1) || 0 - - // Compute the L1 data fee, with a cost of 16 per byte and 4 per empty byte, - // starting at 1088 to account for a 68-byte signature - const txDataFee = bytes.reduce((sum, byte) => sum + (byte === 0 ? 4 : 16), 1088) - - return baseFee * (txDataFee + FIXED_OVERHEAD) * DYNAMIC_OVERHEAD + return [10, 420, 8453, 84531, 84532, 7777777, 11155420].includes(chainId) } diff --git a/resources/utils/index.ts b/resources/utils/index.ts index 49b0f400d..fafef6b41 100644 --- a/resources/utils/index.ts +++ b/resources/utils/index.ts @@ -11,6 +11,19 @@ const weiHexToGweiInt = (weiHex: string) => hexToInt(weiHex) / 1e9 const weiIntToEthInt = (wei: number) => wei / 1e18 const gweiToWeiHex = (gwei: number) => intToHex(gweiToWei(gwei)) +function roundGwei(gwei: number) { + const rounded = + gwei >= 10 + ? Math.round(gwei) + : gwei >= 5 + ? Math.round(gwei * 10) / 10 + : gwei >= 1 + ? Math.round(gwei * 100) / 100 + : Math.round(gwei * 1000) / 1000 + + return parseFloat(rounded.toString()) +} + function randomLetters(num: number) { return [...Array(num)].map(() => String.fromCharCode(65 + randomInt(0, 26))).join('') } @@ -99,6 +112,7 @@ export { weiHexToGweiInt, weiIntToEthInt, gweiToWeiHex, + roundGwei, getAddress, stripHexPrefix, matchFilter, diff --git a/test/resources/utils/chains.test.js b/test/resources/utils/chains.test.js deleted file mode 100644 index c772af213..000000000 --- a/test/resources/utils/chains.test.js +++ /dev/null @@ -1,22 +0,0 @@ -import { calculateOptimismL1DataFee } from '../../../resources/utils/chains' - -describe('#calculateOptimismL1DataFee', () => { - it('calculates a fee for a serialized transaction', () => { - const serializedTx = - '0x02ed0a80837853be837854b3827b0c94b120c885f1527394c78d50e7c7da57defb24f61288016345785d8a000080c0' - const baseFee = '0x' + (35e9).toString(16) // 35 gwei - - const fee = calculateOptimismL1DataFee(serializedTx, baseFee) - - expect(fee).toBe(47975760000000) - }) - - it('calculates a fee as zero if no given base fee', () => { - const serializedTx = - '0x02ed0a80837853be837854b3827b0c94b120c885f1527394c78d50e7c7da57defb24f61288016345785d8a000080c0' - - const fee = calculateOptimismL1DataFee(serializedTx, NaN) - - expect(fee).toBe(0) - }) -})