Skip to content

Commit 9c569f8

Browse files
authored
Merge pull request #931 from blahkheart/embed-calculator
Embed calculator
2 parents 533e797 + 1de7b51 commit 9c569f8

18 files changed

+2109
-65
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
import type { ReactElement } from "react";
2+
import { useState } from "react";
3+
import { TextInput, SelectInput } from "./Inputs";
4+
import { ResultsParams, ResultsTable } from "./ResultsTable";
5+
import {
6+
displayL1BaseFeeScalar,
7+
displayL1BlobBaseFeeScalar,
8+
calculateOverallL1DataAndStateCostsMargin,
9+
calculateModeledDAPlusStateRevenueOnL2,
10+
calculateTotalL1StateProposalCostsInETH,
11+
determineDAInUse,
12+
calculateImpliedDataGasFeePerTxUsingBlobs,
13+
calculateImpliedDataGasFeePerTxUsingL1Calldata,
14+
calculateImpliedDataGasFeePerTxUsingAltDAPlasmaMode,
15+
resultsFeeScalarsAssumed,
16+
impliedDataGasFee
17+
} from "@/utils/calculator-helpers";
18+
import { Loader } from "./Loader";
19+
20+
type ComparableTransactionType = "Base" | "Zora" | "Mint" | "Mode";
21+
type DataAvailabilityType = "Ethereum" | "AltDA Plasma Mode";
22+
23+
export function ChainParametersForm(): ReactElement {
24+
const [transactionsPerDay, setTransactionsPerDay] = useState(500000);
25+
const [comparableTransactionType, setComparableTransactionType] =
26+
useState<ComparableTransactionType>("General OP Mainnet");
27+
const [dataAvailabilityType, setDataAvailabilityType] = useState<DataAvailabilityType>("Ethereum");
28+
const [isFaultProofEnabled, setIsFaultProofEnabled] = useState("yes");
29+
const [targetDataFeeMargin, setTargetDataFeeMargin] = useState(5);
30+
const [maxBlobsPerL1Transaction, setMaxBlobsPerL1Transaction] = useState(5);
31+
const [maxChannelDuration, setMaxChannelDuration] = useState(5);
32+
const [outputRootPostFrequency, setOutputRootPostFrequency] = useState(1 );
33+
const [isIncludeOutputRootCosts, setIsIncludeOutputRootCosts] = useState("yes");
34+
const [resultsParams, setResultsParams] = useState<ResultsParams>({});
35+
const [isLoading, setIsLoading] = useState(false);
36+
const [showResult, setShowResult] = useState(false);
37+
38+
const comparableTransactionTypeOptions = [
39+
"General OP Mainnet",
40+
"Base",
41+
"Zora",
42+
"Mint",
43+
"Mode",
44+
];
45+
const dataAvailabilityTypeOptions = ["Ethereum", "AltDA Plasma Mode"];
46+
const booleanOptions = ["Yes", "No"];
47+
48+
const handleSubmit = async (e: any) => {
49+
e.preventDefault();
50+
setIsLoading(true);
51+
setShowResult(false)
52+
53+
//e37
54+
const l1BlobBaseFeeScalar = await displayL1BlobBaseFeeScalar(
55+
stringToBoolean(isIncludeOutputRootCosts),
56+
stringToBoolean(isFaultProofEnabled),
57+
outputRootPostFrequency,
58+
transactionsPerDay,
59+
maxChannelDuration,
60+
comparableTransactionType,
61+
dataAvailabilityType,
62+
targetDataFeeMargin
63+
);
64+
65+
//e38
66+
const l1BaseFeeScalar = await displayL1BaseFeeScalar(
67+
isIncludeOutputRootCosts,
68+
isFaultProofEnabled,
69+
outputRootPostFrequency,
70+
transactionsPerDay,
71+
maxChannelDuration,
72+
comparableTransactionType,
73+
targetDataFeeMargin,
74+
dataAvailabilityType
75+
);
76+
77+
// e58
78+
const overallL1DataAndStateCostsMargin =
79+
await calculateOverallL1DataAndStateCostsMargin(
80+
transactionsPerDay,
81+
comparableTransactionType,
82+
l1BlobBaseFeeScalar,
83+
l1BaseFeeScalar,
84+
dataAvailabilityType,
85+
maxChannelDuration,
86+
outputRootPostFrequency,
87+
isFaultProofEnabled
88+
);
89+
90+
//e56
91+
const totalL1StateProposalCostsInETH =
92+
await calculateTotalL1StateProposalCostsInETH(
93+
outputRootPostFrequency,
94+
isFaultProofEnabled
95+
);
96+
97+
// e118
98+
const modeledDAPlusStateRevenueOnL2 =
99+
await calculateModeledDAPlusStateRevenueOnL2(
100+
transactionsPerDay,
101+
comparableTransactionType,
102+
l1BlobBaseFeeScalar,
103+
l1BaseFeeScalar
104+
);
105+
106+
// e64
107+
const impliedDataGasFeePerTxUsingBlobs =
108+
await calculateImpliedDataGasFeePerTxUsingBlobs(
109+
isIncludeOutputRootCosts,
110+
isFaultProofEnabled,
111+
outputRootPostFrequency,
112+
transactionsPerDay,
113+
maxChannelDuration,
114+
comparableTransactionType,
115+
dataAvailabilityType,
116+
targetDataFeeMargin
117+
);
118+
119+
// e67
120+
const impliedDataGasFeePerTxUsingL1Calldata =
121+
await calculateImpliedDataGasFeePerTxUsingL1Calldata(
122+
isIncludeOutputRootCosts,
123+
isFaultProofEnabled,
124+
outputRootPostFrequency,
125+
transactionsPerDay,
126+
maxChannelDuration,
127+
comparableTransactionType,
128+
dataAvailabilityType,
129+
targetDataFeeMargin
130+
);
131+
132+
// e66
133+
const impliedDataGasFeePerTxUsingAltDAPlasmaMode =
134+
await calculateImpliedDataGasFeePerTxUsingAltDAPlasmaMode(
135+
isIncludeOutputRootCosts,
136+
isFaultProofEnabled,
137+
outputRootPostFrequency,
138+
transactionsPerDay,
139+
maxChannelDuration,
140+
comparableTransactionType,
141+
dataAvailabilityType,
142+
targetDataFeeMargin
143+
);
144+
145+
const dataAvailabilityInUse = determineDAInUse(dataAvailabilityType);
146+
147+
const assumedFeeScalarMessage = resultsFeeScalarsAssumed(
148+
comparableTransactionType, // e15
149+
transactionsPerDay, // e14
150+
dataAvailabilityType, // E16
151+
targetDataFeeMargin, // E18
152+
isIncludeOutputRootCosts, // E24
153+
maxChannelDuration // E22
154+
);
155+
const impliedDataGasFeeMessage = await impliedDataGasFee(dataAvailabilityType)
156+
157+
const data = {
158+
dataAvailabilityType, // e16
159+
l1BlobBaseFeeScalar, // e37
160+
l1BaseFeeScalar, // e38
161+
overallL1DataAndStateCostsMargin, // e58
162+
totalL1StateProposalCostsInETH, // e56
163+
modeledDAPlusStateRevenueOnL2, // e118
164+
dataAvailabilityInUse, // F35
165+
impliedDataGasFeePerTxUsingBlobs, // e64
166+
impliedDataGasFeePerTxUsingL1Calldata, // e67
167+
impliedDataGasFeePerTxUsingAltDAPlasmaMode, // e66
168+
assumedFeeScalarMessage,
169+
impliedDataGasFeeMessage,
170+
};
171+
setResultsParams(data);
172+
setIsLoading(false);
173+
setShowResult(true)
174+
};
175+
176+
const stringToBoolean = (value: string): boolean => {
177+
return value === "yes" || value === "Yes" ? true : false;
178+
}
179+
180+
return (
181+
<div>
182+
<form className="calculator-form" onSubmit={handleSubmit}>
183+
<div className="calculator-chain-inputs">
184+
<h2 className="calculator-heading_sub">Chain Inputs</h2>
185+
<TextInput
186+
otherProps={{ value: transactionsPerDay }}
187+
onInputChange={setTransactionsPerDay}
188+
labelClass="calculator-label"
189+
description="Txs / Day, excluding Internal system transactions"
190+
type="number"
191+
className="calculator-input mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
192+
label="Transactions per Day"
193+
/>
194+
195+
<SelectInput
196+
labelClass="calculator-label"
197+
data={comparableTransactionTypeOptions}
198+
onSelect={setComparableTransactionType}
199+
description="What are the transaction types are similar to"
200+
className="calculator-select t-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
201+
label="Comparable Transaction Type"
202+
/>
203+
204+
<SelectInput
205+
labelClass="calculator-label"
206+
data={dataAvailabilityTypeOptions}
207+
onSelect={setDataAvailabilityType}
208+
description="Ethereum (Blobs or Calldata) or AltDA Plasma Mode (Alt-DA)"
209+
className="calculator-select t-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
210+
label="Data Availability Type"
211+
/>
212+
213+
<SelectInput
214+
labelClass="calculator-label"
215+
data={booleanOptions}
216+
onSelect={setIsFaultProofEnabled}
217+
description="Are Fault Proofs enabled on the chain? (Note: Ethereum DA Only)"
218+
className="calculator-select t-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
219+
label="Fault Proofs Enabled"
220+
/>
221+
222+
<TextInput
223+
otherProps={{ value: targetDataFeeMargin }}
224+
onInputChange={setTargetDataFeeMargin}
225+
description="Buffer charged on top of L1 & Blob Data costs"
226+
labelClass="calculator-label"
227+
type="number"
228+
className="calculator-input mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
229+
label="Target Data Fee Margin"
230+
/>
231+
</div>
232+
<div className="calculator-advanced-inputs">
233+
<h2 className="calculator-heading_sub">Advanced Inputs</h2>
234+
<TextInput
235+
otherProps={{ value: maxBlobsPerL1Transaction }}
236+
onInputChange={setMaxBlobsPerL1Transaction}
237+
labelClass="calculator-label"
238+
description="Maximum amount of blobs submitted per L1 Transaction (max: 6)"
239+
type="number"
240+
className="calculator-input mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
241+
label="Max # of Blobs per L1 Transaction"
242+
/>
243+
244+
<TextInput
245+
description="Max hours are we willing to wait between batch submissions"
246+
otherProps={{ value: maxChannelDuration }}
247+
onInputChange={setMaxChannelDuration}
248+
labelClass="calculator-label"
249+
type="number"
250+
className="calculator-input mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
251+
label="op-batcher Max Channel Duration (hours)"
252+
/>
253+
<TextInput
254+
description="Hours between each state proposals on L1 (0 if chain doesn't pay)"
255+
otherProps={{ value: outputRootPostFrequency }}
256+
onInputChange={setOutputRootPostFrequency}
257+
labelClass="calculator-label"
258+
type="number"
259+
className="calculator-input mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
260+
label="Output Root Post Frequency (hours)"
261+
/>
262+
<SelectInput
263+
description="Is the cost of state/output proposals passed on to L2 users?"
264+
labelClass="calculator-label"
265+
data={booleanOptions}
266+
onSelect={setIsIncludeOutputRootCosts}
267+
className="calculator-select mt-1 sm:text-lg py-1 px-2 sm:py-2 sm:px-4"
268+
label="Include Root Costs in User Fees?"
269+
/>
270+
</div>
271+
<button className="calculator-button" type="submit">
272+
Calculate
273+
</button>
274+
</form>
275+
{isLoading && <Loader />}
276+
{!isLoading && showResult && <ResultsTable data={resultsParams} />}
277+
</div>
278+
);
279+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from "react";
2+
3+
type Props = {
4+
otherProps?: any;
5+
className?: string;
6+
label?: string;
7+
description?:string;
8+
handleToggle: (e: any) => void;
9+
};
10+
11+
export const CheckboxInput: React.FC<Props> = React.memo(
12+
({ otherProps, label, description, className, handleToggle }) => {
13+
function onCheckboxChange(e: any) {
14+
const isChecked = e.target.checked;
15+
handleToggle(isChecked);
16+
}
17+
return (
18+
<div className="flex items-center gap-2">
19+
{label && <label className="text-sm">{label}</label>}
20+
<p className="text-xs my-1">{description}</p>
21+
<input
22+
{...otherProps}
23+
type="checkbox"
24+
onChange={onCheckboxChange}
25+
className={`${className} meta-checkbox accent-custom-puple toggle bg-custom-puple`}
26+
/>
27+
</div>
28+
);
29+
}
30+
);
31+
CheckboxInput.displayName = "CheckboxInput";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import React from "react";
2+
3+
type Props = {
4+
className?: string;
5+
label?: string;
6+
data: any[];
7+
otherProps?: any;
8+
description?: string;
9+
labelClass?: string;
10+
onSelect?: (e: any) => void;
11+
};
12+
13+
export const SelectInput: React.FC<Props> = React.memo(
14+
({ className, labelClass, description, otherProps, label, data, onSelect }) => {
15+
const handleSelect = (e: any) => {
16+
const value = e.target.value
17+
onSelect(value)
18+
}
19+
return (
20+
<div className="flex flex-col ">
21+
{label && (
22+
<label className={`font-semibold text-sm md:text-xl ${labelClass}`}>
23+
{label}
24+
</label>
25+
)}
26+
<p className="text-xs my-1 calcularor-label_description">
27+
{description}
28+
</p>
29+
<div className="grid">
30+
<select
31+
{...otherProps}
32+
onChange={handleSelect}
33+
className={`${className} appearance-none row-start-1 col-start-1 focus:bg-background bg-transparent py-1 px-2 border w-full rounded-lg border-custom-puple`}
34+
>
35+
{data.map((selectValue, index) => (
36+
<option
37+
key={index}
38+
className="cursor-pointer "
39+
value={selectValue}
40+
>
41+
{selectValue}
42+
</option>
43+
))}
44+
</select>
45+
{/* <IoIosArrowDown className="place-self-end mb-3 sm:mx-4 row-start-1 col-start-1 pointer-events-none " /> */}
46+
</div>
47+
</div>
48+
);
49+
}
50+
);
51+
SelectInput.displayName = "SelectInput";

0 commit comments

Comments
 (0)