From 4647456e064707f90bcce3efa5c8eaf958352e68 Mon Sep 17 00:00:00 2001 From: cgewecke Date: Tue, 2 Apr 2024 17:45:01 -0700 Subject: [PATCH] Add Arbitrum support (#225) --- .github/workflows/ci.yml | 1 + README.md | 100 +++++---- docs/advanced.md | 2 +- package.json | 1 + scripts/gen-options-md.ts | 9 + src/constants.ts | 26 +++ src/lib/options.ts | 23 +- src/lib/render/markdown.ts | 22 +- src/lib/render/terminal.ts | 9 +- src/types.ts | 17 +- src/utils/chains.ts | 23 +- src/utils/gas.ts | 202 +++++++++--------- src/utils/prices.ts | 25 ++- src/utils/ui.ts | 20 +- test/integration/options.g.ts | 61 ++++++ .../options/hardhat.options.g.config.ts | 32 +++ test/unit/cases/arbitrum.ts | 94 +++++++- test/unit/gas.ts | 48 +++++ test/unit/prices.ts | 16 +- yarn.lock | 41 +++- 20 files changed, 570 insertions(+), 202 deletions(-) create mode 100644 test/integration/options.g.ts create mode 100644 test/projects/options/hardhat.options.g.config.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d9c292..b702c82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ env: ETHERSCAN_API_KEY: ${{ secrets.ETHERSCAN_API_KEY }} OPTIMISTIC_API_KEY: ${{ secrets.OPTIMISTIC_API_KEY }} BASE_API_KEY: ${{ secrets.BASE_API_KEY }} + ARBITRUM_API_KEY: ${{ secrets.ARBITRUM_API_KEY }} jobs: lint: diff --git a/README.md b/README.md index 50ac361..794646e 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,9 @@ const config: HardhatUserConfig = { **:mag: Caveats about Accuracy**: + Gas readings for `pure` and `view` methods are **only a lower bound** of their real world cost. Actual gas usage will depend on the way the methods are called and the storage/memory state of the EVM at the moment of invocation. For more information on this see the excellent summary at [wolfio/evm/gas][1] -+ L1 gas readings for Optimism are approximations, typically within 1% of observed usage on [optimistic-etherscan][100]. A small amount of variance is expected. ++ L1 gas readings for Arbitrum & OPStack chains are approximations - some variance is expected. + + Optimism estimates should be within 1% of observed usage on [optimistic-etherscan][100]. + + Arbitrum estimates should be within 10% of observed usage on [arbiscan][111] + The Hardhat client implements the Ethereum Foundation EVM. To get accurate measurements for other EVM-based chains you may need to run your tests against development clients developed specifically for those networks. @@ -72,51 +74,52 @@ const config: HardhatUserConfig = { + Option setups for common and advanced use cases can be seen in the [Config Examples][2] docs]. + Get a [free tier Coinmarketcap API key][3] if you want price data -| Options | Type | Default | Description | -| :------------------------------ | :--------: | :--------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| currency | _string_ | `USD` | National currency to represent gas costs in. Exchange rates are loaded at runtime from the `coinmarketcap` api. Available currency codes can be found [here][5] | -| coinmarketcap | _string_ | - | [API key][3] to use when fetching live token price data | -| enabled | _bool_ | `true` | Produce gas reports with `hardhat test` | -| excludeAutoGeneratedGetters | _bool_ | `false` | Exclude solc generated public state vars when reporting gas for pure and view methods. (Incurs a performance penalty on test startup when `true`) ⚠️ SLOW ⚠️ | -| excludeContracts | _string[]_ | `[]` | Names of contracts to exclude from report. Ex: `["MyContract"]` | -| includeIntrinsicGas | _bool_ | `true` | Include standard 21_000 + calldata bytes overhead in method gas usage data. (Setting to `false` can be useful for modelling contract infra that will never be called by an EOA) | -| L1 | _string_ | `ethereum` | Auto-configure reporter to emulate an L1 network. (See [supported networks][6]) | -| L2 | _string_ | - | Auto-configure reporter to emulate an L2 network (See [supported networks][6]) | -| L1Etherscan | _string_ | - | [API key][4] to use when fetching live gasPrice, baseFee, and blobBaseFee data from an L1 network. (Optional, see [Supported Networks][6]) | -| L2Etherscan | _string_ | - | [API key][4] to use when fetching live gasPrice data from an L2 network (Optional, see [Supported Networks][6]) | -| offline | _bool_ | `false` | Turn off remote calls to fetch data | -| optimismHardfork | _string_ | `ecotone` | Optimism hardfork to emulate L1 & L2 gas costs for. | -| proxyResolver | _Class_ | - | User-defined class which helps reporter identify contract targets of proxied calls. (See [Advanced Usage][7]) | -| remoteContracts | _Array_ | - | List of forked-network deployed contracts to track execution costs for.(See [Advanced Usage][8]) | -| reportPureAndViewMethods | _bool_ | `false` | Track gas usage for methods invoked via `eth_call`. (Incurs a performance penalty that can be significant for large test suites) | -| :high_brightness: **DISPLAY** | | | | -| currencyDisplayPrecision | _number_ | `2` | Decimal precision to show nation state currency costs in | -| darkMode | _bool_ | `false` | Use colors better for dark backgrounds when printing to stdout | -| forceTerminalOutput | _bool_ | `false` | Write to terminal even when saving output to file | -| forceTerminalOutputFormat | _string_ | - | Table format to output forced terminal output in ("legacy" / "terminal" / "markdown") | -| noColors | _bool_ | `false` | Omit terminal color in output | -| reportFormat | _string_ | `terminal` | Report formats ("legacy" / "terminal" / "markdown") | -| showMethodSig | _bool_ | `false` | Display the complete function signature of methods. (Useful if you have overloaded methods) | -| showUncalledMethods | _bool_ | `false` | List all methods and deployments, even if no transactions were recorded for them | -| suppressTerminalOutput | _bool_ | `false` | Skip writing the table to stdout. (Useful if you only want to write JSON to file) | -| :floppy_disk: **OUTPUT** | | | | -| includeBytecodeInJSON | _bool_ | false | Include bytecode and deployedBytecode blobs in JSON output | -| outputFile | _string_ | - | Relative path to a file to output text table to (instead of stdout) | -| outputJSONFile | _string_ | - | Relative path to a file to output gas data in JSON format to. (See [Advanced Usage][9]) | -| outputJSON | _bool_ | `false` | Write options, methods, deployment data in JSON format to file. (See [Advanced Usage][9]) | -| rst | _bool_ | `false` | Output with a reStructured text code-block directive. (Useful if you want to include report in ReadTheDocs or Sphinx docs) | -| rstTitle | _string_ | - | Title for reStructured text header | -| :mag: **LOW-LEVEL CONFIG** | | | | -| gasPrice | _number_ | - | Gwei price per gas unit (Ex: `25`). By default, this is fetched from live network when `coinmarketcap` option is defined | -| baseFee | _number_ | - | Gwei base fee per gas unit used to calculate L1 calldata costs for L2 transactions (Ex: `25`). By default, this is fetched from live network when `L2` & `coinmarketcap` options are defined | -| blobBaseFee | _number_ | - | Gwei blob base fee per gas unit used to calculate post-EIP-7516 L1 calldata costs for L2 transactions (Ex: `25`). By default, this is fetched from live network when `L2` & `coinmarketcap` options are defined | -| blobBaseFeeApi | _string_ | - | URL to fetch live *execution* network blob base fee from. (By default, this is auto-configured based on the `L1` or `L2` setting) | -| gasPriceApi | _string_ | - | URL to fetch live *execution* network gas price from. (By default, this is auto-configured based on the `L1` or `L2` setting) | -| getBlockApi | _string_ | - | URL to fetch L1 block header from when simulating L2. (By default, this is auto-configured based on the `L2` setting) | -| opStackBaseFeeScalar | _number_ | - | Scalar applied to L1 base fee when calculating L1 data cost (see [Advanced Usage][12]) | -| opStackBlobBaseFeeScalar | _number_ | - | Scalar applied to L1 blob base fee when calculating L1 data cost (see [Advanced Usage][12]) | -| token | _string_ | - | Network token gas fees are denominated in (ex:"ETH"). (By default, this is auto-configured based on the `L1` or `L2` setting) | -| tokenPrice | _string_ | - | Network token price per nation state currency unit. (To denominate costs *in network token* set this to `"1"`) | +| Options | Type | Default | Description | +| :------------------------------ | :--------: | :--------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| currency | _string_ | `USD` | National currency to represent gas costs in. Exchange rates are loaded at runtime from the `coinmarketcap` api. Available currency codes can be found [here][5] | +| coinmarketcap | _string_ | - | [API key][3] to use when fetching live token price data | +| enabled | _bool_ | `true` | Produce gas reports with `hardhat test` | +| excludeAutoGeneratedGetters | _bool_ | `false` | Exclude solc generated public state vars when reporting gas for pure and view methods. (Incurs a performance penalty on test startup when `true`) ⚠️ SLOW ⚠️ | +| excludeContracts | _string[]_ | `[]` | Names of contracts to exclude from report. Ex: `["MyContract"]` | +| includeIntrinsicGas | _bool_ | `true` | Include standard 21_000 + calldata bytes overhead in method gas usage data. (Setting to `false` can be useful for modelling contract infra that will never be called by an EOA) | +| L1 | _string_ | `ethereum` | Auto-configure reporter to emulate an L1 network. (See [supported networks][6]) | +| L2 | _string_ | - | Auto-configure reporter to emulate an L2 network (See [supported networks][6]) | +| L1Etherscan | _string_ | - | [API key][4] to use when fetching live gasPrice, baseFee, and blobBaseFee data from an L1 network. (Optional, see [Supported Networks][6]) | +| L2Etherscan | _string_ | - | [API key][4] to use when fetching live gasPrice data from an L2 network (Optional, see [Supported Networks][6]) | +| offline | _bool_ | `false` | Turn off remote calls to fetch data | +| optimismHardfork | _string_ | `ecotone` | Optimism hardfork to emulate L1 & L2 gas costs for. | +| proxyResolver | _Class_ | - | User-defined class which helps reporter identify contract targets of proxied calls. (See [Advanced Usage][7]) | +| remoteContracts | _Array_ | - | List of forked-network deployed contracts to track execution costs for.(See [Advanced Usage][8]) | +| reportPureAndViewMethods | _bool_ | `false` | Track gas usage for methods invoked via `eth_call`. (Incurs a performance penalty that can be significant for large test suites) | +| :high_brightness: **DISPLAY** | | | | +| currencyDisplayPrecision | _number_ | `2` | Decimal precision to show nation state currency costs in | +| darkMode | _bool_ | `false` | Use colors better for dark backgrounds when printing to stdout | +| forceTerminalOutput | _bool_ | `false` | Write to terminal even when saving output to file | +| forceTerminalOutputFormat | _string_ | - | Table format to output forced terminal output in ("legacy" / "terminal" / "markdown") | +| noColors | _bool_ | `false` | Omit terminal color in output | +| reportFormat | _string_ | `terminal` | Report formats ("legacy" / "terminal" / "markdown") | +| showMethodSig | _bool_ | `false` | Display the complete function signature of methods. (Useful if you have overloaded methods) | +| showUncalledMethods | _bool_ | `false` | List all methods and deployments, even if no transactions were recorded for them | +| suppressTerminalOutput | _bool_ | `false` | Skip writing the table to stdout. (Useful if you only want to write JSON to file) | +| :floppy_disk: **OUTPUT** | | | | +| includeBytecodeInJSON | _bool_ | false | Include bytecode and deployedBytecode blobs in JSON output | +| outputFile | _string_ | - | Relative path to a file to output text table to (instead of stdout) | +| outputJSONFile | _string_ | - | Relative path to a file to output gas data in JSON format to. (See [Advanced Usage][9]) | +| outputJSON | _bool_ | `false` | Write options, methods, deployment data in JSON format to file. (See [Advanced Usage][9]) | +| rst | _bool_ | `false` | Output with a reStructured text code-block directive. (Useful if you want to include report in ReadTheDocs or Sphinx docs) | +| rstTitle | _string_ | - | Title for reStructured text header | +| :mag: **LOW-LEVEL CONFIG** | | | | +| gasPrice | _number_ | - | Gwei price per gas unit (Ex: `25`). By default, this is fetched from live network when `coinmarketcap` option is defined | +| baseFee | _number_ | - | Gwei base fee per gas unit used to calculate L1 calldata costs for L2 transactions (Ex: `25`). By default, this is fetched from live network when `L2` & `coinmarketcap` options are defined | +| baseFeePerByte | _number_ | - | Gwei fee per byte used to calculate L1 calldata costs for Arbitrum transactions (Ex: `25`). See [arbitrum gas estimation docs for details][112]. By default, this is fetched from live network when `L2` is set to 'arbitrum' & `coinmarketcap` options are defined | +| blobBaseFee | _number_ | - | Gwei blob base fee per gas unit used to calculate post-EIP-7516 L1 calldata costs for L2 transactions (Ex: `25`). By default, this is fetched from live network when `L2` & `coinmarketcap` options are defined | +| blobBaseFeeApi | _string_ | - | URL to fetch live *execution* network blob base fee from. (By default, this is auto-configured based on the `L1` or `L2` setting) | +| gasPriceApi | _string_ | - | URL to fetch live *execution* network gas price from. (By default, this is auto-configured based on the `L1` or `L2` setting) | +| getBlockApi | _string_ | - | URL to fetch L1 block header from when simulating L2. (By default, this is auto-configured based on the `L2` setting) | +| opStackBaseFeeScalar | _number_ | - | Scalar applied to L1 base fee when calculating L1 data cost (see [Advanced Usage][12]) | +| opStackBlobBaseFeeScalar | _number_ | - | Scalar applied to L1 blob base fee when calculating L1 data cost (see [Advanced Usage][12]) | +| token | _string_ | - | Network token gas fees are denominated in (ex:"ETH"). (By default, this is auto-configured based on the `L1` or `L2` setting) | +| tokenPrice | _string_ | - | Network token price per nation state currency unit. (To denominate costs *in network token* set this to `"1"`) | ## Utility Tasks @@ -138,6 +141,7 @@ API keys for the networks this plugin auto-configures via the `L1` and `L2` opti **L2** ++ [arbitrum][113] (live `baseFeePerByte` prices require an API key) + [base][110] (live `blobBaseFee` prices require an API key) + [optimism][109] (live `blobBaseFee` prices require an API key) @@ -180,3 +184,7 @@ You can support hardhat-gas-reporter via [DRIPS][11], a public goods protocol th [108]: https://snowtrace.io/ [109]: https://docs.optimism.etherscan.io/getting-started/viewing-api-usage-statistics [110]: https://docs.basescan.org/getting-started/viewing-api-usage-statistics +[111]: https://arbiscan.io/ +[112]: https://docs.arbitrum.io/build-decentralized-apps/how-to-estimate-gas#an-example-of-how-to-apply-this-formula-in-your-code +[113]: https://docs.arbiscan.io/getting-started/viewing-api-usage-statistics + diff --git a/docs/advanced.md b/docs/advanced.md index 7b72d52..543df98 100644 --- a/docs/advanced.md +++ b/docs/advanced.md @@ -227,7 +227,6 @@ const config: HardhatUserConfig = { } ``` - ## JSON Output The JSON output includes the full gas reporter option state (API keys are redacted) and all collected gas data for methods and deployments. The object has the following interface: @@ -340,3 +339,4 @@ Example of a report produced with `reportFormat: "markdown"`: [9]: https://docs.optimism.io/stack/transactions/fees#ecotone [10]: https://basescan.org/address/0x420000000000000000000000000000000000000F#readProxyContract [11]: https://optimistic.etherscan.io/address/0x4200000000000000000000000000000000000015#readProxyContract +[12]: https://docs.arbitrum.io/build-decentralized-apps/how-to-estimate-gas#breaking-down-the-formula diff --git a/package.json b/package.json index 4fc1b34..95041da 100644 --- a/package.json +++ b/package.json @@ -80,6 +80,7 @@ "@ethersproject/units": "^5.7.0", "@solidity-parser/parser": "^0.18.0", "axios": "^1.6.7", + "brotli-wasm": "^2.0.1", "chalk": "4.1.2", "cli-table3": "^0.6.3", "ethereum-cryptography": "^2.1.3", diff --git a/scripts/gen-options-md.ts b/scripts/gen-options-md.ts index 06742fd..cfe4b9d 100644 --- a/scripts/gen-options-md.ts +++ b/scripts/gen-options-md.ts @@ -265,6 +265,15 @@ advancedSubtitle, "Gwei base fee per gas unit used to calculate L1 calldata costs for L2 transactions (Ex: `25`). " + "By default, this is fetched from live network when `L2` & `coinmarketcap` options are defined" ], +// baseFeePerByte +[ + "baseFeePerByte", + "_number_", + "-", + "Gwei fee per byte used to calculate L1 calldata costs for Arbitrum transactions (Ex: `25`). " + + "See [arbitrum gas estimation docs for details][112]. " + + "By default, this is fetched from live network when `L2` is set to 'arbitrum' & `coinmarketcap` options are defined" +], // blobBaseFee [ "blobBaseFee", diff --git a/src/constants.ts b/src/constants.ts index d4da13f..f7aac09 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -43,6 +43,32 @@ export const BASE_ECOTONE_BLOB_BASE_FEE_SCALAR = 659851; export const UNICODE_CIRCLE = "◯"; export const UNICODE_TRIANGLE = "△" +export const RANDOM_R_COMPONENT = "0x12354631f8e7f6d04a0f71b4e2a7b50b165ad2e50a83d531cbd88587b4bd62d5"; +export const RANDOM_S_COMPONENT = "0x49cd68893c5952ea1e00288b05699be582081c5fba8c2c6f6e90dd416cdc2e07"; + +/** + * Generated with: + * + * erc20Calldata = ethersV5.Interface.encodeFunctionData("decimals()", []) + * + * ethersV5.Interface.encodeFunctionData( + * "gasEstimateL1Component(address to, bool contractCreation, bytes calldata data)", + * [ + * "0xaf88d065e77c8cC2239327C5EDb3A432268e5831", // USDC + * false, + * erc20Calldata + * ] + * ); + * + */ +export const ARBITRUM_L1_ESTIMATE_CALLDATA = "0x77d488a2000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e5831000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000004313ce56700000000000000000000000000000000000000000000000000000000"; + +// Source: @arbitrum/sdk/dist/lib/dataEntities/constants +export const ARBITRUM_NODE_INTERFACE_ADDRESS = "0x00000000000000000000000000000000000000C8"; + +export const DEFAULT_BASE_FEE_PER_BYTE_API_ARGS = + `action=eth_call&data=${ARBITRUM_L1_ESTIMATE_CALLDATA}&tag=latest&to=${ARBITRUM_NODE_INTERFACE_ADDRESS}`; + export const OPTIMISM_GAS_ORACLE_ABI_PARTIAL = [ { constant: true, diff --git a/src/lib/options.ts b/src/lib/options.ts index de6f8ac..f8df2ea 100644 --- a/src/lib/options.ts +++ b/src/lib/options.ts @@ -1,7 +1,5 @@ import { HardhatUserConfig } from "hardhat/types"; import { - // TODO: enable when arbitrum support added - // DEFAULT_ARBITRUM_HARDFORK, DEFAULT_CURRENCY, DEFAULT_CURRENCY_DISPLAY_PRECISION, DEFAULT_JSON_OUTPUT_FILE, @@ -13,7 +11,7 @@ import { TABLE_NAME_TERMINAL } from "../constants"; -import { /* ArbitrumHardfork,*/ GasReporterOptions, OptimismHardfork } from "../types"; +import { GasReporterOptions, OptimismHardfork } from "../types"; /** * Validates Optimism hardfork option @@ -26,23 +24,10 @@ function isOptimismHardfork(hardfork: string | undefined) { return ["bedrock, ecotone"].includes(hardfork); } -// TODO: Enabled when arbitrum support added -/** - * Validates Arbitrum hardfork option - * @param hardfork - * @returns - */ -// function isArbitrumHardfork(hardfork: string | undefined) { -// if (hardfork === undefined) return false; - -// return ["arbOS11"].includes(hardfork); -// } - /** * Sets default reporter options */ export function getDefaultOptions(userConfig: Readonly): GasReporterOptions { - // let arbitrumHardfork: ArbitrumHardfork; let optimismHardfork: OptimismHardfork; let opStackBaseFeeScalar: number = 0; let opStackBlobBaseFeeScalar: number = 0; @@ -73,15 +58,9 @@ export function getDefaultOptions(userConfig: Readonly): GasR opStackBlobBaseFeeScalar = BASE_ECOTONE_BLOB_BASE_FEE_SCALAR } } - - // TODO: enable when arbitrum support added - // if (userOptions.L2 === "arbitrum" && !isArbitrumHardfork(userOptions.arbitrumHardfork)) { - // arbitrumHardfork = DEFAULT_ARBITRUM_HARDFORK; - // } } return { - // arbitrumHardfork, currency: DEFAULT_CURRENCY, currencyDisplayPrecision: DEFAULT_CURRENCY_DISPLAY_PRECISION, darkMode: false, diff --git a/src/lib/render/markdown.ts b/src/lib/render/markdown.ts index 998bc69..4bc420a 100644 --- a/src/lib/render/markdown.ts +++ b/src/lib/render/markdown.ts @@ -37,10 +37,14 @@ export function generateMarkdownTable( const addedContracts: string[] = []; - if (options.L2 !== undefined) { + if (options.L2 === "optimism" || options.L2 === "base") { gasAverageTitle = ["L2 Avg (Exec)", "L1 Avg (Data)"]; } + if (options.L2 === "arbitrum") { + gasAverageTitle = ["L2 Avg (Exec)", "L1 Avg (Bytes)"]; + } + // --------------------------------------------------------------------------------------------- // Assemble section: Build options // --------------------------------------------------------------------------------------------- @@ -61,11 +65,17 @@ export function generateMarkdownTable( } = getCommonTableVals(options)); gasPrices = (options.L2) - ? [ - [`L1 Base Fee`, `${options.baseFee!} gwei`], - [`L1 Blob Base Fee`, `${options.blobBaseFee!} gwei`], - [`L2 Gas Price`, `${l2gwei} gwei` ] - ] + ? (options.L2 === "arbitrum") + ? [ + [`L1 Base Fee Per Byte`, `${options.baseFeePerByte!} gwei`], + [`L2 Gas Price`, `${l2gwei} gwei` ] + ] + : [ + [`L1 Base Fee`, `${options.baseFee!} gwei`], + [`L1 Blob Base Fee`, `${options.blobBaseFee!} gwei`], + [`L2 Gas Price`, `${l2gwei} gwei` ] + ] + : [[`L1 Gas Price`, `${l1gwei} gwei`]]; tokenPrice = `${rate} ${currency}/${token}` diff --git a/src/lib/render/terminal.ts b/src/lib/render/terminal.ts index 6ffbfe0..57522dd 100644 --- a/src/lib/render/terminal.ts +++ b/src/lib/render/terminal.ts @@ -58,7 +58,14 @@ export function generateTerminalTextTable( deploymentsTitleSpacerWidth = 3; contractTitleSpacerWidth = 6; executionGasAverageTitle = "L2 Avg (Exec)"; - calldataGasAverageTitle = "L1 Avg (Data)" + + if (options.L2 === "optimism" || options.L2 === "base") { + calldataGasAverageTitle = "L1 Avg (Data)"; + } + + if (options.L2 === "arbitrum") { + calldataGasAverageTitle = "L1 Avg (Bytes)"; + } } // eslint-disable-next-line diff --git a/src/types.ts b/src/types.ts index de96074..902f85d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,7 +8,6 @@ declare module "hardhat/types/config" { } } -export type ArbitrumHardfork = "arbOS11" | "arbOS20" | undefined; export type OptimismHardfork = "bedrock" | "ecotone" | undefined; export interface GasReporterOptions { @@ -20,6 +19,13 @@ export interface GasReporterOptions { */ baseFee?: number; + /** @property Arbitrum-specific gwei price per byte of L1 calldata. */ + /** + * This is the `l1BaseFeeEstimate` value returned by NodeInterface.gasEstimateL1Component(...) multiplied by 16. + * See: https://docs.arbitrum.io/build-decentralized-apps/how-to-estimate-gas#an-example-of-how-to-apply-this-formula-in-your-code + */ + baseFeePerByte?: number; + /** @property Gwei blob base fee per gas unit */ /* * Used to calculate L1 calldata costs post EIP-7516 and typically obtained via api call @@ -75,9 +81,8 @@ export interface GasReporterOptions { /** @property L1 Network to calculate execution or data costs for */ L1?: "ethereum" | "polygon" | "binance" | "fantom" | "moonbeam" | "moonriver" | "gnosis" | "avalanche"; - // TODO: Enable arbitrum when support added /** @property L2 Network to calculate execution costs for */ - L2?: "optimism" | "base" // | "arbitrum" + L2?: "optimism" | "base" | "arbitrum" /** @property Etherscan API key for L1 networks */ L1Etherscan?: string; @@ -150,9 +155,6 @@ export interface GasReporterOptions { /** @ignore */ blockGasLimit?: number; - - /** @ignore Arbitrum client version to emulate gas costs for. Only applied when L2 is "arbitrum" */ - arbitrumHardfork?: ArbitrumHardfork, } export interface GasReporterExecutionContext { @@ -267,6 +269,9 @@ export interface JsonRpcTx { hash: string nonce: string value: string + v? : string, + r? : string, + s? : string // maxFeePerBlobGas?: string // QUANTITY - max data fee for blob transactions // blobVersionedHashes?: string[] // DATA - array of 32 byte versioned hashes for blob transactions } diff --git a/src/utils/chains.ts b/src/utils/chains.ts index 17cd4f5..0bdd0f4 100644 --- a/src/utils/chains.ts +++ b/src/utils/chains.ts @@ -2,7 +2,8 @@ import { DEFAULT_API_KEY_ARGS, DEFAULT_GAS_PRICE_API_ARGS, DEFAULT_GET_BLOCK_API_ARGS, - DEFAULT_BLOB_BASE_FEE_API_ARGS + DEFAULT_BLOB_BASE_FEE_API_ARGS, + DEFAULT_BASE_FEE_PER_BYTE_API_ARGS, } from "../constants" import { GasReporterOptions } from "../types" @@ -66,7 +67,7 @@ export function getBlockUrlForChain(options: GasReporterOptions): string { } /** - * Gets Etherscan eth_call api url to read OP Stack GasPriceOracle for blobBaseFee. + * Gets Etherscan eth_call api url to read OP Stack GasPriceOracle for blobBaseFee. * Attaches L2 apikey if configured. (This fee fetched from L2 contract b/c its the only available place at * time of PR - eth_blobBaseFee hasn't been implemented in geth yet) * @param {GasReporterOptions} options @@ -83,6 +84,23 @@ export function getBlobBaseFeeUrlForChain(options: GasReporterOptions): string { return `${L2[options.L2!].baseUrl}${DEFAULT_BLOB_BASE_FEE_API_ARGS}${L2[options.L2!].gasPriceOracle}${apiKey}`; } +/** + * Gets Etherscan eth_call api url to read OP Stack GasPriceOracle for blobBaseFee. + * Attaches L2 apikey if configured. (This fee fetched from L2 contract b/c its the only available place at + * time of PR - eth_blobBaseFee hasn't been implemented in geth yet) + * @param {GasReporterOptions} options + * @returns + */ +export function getBaseFeePerByteUrlForChain(options: GasReporterOptions): string { + if (options.L2 !== "arbitrum") return ""; + + const apiKey = (options.L2Etherscan) + ? `${DEFAULT_API_KEY_ARGS}${options.L2Etherscan}` + : ""; + + return `${L2[options.L2!].baseUrl}${DEFAULT_BASE_FEE_PER_BYTE_API_ARGS}${apiKey}`; +} + /** * L1 & L2 chain configurations for fetching gas price and block fee data from Etherscan as well * as currency prices from Coinmarketcap @@ -135,6 +153,7 @@ export const L2 = { }, arbitrum: { baseUrl: "https://api.arbiscan.io/api?module=proxy&", + gasPriceOracle: "", token: "ETH" } } diff --git a/src/utils/gas.ts b/src/utils/gas.ts index 83d4fa8..c5f30af 100644 --- a/src/utils/gas.ts +++ b/src/utils/gas.ts @@ -1,8 +1,11 @@ import { serializeTransaction, Hex } from 'viem'; +import { compress } from 'brotli-wasm'; import { EVM_BASE_TX_COST, OPTIMISM_BEDROCK_DYNAMIC_OVERHEAD, - OPTIMISM_BEDROCK_FIXED_OVERHEAD + OPTIMISM_BEDROCK_FIXED_OVERHEAD, + RANDOM_R_COMPONENT, + RANDOM_S_COMPONENT } from "../constants"; import { GasReporterOptions, JsonRpcTx } from "../types"; @@ -32,10 +35,7 @@ Source: https://docs.optimism.io/stack/transactions/fees#formula * @returns */ export function getOptimismBedrockL1Gas(tx: JsonRpcTx): number { - // TODO: Am getting a small underestimate here compared to Etherscan, plus - // its weird to split up the overhead calc into different functions? (Just doing this - // so the numbers look right compared to scan but seems wrong) - const txDataGas = getSerializedTxDataGas(tx); + const txDataGas = getOPStackDataGas(tx); return txDataGas + OPTIMISM_BEDROCK_FIXED_OVERHEAD; } @@ -50,47 +50,31 @@ export function getOptimismBedrockL1Cost(txDataGas: number, baseFee: number): nu } /* -* ========================== -* OPTIMISM ECOTONE -* ========================== -* -* The Ecotone L1 Data Fee calculation begins with counting the number of zero bytes and non-zero bytes -* in the transaction data. Each zero byte costs 4 gas and each non-zero byte costs 16 gas. This value, -* when divided by 16, can be thought of as a rough estimate of the size of the transaction data after -* compression. -* -* ``` -* tx_compressed_size = [(count_zero_bytes(tx_data)*4 + count_non_zero_bytes(tx_data)*16)] / 16 -* `` -* Next, the two scalars are applied to the base fee and blob base fee parameters to compute a weighted -* gas price multiplier. -* -* ``` -* weighted_gas_price = 16*base_fee_scalar*base_fee + blob_base_fee_scalar*blob_base_fee -* ``` - -* The l1 data fee is then: -* -* ``` -* l1_data_fee = tx_compressed_size * weighted_gas_price -* ``` -*/ - -/** - * Gets transaction calldata gas usage (an input into the cost function below) - * @param tx JSONRPC formatted getTransaction response - * @returns - */ -export function getOptimismEcotoneL1Gas(tx: JsonRpcTx) { - return getSerializedTxDataGas(tx); -} - -/** - * Gets the native token denominated cost of registering tx calldata to L1 - * @param txCompressed - * @param baseFee - * @param blobBaseFee - * @returns + * ========================== + * OPTIMISM ECOTONE + * ========================== + * + * The Ecotone L1 Data Fee calculation begins with counting the number of zero bytes and non-zero bytes + * in the transaction data. Each zero byte costs 4 gas and each non-zero byte costs 16 gas. This value, + * when divided by 16, can be thought of as a rough estimate of the size of the transaction data after + * compression. + * + * ``` + * tx_compressed_size = [(count_zero_bytes(tx_data)*4 + count_non_zero_bytes(tx_data)*16)] / 16 + * `` + * Next, the two scalars are applied to the base fee and blob base fee parameters to compute a weighted + * gas price multiplier. + * + * ``` + * weighted_gas_price = 16*base_fee_scalar*base_fee + blob_base_fee_scalar*blob_base_fee + * ``` + * + * The l1 data fee is then: + * + * ``` + * l1_data_fee = tx_compressed_size * weighted_gas_price + * ``` + * * * Source: https://github.com/ethereum-optimism/optimism/blob/e57787ea7d0b9782cea5f32bcb92d0fdeb7bd870/ + * packages/contracts-bedrock/src/L2/GasPriceOracle.sol#L88-L92 @@ -105,6 +89,17 @@ export function getOptimismEcotoneL1Gas(tx: JsonRpcTx) { * return fee / (16 * 10 ** DECIMALS); * } */ + +/** + * Gets the native token denominated cost of registering tx calldata to L1 + * @param txSerialized + * @param txCompressed + * @param baseFee + * @param blobBaseFee + * @param opStackBaseFeeScalar + * @param opStackBlobBaseFeeScalar + * @returns + */ export function getOPStackEcotoneL1Cost( txSerialized: number, baseFee: number, @@ -117,37 +112,6 @@ export function getOPStackEcotoneL1Cost( return (txSerialized * (weightedBaseFee + weightedBlobBaseFee)) / 16000000; } -// ========================== -// ARBITRUM OS11 -// ========================== - -// STUB -// eslint-disable-next-line -export function getArbitrum_OS11_L1Gas(tx: JsonRpcTx) { - return 0; -} - -// eslint-disable-next-line -export function getArbitrum_OS20_L1Gas(tx: JsonRpcTx) { - return 0; -} - -// ========================== -// ARBITRUM OS20 -// ========================== - -// STUB -// eslint-disable-next-line -export function getArbitrum_OS11_L1Cost(gas: number) { - return 0; -} - -// STUB -// eslint-disable-next-line -export function getArbitrum_OS20_L1Cost(gas: number) { - return 0; -} - /** * Computes the amount of L1 gas used for a transaction. The overhead represents the per batch * gas overhead of posting both transaction and state roots to L1 given larger batch sizes. @@ -169,7 +133,38 @@ export function getArbitrum_OS20_L1Cost(gas: number) { * * SOURCE: optimism/packages/contracts/contracts/L2/predeploys/OVM_GasPriceOracle.sol */ -export function getSerializedTxDataGas(tx: JsonRpcTx): number { +export function getOPStackDataGas(tx: JsonRpcTx): number { + const serializedTx = getSerializedTx (tx); + const total = getCalldataBytesGas(serializedTx); + return total + (68 * 16); +} + +// ========================== +// ARBITRUM OS20 +// ========================== +export function getArbitrumL1Bytes(tx: JsonRpcTx) { + const serializedTx = getSerializedTx(tx, true); + const compressedTx = compress(Buffer.from(serializedTx), {quality: 2}); + const compressedLength = Buffer.from(compressedTx).toString('utf8').length; + return compressedLength + 140; +} + +export function getArbitrumL1Cost(bytes: number, gasPrice: number, baseFeePerByte: number) { + // Debit 10% estimate buffer + const adjustedBaseFeePerByte = Math.round(baseFeePerByte - (baseFeePerByte/10)) + const l1Gas = adjustedBaseFeePerByte * 1e9 * bytes; + const l1Cost = l1Gas / (gasPrice * 1e9) + return l1Cost; +} + +/** + * Serializes transaction + * @param tx + * @returns + */ +export function getSerializedTx(tx: JsonRpcTx, emulateSignatureComponents = false): string { + let signature; + const type = normalizeTxType(tx.type); const maxFeePerGas = (tx.maxFeePerGas) @@ -180,7 +175,16 @@ export function getSerializedTxDataGas(tx: JsonRpcTx): number { ? hexToBigInt(tx.maxPriorityFeePerGas) : BigInt(0); - const serializedTx = serializeTransaction ({ + // For arbitrum - part of their estimation flow at nitro + if (emulateSignatureComponents) { + signature = { + v: BigInt(0), + r: RANDOM_R_COMPONENT as `0x${string}`, + s: RANDOM_S_COMPONENT as `0x${string}` + } + } + + return serializeTransaction ({ to: tx.to as Hex, maxFeePerGas, maxPriorityFeePerGas, @@ -190,10 +194,7 @@ export function getSerializedTxDataGas(tx: JsonRpcTx): number { type, accessList: tx.accessList, nonce: parseInt(tx.nonce) - }) - - const total = getCalldataBytesGas(serializedTx); - return total + (68 * 16); + }, signature) } /** @@ -248,17 +249,13 @@ export function getCalldataGasForNetwork( if (options.L2 === "optimism" || options.L2 === "base") { switch (options.optimismHardfork){ case "bedrock": return getOptimismBedrockL1Gas(tx); - case "ecotone": return getOptimismEcotoneL1Gas(tx); + case "ecotone": return getOPStackDataGas(tx); default: return 0; /** This shouldn't happen */ } } if (options.L2 === "arbitrum") { - switch (options.arbitrumHardfork){ - case "arbOS11": return getArbitrum_OS11_L1Gas(tx); - case "arbOS20": return getArbitrum_OS20_L1Gas(tx); - default: return 0; /** This shouldn't happen */ - } + return getArbitrumL1Bytes(tx); } // If not configured for L2 @@ -281,8 +278,8 @@ export function getCalldataCostForNetwork( switch (options.optimismHardfork){ case "bedrock": return getOptimismBedrockL1Cost(gas, options.baseFee!); case "ecotone": return getOPStackEcotoneL1Cost( - gas, - options.baseFee!, + gas, + options.baseFee!, options.blobBaseFee!, options.opStackBaseFeeScalar!, options.opStackBlobBaseFeeScalar! @@ -292,11 +289,7 @@ export function getCalldataCostForNetwork( } if (options.L2 === "arbitrum") { - switch (options.arbitrumHardfork){ - case "arbOS11": return getArbitrum_OS11_L1Cost(gas); - case "arbOS20": return getArbitrum_OS20_L1Cost(gas); - default: return 0; /** This shouldn't happen */ - } + return getArbitrumL1Cost(gas, options.gasPrice!, options.baseFeePerByte!); } // If not configured for L2 @@ -319,9 +312,13 @@ export function gasToCost( if (options.L2) { const cost = getCalldataCostForNetwork(options, calldataGas); - calldataCost = (cost / 1e9) * parseFloat(options.tokenPrice!); + if (options.L2 === "optimism" || options.L2 === "base") { + calldataCost = (cost / 1e9) * parseFloat(options.tokenPrice!); + } + if (options.L2 === "arbitrum") { + executionGas += cost; + } } - const executionCost = (options.gasPrice! / 1e9) * executionGas * parseFloat(options.tokenPrice!); return (executionCost + calldataCost).toFixed(options.currencyDisplayPrecision); } @@ -358,6 +355,15 @@ export function hexWeiToIntGwei(val: string): number { return hexToDecimal(val) / Math.pow(10, 9); } +/** + * Converts wei `l1 fee estimate` to gwei estimated price per byte + * @param val + */ +export function getArbitrumBaseFeePerByte(val: number): number { + const gwei = (BigInt(16) * BigInt(val)) / BigInt(Math.pow(10, 9)); + return parseInt(gwei.toString()); +} + export function normalizeTxType(_type: string): ("legacy" | "eip1559" | "eip2930" | "eip4844") { switch(hexToDecimal(_type)) { case 0: return 'legacy'; diff --git a/src/utils/prices.ts b/src/utils/prices.ts index 2807674..3f6fadb 100644 --- a/src/utils/prices.ts +++ b/src/utils/prices.ts @@ -1,16 +1,19 @@ import axios from "axios"; +import { defaultAbiCoder } from "@ethersproject/abi"; import { DEFAULT_COINMARKET_BASE_URL, DEFAULT_BLOB_BASE_FEE } from "../constants"; import { GasReporterOptions } from "../types"; + import { warnCMCRemoteCallFailed, warnGasPriceRemoteCallFailed, warnBaseFeeRemoteCallFailed, warnBlobBaseFeeRemoteCallFailed, + warnBaseFeePerByteRemoteCallFailed, warnUnsupportedChainConfig, } from "./ui"; -import { hexWeiToIntGwei } from "./gas"; -import { getTokenForChain, getGasPriceUrlForChain, getBlockUrlForChain, getBlobBaseFeeUrlForChain } from "./chains"; +import { hexWeiToIntGwei, getArbitrumBaseFeePerByte } from "./gas"; +import { getTokenForChain, getGasPriceUrlForChain, getBlockUrlForChain, getBlobBaseFeeUrlForChain, getBaseFeePerByteUrlForChain } from "./chains"; /** * Fetches gas, base, & blob fee rates from etherscan as well as current market value of @@ -39,6 +42,7 @@ export async function setGasAndPriceRates(options: GasReporterOptions): Promise< let blockUrl; let gasPriceUrl; let blobBaseFeeUrl; + let baseFeePerByteUrl; const warnings: string[] = []; try { @@ -46,6 +50,7 @@ export async function setGasAndPriceRates(options: GasReporterOptions): Promise< gasPriceUrl = getGasPriceUrlForChain(options); blockUrl = getBlockUrlForChain(options); blobBaseFeeUrl = getBlobBaseFeeUrlForChain(options); + baseFeePerByteUrl = getBaseFeePerByteUrlForChain(options); } catch (err: any){ if (options.L2) warnings.push(warnUnsupportedChainConfig(options.L2!)); @@ -91,8 +96,22 @@ export async function setGasAndPriceRates(options: GasReporterOptions): Promise< } } + // baseFeePerByte data: etherscan eth_call to NodeInterface + if ((options.L2 === "arbitrum") && !options.baseFeePerByte) { + try { + const response = await axiosInstance.get(baseFeePerByteUrl); + checkForEtherscanError(response.data.result); + const decoded = defaultAbiCoder.decode(['uint256', 'uint256', 'uint256'], response.data.result); + const baseFeePerByte = getArbitrumBaseFeePerByte(decoded[2]); + options.baseFeePerByte = (baseFeePerByte >= 1 ) ? Math.round(baseFeePerByte) : baseFeePerByte; + } catch (error) { + options.baseFeePerByte = 20; + warnings.push(warnBaseFeePerByteRemoteCallFailed(error)); + } + } + // baseFee data (Etherscan) - if (options.L2 && !options.baseFee) { + if ((options.L2 === "optimism" || options.L2 === "base") && !options.baseFee) { try { block = await axiosInstance.get(blockUrl); checkForEtherscanError(block.data.result); diff --git a/src/utils/ui.ts b/src/utils/ui.ts index 4328cea..f5fd025 100644 --- a/src/utils/ui.ts +++ b/src/utils/ui.ts @@ -97,6 +97,14 @@ export function warnBlobBaseFeeRemoteCallFailed(err: any): string { }${remoteCallEndMessage(err)}`; } +export function warnBaseFeePerByteRemoteCallFailed(err: any): string { + return `${ + startWarning }${EOL + }${chalk.bold(`Failed to fetch Arbitrum L1 base fee data, defaulting to 20 gwei.`) }${EOL + }${chalk.bold(`Try setting an API key for the "L2Etherscan" option.`) }${EOL + }${remoteCallEndMessage(err)}`; +} + export function warnUnsupportedChainConfig(chain: string): string { return `${ startWarning }${EOL @@ -201,10 +209,18 @@ export function reportMerge(files: string[], output: string) { export function getCommonTableVals(options: GasReporterOptions) { const usingL1 = options.L2 === undefined; + let l2BaseFeeNote = "(baseFee)"; + let l1GweiForL2 = options.baseFee; + + if (options.L2 === "arbitrum"){ + l2BaseFeeNote = "(baseFeePerByte)" + l1GweiForL2 = options.baseFeePerByte; + } + let token = ""; - let l1gwei: string | number = (usingL1) ? options.gasPrice!: options.baseFee!; + let l1gwei: string | number = (usingL1) ? options.gasPrice!: l1GweiForL2!; let l2gwei: string | number = (usingL1) ? "" : options.gasPrice!; - const l1gweiNote: string = (usingL1) ? "" : "(baseFee)"; + const l1gweiNote: string = (usingL1) ? "" : l2BaseFeeNote; const l2gweiNote: string = (usingL1) ? "" : "(gasPrice)"; const network = (usingL1) ? options.L1!.toUpperCase() : options.L2!.toUpperCase(); diff --git a/test/integration/options.g.ts b/test/integration/options.g.ts new file mode 100644 index 0000000..9406386 --- /dev/null +++ b/test/integration/options.g.ts @@ -0,0 +1,61 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +// TODO: REMOVE LINT DISABLE +/* eslint-disable */ +import { assert } from "chai"; +import { execSync } from "child_process"; +import { readFileSync } from "fs"; +import { TASK_TEST } from "hardhat/builtin-tasks/task-names"; +import path from "path"; +import { Deployment, GasReporterOptions, GasReporterOutput, MethodData } from "../types"; + +import { useEnvironment, findMethod, findDeployment } from "../helpers"; + +/** + * OPTIONS ARE SET UP TO TEST: + * + Default Terminal Format + * + L2: Arbitrum + * + reportPureAndViewMethods + * + excludeAutoGeneratedGetters + */ +describe("Options G (Arbitrum with live pricing & `reportPureAndViewMethods`)", function () { + let output: GasReporterOutput; + let options: GasReporterOptions; + let methods: MethodData; + let deployments: Deployment[]; + + const projectPath = path.resolve( + __dirname, + "../projects/options" + ); + + const outputPath = path.resolve( + __dirname, + "../projects/options/gasReporterOutput.json" + ); + + const network = undefined; + const configPath = "./hardhat.options.g.config.ts"; + + useEnvironment(projectPath, network, configPath); + + before(async function(){ + await this.env.run(TASK_TEST, { testFiles: [] }); + output = JSON.parse(readFileSync(outputPath, 'utf-8')); + options = output.options; + methods = output.data!.methods; + deployments = output.data!.deployments; + }) + + after(() => execSync(`rm ${outputPath}`)); + + it("auto-configures options correctly", function () { + assert.equal(options.L2, "arbitrum"); + assert.isDefined(options.gasPrice); + assert.isDefined(options.baseFeePerByte); + assert.isBelow(options.gasPrice!, 1); + assert.isAbove(options.baseFeePerByte!, 1); + + assert.isDefined(options.tokenPrice); + assert.isAbove(parseFloat(options.tokenPrice!), 1000); // Eth-ish + }); +}); diff --git a/test/projects/options/hardhat.options.g.config.ts b/test/projects/options/hardhat.options.g.config.ts new file mode 100644 index 0000000..568fad0 --- /dev/null +++ b/test/projects/options/hardhat.options.g.config.ts @@ -0,0 +1,32 @@ +/** + * TESTS: + * + Default Terminal Format + * + L2: Base + * + reportPureAndViewMethods + * + excludeAutoGeneratedGetters + */ +// eslint-disable-next-line import/no-extraneous-dependencies +import "@nomicfoundation/hardhat-ethers"; +import { HardhatUserConfig } from "hardhat/types"; + +// We load the plugin here. +import "../../../src/index"; + +const config: HardhatUserConfig = { + solidity: "0.8.24", + mocha: { + reporter: 'dot' + }, + gasReporter: { + coinmarketcap: process.env.CMC_API_KEY, + L2: "arbitrum", + L1Etherscan: process.env.ETHERSCAN_API_KEY, + L2Etherscan: process.env.ARBITRUM_API_KEY, + enabled: true, + reportPureAndViewMethods: true, + excludeAutoGeneratedGetters: true + } +}; + +// eslint-disable-next-line import/no-default-export +export default config; diff --git a/test/unit/cases/arbitrum.ts b/test/unit/cases/arbitrum.ts index c07fcb2..daaea45 100644 --- a/test/unit/cases/arbitrum.ts +++ b/test/unit/cases/arbitrum.ts @@ -1,6 +1,92 @@ export const cases = { - arbOS11Function: {}, - arbOS11Deployment: {}, - arbOS20Function: {}, - arbOS20Deployment: {} + // mainnet:txHash: 0x28d35baa4eae20619de33c24457068c96884333090c3b8a694bd834e30554375 + arbOSFunction_1: { + tx: { + "blockHash": "0xcc3ee4b3c2086a9db1ff83ea68136d4e4eea101386dd59a6e9121de30fa8e2bd", + "blockNumber": "0xbb6bc9b", + "from": "0x97fc46d8e69f2b7dd2900951252213587d83e775", + "gas": "0x1d605a", + "gasPrice": "0xb71b00", + "hash": "0x28d35baa4eae20619de33c24457068c96884333090c3b8a694bd834e30554375", + "input": "0x126928c40000000000000000000000000000000000000000000000000000000000000091000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000001497fc46d8e69f2b7dd2900951252213587d83e775000000000000000000000000000000000000000000000000000000000000000000000000000000000000005600020000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000b1a2bc2ec5000097fc46d8e69f2b7dd2900951252213587d83e77500000000000000000000", + "nonce": "0x7", + "to": "0x4ae8cebccd7027820ba83188dfd73ccad0a92806", + "transactionIndex": "0x2", + "value": "0x1dfa970f48dc", + "type": "0x0", + "chainId": "0xa4b1", + "v": "0x14986", + "r": "0x33494853944d7347ba73ee5971f1aabe63b81339b57c2fdf9adf7c6fb4965689", + "s": "0x5b05a3ffe7ae12a9d79e955514d97453b392481494b4e025b4e8ae5c8dea93b2", + "yParity": "0x0" + }, + // Etherscan + l1GasUsed: 833_334, + l2GasUsed: 228_901, + l2GasPrice: 0.01, + l1BaseFeePerByte: 30, + txFeeETH: 0.00001062235, + }, + // mainnet:txHash: 0xfa76391132c4107e61fbf3456e3ab4a2ea8ed34fc212fa738106efe298cd6f44 + arbOSFunction_2: { + tx: { + "blockHash": "0x3087afdb0a2e45848b5eceb64558ef9bbbb69b215270b3cd6ee8a34428157fe5", + "blockNumber": "0xbb6c040", + "from": "0xce84c1be5a1502c47a2151c2cdaf8467048f1cc1", + "gas": "0x1766e4", + "gasPrice": "0x989680", + "maxFeePerGas": "0xcdfe60", + "maxPriorityFeePerGas": "0x0", + "hash": "0xfa76391132c4107e61fbf3456e3ab4a2ea8ed34fc212fa738106efe298cd6f44", + "input": "0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000660ae3b600000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000011cc74f5a3b060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000011cc74f5a3b0600000000000000000000000000000000000000000000000014e43573b84a4d07f00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b82af49447d8a07e3bd95bd0d56f35241523fbab100271005cbef357cb14f9861c01f90ac7d5c90ce0ef05e000000000000000000000000000000000000000000", + "nonce": "0x53", + "to": "0x5e325eda8064b456f4781070c0738d849c824258", + "transactionIndex": "0x2", + "value": "0x11cc74f5a3b060", + "type": "0x2", + "accessList": [], + "chainId": "0xa4b1", + "v": "0x0", + "r": "0x12354631f8e7f6d04a0f71b4e2a7b50b165ad2e50a83d531cbd88587b4bd62d5", + "s": "0x49cd68893c5952ea1e00288b05699be582081c5fba8c2c6f6e90dd416cdc2e07", + "yParity": "0x0" + }, + // Etherscan + l1GasUsed: 921_874, + l2GasUsed: 129_602, + l2GasPrice: 0.01, + l1BaseFeePerByte: 26, + txFeeETH: 0.00001051476, + }, + // mainnet:txHash: 0xc24263b26ece4eff556e865ffdaf4d2d41500a92ffcd40485575ca4e69b41903 + arbOSDeployment_1: { + tx: { + "blockHash": "0x0a81510a72d59f077b786997e454238b84a127a8b3c0c5917789d93cddf18115", + "blockNumber": "0xbbd0508", + "from": "0x27e0a5b97f0772b2c840704988ae1fdbc19ee902", + "gas": "0x31abe3d", + "gasPrice": "0x989680", + "maxFeePerGas": "0x989680", + "maxPriorityFeePerGas": "0x0", + "hash": "0xc24263b26ece4eff556e865ffdaf4d2d41500a92ffcd40485575ca4e69b41903", + "input": "0x608060405260126013553480156200001657600080fd5b50604051620060443803806200604483398101604081905262000039916200034d565b60016002556200004b600033620001da565b620000777fa49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c2177533620001da565b6127106003541115620000e45760405162461bcd60e51b815260206004820152602a60248201527f706c6174666f726d206665652063616e2774206265206d6f7265207468616e206044820152690c4c081c195c98d95b9d60b21b60648201526084015b60405180910390fd5b6001600160a01b0383166200013c5760405162461bcd60e51b815260206004820152601f60248201527f66656520726563697069656e74206e6f742076616c69642061646472657373006044820152606401620000db565b6001600160a01b0382166200019f5760405162461bcd60e51b815260206004820152602260248201527f70617961626c6520746f6b656e206973206e6f742076616c6964206164647265604482015261737360f01b6064820152608401620000db565b600393909355600480546001600160a01b039384166001600160a01b0319918216179091556005805492909316911617905560065562000396565b620001f182826200021d60201b6200480a1760201c565b6000828152600160209081526040909120620002189183906200488e620002be821b17901c565b505050565b6000828152602081815260408083206001600160a01b038516845290915290205460ff16620002ba576000828152602081815260408083206001600160a01b03851684529091529020805460ff19166001179055620002793390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45b5050565b6000620002d5836001600160a01b038416620002de565b90505b92915050565b60008181526001830160205260408120546200032757508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155620002d8565b506000620002d8565b80516001600160a01b03811681146200034857600080fd5b919050565b600080600080608085870312156200036457600080fd5b84519350620003766020860162000330565b9250620003866040860162000330565b6060959095015193969295505050565b615c9e80620003a66000396000f3fe608060405234801561001057600080fd5b50600436106102275760003560e01c806379c94f671161013057806395f42098116100b8578063bfacf7e21161007c578063bfacf7e21461055e578063c4f0ee3614610571578063ca15c87314610584578063d547741f14610597578063f160d369146105aa57600080fd5b806395f42098146104fd578063a217fddf14610510578063a66bbb5a14610518578063aa0b598814610538578063b3ffb7601461054b57600080fd5b80637fb1fdb7116100ff5780637fb1fdb7146104845780638c672f27146104995780639010d07c146104ac57806391d14854146104bf5780639461986e146104d257600080fd5b806379c94f67146104385780637c1402181461044b5780637c2fd4891461045e5780637e887d671461047157600080fd5b80632f2ff15d116101b357806345c5be761161018257806345c5be761461039c57806346904840146103bc57806357965439146103cf578063627eb0d4146103fa578063764292ea1461040d57600080fd5b80632f2ff15d1461033857806331002cdf1461034b57806336568abe1461037657806342150bb51461038957600080fd5b806320ca53f3116101fa57806320ca53f3146102a9578063248a9ca3146102d357806326232a2e146102f65780632b35b485146102ff5780632c0a91301461031457600080fd5b806301ffc9a71461022c5780630cbab4f7146102545780630ed004fd146102755780631b09dc9b1461027e575b600080fd5b61023f61023a366004614ecd565b6105bd565b60405190151581526020015b60405180910390f35b610267610262366004614ef7565b6105e8565b60405190815260200161024b565b61026760065481565b600554610291906001600160a01b031681565b6040516001600160a01b03909116815260200161024b565b6102bc6102b7366004614f25565b610605565b60405161024b9b9a99989796959493929190614fa1565b6102676102e1366004614ef7565b60009081526020819052604090206001015490565b61026760035481565b61031261030d366004614f25565b610702565b005b610327610322366004614ef7565b6107b1565b60405161024b959493929190615016565b610312610346366004615066565b610903565b610267610359366004615096565b600a60209081526000928352604080842090915290825290205481565b610312610384366004615066565b61092d565b61031261039736600461510d565b6109ab565b6103af6103aa3660046151ad565b610b8c565b60405161024b919061528f565b600454610291906001600160a01b031681565b6102676103dd366004615096565b600b60209081526000928352604080842090915290825290205481565b6103126104083660046152f1565b610e7f565b61026761041b366004615096565b600d60209081526000928352604080842090915290825290205481565b6103af6104463660046151ad565b61141d565b6103af610459366004615096565b611706565b6103af61046c3660046151ad565b611ccd565b61031261047f366004615339565b612555565b61048c612c13565b60405161024b9190615383565b6103126104a7366004614f25565b612e68565b6102916104ba36600461543a565b6132b9565b61023f6104cd366004615066565b6132d8565b6102676104e0366004615096565b600c60209081526000928352604080842090915290825290205481565b61031261050b366004614f25565b613301565b610267600081565b61052b6105263660046151ad565b61373b565b60405161024b919061545c565b610312610546366004614ef7565b613aa3565b6103126105593660046152f1565b613b13565b6102bc61056c366004614f25565b613fd7565b61031261057f366004615512565b614051565b610267610592366004614ef7565b61476d565b6103126105a5366004615066565b614784565b6103126105b83660046151ad565b6147a9565b60006001600160e01b03198216635a05180f60e01b14806105e257506105e2826148a3565b92915050565b6000612710600354836105fb919061555d565b6105e29190615574565b600f602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a018054999a98999798969760ff8716976101009097046001600160a01b039081169796811696951694919061067f90615596565b80601f01602080910402602001604051908101604052809291908181526020018280546106ab90615596565b80156106f85780601f106106cd576101008083540402835291602001916106f8565b820191906000526020600020905b8154815290600101906020018083116106db57829003601f168201915b505050505090508b565b600080516020615c4983398151915261071a816148d8565b6001600160a01b0383166107495760405162461bcd60e51b8152600401610740906155ca565b60405180910390fd5b8160000361078a5760405162461bcd60e51b815260206004820152600e60248201526d0646563696d616c732067746520360941b6044820152606401610740565b50600580546001600160a01b0319166001600160a01b039390931692909217909155600655565b60096020526000908152604090208054600182015460028301805492936001600160a01b03909216926107e390615596565b80601f016020809104026020016040519081016040528092919081815260200182805461080f90615596565b801561085c5780601f106108315761010080835404028352916020019161085c565b820191906000526020600020905b81548152906001019060200180831161083f57829003601f168201915b50505050509080600301805461087190615596565b80601f016020809104026020016040519081016040528092919081815260200182805461089d90615596565b80156108ea5780601f106108bf576101008083540402835291602001916108ea565b820191906000526020600020905b8154815290600101906020018083116108cd57829003601f168201915b505050600490930154919250506001600160a01b031685565b60008281526020819052604090206001015461091e81614936565b6109288383614940565b505050565b6001600160a01b038116331461099d5760405162461bcd60e51b815260206004820152602f60248201527f416363657373436f6e74726f6c3a2063616e206f6e6c792072656e6f756e636560448201526e103937b632b9903337b91039b2b63360891b6064820152608401610740565b6109a78282614962565b5050565b600080516020615c498339815191526109c3816148d8565b6001600160a01b03871660009081526012602052604090205460ff1615610a2c5760405162461bcd60e51b815260206004820152601f60248201527f56657374696e6720436f6e747261637420616c726561647920657869737473006044820152606401610740565b6000610a3760075490565b9050610a47600780546001019055565b6040518060a001604052808a8152602001896001600160a01b0316815260200188888080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250505090825250604080516020601f89018190048102820181019092528781529181019190889088908190840183828082843760009201829052509385525050506001600160a01b038681166020938401528482526009835260409182902084518155928401516001840180546001600160a01b031916919092161790558201516002820190610b299082615657565b5060608201516003820190610b3e9082615657565b5060809190910151600490910180546001600160a01b0319166001600160a01b03928316179055979097166000908152601260205260409020805460ff191660011790555050505050505050565b6001600160a01b03811660009081526010602090815260408083208151808301909252805480835260019091015492820192909252606092909167ffffffffffffffff811115610bde57610bde6155f3565b604051908082528060200260200182016040528015610c1757816020015b610c04614e08565b815260200190600190039081610bfc5790505b508251909150600003610c2b579392505050565b6000805b8360200151811015610e75576001600160a01b038087166000908152600e6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549293919261014084019190610cf690615596565b80601f0160208091040260200160405190810160405280929190818152602001828054610d2290615596565b8015610d6f5780601f10610d4457610100808354040283529160200191610d6f565b820191906000526020600020905b815481529060010190602001808311610d5257829003601f168201915b505050919092525050506080810151909150158015610d9a575060a08101516001600160a01b031615155b15610e6257604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b0316815260200182610100015181526020018261012001518152602001826101400151815250848481518110610e4957610e49615717565b6020908102919091010152610e5f83600161572d565b92505b5080610e6d81615740565b915050610c2f565b5090949350505050565b6002805403610ea05760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b038416610eca5760405162461bcd60e51b815260040161074090615790565b610ed384614984565b1515600114610ef45760405162461bcd60e51b8152600401610740906157c7565b6001600160a01b038216610f1a5760405162461bcd60e51b81526004016107409061580a565b6005546001600160a01b03838116911614610f475760405162461bcd60e51b815260040161074090615841565b80600003610f8b5760405162461bcd60e51b8152602060048201526011602482015270070726963652063616e6e6f74206265203607c1b6044820152606401610740565b60008490506000816001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa158015610fd0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ff49190615886565b6001600160a01b0381166000908152600f6020908152604080832089845290915290206002810154919250339185146110665760405162461bcd60e51b81526020600482015260146024820152731c1c9a58d9481a5cc81b9bdd0818dbdc9c9958dd60621b6044820152606401610740565b805487146110ae5760405162461bcd60e51b8152602060048201526015602482015274189a59081a59081a5cc81b9bdd0818dbdc9c9958dd605a1b6044820152606401610740565b604051630988931960e21b81526001600160a01b03838116600483015260009182918291908816906326224c6490602401608060405180830381865afa1580156110fc573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112091906158a3565b50919450925090506000808261113685876158d9565b61114091906158d9565b111561115e578161115184866158d9565b61115b91906158d9565b90505b80856001015411156111825760405162461bcd60e51b8152600401610740906158ec565b6004850180546001600160a01b038816610100026001600160a81b03199091161760011790554260088601558860006111ba826105e8565b6004805460405163a9059cbb60e01b81526001600160a01b039182169281019290925260248201839052919250908d169063a9059cbb906044016020604051808303816000875af1158015611213573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112379190615934565b506001600160a01b038c1663a9059cbb8961125284866158d9565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af115801561129d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112c19190615934565b50600587015460018801546040516327d1133960e21b81526001600160a01b038d811693639f444ce4936112fd938e9390921691600401615956565b600060405180830381600087803b15801561131757600080fd5b505af115801561132b573d6000803e3d6000fd5b5050506001600160a01b038a1660009081526011602052604090205461135491506001906158d9565b6001600160a01b03808b1660008181526011602090815260408083209590955560058c0154909316808252600d8452848220928252919092529190205461139d906001906158d9565b6001600160a01b038083166000908152600d60209081526040808320938f16808452939091529081902092909255895491519091907f07ee93e920b82120bd0fa8a31236a4a25d1c0cff3ee744f0457c8fa061835c1d906113ff908c906159f7565b60405180910390a35050600160025550505050505050505050505050565b6001600160a01b03811660009081526011602090815260408083208151808301909252805480835260019091015492820192909252606092909167ffffffffffffffff81111561146f5761146f6155f3565b6040519080825280602002602001820160405280156114a857816020015b611495614e08565b81526020019060019003908161148d5790505b5082519091506000036114bc579392505050565b6000805b8360200151811015610e75576001600160a01b038087166000908152600f6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e08301526007810154938201939093526008830154610120820152600983018054929391926101408401919061158790615596565b80601f01602080910402602001604051908101604052809291908181526020018280546115b390615596565b80156116005780601f106115d557610100808354040283529160200191611600565b820191906000526020600020905b8154815290600101906020018083116115e357829003601f168201915b50505091909252505050608081015190915015801561162b575060c08101516001600160a01b031615155b156116f357604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b03168152602001826101000151815260200182610120015181526020018261014001518152508484815181106116da576116da615717565b60209081029190910101526116f083600161572d565b92505b50806116fe81615740565b9150506114c0565b6001600160a01b038083166000818152600c6020908152604080832094861680845294825280832054938352600d825280832094835293905291822054606092611750828461572d565b905060008167ffffffffffffffff81111561176d5761176d6155f3565b6040519080825280602002602001820160405280156117a657816020015b611793614e08565b81526020019060019003908161178b5790505b506001600160a01b0387166000818152601060209081526040808320815180830183528154815260019182015481850152948452601183528184208251808401909352805483520154918101919091528251939450919215801561180957508151155b1561181d57839750505050505050506105e2565b60005b8360200151811015611a6d576001600160a01b03808b166000908152600e6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e0830152600781015493820193909352600883015461012082015260098301805492939192610140840191906118e790615596565b80601f016020809104026020016040519081016040528092919081815260200182805461191390615596565b80156119605780601f1061193557610100808354040283529160200191611960565b820191906000526020600020905b81548152906001019060200180831161194357829003601f168201915b50505050508152505090508b6001600160a01b03168160a001516001600160a01b031614801561199257506080810151155b15611a5a57604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b0316815260200182610100015181526020018261012001518152602001826101400151815250868481518110611a4157611a41615717565b6020908102919091010152611a5783600161572d565b92505b5080611a6581615740565b915050611820565b5060005b8260200151811015611cbe576001600160a01b03808b166000908152600f6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549293919261014084019190611b3890615596565b80601f0160208091040260200160405190810160405280929190818152602001828054611b6490615596565b8015611bb15780601f10611b8657610100808354040283529160200191611bb1565b820191906000526020600020905b815481529060010190602001808311611b9457829003601f168201915b50505050508152505090508b6001600160a01b03168160c001516001600160a01b0316148015611be357506080810151155b15611cab57604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b0316815260200182610100015181526020018261012001518152602001826101400151815250868481518110611c9257611c92615717565b6020908102919091010152611ca883600161572d565b92505b5080611cb681615740565b915050611a71565b50929998505050505050505050565b60606001600160a01b038216611cf55760405162461bcd60e51b8152600401610740906155ca565b6001600160a01b03821660008181526010602090815260408083208151808301835281548152600191820154818501529484526011835281842082518084019093528054835201549181019190915290805b8360200151811015611ec3576001600160a01b038087166000908152600e6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549293919261014084019190611e0e90615596565b80601f0160208091040260200160405190810160405280929190818152602001828054611e3a90615596565b8015611e875780601f10611e5c57610100808354040283529160200191611e87565b820191906000526020600020905b815481529060010190602001808311611e6a57829003601f168201915b5050505050815250509050806080015115156001151503611eb05782611eac81615740565b9350505b5080611ebb81615740565b915050611d47565b5060005b8260200151811015612043576001600160a01b038087166000908152600f6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549293919261014084019190611f8e90615596565b80601f0160208091040260200160405190810160405280929190818152602001828054611fba90615596565b80156120075780601f10611fdc57610100808354040283529160200191612007565b820191906000526020600020905b815481529060010190602001808311611fea57829003601f168201915b5050505050815250509050806080015115156001151503612030578261202c81615740565b9350505b508061203b81615740565b915050611ec7565b508060000361208857604080516000808252602082019092528161207d565b61206a614e08565b8152602001906001900390816120625790505b509695505050505050565b60008167ffffffffffffffff8111156120a3576120a36155f3565b6040519080825280602002602001820160405280156120dc57816020015b6120c9614e08565b8152602001906001900390816120c15790505b5090506000805b8560200151811015612314576001600160a01b038089166000908152600e6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e0830152600781015493820193909352600883015461012082015260098301805492939192610140840191906121aa90615596565b80601f01602080910402602001604051908101604052809291908181526020018280546121d690615596565b80156122235780601f106121f857610100808354040283529160200191612223565b820191906000526020600020905b81548152906001019060200180831161220657829003601f168201915b505050505081525050905080608001511515600115150361230157604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b03168152602001826101000151815260200182610120015181526020018261014001518152508484815181106122e8576122e8615717565b60209081029190910101526122fe83600161572d565b92505b508061230c81615740565b9150506120e3565b5060005b8460200151811015612549576001600160a01b038089166000908152600f6020908152604080832085845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e0830152600781015493820193909352600883015461012082015260098301805492939192610140840191906123df90615596565b80601f016020809104026020016040519081016040528092919081815260200182805461240b90615596565b80156124585780601f1061242d57610100808354040283529160200191612458565b820191906000526020600020905b81548152906001019060200180831161243b57829003601f168201915b505050505081525050905080608001511515600115150361253657604051806101600160405280826000015181526020018260200151815260200182604001518152602001826060015181526020018260800151151581526020018260a001516001600160a01b031681526020018260c001516001600160a01b031681526020018260e001516001600160a01b031681526020018261010001518152602001826101200151815260200182610140015181525084848151811061251d5761251d615717565b602090810291909101015261253383600161572d565b92505b508061254181615740565b915050612318565b50909695505050505050565b60028054036125765760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b0384166125a05760405162461bcd60e51b815260040161074090615790565b6125a984614984565b15156001146125ca5760405162461bcd60e51b8152600401610740906157c7565b6001600160a01b0381166125f05760405162461bcd60e51b81526004016107409061580a565b6005546001600160a01b0382811691161461261d5760405162461bcd60e51b815260040161074090615841565b600061262f84846006546013546149da565b9050806000036126785760405162461bcd60e51b8152602060048201526014602482015273070726963652070657220746f6b656e20677420360641b6044820152606401610740565b600084116126bf5760405162461bcd60e51b815260206004820152601460248201527307175616e746174792063616e6e6f7420626520360641b6044820152606401610740565b600083116127085760405162461bcd60e51b815260206004820152601660248201527505f66756c6c50726963652063616e6e6f7420626520360541b6044820152606401610740565b60008590506000816001600160a01b031663ebfc4fb26040518163ffffffff1660e01b8152600401602060405180830381865afa15801561274d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127719190615934565b905080156127cd5760405162461bcd60e51b8152602060048201526024808201527f63616e6e6f742063726561746520626964207768696c6520646973747269627560448201526374696e6760e01b6064820152608401610740565b60003390506000836001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612812573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128369190615886565b6040516323b872dd60e01b81529091506001600160a01b038716906323b872dd9061286990859030908c90600401615956565b6020604051808303816000875af1158015612888573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128ac9190615934565b506001600160a01b03811660009081526011602090815260409182902082518084019093528054808452600191820154928401929092526128ed919061572d565b6001600160a01b03831660009081526011602090815260409091209190915581015161291a90600161572d565b6001600160a01b0380841660008181526011602090815260408083206001908101969096559388168252600b815283822092825291909152205461295d9161572d565b6001600160a01b038085166000818152600b6020908152604080832094881680845294825280832095909555918152600d825283812092815291905220546129a690600161572d565b600d6000856001600160a01b03166001600160a01b031681526020019081526020016000206000846001600160a01b03166001600160a01b03168152602001908152602001600020819055506000604051806101600160405280836020015181526020018b81526020018a815260200188815260200160001515815260200160006001600160a01b03168152602001856001600160a01b031681526020018c6001600160a01b03168152602001428152602001600081526020016040518060400160405280600381526020016210925160ea1b815250815250905080600f6000856001600160a01b03166001600160a01b031681526020019081526020016000206000846020015181526020019081526020016000206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a81548160ff02191690831515021790555060a08201518160040160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555061010082015181600701556101208201518160080155610140820151816009019081612bb79190615657565b50905050826001600160a01b031682602001517f821b00729e5aea236bbe01c0da61dc9f342fe560b297e588a1510feeb1f5e0db83604051612bf99190615a90565b60405180910390a350506001600255505050505050505050565b60606000612c2060075490565b67ffffffffffffffff811115612c3857612c386155f3565b604051908082528060200260200182016040528015612cad57816020015b612c9a6040518060a001604052806000815260200160006001600160a01b03168152602001606081526020016060815260200160006001600160a01b031681525090565b815260200190600190039081612c565790505b50905060005b600754811015612e6257600081815260096020908152604091829020825160a0810184528154815260018201546001600160a01b0316928101929092526002810180549293919291840191612d0790615596565b80601f0160208091040260200160405190810160405280929190818152602001828054612d3390615596565b8015612d805780601f10612d5557610100808354040283529160200191612d80565b820191906000526020600020905b815481529060010190602001808311612d6357829003601f168201915b50505050508152602001600382018054612d9990615596565b80601f0160208091040260200160405190810160405280929190818152602001828054612dc590615596565b8015612e125780601f10612de757610100808354040283529160200191612e12565b820191906000526020600020905b815481529060010190602001808311612df557829003601f168201915b5050509183525050600491909101546001600160a01b03166020909101528251839083908110612e4457612e44615717565b60200260200101819052508080612e5a90615740565b915050612cb3565b50919050565b6002805403612e895760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b038216612eb35760405162461bcd60e51b815260040161074090615790565b612ebc82614984565b1515600114612edd5760405162461bcd60e51b8152600401610740906157c7565b60008290506000816001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa158015612f22573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f469190615886565b6001600160a01b038082166000908152600f6020908152604080832088845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549495503394929391926101408401919061300690615596565b80601f016020809104026020016040519081016040528092919081815260200182805461303290615596565b801561307f5780601f106130545761010080835404028352916020019161307f565b820191906000526020600020905b81548152906001019060200180831161306257829003601f168201915b5050505050815250509050816001600160a01b03168160c001516001600160a01b0316146130df5760405162461bcd60e51b815260206004820152600d60248201526c3737ba103134b21037bbb732b960991b6044820152606401610740565b600554604082810151905163a9059cbb60e01b81526001600160a01b038581166004830152602482019290925291169063a9059cbb906044016020604051808303816000875af1158015613137573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061315b9190615934565b506001600160a01b038316600090815260116020526040902054613181906001906158d9565b6001600160a01b038085166000818152601160209081526040808320959095559286168152600b8352838120918152915220546131c0906001906158d9565b6001600160a01b038084166000818152600b6020908152604080832094891680845294825280832095909555918152600d8252838120928152919052205461320a906001906158d9565b6001600160a01b038084166000908152600d60209081526040808320938816835292815282822093909355600f835281812088825290925281208181556001810182905560028101829055600381018290556004810180546001600160a81b03191690556005810180546001600160a01b031990811690915560068201805490911690556007810182905560088101829055906132aa6009830182614e7f565b50506001600255505050505050565b60008281526001602052604081206132d19083614a43565b9392505050565b6000918252602082815260408084206001600160a01b0393909316845291905290205460ff1690565b60028054036133225760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b03821661334c5760405162461bcd60e51b815260040161074090615790565b61335582614984565b15156001146133765760405162461bcd60e51b8152600401610740906157c7565b60008290506000816001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156133bb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133df9190615886565b6001600160a01b038082166000908152600e6020908152604080832088845282528083208151610160810183528154815260018201549381019390935260028101549183019190915260038101546060830152600481015460ff81161515608084015261010090819004851660a08401526005820154851660c0840152600682015490941660e083015260078101549382019390935260088301546101208201526009830180549495503394929391926101408401919061349f90615596565b80601f01602080910402602001604051908101604052809291908181526020018280546134cb90615596565b80156135185780601f106134ed57610100808354040283529160200191613518565b820191906000526020600020905b8154815290600101906020018083116134fb57829003601f168201915b5050505050815250509050816001600160a01b03168160a001516001600160a01b0316146135785760405162461bcd60e51b815260206004820152600d60248201526c3737ba1030b9b59037bbb732b960991b6044820152606401610740565b6001600160a01b038083166000908152600a60209081526040808320938716835292905220546135aa906001906158d9565b6001600160a01b038084166000818152600a6020908152604080832094891680845294825280832095909555918152600c825283812092815291905220546135f4906001906158d9565b6001600160a01b038084166000908152600c602090815260408083209388168352928152828220939093556010909252902054613633906001906158d9565b6001600160a01b0384811660009081526010602090815260409182902093909355918301519151634eab26cd60e11b815284821660048201526024810192909252851690639d564d9a90604401600060405180830381600087803b15801561369a57600080fd5b505af11580156136ae573d6000803e3d6000fd5b5050506001600160a01b0384166000908152600e6020908152604080832089845290915281208181556001810182905560028101829055600381018290556004810180546001600160a81b03191690556005810180546001600160a01b03199081169091556006820180549091169055600781018290556008810182905591506132aa6009830182614e7f565b606081600061374960075490565b67ffffffffffffffff811115613761576137616155f3565b6040519080825280602002602001820160405280156137dd57816020015b6137ca6040518060c001604052806000815260200160006001600160a01b03168152602001606081526020016060815260200160006001600160a01b03168152602001600081525090565b81526020019060019003908161377f5790505b50905060005b600754811015613a9b576000818152600960209081526040808320815160a0810183528154815260018201546001600160a01b031693810193909352600281018054919284019161383390615596565b80601f016020809104026020016040519081016040528092919081815260200182805461385f90615596565b80156138ac5780601f10613881576101008083540402835291602001916138ac565b820191906000526020600020905b81548152906001019060200180831161388f57829003601f168201915b505050505081526020016003820180546138c590615596565b80601f01602080910402602001604051908101604052809291908181526020018280546138f190615596565b801561393e5780601f106139135761010080835404028352916020019161393e565b820191906000526020600020905b81548152906001019060200180831161392157829003601f168201915b50505091835250506004918201546001600160a01b0390811660209283015290830151604051630988931960e21b8152888316938101939093529293506000918291829182918616906326224c6490602401608060405180830381865afa1580156139ad573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906139d191906158a3565b93509350935093506000808385876139e991906158d9565b6139f391906158d9565b1115613a115782613a0485876158d9565b613a0e91906158d9565b90505b6040518060c001604052808860000151815260200188602001516001600160a01b03168152602001886040015181526020018860600151815260200188608001516001600160a01b0316815260200182815250898981518110613a7657613a76615717565b6020026020010181905250505050505050508080613a9390615740565b9150506137e3565b509392505050565b600080516020615c49833981519152613abb816148d8565b612710821115613b0d5760405162461bcd60e51b815260206004820152601b60248201527f63616e2774206d6f7265207468616e203130302070657263656e7400000000006044820152606401610740565b50600355565b6002805403613b345760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b038416613b5e5760405162461bcd60e51b815260040161074090615790565b613b6784614984565b1515600114613b885760405162461bcd60e51b8152600401610740906157c7565b6001600160a01b038216613bae5760405162461bcd60e51b81526004016107409061580a565b6005546001600160a01b03838116911614613bdb5760405162461bcd60e51b815260040161074090615841565b60008490506000816001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa158015613c20573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613c449190615886565b6001600160a01b038082166000908152600e602090815260408083208a8452909152902060048101549293503392909161010090910416613cbd5760405162461bcd60e51b81526020600482015260136024820152721cd95b1b195c881a5cc81b9bdd081d985b1a59606a1b6044820152606401610740565b80600201548514613d075760405162461bcd60e51b81526020600482015260146024820152731c1c9a58d9481a5cc81b9bdd0818dbdc9c9958dd60621b6044820152606401610740565b80548714613d4b5760405162461bcd60e51b81526020600482015260116024820152701a59081a5cc81b9bdd0818dbdc9c9958dd607a1b6044820152606401610740565b60048101805460ff191660011790556005810180546001600160a01b0384166001600160a01b0319909116179055426008820155846000613d8b826105e8565b600480546040516323b872dd60e01b81529293506001600160a01b03808c16936323b872dd93613dc1938a931691879101615956565b6020604051808303816000875af1158015613de0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e049190615934565b5060048301546001600160a01b03808a16916323b872dd918791610100900416613e2e85876158d9565b6040518463ffffffff1660e01b8152600401613e4c93929190615956565b6020604051808303816000875af1158015613e6b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613e8f9190615934565b506004808401546001850154604051630a932cfd60e11b81526001600160a01b03808b169463152659fa94613ed194610100909104909216928a929101615956565b600060405180830381600087803b158015613eeb57600080fd5b505af1158015613eff573d6000803e3d6000fd5b50505060048401546001600160a01b03878116600090815260106020526040902054610100909204169150613f36906001906158d9565b6001600160a01b038088166000818152601060209081526040808320959095559285168152600c835283812091815291522054613f75906001906158d9565b6001600160a01b038083166000908152600c60209081526040808320938b16808452939091529081902092909255855491519091907f07ee93e920b82120bd0fa8a31236a4a25d1c0cff3ee744f0457c8fa061835c1d90612bf99088906159f7565b600e602090815260009283526040808420909152908252902080546001820154600283015460038401546004850154600586015460068701546007880154600889015460098a018054999a98999798969760ff8716976101009097046001600160a01b039081169796811696951694919061067f90615596565b60028054036140725760405162461bcd60e51b815260040161074090615759565b600280556001600160a01b03831661409c5760405162461bcd60e51b815260040161074090615790565b6140a583614984565b15156001146140c65760405162461bcd60e51b8152600401610740906157c7565b600082116141165760405162461bcd60e51b815260206004820152601f60248201527f7175616e74697479206d7573742062652067726561746572207468616e2030006044820152606401610740565b600081116141665760405162461bcd60e51b815260206004820152601c60248201527f7072696365206d7573742062652067726561746572207468616e2030000000006044820152606401610740565b600061417883836006546013546149da565b9050806000036141c15760405162461bcd60e51b8152602060048201526014602482015273070726963652070657220746f6b656e20677420360641b6044820152606401610740565b60008490506000816001600160a01b031663ebfc4fb26040518163ffffffff1660e01b8152600401602060405180830381865afa158015614206573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061422a9190615934565b905080156142865760405162461bcd60e51b8152602060048201526024808201527f63616e6e6f74206372656174652061736b207768696c6520646973747269627560448201526374696e6760e01b6064820152608401610740565b604051630988931960e21b8152336004820181905290600090819081906001600160a01b038716906326224c6490602401608060405180830381865afa1580156142d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906142f891906158a3565b50919450925090506000808261430e85876158d9565b61431891906158d9565b1115614336578161432984866158d9565b61433391906158d9565b90505b808a11156143565760405162461bcd60e51b8152600401610740906158ec565b6040516358e12ac360e11b81526001600160a01b038681166004830152602482018c905288169063b1c2558690604401600060405180830381600087803b1580156143a057600080fd5b505af11580156143b4573d6000803e3d6000fd5b505050506000876001600160a01b031663e246cbd06040518163ffffffff1660e01b8152600401602060405180830381865afa1580156143f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061441c9190615886565b6001600160a01b038088166000908152600a602090815260408083209385168352929052205490915061445090600161572d565b6001600160a01b038088166000818152600a6020908152604080832094871680845294825280832095909555918152600c8252838120928152919052205461449990600161572d565b6001600160a01b038088166000908152600c6020908152604080832093861683529281528282209390935560108352819020815180830190925280548083526001918201549383019390935290916144f09161572d565b6001600160a01b03831660009081526010602090815260409091209190915581015161451d90600161572d565b60106000846001600160a01b03166001600160a01b03168152602001908152602001600020600101819055506000604051806101600160405280836020015181526020018e81526020018d81526020018c8152602001600015158152602001896001600160a01b0316815260200160006001600160a01b031681526020018f6001600160a01b03168152602001428152602001600081526020016040518060400160405280600381526020016241534b60e81b815250815250905080600e6000856001600160a01b03166001600160a01b031681526020019081526020016000206000846020015181526020019081526020016000206000820151816000015560208201518160010155604082015181600201556060820151816003015560808201518160040160006101000a81548160ff02191690831515021790555060a08201518160040160016101000a8154816001600160a01b0302191690836001600160a01b0316021790555060c08201518160050160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060e08201518160060160006101000a8154816001600160a01b0302191690836001600160a01b031602179055506101008201518160070155610120820151816008015561014082015181600901908161470e9190615657565b50905050826001600160a01b031682602001517ffee2a8fee66de06af9e814176297a302454d8971daede71171a13b449464b821836040516147509190615a90565b60405180910390a350506001600255505050505050505050505050565b60008181526001602052604081206105e290614a4f565b60008281526020819052604090206001015461479f81614936565b6109288383614962565b600080516020615c498339815191526147c1816148d8565b6001600160a01b0382166147e75760405162461bcd60e51b8152600401610740906155ca565b50600480546001600160a01b0319166001600160a01b0392909216919091179055565b61481482826132d8565b6109a7576000828152602081815260408083206001600160a01b03851684529091529020805460ff1916600117905561484a3390565b6001600160a01b0316816001600160a01b0316837f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d60405160405180910390a45050565b60006132d1836001600160a01b038416614a59565b60006001600160e01b03198216637965db0b60e01b14806105e257506301ffc9a760e01b6001600160e01b03198316146105e2565b6148e281336132d8565b614933576148f1336014614aa8565b6148fc826020614aa8565b60405160200161490d929190615aa3565b60408051601f198184030181529082905262461bcd60e51b825261074091600401615b18565b50565b6149338133614c44565b61494a828261480a565b6000828152600160205260409020610928908261488e565b61496c8282614c71565b60008281526001602052604090206109289082614cd6565b6000805b6007548110156149d1576000818152600960205260409020600101546001600160a01b038085169116036149bf5750600192915050565b806149c981615740565b915050614988565b50600092915050565b6000806149e784846158d9565b905060006149f682600a615c0f565b614a00908761555d565b614a1290670de0b6b3a764000061555d565b90506000614a208883615574565b9050614a2d83600a615c0f565b614a379082615574565b98975050505050505050565b60006132d18383614ceb565b60006105e2825490565b6000818152600183016020526040812054614aa0575081546001818101845560008481526020808220909301849055845484825282860190935260409020919091556105e2565b5060006105e2565b60606000614ab783600261555d565b614ac290600261572d565b67ffffffffffffffff811115614ada57614ada6155f3565b6040519080825280601f01601f191660200182016040528015614b04576020820181803683370190505b509050600360fc1b81600081518110614b1f57614b1f615717565b60200101906001600160f81b031916908160001a905350600f60fb1b81600181518110614b4e57614b4e615717565b60200101906001600160f81b031916908160001a9053506000614b7284600261555d565b614b7d90600161572d565b90505b6001811115614bf5576f181899199a1a9b1b9c1cb0b131b232b360811b85600f1660108110614bb157614bb1615717565b1a60f81b828281518110614bc757614bc7615717565b60200101906001600160f81b031916908160001a90535060049490941c93614bee81615c1b565b9050614b80565b5083156132d15760405162461bcd60e51b815260206004820181905260248201527f537472696e67733a20686578206c656e67746820696e73756666696369656e746044820152606401610740565b614c4e82826132d8565b6109a757614c66816001600160a01b03166014614aa8565b6148fc836020614aa8565b614c7b82826132d8565b156109a7576000828152602081815260408083206001600160a01b0385168085529252808320805460ff1916905551339285917ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9190a45050565b60006132d1836001600160a01b038416614d15565b6000826000018281548110614d0257614d02615717565b9060005260206000200154905092915050565b60008181526001830160205260408120548015614dfe576000614d396001836158d9565b8554909150600090614d4d906001906158d9565b9050818114614db2576000866000018281548110614d6d57614d6d615717565b9060005260206000200154905080876000018481548110614d9057614d90615717565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080614dc357614dc3615c32565b6001900381819060005260206000200160009055905585600101600086815260200190815260200160002060009055600193505050506105e2565b60009150506105e2565b6040518061016001604052806000815260200160008152602001600081526020016000815260200160001515815260200160006001600160a01b0316815260200160006001600160a01b0316815260200160006001600160a01b031681526020016000815260200160008152602001606081525090565b508054614e8b90615596565b6000825580601f10614e9b575050565b601f01602090049060005260206000209081019061493391905b80821115614ec95760008155600101614eb5565b5090565b600060208284031215614edf57600080fd5b81356001600160e01b0319811681146132d157600080fd5b600060208284031215614f0957600080fd5b5035919050565b6001600160a01b038116811461493357600080fd5b60008060408385031215614f3857600080fd5b8235614f4381614f10565b946020939093013593505050565b60005b83811015614f6c578181015183820152602001614f54565b50506000910152565b60008151808452614f8d816020860160208601614f51565b601f01601f19169290920160200192915050565b60006101608d83528c60208401528b60408401528a6060840152891515608084015260018060a01b03808a1660a085015280891660c085015280881660e08501525085610100840152846101208401528061014084015261500481840185614f75565b9e9d5050505050505050505050505050565b858152600060018060a01b03808716602084015260a0604084015261503e60a0840187614f75565b83810360608501526150508187614f75565b9250508084166080840152509695505050505050565b6000806040838503121561507957600080fd5b82359150602083013561508b81614f10565b809150509250929050565b600080604083850312156150a957600080fd5b82356150b481614f10565b9150602083013561508b81614f10565b60008083601f8401126150d657600080fd5b50813567ffffffffffffffff8111156150ee57600080fd5b60208301915083602082850101111561510657600080fd5b9250929050565b600080600080600080600060a0888a03121561512857600080fd5b87359650602088013561513a81614f10565b9550604088013567ffffffffffffffff8082111561515757600080fd5b6151638b838c016150c4565b909750955060608a013591508082111561517c57600080fd5b506151898a828b016150c4565b909450925050608088013561519d81614f10565b8091505092959891949750929550565b6000602082840312156151bf57600080fd5b81356132d181614f10565b6000610160825184526020830151602085015260408301516040850152606083015160608501526080830151615204608086018215159052565b5060a083015161521f60a08601826001600160a01b03169052565b5060c083015161523a60c08601826001600160a01b03169052565b5060e083015161525560e08601826001600160a01b03169052565b50610100838101519085015261012080840151908501526101408084015181860183905261528583870182614f75565b9695505050505050565b6000602080830181845280855180835260408601915060408160051b870101925083870160005b828110156152e457603f198886030184526152d28583516151ca565b945092850192908501906001016152b6565b5092979650505050505050565b6000806000806080858703121561530757600080fd5b843561531281614f10565b935060208501359250604085013561532981614f10565b9396929550929360600135925050565b6000806000806080858703121561534f57600080fd5b843561535a81614f10565b93506020850135925060408501359150606085013561537881614f10565b939692955090935050565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561542c57888303603f19018552815180518452878101516001600160a01b03908116898601528782015160a0898701819052916153ed83880183614f75565b92506060915081840151878403838901526154088482614f75565b608095860151909216979094019690965250505093860193908601906001016153aa565b509098975050505050505050565b6000806040838503121561544d57600080fd5b50508035926020909101359150565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b8381101561542c57888303603f19018552815180518452878101516001600160a01b03908116898601528782015160c0898701819052916154c683880183614f75565b92506060915081840151878403838901526154e18482614f75565b608086810151909316928901929092525060a093840151939096019290925250509386019390860190600101615483565b60008060006060848603121561552757600080fd5b833561553281614f10565b95602085013595506040909401359392505050565b634e487b7160e01b600052601160045260246000fd5b80820281158282048414176105e2576105e2615547565b60008261559157634e487b7160e01b600052601260045260246000fd5b500490565b600181811c908216806155aa57607f821691505b602082108103612e6257634e487b7160e01b600052602260045260246000fd5b6020808252600f908201526e696e76616c6964206164647265737360881b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b601f82111561092857600081815260208120601f850160051c810160208610156156305750805b601f850160051c820191505b8181101561564f5782815560010161563c565b505050505050565b815167ffffffffffffffff811115615671576156716155f3565b6156858161567f8454615596565b84615609565b602080601f8311600181146156ba57600084156156a25750858301515b600019600386901b1c1916600185901b17855561564f565b600085815260208120601f198616915b828110156156e9578886015182559484019460019091019084016156ca565b50858210156157075787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052603260045260246000fd5b808201808211156105e2576105e2615547565b60006001820161575257615752615547565b5060010190565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b6020808252601e908201527f616464726573732063616e6e6f74206265206e756c6c20616464726573730000604082015260600190565b60208082526023908201527f61646472657373206973206e6f74206120737570706f7274656420636f6e74726040820152621858dd60ea1b606082015260800190565b60208082526019908201527f696e76616c69642070617920746f6b656e206164647265737300000000000000604082015260600190565b60208082526025908201527f70617920746f6b656e206e6f7420737570706f7274656420666f7220746869736040820152642073616c6560d81b606082015260800190565b60006020828403121561589857600080fd5b81516132d181614f10565b600080600080608085870312156158b957600080fd5b845193506020850151925060408501519150606085015161537881614f10565b818103818111156105e2576105e2615547565b60208082526028908201527f7175616e7469747920697320686967686572207468616e20617661696c61626c6040820152671948185b5bdd5b9d60c21b606082015260800190565b60006020828403121561594657600080fd5b815180151581146132d157600080fd5b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000815461598781615596565b8085526020600183811680156159a457600181146159be576159ec565b60ff1985168884015283151560051b8801830195506159ec565b866000528260002060005b858110156159e45781548a82018601529083019084016159c9565b890184019650505b505050505092915050565b602081528154602082015260018201546040820152600282015460608201526003820154608082015260006004830154615a3860a0840160ff831615159052565b6001600160a01b03600891821c811660c08501526005850154811660e08501526006850154166101008401526007840154610120840152830154610140830152610160808301526132d161018083016009850161597a565b6020815260006132d160208301846151ca565b7f416363657373436f6e74726f6c3a206163636f756e7420000000000000000000815260008351615adb816017850160208801614f51565b7001034b99036b4b9b9b4b733903937b6329607d1b6017918401918201528351615b0c816028840160208801614f51565b01602801949350505050565b6020815260006132d16020830184614f75565b600181815b80851115615b66578160001904821115615b4c57615b4c615547565b80851615615b5957918102915b93841c9390800290615b30565b509250929050565b600082615b7d575060016105e2565b81615b8a575060006105e2565b8160018114615ba05760028114615baa57615bc6565b60019150506105e2565b60ff841115615bbb57615bbb615547565b50506001821b6105e2565b5060208310610133831016604e8410600b8410161715615be9575081810a6105e2565b615bf38383615b2b565b8060001904821115615c0757615c07615547565b029392505050565b60006132d18383615b6e565b600081615c2a57615c2a615547565b506000190190565b634e487b7160e01b600052603160045260246000fdfea49807205ce4d355092ef5a8a18f56e8913cf4a201fbe287825b095693c21775a2646970667358221220cfeb5ee0c1a77bb944a17f78ce61f40442607863857ca3a97d61a9dff7d9214764736f6c6343000811003300000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000fbb4a89e603cb3aa780a00a28f9c83a6633a0f90000000000000000000000000af88d065e77c8cc2239327c5edb3a432268e58310000000000000000000000000000000000000000000000000000000000000006", + "nonce": "0xa", + "to": null, + "transactionIndex": "0x1", + "value": "0x0", + "type": "0x2", + "accessList": [], + "chainId": "0xa4b1", + "v": "0x1", + "r": "0x52686618911830c13d286e2030ea6e03c6eac79d44c38d77a5e46dc12a16d9f1", + "s": "0x12be8710d43185472697db41580190aee9d147830cbf56b3a433d4b83ad575a7", + "yParity": "0x1" + }, + // Etherscan + l1GasUsed: 41_790_419, + l2GasUsed: 5_506_757, + l2GasPrice: 0.01, + l1BaseFeePerByte: 42, + txFeeETH: 0.00047297176, + } }; diff --git a/test/unit/gas.ts b/test/unit/gas.ts index 3142f99..b85db84 100644 --- a/test/unit/gas.ts +++ b/test/unit/gas.ts @@ -12,6 +12,7 @@ import { OPTIMISM_ECOTONE_BASE_FEE_SCALAR, OPTIMISM_ECOTONE_BLOB_BASE_FEE_SCALAR } from "../../src/constants"; +import { cases as arbitrumCases } from "./cases/arbitrum"; import { cases as baseCases } from "./cases/base"; import { cases as optimismCases } from "./cases/optimism"; import { cases as evmCases } from "./cases/evm"; @@ -177,3 +178,50 @@ describe("Base: getCalldataCostForNetwork", function () { assert(diff < .01); }); }); + +describe("Arbitrum: getCalldataCostForNetwork", function () { + const options: GasReporterOptions = { + L2: "arbitrum", + tokenPrice: "1", + currencyDisplayPrecision: 8, + } + + it("calculates gas cost for function call tx", function () { + const fn = arbitrumCases.arbOSFunction_1; + options.gasPrice = fn.l2GasPrice; + options.baseFeePerByte = fn.l1BaseFeePerByte; + + const gas = getCalldataGasForNetwork(options, fn.tx); + const cost = gasToCost(fn.l2GasUsed, gas, options); + const diff = getPercentDiff(parseFloat(cost), fn.txFeeETH); + + // Actual ~ 0.07 + assert(diff < .1); + }); + + it("calculates gas cost for function call tx", function () { + const fn = arbitrumCases.arbOSFunction_2; + options.gasPrice = fn.l2GasPrice; + options.baseFeePerByte = fn.l1BaseFeePerByte; + + const gas = getCalldataGasForNetwork(options, fn.tx); + const cost = gasToCost(fn.l2GasUsed, gas, options); + const diff = getPercentDiff(parseFloat(cost), fn.txFeeETH); + + // Actual ~ 0.01 + assert(diff < .1); + }); + + it("calculates gas cost for a deployment tx", function () { + const fn = arbitrumCases.arbOSDeployment_1; + options.gasPrice = fn.l2GasPrice; + options.baseFeePerByte = fn.l1BaseFeePerByte; + + const gas = getCalldataGasForNetwork(options, fn.tx); + const cost = gasToCost(fn.l2GasUsed, gas, options); + const diff = getPercentDiff(parseFloat(cost), fn.txFeeETH); + + // Actual ~ 0.089 + assert(diff < .1); + }); +}); diff --git a/test/unit/prices.ts b/test/unit/prices.ts index e41d392..e108ab3 100644 --- a/test/unit/prices.ts +++ b/test/unit/prices.ts @@ -72,12 +72,26 @@ describe("setGasAndPriceRates", function(){ assert.isUndefined(options.tokenPrice); await setGasAndPriceRates(options); - assert.equal(options.gasPrice, initialGasPrice); assert.isDefined(options.tokenPrice); assert.typeOf(options.tokenPrice, "string"); }); + it("when tokenPrice and gasPrice are set but baseFeePerByte is not set (arbitrum)", async function(){ + options.tokenPrice = "1"; + options.gasPrice = 1; + options.L2 = 'arbitrum'; + options.coinmarketcap = process.env.CMC_API_KEY; + options.L2Etherscan = process.env.ARBITRUM_API_KEY; + + assert.isUndefined(options.baseFeePerByte); + + await setGasAndPriceRates(options); + + assert.isDefined(options.baseFeePerByte); + assert.typeOf(options.baseFeePerByte, "number"); + }); + it("when tokenPrice and gasPrice are set but baseFee is not set", async function(){ options.tokenPrice = "1"; options.gasPrice = 1; diff --git a/yarn.lock b/yarn.lock index 1f325db..cc7794c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1572,6 +1572,11 @@ brorand@^1.0.1, brorand@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" +brotli-wasm@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brotli-wasm/-/brotli-wasm-2.0.1.tgz#2b3f4dc3db0c3e60d2635c055e6bac4ddf4bd3f5" + integrity sha512-+3USgYsC7bzb5yU0/p2HnnynZl0ak0E6uoIm4UW4Aby/8s8HFCq6NCfrrf1E9c3O8OCSzq3oYO1tUVqIi61Nww== + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -3839,7 +3844,15 @@ stacktrace-parser@^0.1.10: version "1.5.0" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" dependencies: @@ -3885,7 +3898,13 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" dependencies: @@ -4090,13 +4109,7 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" -undici@^5.14.0: - version "5.28.3" - resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" - dependencies: - "@fastify/busboy" "^2.0.0" - -undici@^5.28.2: +undici@^5.14.0, undici@^5.28.2: version "5.28.3" resolved "https://registry.yarnpkg.com/undici/-/undici-5.28.3.tgz#a731e0eff2c3fcfd41c1169a869062be222d1e5b" dependencies: @@ -4188,7 +4201,15 @@ workerpool@6.2.1: version "6.2.1" resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" dependencies: