diff --git a/components/calculator/ChainParametersForm.tsx b/components/calculator/ChainParametersForm.tsx new file mode 100644 index 000000000..04c7d0d35 --- /dev/null +++ b/components/calculator/ChainParametersForm.tsx @@ -0,0 +1,279 @@ +import type { ReactElement } from "react"; +import { useState } from "react"; +import { TextInput, SelectInput } from "./Inputs"; +import { ResultsParams, ResultsTable } from "./ResultsTable"; +import { + displayL1BaseFeeScalar, + displayL1BlobBaseFeeScalar, + calculateOverallL1DataAndStateCostsMargin, + calculateModeledDAPlusStateRevenueOnL2, + calculateTotalL1StateProposalCostsInETH, + determineDAInUse, + calculateImpliedDataGasFeePerTxUsingBlobs, + calculateImpliedDataGasFeePerTxUsingL1Calldata, + calculateImpliedDataGasFeePerTxUsingAltDAPlasmaMode, + resultsFeeScalarsAssumed, + impliedDataGasFee +} from "@/utils/calculator-helpers"; +import { Loader } from "./Loader"; + +type ComparableTransactionType = "Base" | "Zora" | "Mint" | "Mode"; +type DataAvailabilityType = "Ethereum" | "AltDA Plasma Mode"; + +export function ChainParametersForm(): ReactElement { + const [transactionsPerDay, setTransactionsPerDay] = useState(500000); + const [comparableTransactionType, setComparableTransactionType] = + useState("General OP Mainnet"); + const [dataAvailabilityType, setDataAvailabilityType] = useState("Ethereum"); + const [isFaultProofEnabled, setIsFaultProofEnabled] = useState("yes"); + const [targetDataFeeMargin, setTargetDataFeeMargin] = useState(5); + const [maxBlobsPerL1Transaction, setMaxBlobsPerL1Transaction] = useState(5); + const [maxChannelDuration, setMaxChannelDuration] = useState(5); + const [outputRootPostFrequency, setOutputRootPostFrequency] = useState(1 ); + const [isIncludeOutputRootCosts, setIsIncludeOutputRootCosts] = useState("yes"); + const [resultsParams, setResultsParams] = useState({}); + const [isLoading, setIsLoading] = useState(false); + const [showResult, setShowResult] = useState(false); + + const comparableTransactionTypeOptions = [ + "General OP Mainnet", + "Base", + "Zora", + "Mint", + "Mode", + ]; + const dataAvailabilityTypeOptions = ["Ethereum", "AltDA Plasma Mode"]; + const booleanOptions = ["Yes", "No"]; + + const handleSubmit = async (e: any) => { + e.preventDefault(); + setIsLoading(true); + setShowResult(false) + + //e37 + const l1BlobBaseFeeScalar = await displayL1BlobBaseFeeScalar( + stringToBoolean(isIncludeOutputRootCosts), + stringToBoolean(isFaultProofEnabled), + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTransactionType, + dataAvailabilityType, + targetDataFeeMargin + ); + + //e38 + const l1BaseFeeScalar = await displayL1BaseFeeScalar( + isIncludeOutputRootCosts, + isFaultProofEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTransactionType, + targetDataFeeMargin, + dataAvailabilityType + ); + + // e58 + const overallL1DataAndStateCostsMargin = + await calculateOverallL1DataAndStateCostsMargin( + transactionsPerDay, + comparableTransactionType, + l1BlobBaseFeeScalar, + l1BaseFeeScalar, + dataAvailabilityType, + maxChannelDuration, + outputRootPostFrequency, + isFaultProofEnabled + ); + + //e56 + const totalL1StateProposalCostsInETH = + await calculateTotalL1StateProposalCostsInETH( + outputRootPostFrequency, + isFaultProofEnabled + ); + + // e118 + const modeledDAPlusStateRevenueOnL2 = + await calculateModeledDAPlusStateRevenueOnL2( + transactionsPerDay, + comparableTransactionType, + l1BlobBaseFeeScalar, + l1BaseFeeScalar + ); + + // e64 + const impliedDataGasFeePerTxUsingBlobs = + await calculateImpliedDataGasFeePerTxUsingBlobs( + isIncludeOutputRootCosts, + isFaultProofEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTransactionType, + dataAvailabilityType, + targetDataFeeMargin + ); + + // e67 + const impliedDataGasFeePerTxUsingL1Calldata = + await calculateImpliedDataGasFeePerTxUsingL1Calldata( + isIncludeOutputRootCosts, + isFaultProofEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTransactionType, + dataAvailabilityType, + targetDataFeeMargin + ); + + // e66 + const impliedDataGasFeePerTxUsingAltDAPlasmaMode = + await calculateImpliedDataGasFeePerTxUsingAltDAPlasmaMode( + isIncludeOutputRootCosts, + isFaultProofEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTransactionType, + dataAvailabilityType, + targetDataFeeMargin + ); + + const dataAvailabilityInUse = determineDAInUse(dataAvailabilityType); + + const assumedFeeScalarMessage = resultsFeeScalarsAssumed( + comparableTransactionType, // e15 + transactionsPerDay, // e14 + dataAvailabilityType, // E16 + targetDataFeeMargin, // E18 + isIncludeOutputRootCosts, // E24 + maxChannelDuration // E22 + ); + const impliedDataGasFeeMessage = await impliedDataGasFee(dataAvailabilityType) + + const data = { + dataAvailabilityType, // e16 + l1BlobBaseFeeScalar, // e37 + l1BaseFeeScalar, // e38 + overallL1DataAndStateCostsMargin, // e58 + totalL1StateProposalCostsInETH, // e56 + modeledDAPlusStateRevenueOnL2, // e118 + dataAvailabilityInUse, // F35 + impliedDataGasFeePerTxUsingBlobs, // e64 + impliedDataGasFeePerTxUsingL1Calldata, // e67 + impliedDataGasFeePerTxUsingAltDAPlasmaMode, // e66 + assumedFeeScalarMessage, + impliedDataGasFeeMessage, + }; + setResultsParams(data); + setIsLoading(false); + setShowResult(true) + }; + + const stringToBoolean = (value: string): boolean => { + return value === "yes" || value === "Yes" ? true : false; + } + + return ( +
+
+
+

Chain Inputs

+ + + + + + + + + +
+
+

Advanced Inputs

+ + + + + +
+ +
+ {isLoading && } + {!isLoading && showResult && } +
+ ); +} diff --git a/components/calculator/Inputs/CheckboxInput.tsx b/components/calculator/Inputs/CheckboxInput.tsx new file mode 100644 index 000000000..3e63f5ac6 --- /dev/null +++ b/components/calculator/Inputs/CheckboxInput.tsx @@ -0,0 +1,31 @@ +import React from "react"; + +type Props = { + otherProps?: any; + className?: string; + label?: string; + description?:string; + handleToggle: (e: any) => void; +}; + +export const CheckboxInput: React.FC = React.memo( + ({ otherProps, label, description, className, handleToggle }) => { + function onCheckboxChange(e: any) { + const isChecked = e.target.checked; + handleToggle(isChecked); + } + return ( +
+ {label && } +

{description}

+ +
+ ); + } +); +CheckboxInput.displayName = "CheckboxInput"; diff --git a/components/calculator/Inputs/SelectInput.tsx b/components/calculator/Inputs/SelectInput.tsx new file mode 100644 index 000000000..8ed61b844 --- /dev/null +++ b/components/calculator/Inputs/SelectInput.tsx @@ -0,0 +1,51 @@ +import React from "react"; + +type Props = { + className?: string; + label?: string; + data: any[]; + otherProps?: any; + description?: string; + labelClass?: string; + onSelect?: (e: any) => void; +}; + +export const SelectInput: React.FC = React.memo( + ({ className, labelClass, description, otherProps, label, data, onSelect }) => { + const handleSelect = (e: any) => { + const value = e.target.value + onSelect(value) + } + return ( +
+ {label && ( + + )} +

+ {description} +

+
+ + {/* */} +
+
+ ); + } +); +SelectInput.displayName = "SelectInput"; diff --git a/components/calculator/Inputs/TextInput.tsx b/components/calculator/Inputs/TextInput.tsx new file mode 100644 index 000000000..65b92bf75 --- /dev/null +++ b/components/calculator/Inputs/TextInput.tsx @@ -0,0 +1,50 @@ +import React from "react"; + +type Props = { + placeholder?: string; + className?: string; + type: "text" | "email" | "password" | "number"; + label?: string; + labelClass?: string; + otherProps?: any; + description?: string; + error?: string; + isDisabled?: boolean; + onInputChange?: (e: any) => void; +}; + +export const TextInput = ({ + label, + placeholder, + className, + type, + otherProps, + isDisabled, + description, + labelClass, + onInputChange, +}: Props) => { + const handleInputChange = (e: any) => { + const val = e.target.value; + onInputChange(val); + }; + return ( +
+ {label && ( + + )} +

{description}

+ + +
+ ); +}; diff --git a/components/calculator/Inputs/index.ts b/components/calculator/Inputs/index.ts new file mode 100644 index 000000000..1447fe40e --- /dev/null +++ b/components/calculator/Inputs/index.ts @@ -0,0 +1,5 @@ +"use client"; + +export * from "./TextInput"; +export * from "./SelectInput"; +export * from "./CheckboxInput"; diff --git a/components/calculator/Loader.tsx b/components/calculator/Loader.tsx new file mode 100644 index 000000000..d437554b9 --- /dev/null +++ b/components/calculator/Loader.tsx @@ -0,0 +1,66 @@ +import React from "react"; + +export const Loader: React.FC = () => { + return ( +
+ + + + + + + + + + + +
+ ); + } + +Loader.displayName = "Loader"; diff --git a/components/calculator/ResultsTable.tsx b/components/calculator/ResultsTable.tsx new file mode 100644 index 000000000..07c4d812b --- /dev/null +++ b/components/calculator/ResultsTable.tsx @@ -0,0 +1,168 @@ +import { convertToMillionUnits } from "@/utils/calculator-helpers"; +import type { ReactElement } from "react"; + +export type ResultsParams = { + data: { + dataAvailabilityType: string; // e16 + l1BlobBaseFeeScalar: number; // e37 + l1BaseFeeScalar: number; // e38 + overallL1DataAndStateCostsMargin: number; // e58 + totalL1StateProposalCostsInETH: number; // e56 + modeledDAPlusStateRevenueOnL2: number; // e118 + dataAvailabilityInUse: string; // f35 + impliedDataGasFeePerTxUsingBlobs: number; // e64 + impliedDataGasFeePerTxUsingL1Calldata: number; // e67 + impliedDataGasFeePerTxUsingAltDAPlasmaMode: number; // e66, + assumedFeeScalarMessage: string; + impliedDataGasFeeMessage: string; + }; +}; + +export function ResultsTable({ + data +}: ResultsParams): ReactElement { + + const { + dataAvailabilityType, + l1BlobBaseFeeScalar, + l1BaseFeeScalar, + overallL1DataAndStateCostsMargin, + totalL1StateProposalCostsInETH, + modeledDAPlusStateRevenueOnL2, + dataAvailabilityInUse, + impliedDataGasFeePerTxUsingBlobs, + impliedDataGasFeePerTxUsingAltDAPlasmaMode, + impliedDataGasFeePerTxUsingL1Calldata, + assumedFeeScalarMessage, + impliedDataGasFeeMessage, + } = data; + + function calculateConstructionMessage( + _overallL1DataAndStateCostsMargin: number, // Corresponds to E58 + _totalL1StateProposalCostsInETH: number, // Corresponds to E56 + _modeledDAPlusStateRevenueOnL2: number // Corresponds to E118 + ): string { + const roundedE58IfNegative = + Math.round(_overallL1DataAndStateCostsMargin * -1000) / 1000; + const roundedE56 = + Math.round(_totalL1StateProposalCostsInETH * 1000) / 1000; + const roundedE58IfPositive = + Math.round(_overallL1DataAndStateCostsMargin * 1000) / 1000; + const marginPercentage = + Math.round(100 * (_overallL1DataAndStateCostsMargin / _modeledDAPlusStateRevenueOnL2) * 10) / 10; + const messageIfE58Negative = `This construction has ${roundedE58IfNegative} ETH / day of estimated State Output root costs, not covered by Data Margin (${roundedE56} ETH Total Output Root Cost / Day) at inputted Blob/L1 Gas Prices.`; + const messageIfE58Positive = `This construction is expected to have +${roundedE58IfPositive} ETH Margin on Data Costs (${marginPercentage}% Margin) at inputted L1 Gas Prices.`; + return _overallL1DataAndStateCostsMargin < 0 ? messageIfE58Negative : messageIfE58Positive + } + + function calculateDataGasFee( + _dataAvailabilityType: string, // Corresponds to E16 + _dataAvailabilityInUse: string, // Corresponds to F35 + _impliedDataGasFeePerTxUsingAltDAPlasmaMode: number, // Corresponds to E66 + _impliedDataGasFeePerTxUsingBlobs: number, // Corresponds to E64 + _impliedDataGasFeePerTxUsingL1Calldata: number // Corresponds to E67 + ): string { + let gasFee: number; + _dataAvailabilityType === "AltDA Plasma Mode" + ? (gasFee = _impliedDataGasFeePerTxUsingAltDAPlasmaMode) + : _dataAvailabilityInUse === "EIP-4844" + ? (gasFee = _impliedDataGasFeePerTxUsingBlobs) + : (gasFee = _impliedDataGasFeePerTxUsingL1Calldata); + + // Round the gas fee to 4 decimal places + const roundedGasFee = Math.round(gasFee * 10000) / 10000; + return `Implied Data Gas Fee per User Transaction: $${roundedGasFee}`; + } + + return ( +
+
+

+ {calculateConstructionMessage( + overallL1DataAndStateCostsMargin, + totalL1StateProposalCostsInETH, + modeledDAPlusStateRevenueOnL2 + )} +

+

+ {calculateDataGasFee( + dataAvailabilityType, + dataAvailabilityInUse, + impliedDataGasFeePerTxUsingAltDAPlasmaMode, + impliedDataGasFeePerTxUsingBlobs, + impliedDataGasFeePerTxUsingL1Calldata + )} +

+
+
+

Results

+ +
+

+ Fee Scalar Recommendations - Values to Set as Chain Inputs{" "} +

+

+ Recommended fee scalar configurations to achieve your target Data + Margin, given the transaction type and volume are shown below{" "} +

+

+ Note: This is an estimation,{" "} + + see the Optimism Docs + {" "} + for steps on modifying parameters if needed once the chain is on + mainnet{" "} +

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
DA Recommendation:{`${ + dataAvailabilityInUse === "EIP-4844" + ? `Blobs (EIP-4844)` + : dataAvailabilityInUse + }`}
Scalar TypeChain InputDecimal-Adjusted (6 decimals)
l1BlobBaseBaseScalar{l1BlobBaseFeeScalar}{convertToMillionUnits(l1BlobBaseFeeScalar)}
l1BaseFeeScalar{l1BaseFeeScalar}{convertToMillionUnits(l1BaseFeeScalar)}
+
+

+ Using Blobs (EIP-4844), posting transaction data will be 99.7% + cheaper than using L1 Calldata{" "} +

+
+
+

+ {assumedFeeScalarMessage} +

+

+ {impliedDataGasFeeMessage} +

+
+
+
+
+ ); +} diff --git a/package.json b/package.json index 7ea954ca7..a81de2a22 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@eth-optimism/contracts-ts": "^0.17.0", "@eth-optimism/tokenlist": "^9.0.9", "@feelback/react": "^0.3.4", - "@headlessui/react": "^2.1.0", + "@headlessui/react": "^2.1.8", "algoliasearch": "^4.23.3", "clsx": "^2.1.1", "escape-string-regexp": "^5.0.0", diff --git a/pages/builders/tools/_meta.json b/pages/builders/tools/_meta.json index d89d5d509..670f6209a 100644 --- a/pages/builders/tools/_meta.json +++ b/pages/builders/tools/_meta.json @@ -3,5 +3,6 @@ "connect": "Connecting", "build": "Building", "monitor": "Monitoring", - "op-tools": "OP Tools" + "op-tools": "OP Tools", + "fee-calculator": "Fee Calculator" } diff --git a/pages/builders/tools/fee-calculator.mdx b/pages/builders/tools/fee-calculator.mdx new file mode 100644 index 000000000..5534d82f2 --- /dev/null +++ b/pages/builders/tools/fee-calculator.mdx @@ -0,0 +1,23 @@ +--- +title: Fjord Fee Parameter Calculator +lang: en-US +description: Use the Fjord Fee Parameter Calculator to estimate and calculate fees for transactions on the Fjord network. +--- + +import { ChainParametersForm } from '@/components/calculator/ChainParametersForm' + +# Fjord Fee Parameter Calculator + +The Fjord Fee Parameter Calculator helps you estimate transaction fees on the Fjord network. Use this tool to: + +Calculate potential fees for different transaction types +Understand how network parameters affect fee calculations +Plan your transactions more effectively + +## How to use the calculator + +1. Input the relevant parameters in the form below. +2. The calculator will automatically update the fee estimates based on your inputs. +3. Adjust the parameters as needed to see how they affect the fee calculations. + + diff --git a/pages/builders/tools/overview.mdx b/pages/builders/tools/overview.mdx index cb146b2fa..e315426b6 100644 --- a/pages/builders/tools/overview.mdx +++ b/pages/builders/tools/overview.mdx @@ -57,4 +57,7 @@ If you are already familiar with [building on OP Mainnet](/chain/getting-started } /> } /> + + } /> + diff --git a/pages/index.mdx b/pages/index.mdx index 6c276002e..3ad6a6487 100644 --- a/pages/index.mdx +++ b/pages/index.mdx @@ -25,6 +25,7 @@ Whether you're a developer building a app on OP Mainnet, a node operator running } /> } /> + ## Featured Tools @@ -39,6 +40,9 @@ Check out these amazing tools, so you can get building with Optimism. } /> } /> + + } /> + ## Learn About Optimism diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 03596b6ff..432ebb0c7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,8 +29,8 @@ importers: specifier: ^0.3.4 version: 0.3.4(react@18.3.1) '@headlessui/react': - specifier: ^2.1.0 - version: 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + specifier: ^2.1.8 + version: 2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) algoliasearch: specifier: ^4.23.3 version: 4.23.3 @@ -570,26 +570,26 @@ packages: peerDependencies: react: '>=17' - '@floating-ui/core@1.6.2': - resolution: {integrity: sha512-+2XpQV9LLZeanU4ZevzRnGFg2neDeKHgFLjP6YLW+tly0IvrhqT4u8enLGjLH3qeh85g19xY5rsAusfwTdn5lg==} + '@floating-ui/core@1.6.8': + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} - '@floating-ui/dom@1.6.5': - resolution: {integrity: sha512-Nsdud2X65Dz+1RHjAIP0t8z5e2ff/IRbei6BqFrl1urT8sDVzM1HMQ+R0XcU5ceRfyO3I6ayeqIfh+6Wb8LGTw==} + '@floating-ui/dom@1.6.11': + resolution: {integrity: sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==} - '@floating-ui/react-dom@2.1.0': - resolution: {integrity: sha512-lNzj5EQmEKn5FFKc04+zasr09h/uX8RtJRNj5gUXsSQIXHVWTVh+hVAg1vOMCexkX8EgvemMvIFpQfkosnVNyA==} + '@floating-ui/react-dom@2.1.2': + resolution: {integrity: sha512-06okr5cgPzMNBy+Ycse2A6udMi4bqwW/zgBF/rwjcNqWkyr82Mcg8b0vjX8OJpZFy/FKjJmw6wV7t44kK6kW7A==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.26.17': - resolution: {integrity: sha512-ESD+jYWwqwVzaIgIhExrArdsCL1rOAzryG/Sjlu8yaD3Mtqi3uVyhbE2V7jD58Mo52qbzKz2eUY/Xgh5I86FCQ==} + '@floating-ui/react@0.26.24': + resolution: {integrity: sha512-2ly0pCkZIGEQUq5H8bBK0XJmc1xIK/RM3tvVzY3GBER7IOD1UgmC2Y2tjj4AuS+TC+vTE1KJv2053290jua0Sw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/utils@0.2.2': - resolution: {integrity: sha512-J4yDIIthosAsRZ5CPYP/jQvUAQtlZTTD/4suA08/FEnlxqW3sKS9iAhgsa9VYLZ6vDHn/ixJgIqRQPotoBjxIw==} + '@floating-ui/utils@0.2.8': + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} '@headlessui/react@1.7.19': resolution: {integrity: sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw==} @@ -598,8 +598,8 @@ packages: react: ^16 || ^17 || ^18 react-dom: ^16 || ^17 || ^18 - '@headlessui/react@2.1.0': - resolution: {integrity: sha512-/MizQk2xqR5ELkmCI1xWy3VgJULvR8gcAXtZhcK7sY53TNRCPeMdeODEXKSv9LPSSRlEAyzW1+NGJiaXq6dLRw==} + '@headlessui/react@2.1.8': + resolution: {integrity: sha512-uajqVkAcVG/wHwG9Fh5PFMcFpf2VxM4vNRNKxRjuK009kePVur8LkuuygHfIE+2uZ7z7GnlTtYsyUe6glPpTLg==} engines: {node: '>=10'} peerDependencies: react: ^18 @@ -816,36 +816,36 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - '@react-aria/focus@3.17.1': - resolution: {integrity: sha512-FLTySoSNqX++u0nWZJPPN5etXY0WBxaIe/YuL/GTEeuqUIuC/2bJSaw5hlsM6T2yjy6Y/VAxBcKSdAFUlU6njQ==} + '@react-aria/focus@3.18.2': + resolution: {integrity: sha512-Jc/IY+StjA3uqN73o6txKQ527RFU7gnG5crEl5Xy3V+gbYp2O5L3ezAo/E0Ipi2cyMbG6T5Iit1IDs7hcGu8aw==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 - '@react-aria/interactions@3.21.3': - resolution: {integrity: sha512-BWIuf4qCs5FreDJ9AguawLVS0lV9UU+sK4CCnbCNNmYqOWY+1+gRXCsnOM32K+oMESBxilAjdHW5n1hsMqYMpA==} + '@react-aria/interactions@3.22.2': + resolution: {integrity: sha512-xE/77fRVSlqHp2sfkrMeNLrqf2amF/RyuAS6T5oDJemRSgYM3UoxTbWjucPhfnoW7r32pFPHHgz4lbdX8xqD/g==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 - '@react-aria/ssr@3.9.4': - resolution: {integrity: sha512-4jmAigVq409qcJvQyuorsmBR4+9r3+JEC60wC+Y0MZV0HCtTmm8D9guYXlJMdx0SSkgj0hHAyFm/HvPNFofCoQ==} + '@react-aria/ssr@3.9.5': + resolution: {integrity: sha512-xEwGKoysu+oXulibNUSkXf8itW0npHHTa6c4AyYeZIJyRoegeteYuFpZUBPtIDE8RfHdNsSmE1ssOkxRnwbkuQ==} engines: {node: '>= 12'} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 - '@react-aria/utils@3.24.1': - resolution: {integrity: sha512-O3s9qhPMd6n42x9sKeJ3lhu5V1Tlnzhu6Yk8QOvDuXf7UGuUjXf9mzfHJt1dYzID4l9Fwm8toczBzPM9t0jc8Q==} + '@react-aria/utils@3.25.2': + resolution: {integrity: sha512-GdIvG8GBJJZygB4L2QJP1Gabyn2mjFsha73I2wSe+o4DYeGWoJiMZRM06PyTIxLH4S7Sn7eVDtsSBfkc2VY/NA==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 - '@react-stately/utils@3.10.1': - resolution: {integrity: sha512-VS/EHRyicef25zDZcM/ClpzYMC5i2YGN6uegOeQawmgfGjb02yaCX0F0zR69Pod9m2Hr3wunTbtpgVXvYbZItg==} + '@react-stately/utils@3.10.3': + resolution: {integrity: sha512-moClv7MlVSHpbYtQIkm0Cx+on8Pgt1XqtPx6fy9rQFb2DNc9u1G3AUVnqA17buOkH1vLxAtX4MedlxMWyRCYYA==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 - '@react-types/shared@3.23.1': - resolution: {integrity: sha512-5d+3HbFDxGZjhbMBeFHRQhexMFt4pUce3okyRtUVKbbedQFUrtXSBg9VszgF2RTeQDKDkMCIQDtz5ccP/Lk1gw==} + '@react-types/shared@3.24.1': + resolution: {integrity: sha512-AUQeGYEm/zDTN6zLzdXolDxz3Jk5dDL7f506F07U8tBwxNNI3WRdhU84G0/AaFikOZzDXhOZDr3MhQMzyE7Ydw==} peerDependencies: - react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 + react: ^16.8.0 || ^17.0.0-rc.1 || ^18.0.0 || ^19.0.0 '@scure/base@1.1.6': resolution: {integrity: sha512-ok9AWwhcgYuGG3Zfhyqg+zwl+Wn5uE+dwC0NV/2qQkx4dABbb/bx96vWu8NSj+BNjjSjno+JRYRjle1jV08k3g==} @@ -865,12 +865,21 @@ packages: '@swc/helpers@0.5.2': resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==} + '@tanstack/react-virtual@3.10.8': + resolution: {integrity: sha512-VbzbVGSsZlQktyLrP5nxE+vE1ZR+U0NFAWPbJLoG2+DKPwd2D7dVICTVIIaYlJqX1ZCEnYDbaOpmMwbsyhBoIA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@tanstack/react-virtual@3.5.0': resolution: {integrity: sha512-rtvo7KwuIvqK9zb0VZ5IL7fiJAEnG+0EiFZz8FUOs+2mhGqdGmjKIaT1XU7Zq0eFqL0jonLlhbayJI/J2SA/Bw==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@tanstack/virtual-core@3.10.8': + resolution: {integrity: sha512-PBu00mtt95jbKFi6Llk9aik8bnR3tR/oQP1o3TSi+iG//+Q2RTIzCEgKkHG8BB86kxMNW6O8wku+Lmi+QFR6jA==} + '@tanstack/virtual-core@3.5.0': resolution: {integrity: sha512-KnPRCkQTyqhanNC0K63GBG3wA8I+D1fQuVnAvcBF8f13akOKeQp1gSbu6f77zCxhEk727iV5oQnbHLYzHrECLg==} @@ -4346,30 +4355,30 @@ snapshots: '@feelback/js': 0.3.4 react: 18.3.1 - '@floating-ui/core@1.6.2': + '@floating-ui/core@1.6.8': dependencies: - '@floating-ui/utils': 0.2.2 + '@floating-ui/utils': 0.2.8 - '@floating-ui/dom@1.6.5': + '@floating-ui/dom@1.6.11': dependencies: - '@floating-ui/core': 1.6.2 - '@floating-ui/utils': 0.2.2 + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 - '@floating-ui/react-dom@2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react-dom@2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/dom': 1.6.5 + '@floating-ui/dom': 1.6.11 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react@0.26.17(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@floating-ui/react@0.26.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/react-dom': 2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@floating-ui/utils': 0.2.2 + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/utils': 0.2.8 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) tabbable: 6.2.0 - '@floating-ui/utils@0.2.2': {} + '@floating-ui/utils@0.2.8': {} '@headlessui/react@1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: @@ -4378,12 +4387,12 @@ snapshots: react: 18.3.1 react-dom: 18.3.1(react@18.3.1) - '@headlessui/react@2.1.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@headlessui/react@2.1.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: - '@floating-ui/react': 0.26.17(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@react-aria/focus': 3.17.1(react@18.3.1) - '@react-aria/interactions': 3.21.3(react@18.3.1) - '@tanstack/react-virtual': 3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@floating-ui/react': 0.26.24(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@react-aria/focus': 3.18.2(react@18.3.1) + '@react-aria/interactions': 3.22.2(react@18.3.1) + '@tanstack/react-virtual': 3.10.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: 18.3.1 react-dom: 18.3.1(react@18.3.1) @@ -4569,43 +4578,43 @@ snapshots: '@popperjs/core@2.11.8': {} - '@react-aria/focus@3.17.1(react@18.3.1)': + '@react-aria/focus@3.18.2(react@18.3.1)': dependencies: - '@react-aria/interactions': 3.21.3(react@18.3.1) - '@react-aria/utils': 3.24.1(react@18.3.1) - '@react-types/shared': 3.23.1(react@18.3.1) + '@react-aria/interactions': 3.22.2(react@18.3.1) + '@react-aria/utils': 3.25.2(react@18.3.1) + '@react-types/shared': 3.24.1(react@18.3.1) '@swc/helpers': 0.5.2 clsx: 2.1.1 react: 18.3.1 - '@react-aria/interactions@3.21.3(react@18.3.1)': + '@react-aria/interactions@3.22.2(react@18.3.1)': dependencies: - '@react-aria/ssr': 3.9.4(react@18.3.1) - '@react-aria/utils': 3.24.1(react@18.3.1) - '@react-types/shared': 3.23.1(react@18.3.1) + '@react-aria/ssr': 3.9.5(react@18.3.1) + '@react-aria/utils': 3.25.2(react@18.3.1) + '@react-types/shared': 3.24.1(react@18.3.1) '@swc/helpers': 0.5.2 react: 18.3.1 - '@react-aria/ssr@3.9.4(react@18.3.1)': + '@react-aria/ssr@3.9.5(react@18.3.1)': dependencies: '@swc/helpers': 0.5.2 react: 18.3.1 - '@react-aria/utils@3.24.1(react@18.3.1)': + '@react-aria/utils@3.25.2(react@18.3.1)': dependencies: - '@react-aria/ssr': 3.9.4(react@18.3.1) - '@react-stately/utils': 3.10.1(react@18.3.1) - '@react-types/shared': 3.23.1(react@18.3.1) + '@react-aria/ssr': 3.9.5(react@18.3.1) + '@react-stately/utils': 3.10.3(react@18.3.1) + '@react-types/shared': 3.24.1(react@18.3.1) '@swc/helpers': 0.5.2 clsx: 2.1.1 react: 18.3.1 - '@react-stately/utils@3.10.1(react@18.3.1)': + '@react-stately/utils@3.10.3(react@18.3.1)': dependencies: '@swc/helpers': 0.5.2 react: 18.3.1 - '@react-types/shared@3.23.1(react@18.3.1)': + '@react-types/shared@3.24.1(react@18.3.1)': dependencies: react: 18.3.1 @@ -4637,12 +4646,20 @@ snapshots: dependencies: tslib: 2.6.2 + '@tanstack/react-virtual@3.10.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@tanstack/virtual-core': 3.10.8 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + '@tanstack/react-virtual@3.5.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/virtual-core': 3.5.0 react: 18.3.1 react-dom: 18.3.1(react@18.3.1) + '@tanstack/virtual-core@3.10.8': {} + '@tanstack/virtual-core@3.5.0': {} '@testing-library/dom@9.3.4': diff --git a/public/img/icons/caret-down.svg b/public/img/icons/caret-down.svg new file mode 100644 index 000000000..ea15ee513 --- /dev/null +++ b/public/img/icons/caret-down.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/styles/calculator.css b/styles/calculator.css new file mode 100644 index 000000000..eee6440db --- /dev/null +++ b/styles/calculator.css @@ -0,0 +1,208 @@ +/* Fee Parameter Calculator */ +@import url('colors.css'); + +/**** Chain Inputs Form Styles ****/ + +button.calculator-button { + padding: 17px 17px; + background: var(--op-red-500); + color: var(--op-neutral-0); + border-radius: 10px; + margin-top: 30px; + margin-bottom: 10px; +} + +.calculator-heading_sub { + font-size: 23px; + margin-bottom: 40px; + text-align: center; +} + +.calcularor-label_description { + font-size: 11px; + margin-bottom: 3px; + color: var(--op-neutral-400) +} + +.calculator-label { + display: flex; + margin-bottom: 5px; +} + +.calculator-select { + width: 100%; + padding: 8px 12px; + border: 1px solid #d3d3d3; + border-radius: 10px; + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background-image: url('../public/img/icons/caret-down.svg'); + background-repeat: no-repeat; + background-position: right 10px center; + background-size: 20px; +} + +.calculator-select, +.calculator-input { + margin-bottom: 20px; +} + +select.calculator-select :hover, +select.calculator-select :focus { + border-color: #a9a9a9; + outline: none; +} + +.calculator-form { + margin-top: 40px; + margin-bottom: 30px; + border: 1px solid #efefef; + padding: 35px 30px; + border-radius: 10px; +} + +.calculator-input { + border: 1px solid #dedede; + width: 100%; + border-radius: 10px; + padding: 8px 12px; +} + +/**** Construction Info Styles ****/ + +.construction-info { + margin-bottom: 50px; +} + +.construction-info p { + font-weight: 500; + font-size: 14px; + text-align: center; + padding: 0 40px; + color: var(--op-neutral-500) +} + +.construction-info p span { + font-weight: 700; +} + +/**** Results & Table Styles ****/ + +.results-extra-info, .additional-info p:first-of-type { + margin-bottom: 7px; +} + +.results-table-wrap div.calculator-text p { + font-style: italic; + font-weight: 500; + font-size: 12px; + text-align: center; + color: var(--op-neutral-700) +} + +table { + width: 100%; + border-collapse: collapse; + margin-bottom: 40px; +} + +th, +td { + border: 1px solid var(--op-red-200); + padding: 8px; + text-align: left; +} + +thead .sub-header { + background-color: var(--op-red-600) !important; + color: var(--op-neutral-0); +} + +tbody tr td, +thead tr:nth-of-type(2) th { + text-align: center; +} + +tbody tr td:first-of-type, +thead tr:nth-of-type(2) th:first-of-type { + text-align: right; +} + +div.calculator-results-wrap .results-container .results-table-wrap tbody { + font-size: 14px; + color: var(--op-red-600); + font-weight: 700; +} + +thead th[colspan="2"] { + text-align: right; +} + +div.calculator-results-wrap +.results-container +.results-table-wrap { + display: flex; + flex-direction: column; + align-items: center; + } + +div.calculator-results-wrap +.results-container +.results-table-wrap +table.results-table.table { + border: 1px solid #efefef; + padding: 30px; + border-radius: 10px; +} + +div.calculator-results-wrap +.results-container +.results-recommendations +.calculator-info { + padding: 20px 15px; + background: var(--op-blue-200); + color: var(--op-blue-500); + border-radius: 20px; + margin: 30px 0px; +} + +div.calculator-results-wrap +.results-container +.results-recommendations +.calculator-info.calculator-text a { + text-decoration: underline; + font-style: italic; +} + +.results-recommendations { + margin-bottom: 40px; +} + +div.calculator-results-wrap +.results-container +h3.calculator-heading_text { + font-weight: 100; + color: var(--op-neutral-500); +} + +div.calculator-results-wrap +.results-container .calculator-text { + font-size: 14px; + color: var(--op-neutral-500); +} + +div.calculator-results-wrap .results-container{ + border: 1px solid #efefef; + border-radius: 10px; + padding: 40px 30px 50px; +} + +.loader-container { + display: flex; + justify-content: center; + width: 100%; +} +.loader-container svg { + width: 40px; +} \ No newline at end of file diff --git a/styles/global.css b/styles/global.css index 498779c39..2d455417f 100644 --- a/styles/global.css +++ b/styles/global.css @@ -2,6 +2,7 @@ @import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400..700&display=swap'); @import url('colors.css'); @import url('theme.css'); +@import url('calculator.css'); /* Override Nextra so content gets more breathing room */ .nextra-content h2 ~ p, diff --git a/utils/calculator-helpers.ts b/utils/calculator-helpers.ts new file mode 100644 index 000000000..c6920a9c3 --- /dev/null +++ b/utils/calculator-helpers.ts @@ -0,0 +1,1083 @@ +import { transactionTypes } from "./transaction-types"; + +const L1GasBaseFee = + "https://static.optimism.io/op-analytics/reference_data/market_data/outputs/suggest_base_fee.txt"; // E76 +const ethToUsdRate = + "https://static.optimism.io/op-analytics/reference_data/market_data/outputs/ethusd.txt"; // E77 +const blobBaseFee = + "https://static.optimism.io/op-analytics/reference_data/market_data/outputs/blob_base_fee.txt"; // E78 + +// transactionsPerDay === E14: number +// comparableTxnType === E15: string +// dataAvailabilityType === E16: string +// isFaultProofsEnabled === E17: boolean +// targetDataMargin === E18: number +// maxChannelDuration === E22: number +// outputRootPostFrequency === E23: number +// isStateEnabled: boolean, === E24: string + +// ModeledExpectedStateCostsOnL1: number === e120 == n40 == e56 +// ModeledDACostsOnL1: number === e119 == e55 +// ModeledDAPlusStateRevenueOnL2: number === e118 + +function calculateBlobTransactionCost( + dataAvailabilityType: string, // E16: string + altDATransactionCost: number, // E98: number + blobDataFee: number, // E64: number + l1CalldataFee: number, // E67: number + l1CalldataCost: number, // E96: number + blobCost: number // E94: number +): number { + return dataAvailabilityType === "AltDA Plasma Mode" + ? altDATransactionCost + : blobDataFee > l1CalldataFee + ? l1CalldataCost + : blobCost; +} // output = E37 + +function calculateAltDAOrL1TransactionCost( + dataAvailabilityType: string, //E16 + altDAPlasmaModeCost: number, // F98 + blobDataFee: number, // E64 + l1CalldataFee: number, // E67 + l1CalldataAltCost: number, // F96 + blobAltCost: number // F94 +): number { + if (dataAvailabilityType === "AltDA Plasma Mode") { + return altDAPlasmaModeCost; + } else { + return blobDataFee > l1CalldataFee ? l1CalldataAltCost : blobAltCost; + } +} // output = E38 + +export function resultsFeeScalarsAssumed( + comparableTxnType: string, // e15 + transactionsPerDay: number, // e14 + dataAvailabilityType: string, // E16 + targetDataMargin: number, // E18 + isStateEnabled: string, // E24 + maxChannelDuration: number // E22 +): string { + const n25: number = calculateBlobLevelImpliedBlobFullness( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ) // n25 + + const n26: number = calculateImpliedBlobsPerL1Tx( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); // n26 + const mode = + dataAvailabilityType === "AltDA Plasma Mode" + ? "AltDA Plasma Mode, " + : `${Math.round(n25 * 100)}% Blob Fullness and ${ + Math.round(n26 * 10) / 10 + } Blobs per L1 Tx (Avg), `; + const state = isStateEnabled === "Yes" ? " & State" : ""; + return `Fee Scalars Assume: ${mode}Target a ${Math.round( + targetDataMargin + )}% Margin on DA${state}, ${ + Math.round(maxChannelDuration * 100000) / 100000 + } hour Max Submission Window.`; +} // output = G41 + +export async function impliedDataGasFee( + dataAvailabilityType: string, // E16 +): Promise { + const blobgasBaseFee: number = await getBlobBaseFee()// E78 + const l1BaseFee: number = await getL1GasBaseFee(); // E76 + const ethToUsdRate: number = await getEthToUsdRate() // E77 + const mode = + dataAvailabilityType === "AltDA Plasma Mode" + ? "AltDA Plasma Mode, " + : `${Math.round(blobgasBaseFee * 100) / 100} gwei Blobgas Base Fee, `; + return `Implied Data Gas Fee Assumes: ${mode}${ + Math.round(l1BaseFee * 10) / 10 + } gwei L1 Base Fee, ${Math.round(ethToUsdRate)} ETH/USD`; +} // output = G42 + +export function convertToMillionUnits(value: number): number { + return value / 1000000; +} + +export async function getEthToUsdRate(): Promise { + try { + const response = await fetch(ethToUsdRate); + if (!response.ok) { + throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`); + } + const rateText = await response.text(); + const rate = parseFloat(rateText); + if (isNaN(rate)) { + throw new Error(`Failed to parse ETH to USD rate: ${rateText}`); + } + return rate; + } catch (error) { + console.error('Error fetching ETH to USD rate:', error); + throw error; + } +} + +export const determineDAInUse = (dataAvailabilityType: string): string => { + return dataAvailabilityType === "AltDA Plasma Mode" + ? "AltDA Plasma Mode" + : dataAvailabilityType === "L1 Calldata" + ? "L1 Calldata" + : "EIP-4844"; +}; + +// =INDEX($A$20:$G$32,MATCH('Chain Estimator'!$E$15,$A$20:$A$32,0),MATCH($B8,$A$20:$G$20,0)) +const getAvgEstimatedSizePerTx = (comparableTxnType: string) => { + if (!transactionTypes[comparableTxnType]) { + throw new Error(`Invalid transaction type: ${comparableTxnType}`); + } + const output = transactionTypes[comparableTxnType].AvgEstimatedSizePerTx; + console.log("c8::", output); + return output; +}; // c8 done + +// =(N22*N5)/(C8*'Chain Estimator'!E14) +const calculateImpliedCTSL1Data = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n22 = calculateImpliedBlobsPerDay( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const n5 = Total_Blobgas_Per_Blob; + const output = (n22 * n5) / (c8 * transactionsPerDay); ; + console.log("c10::", output); + return output; +}; // c10 done + +// =(C8*'Chain Estimator'!E14*C13 + N11*N27)/(C8*'Chain Estimator'!E14) +const calculateImpliedCTSL1Gas = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const c13 = getEstimatedSizeCalldataGasRatio(comparableTxnType); + const n27 = calculateImpliedL1Txs( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const numerator = + c8 * transactionsPerDay * c13 + Avg_Compressed_Overhead_Gas_Per_Blob * n27; + const denominator = c8 * transactionsPerDay; + const output = numerator / denominator; + console.log("c11::", output); + return output; +}; // c11 done + +// =INDEX($A$20:$G$32,MATCH('Chain Estimator'!$E$15,$A$20:$A$32,0),MATCH($B12,$A$20:$G$20,0)) +const getEstimatedSizeBlobgasRatio = (comparableTxnType: string) => { + const output = transactionTypes[comparableTxnType].EstimatedSizeBlobgasRatio; + console.log("c12::", output); + return output; +}; // c12 done + +const getEstimatedSizeCalldataGasRatio = (comparableTxnType: string) => { + const output = + transactionTypes[comparableTxnType].EstimatedSizeCalldataGasRatio; + console.log("c13::", output); + return output; +}; // c13 done + +// =24/'Chain Estimator'!E22 +const calculateImpliedMinimumBlobsPerDay = ( + maxChannelDuration: number +) => { + const output = 24 / maxChannelDuration; + console.log("n19::", output); + return output; +}; // n19 + +// =(N5-N10-N6)*C12 +const calculateImpliedEstimatedSizePerBlob = ( + comparableTxnType: string +): number => { + const c12 = getEstimatedSizeBlobgasRatio(comparableTxnType); + const output = + (Total_Blobgas_Per_Blob - + Avg_Compressed_Overhead_Bytes_Per_Blob - + Overhead_Blobgas_per_Blob) * + c12; + console.log("n20::", output); + return output; +}; // n20 done + +// =MIN(N20/C8,'Chain Estimator'!E14/(24/'Chain Estimator'!E22)) +const calculateImpliedL2TxsPerBlob = ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const n20 = calculateImpliedEstimatedSizePerBlob(comparableTxnType); + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const value1 = n20 / c8; + const value2 = transactionsPerDay / (24 / maxChannelDuration); + const output = Math.min(value1, value2); + console.log("n21::", output); + return output; +}; // n21 done + +// ='Chain Estimator'!E14/N21 +const calculateImpliedBlobsPerDay = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const output = + transactionsPerDay / + calculateImpliedL2TxsPerBlob( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); + console.log("n22::", output); + return output; +}; // n22 done + +// =N20*N22*(C11/16)+(N11*N22) +const calculateImpliedCalldataGasUsedIfL1 = ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const n20 = calculateImpliedEstimatedSizePerBlob(comparableTxnType); + const n22 = calculateImpliedBlobsPerDay( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const c11 = calculateImpliedCTSL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const output = + n20 * n22 * (c11 / 16) + (Avg_Compressed_Overhead_Gas_Per_Blob * n22); + console.log("n23::", output); + return output; +}; // n23 done + +// =MIN(N9,(C8*'Chain Estimator'!E14)*('Chain Estimator'!E22/24)/N20) +const calculateL1TxLevelImpliedBlobFullness = ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const c8 = getEstimatedSizeCalldataGasRatio(comparableTxnType); + const n20 = calculateImpliedEstimatedSizePerBlob(comparableTxnType); + const result = (c8 * transactionsPerDay * (maxChannelDuration / 24)) / n20; + const output = Math.min(Max_No_Of_Blobs_Per_L1_Transaction, result); + console.log("n24::", output); + return output; +}; // n24 done + +// =(N21*C8)/N20 +const calculateBlobLevelImpliedBlobFullness = ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const n21 = calculateImpliedL2TxsPerBlob( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const n20 = calculateImpliedEstimatedSizePerBlob(comparableTxnType); + const output = (n21 * c8) / n20; + console.log("n25::", output); + return output; +}; // n25 done + +// =ROUND(MAX(N24/1,1),0) +const calculateImpliedBlobsPerL1Tx = ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const n24 = calculateL1TxLevelImpliedBlobFullness( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); + const maxValue = Math.max(n24, 1); + const output = Math.round(maxValue); + console.log("n26::", output); + return output; +}; // n26 done + +// =N22/N26 +const calculateImpliedL1Txs = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n22 = calculateImpliedBlobsPerDay( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const n26 = calculateImpliedBlobsPerL1Tx( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); + const output = n22 / n26; + console.log("n27::", output); + return output; +}; // n27 done + +// =N27*N7 +const calculateTotalBlobCommitmentL1Gas = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n27 = calculateImpliedL1Txs( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const output = n27 * L1_Gas_per_Blob_Commitment; + console.log("n30::", output); + return output; +}; // n30 done + +// =N22*N8 +const calculateTotalAltDAPlasmaModeCommitmentL1Gas = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n22 = calculateImpliedBlobsPerDay( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const output = n22 * L1_Gas_Per_AltDA_Plasma_Mode_Commitment; + console.log("n31::", output); + return output; +}; // n31 done + +// N22 * N5 +const calculateTotalBlobgas = ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n22 = calculateImpliedBlobsPerDay( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const output = n22 * Total_Blobgas_Per_Blob; + console.log("n32::", output) + return output; +}; // n32 + +// =IF('Chain Estimator'!E23=0,0,24/'Chain Estimator'!E23) +const calculateImpliedStateProposalsPerDay = ( + outputRootPostFrequency: number +) => { + const output = + outputRootPostFrequency === 0 ? 0 : 24 / outputRootPostFrequency; + console.log("n33::", output); + return output; +}; // n33 done + +// =N33*IF('Chain Estimator'!E17="Yes",N16,N12) +const calculateTotalStateProposalL1Gas = ( + outputRootPostFrequency: number, + isFaultProofsEnabled: boolean +): number => { + const n33 = calculateImpliedStateProposalsPerDay(outputRootPostFrequency); + const output = + n33 * + (isFaultProofsEnabled + ? Avg_Total_Gas_Used_Per_L1_Fault_Proof_State_Proposal + : Avg_Total_Gas_Used_Per_L1_State_Proposal); + console.log("n34::", output); + return output; +}; // n34 done + +// =IF('Chain Estimator'!E24="Yes",1,0)*N34 +const calculateTotalStateProposalL1GasCoveredByUsers = ( + isStateEnabled: boolean, + outputRootPostFrequency: number, + isFaultProofsEnabled: boolean +) => { + const n34 = calculateTotalStateProposalL1Gas( + outputRootPostFrequency, + isFaultProofsEnabled + ); + const output = (isStateEnabled ? 1 : 0) * n34; + console.log("n35::", output); + return output; +}; // n35 done + +// =N30*'Chain Estimator'!E76/1000000000 +const calculateTotalBlobCommitmentCostsInETH = async ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n30 = calculateTotalBlobCommitmentL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const e76 = await getL1GasBaseFee(); + const output = (n30 * e76) / 1000000000; + console.log("n36::", output) + return output; +} // n36 + +// =N31*'Chain Estimator'!E76/1000000000 +const calculateTotalAltDAPlasmaModeCommitmentCostsInETH = async ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n31 = calculateTotalAltDAPlasmaModeCommitmentL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const e76 = await getL1GasBaseFee(); + const output = n31 * e76 / 1000000000; + console.log("n37::", output) + return output; +} // n37 done + +// =N32*'Chain Estimator'!E78/1000000000 +const calculateTotalBlobgasCostsInETH = async ( + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +) => { + const n32 = calculateTotalBlobgas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const e78 = await getBlobBaseFee(); + const output = (n32 * e78) / 1000000000; + console.log("n38::", output); + return output; +} // n38 + +// =N23*'Chain Estimator'!E76/1000000000 +const calculateTotalL1CalldataCostsInETHIfL1 = async ( + comparableTxnType: string, + transactionsPerDay: number, + maxChannelDuration: number +) => { + const n23 = calculateImpliedCalldataGasUsedIfL1( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ) + const e76 = await getL1GasBaseFee(); + const output = (n23 * e76) / 1000000000; + console.log("n39::", output); + return output; +} // n39 + +const _calculateL1BlobBaseFeeScalar = ( + determinedDAInUse: string, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number +) => { + let output = 0; + const c10 = calculateImpliedCTSL1Data( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const n25 = calculateBlobLevelImpliedBlobFullness( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ); + const e18 = _targetDataMarginInPercentage(targetDataMargin); + if (determinedDAInUse === "EIP-4844") { + output = (c10 / n25 / (1 - e18)) * 1000000; + } + + console.log("_calculateL1BlobBaseFeeScalar:::", output); + return Math.round(output); +}; + +async function getL1GasBaseFee(): Promise { + try { + const response = await fetch(L1GasBaseFee); + if (!response.ok) { + throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`); + } + const baseFeeText = await response.text(); + console.log("L1GasBaseFee_response::", baseFeeText); + const output = parseFloat(baseFeeText); + if (isNaN(output)) { + throw new Error(`Failed to parse L1 Gas Base Fee: ${baseFeeText}`); + } + console.log("e76:::", output); + return output; + } catch (error) { + console.error('Error fetching L1 Gas Base Fee:', error); + throw error; + } +} + +const getBlobBaseFee = async (): Promise => { + try { + const response = await fetch(blobBaseFee); + if (!response.ok) { + throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`); + } + const feeText = await response.text(); + console.log("BlobBaseFee_response::", feeText); + const output = parseFloat(feeText); + if (isNaN(output)) { + throw new Error(`Failed to parse Blob Base Fee: ${feeText}`); + } + console.log("e78:::", output); + return output; + } catch (error) { + console.error('Error fetching Blob Base Fee:', error); + throw error; + } +}; + +// =ROUND((('Advanced Inputs'!C10/'Advanced Inputs'!N25/(1-E18))*1000000),0) +const calculateL1BlobBaseFeeScalarUsingBlob = ( + determinedDAInUse: string, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number +) => { + const output = _calculateL1BlobBaseFeeScalar( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + console.log("e94:::", output); + return output; +}; // e94 done + +const calculateL1BlobBaseFeeScalarUsingL1Calldata = ( + determinedDAInUse: string, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number +) => { + const output = _calculateL1BlobBaseFeeScalar( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + console.log("e96::", output); + return output; +}; // e96 done + +const calculateL1BlobBaseFeeScalarUsingPlasmaMode = ( + determinedDAInUse: string, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number +) => { + const output = _calculateL1BlobBaseFeeScalar( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + console.log("e98::", output); + return output; +}; // e98 done + +const calculateL1BaseFeeScalarUsingBlobs = ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number +) => { + const n30 = calculateTotalBlobCommitmentL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const n35 = calculateTotalStateProposalL1GasCoveredByUsers( + isStateEnabled, + outputRootPostFrequency, + isFaultProofsEnabled + ); + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const e18 = _targetDataMarginInPercentage(targetDataMargin); + const numerator = n30 + n35; + const denominator = transactionsPerDay * (16 * c8); + const result = numerator / denominator / (1 - e18); + return Math.round(result * 1000000); +}; // f94 done + +const calculateL1BaseFeeScalarUsingL1Calldata = ( + targetDataMargin: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +): number => { + const e18 = _targetDataMarginInPercentage(targetDataMargin); + const c11 = calculateImpliedCTSL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const value = c11 / 16 / (1 - e18); + const output = Math.round(value * 1000000); + console.log("f96::", output) + return output +}; // f96 done + +const calculateL1BaseFeeScalarUsingPlasmaMode = ( + targetDataMargin: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + isStateEnabled: boolean, + outputRootPostFrequency: number, + isFaultProofsEnabled: boolean +) => { + const n31 = calculateTotalAltDAPlasmaModeCommitmentL1Gas( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const n35 = calculateTotalStateProposalL1GasCoveredByUsers( + isStateEnabled, + outputRootPostFrequency, + isFaultProofsEnabled + ); + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const e18 = _targetDataMarginInPercentage(targetDataMargin); + const value = (n31 + n35) / (transactionsPerDay * (16 * c8)) / (1 - e18); + const output = Math.round(value * 1000000); + console.log("f98::", output); + return output; +}; // f98 done + +const _targetDataMarginInPercentage = (targetDataMargin: number): number => { + return targetDataMargin / 100; +}; + +const _getCalculateImpliedDataGasFeePerTxParams = async ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number, + dataAvailabilityType: string +) => { + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const f94 = calculateL1BaseFeeScalarUsingBlobs( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const f96 = calculateL1BaseFeeScalarUsingL1Calldata( + targetDataMargin, + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const e76 = await getL1GasBaseFee(); + const determinedDAInUse = determineDAInUse(dataAvailabilityType); + const e94 = calculateL1BlobBaseFeeScalarUsingBlob( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const e96 = calculateL1BlobBaseFeeScalarUsingL1Calldata( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const e78 = await getBlobBaseFee(); + const e77 = await getEthToUsdRate(); + return { c8, e76, e77, e78, e94, e96, f94, f96 }; +}; + +const _getBaseFeeScalarCalculationParams = async ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number, + dataAvailabilityType: string +) => { + const determinedDAInUse = determineDAInUse(dataAvailabilityType); + const e98 = calculateL1BlobBaseFeeScalarUsingPlasmaMode( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const e64 = await calculateImpliedDataGasFeePerTxUsingBlobs( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + dataAvailabilityType, + targetDataMargin + ); + const e67 = await calculateImpliedDataGasFeePerTxUsingL1Calldata( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + dataAvailabilityType, + targetDataMargin + ); + const e96 = calculateL1BlobBaseFeeScalarUsingL1Calldata( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const e94 = calculateL1BlobBaseFeeScalarUsingBlob( + determinedDAInUse, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const f94 = calculateL1BaseFeeScalarUsingBlobs( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin + ); + const f96 = calculateL1BaseFeeScalarUsingL1Calldata( + targetDataMargin, + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const f98 = calculateL1BaseFeeScalarUsingPlasmaMode( + targetDataMargin, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + isStateEnabled, + outputRootPostFrequency, + isFaultProofsEnabled + ); + return { e98, e64, e67, e96, e94, f94, f96, f98 }; +}; + +export const calculateImpliedDataGasFeePerTxUsingBlobs = async ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + dataAvailabilityType: string, + targetDataMargin: number +) => { + const { c8, f94, e76, e77, e78, e94 } = + await _getCalculateImpliedDataGasFeePerTxParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + const value = (c8 * (16 * f94 * e76 + e94 * e78)) / 1000000 / 1000000000; + const output = value * e77; + console.log("e64::", output) + return output +}; // e64 done + +// =('Advanced Inputs'!C8*(16*F98*E76+E98*E78)/1000000/1000000000)*E77 +export const calculateImpliedDataGasFeePerTxUsingAltDAPlasmaMode = async ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + dataAvailabilityType: string, + targetDataMargin: number +) => { + const { c8, e76, e77, e78} = + await _getCalculateImpliedDataGasFeePerTxParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + const { f98, e98 } = await _getBaseFeeScalarCalculationParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + + const part1 = 16 * f98 * e76; + const part2 = e98 * e78; + const sum = part1 + part2; + const result = sum / 1000000 / 1000000000; + const output = c8 * result * e77; + console.log("e66::", output); + return output; +}; // e66 + +export const calculateImpliedDataGasFeePerTxUsingL1Calldata = async ( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + dataAvailabilityType: string, + targetDataMargin: number +) => { + const { c8, f96, e76, e77, e78, e96 } = + await _getCalculateImpliedDataGasFeePerTxParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + const value = (c8 * (16 * f96 * e76 + e96 * e78)) / 1000000 / 1000000000; + const output = value * e77; + console.log("e67::", output); + return output; +}; // e67 done + +// =N34*'Chain Estimator'!E76/1000000000 +export const calculateTotalL1StateProposalCostsInETH = async ( + outputRootPostFrequency: number, + isFaultProofsEnabled: boolean +) => { + const n34 = calculateTotalStateProposalL1Gas( + outputRootPostFrequency, + isFaultProofsEnabled + ); + const e76 = await getL1GasBaseFee(); + const output = (n34 * e76) / 1000000000; + console.log("n40::", output) + return output; +}; // n40 done + +export async function displayL1BlobBaseFeeScalar( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + dataAvailabilityType: string, + targetDataMargin: number +) { + const { e98, e64, e67, e96, e94 } = await _getBaseFeeScalarCalculationParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + return calculateBlobTransactionCost( + dataAvailabilityType, + e98, + e64, + e67, + e96, + e94 + ); +} // e37 done + +export async function displayL1BaseFeeScalar( + isStateEnabled: boolean, + isFaultProofsEnabled: boolean, + outputRootPostFrequency: number, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string, + targetDataMargin: number, + dataAvailabilityType: string +) { + const { f98, e64, e67, f96, f94 } = await _getBaseFeeScalarCalculationParams( + isStateEnabled, + isFaultProofsEnabled, + outputRootPostFrequency, + transactionsPerDay, + maxChannelDuration, + comparableTxnType, + targetDataMargin, + dataAvailabilityType + ); + return calculateAltDAOrL1TransactionCost(dataAvailabilityType, f98, e64, e67, f96, f94); +} // e38 done + +// =E118-(E56+E55) | OverallL1DataAndStateCostsMargin +export const calculateOverallL1DataAndStateCostsMargin = async ( + transactionsPerDay: number, + comparableTxnType: string, + displayL1BlobBaseFeeScalar: number, + displayL1BaseFeeScalar: number, + dataAvailabilityType: string, + maxChannelDuration: number, + outputRootPostFrequency: number, + isFaultProofsEnabled: boolean +) => { + const e118 = await calculateModeledDAPlusStateRevenueOnL2(transactionsPerDay, comparableTxnType, displayL1BlobBaseFeeScalar, displayL1BaseFeeScalar) + const e55 = await calculateModeledDACostsOnL1( + dataAvailabilityType, + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const e56 = await calculateTotalL1StateProposalCostsInETH( + outputRootPostFrequency, + isFaultProofsEnabled + ) + const output = e118 - (e56 + e55); + console.log("e58::", output); + return output; +} // e58 + +// =(E14*'Advanced Inputs'!C8*(16*G38*E76/1000000000+G37*E78/1000000000)) +export const calculateModeledDAPlusStateRevenueOnL2 = async ( + transactionsPerDay: number, + comparableTxnType: string, + displayL1BlobBaseFeeScalar: number, + displayL1BaseFeeScalar: number +) => { + const c8 = getAvgEstimatedSizePerTx(comparableTxnType); + const g38 = convertToMillionUnits(displayL1BaseFeeScalar); + const g37 = convertToMillionUnits(displayL1BlobBaseFeeScalar); + const e76 = await getL1GasBaseFee(); + const e78 = await getBlobBaseFee(); + const part1 = (16 * g38 * e76) / 1000000000; + const part2 = (g37 * e78) / 1000000000; + const output = transactionsPerDay * c8 * (part1 + part2); + console.log("e118::", output) + return output +} // e118 + +async function calculateModeledDACostsOnL1( + dataAvailabilityType: string, + transactionsPerDay: number, + maxChannelDuration: number, + comparableTxnType: string +): Promise { + let output = 0; + const f35 = determineDAInUse(dataAvailabilityType); + const n36 = await calculateTotalBlobCommitmentCostsInETH( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ); + const n37 = await calculateTotalAltDAPlasmaModeCommitmentCostsInETH( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const n38 = await calculateTotalBlobgasCostsInETH( + transactionsPerDay, + maxChannelDuration, + comparableTxnType + ) + const n39 = await calculateTotalL1CalldataCostsInETHIfL1( + comparableTxnType, + transactionsPerDay, + maxChannelDuration + ) + if (dataAvailabilityType === "AltDA Plasma Mode") { + output = n37; + } else if (f35 === "EIP-4844") { + output = n36 + n38; + } else { + output = n39; + } + console.log("e119::", output) + return output +} // e119 + + +export const Total_Blobgas_Per_Blob = 131072; // N5 +export const Overhead_Blobgas_per_Blob = 1028; // N6 +export const L1_Gas_per_Blob_Commitment = 21000.0; // N7 +export const L1_Gas_Per_AltDA_Plasma_Mode_Commitment = 21532.0; // N8 +export const Max_No_Of_Blobs_Per_L1_Transaction = 5; // N9 +export const Avg_Compressed_Overhead_Bytes_Per_Blob = 406; // N10 +export const Avg_Compressed_Overhead_Gas_Per_Blob = 6385; // N11 +export const Avg_Total_Gas_Used_Per_L1_State_Proposal = 86847.5; // N12 +export const FastLZ_Intercept = -42585600; // N13 +export const FastLZ_Coefficient = 836500; // N14 +export const FatLZ_Min_Transaction_Size = 100; // N15 +export const Avg_Total_Gas_Used_Per_L1_Fault_Proof_State_Proposal = 420926.0; // N16 \ No newline at end of file diff --git a/utils/transaction-types.ts b/utils/transaction-types.ts new file mode 100644 index 000000000..70f154ad6 --- /dev/null +++ b/utils/transaction-types.ts @@ -0,0 +1,50 @@ +export const transactionTypes = { + "General OP Mainnet": { + TransactionsPerDay: 489109, + AvgCalldataBytesPerTx: 1007.8, + AvgEstimatedSizePerTx: 474.6, + AvgBlobgasPerL2Tx: 361.6153521, + EstimatedSizeBlobgasRatio: 1.313, + EstimatedSizeCalldataGasRatio: 21.0, + }, + Base: { + TransactionsPerDay: 3227633, + AvgCalldataBytesPerTx: 632.3006064, + AvgEstimatedSizePerTx: 368.6, + AvgBlobgasPerL2Tx: 168.0497343, + EstimatedSizeBlobgasRatio: 2.193, + EstimatedSizeCalldataGasRatio: 35.09, + }, + Mode: { + TransactionsPerDay: 123889, + AvgCalldataBytesPerTx: 131.8318268, + AvgEstimatedSizePerTx: 144.3, + AvgBlobgasPerL2Tx: 102.9448416, + EstimatedSizeBlobgasRatio: 1.402, + EstimatedSizeCalldataGasRatio: 22.43, + }, + Zora: { + TransactionsPerDay: 126719, + AvgCalldataBytesPerTx: 318.8965479, + AvgEstimatedSizePerTx: 174.6, + AvgBlobgasPerL2Tx: 121.6317714, + EstimatedSizeBlobgasRatio: 1.435, + EstimatedSizeCalldataGasRatio: 22.96, + }, + Mint: { + TransactionsPerDay: 6341, + AvgCalldataBytesPerTx: 274.5535557, + AvgEstimatedSizePerTx: 206.9, + AvgBlobgasPerL2Tx: 317.11, + EstimatedSizeBlobgasRatio: 0.65, + EstimatedSizeCalldataGasRatio: 10.44, + }, + Metal: { + TransactionsPerDay: 430, + AvgCalldataBytesPerTx: 296.1833811, + AvgEstimatedSizePerTx: 237.2, + AvgBlobgasPerL2Tx: 947549.16, + EstimatedSizeBlobgasRatio: 0.0, + EstimatedSizeCalldataGasRatio: 0.0, + }, +};