Re-structure inputs + better tooltips
This commit is contained in:
parent
f17679e651
commit
9c4de97ae3
36
src/App.tsx
36
src/App.tsx
|
|
@ -9,7 +9,8 @@ import Grid from "@material-ui/core/Grid";
|
|||
import Button from "@material-ui/core/Button";
|
||||
// Components
|
||||
import Header from "./Header";
|
||||
import InputParams from "./InputParams";
|
||||
import CurveDesignInputParams from "./CurveDesignInputParams";
|
||||
import SimulationInputParams from "./SimulationInputParams";
|
||||
import SupplyVsDemandChart from "./SupplyVsDemandChart";
|
||||
import ResultParams from "./ResultParams";
|
||||
import PriceSimulationChart from "./PriceSimulationChart";
|
||||
|
|
@ -53,8 +54,7 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||
backgroundColor: "#293640"
|
||||
},
|
||||
box: {
|
||||
padding: theme.spacing(3, 3),
|
||||
minHeight: 310
|
||||
padding: theme.spacing(3, 3)
|
||||
},
|
||||
boxButton: {
|
||||
padding: theme.spacing(3, 3)
|
||||
|
|
@ -66,6 +66,12 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||
alignItems: "center",
|
||||
borderBottom: "1px solid #313d47"
|
||||
},
|
||||
boxBorderBottom: {
|
||||
borderBottom: "1px solid #313d47"
|
||||
},
|
||||
initialRaise: {
|
||||
justifyContent: "space-between"
|
||||
},
|
||||
boxChart: {
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
|
|
@ -93,7 +99,8 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||
marginBottom: -theme.spacing(headerOffset)
|
||||
},
|
||||
button: {
|
||||
background: "linear-gradient(290deg, #2ad179, #4ab47c)",
|
||||
// background: "linear-gradient(290deg, #2ad179, #4ab47c)", // Green gradient
|
||||
background: "linear-gradient(290deg, #1880e0, #3873d8)", // blue gradient
|
||||
color: "white"
|
||||
},
|
||||
// Descriptions
|
||||
|
|
@ -170,11 +177,11 @@ const resultParameterDescriptions = [
|
|||
|
||||
export default function App() {
|
||||
const [curveParams, setCurveParams] = useState({
|
||||
d0: 1e6, // Initial raise, d0 (DAI)
|
||||
theta: 0.35, // fraction allocated to reserve (.)
|
||||
p0: 0.1, // Hatch sale price p0 (DAI / token)
|
||||
p1: 0.3, // Return factor (.)
|
||||
wFee: 0.05 // friction coefficient (.)
|
||||
wFee: 0.05, // friction coefficient (.)
|
||||
d0: 3e6 // Initial raise, d0 (DAI)
|
||||
});
|
||||
|
||||
const { d0, theta, p0, p1, wFee } = curveParams;
|
||||
|
|
@ -321,6 +328,7 @@ export default function App() {
|
|||
];
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className={classes.header}>
|
||||
|
|
@ -364,8 +372,22 @@ export default function App() {
|
|||
/>
|
||||
</Box>
|
||||
|
||||
<Box className={`${classes.box} ${classes.boxBorderBottom}`}>
|
||||
<CurveDesignInputParams
|
||||
curveParams={curveParams}
|
||||
setCurveParams={setCurveParamsThrottle}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<Box className={`${classes.boxHeader} ${classes.initialRaise}`}>
|
||||
<Typography variant="h6">Run parameters</Typography>
|
||||
</Box>
|
||||
|
||||
<Box className={classes.box}>
|
||||
<InputParams setCurveParams={setCurveParamsThrottle} />
|
||||
<SimulationInputParams
|
||||
curveParams={curveParams}
|
||||
setCurveParams={setCurveParamsThrottle}
|
||||
/>
|
||||
</Box>
|
||||
</Paper>
|
||||
</Grid>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { InputFieldInterface, CurveParamsInterface } from "./types";
|
||||
import InputParams from "./InputParams";
|
||||
|
||||
export default function CurveDesignInputParams({
|
||||
curveParams,
|
||||
setCurveParams
|
||||
}: {
|
||||
curveParams: CurveParamsInterface;
|
||||
setCurveParams(newCurveParams: any): void;
|
||||
}) {
|
||||
const [theta, setTheta] = useState(0.35); // fraction allocated to reserve (.)
|
||||
const [p0, setP0] = useState(0.1); // Hatch sale Price p0 (DAI / token)
|
||||
const [p1, setP1] = useState(0.3); // Return factor (.)
|
||||
const [wFee, setWFee] = useState(0.05); // friction coefficient (.)
|
||||
|
||||
useEffect(() => {
|
||||
setTheta(curveParams.theta);
|
||||
setP0(curveParams.p0);
|
||||
setP1(curveParams.p1);
|
||||
setWFee(curveParams.wFee);
|
||||
}, [curveParams]);
|
||||
|
||||
function _setP0(newP0: number) {
|
||||
setP0(newP0);
|
||||
if (p1 < newP0) setP1(newP0);
|
||||
else if (p1 > newP0 * maxReturnRate) setP1(newP0 * maxReturnRate);
|
||||
}
|
||||
|
||||
function setParentCurveParams() {
|
||||
setCurveParams((params: CurveParamsInterface) => ({
|
||||
...params,
|
||||
theta,
|
||||
p0,
|
||||
p1,
|
||||
wFee
|
||||
}));
|
||||
}
|
||||
|
||||
const maxReturnRate = 10;
|
||||
|
||||
const inputFields: InputFieldInterface[] = [
|
||||
{
|
||||
label: "Allocation to funding pool",
|
||||
value: theta,
|
||||
setter: setTheta,
|
||||
min: 0,
|
||||
max: 0.9,
|
||||
step: 0.01,
|
||||
unit: "%",
|
||||
suffix: "%",
|
||||
format: (n: number) => `${Math.round(100 * n)}%`,
|
||||
toText: (n: number) => String(+(n * 1e2).toFixed(0)),
|
||||
toNum: (n: string) => parseFloat(n) * 1e-2
|
||||
},
|
||||
{
|
||||
label: "Hatch price",
|
||||
value: p0,
|
||||
setter: _setP0,
|
||||
min: 0.01,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
unit: "$",
|
||||
prefix: "$",
|
||||
toText: (n: number) => String(+n.toFixed(2)),
|
||||
toNum: (n: string) => parseFloat(n),
|
||||
format: (n: number) => `$${n}`
|
||||
},
|
||||
{
|
||||
label: "Post-hatch price",
|
||||
value: p1,
|
||||
setter: setP1,
|
||||
min: p0 || 0.1,
|
||||
max: Number((maxReturnRate * p0).toFixed(2)),
|
||||
step: 0.01,
|
||||
unit: "$",
|
||||
prefix: "$",
|
||||
toText: (n: number) => String(+n.toFixed(2)),
|
||||
toNum: (n: string) => parseFloat(n),
|
||||
format: (n: number) => `$${n}`
|
||||
},
|
||||
{
|
||||
label: "Exit tribute",
|
||||
value: wFee,
|
||||
setter: setWFee,
|
||||
min: 0,
|
||||
max: 0.1,
|
||||
step: 0.001,
|
||||
unit: "%",
|
||||
suffix: "%",
|
||||
format: (n: number) => `${+(100 * n).toFixed(1)}%`,
|
||||
toText: (n: number) => String(+(n * 1e2).toFixed(1)),
|
||||
toNum: (n: string) => parseFloat(n) * 1e-2
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<InputParams
|
||||
inputFields={inputFields}
|
||||
onChangeCommited={setParentCurveParams}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,47 +1,11 @@
|
|||
import React, { useState } from "react";
|
||||
import {
|
||||
createStyles,
|
||||
makeStyles,
|
||||
withStyles,
|
||||
Theme
|
||||
} from "@material-ui/core/styles";
|
||||
import React from "react";
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||
import Typography from "@material-ui/core/Typography";
|
||||
import Slider from "@material-ui/core/Slider";
|
||||
import Grid from "@material-ui/core/Grid";
|
||||
import TextField from "@material-ui/core/TextField";
|
||||
import NumberFormat from "react-number-format";
|
||||
|
||||
const PrettoSlider = withStyles({
|
||||
root: {
|
||||
height: 8
|
||||
},
|
||||
thumb: {
|
||||
height: 24,
|
||||
width: 24,
|
||||
backgroundColor: "#fff",
|
||||
border: "2px solid currentColor",
|
||||
marginTop: -8,
|
||||
marginLeft: -12,
|
||||
"&:focus,&:hover,&$active": {
|
||||
boxShadow: "inherit"
|
||||
}
|
||||
},
|
||||
active: {},
|
||||
valueLabel: {
|
||||
left: "calc(-50% + 4px)"
|
||||
},
|
||||
track: {
|
||||
height: 8,
|
||||
borderRadius: 4
|
||||
},
|
||||
rail: {
|
||||
height: 8,
|
||||
borderRadius: 4
|
||||
},
|
||||
markLabel: {
|
||||
top: 30
|
||||
}
|
||||
})(Slider);
|
||||
import { InputFieldInterface } from "./types";
|
||||
import PrettoSlider from "./PrettoSlider";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
|
|
@ -79,6 +43,9 @@ const useStyles = makeStyles((theme: Theme) =>
|
|||
},
|
||||
slider: {
|
||||
color: theme.palette.primary.main
|
||||
},
|
||||
secondaryColor: {
|
||||
color: theme.palette.secondary.light
|
||||
}
|
||||
})
|
||||
);
|
||||
|
|
@ -101,118 +68,12 @@ function NumberFormatCustom(props: any) {
|
|||
}
|
||||
|
||||
export default function InputParams({
|
||||
curveParams,
|
||||
setCurveParams
|
||||
inputFields,
|
||||
onChangeCommited
|
||||
}: {
|
||||
curveParams?: {
|
||||
d0: number;
|
||||
theta: number;
|
||||
p0: number;
|
||||
p1: number;
|
||||
wFee: number;
|
||||
};
|
||||
setCurveParams(newCurveParams: any): void;
|
||||
inputFields: InputFieldInterface[];
|
||||
onChangeCommited(): void;
|
||||
}) {
|
||||
const [d0, setD0] = useState(1e6); // Initial raise, d0 (DAI)
|
||||
const [theta, setTheta] = useState(0.35); // fraction allocated to reserve (.)
|
||||
const [p0, setP0] = useState(0.1); // Hatch sale Price p0 (DAI / token)
|
||||
const [p1, setP1] = useState(0.3); // Return factor (.)
|
||||
const [wFee, setWFee] = useState(0.05); // friction coefficient (.)
|
||||
|
||||
function _setP0(newP0: number) {
|
||||
setP0(newP0);
|
||||
if (p1 < newP0) setP1(newP0);
|
||||
else if (p1 > newP0 * maxReturnRate) setP1(newP0 * maxReturnRate);
|
||||
}
|
||||
|
||||
function setParentCurveParams() {
|
||||
setCurveParams({ d0, theta, p0, p1, wFee });
|
||||
}
|
||||
|
||||
const maxReturnRate = 10;
|
||||
|
||||
const inputFields: {
|
||||
label: string;
|
||||
value: number;
|
||||
setter(newValue: any): void;
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
unit?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
toText?(value: number): string;
|
||||
toNum?(value: string): number;
|
||||
format(value: number): string;
|
||||
}[] = [
|
||||
{
|
||||
label: "Initial raise",
|
||||
value: d0,
|
||||
setter: setD0,
|
||||
min: 0.1e6,
|
||||
max: 10e6,
|
||||
step: 0.1e6,
|
||||
unit: "$M",
|
||||
prefix: "$",
|
||||
suffix: "M",
|
||||
format: (n: number) => `$${+(n * 1e-6).toFixed(1)}M`,
|
||||
toText: (n: number) => String(+(n * 1e-6).toFixed(1)),
|
||||
toNum: (n: string) => Math.floor(parseFloat(n) * 1e6)
|
||||
},
|
||||
{
|
||||
label: "Allocation to funding pool",
|
||||
value: theta,
|
||||
setter: setTheta,
|
||||
min: 0,
|
||||
max: 0.9,
|
||||
step: 0.01,
|
||||
unit: "%",
|
||||
suffix: "%",
|
||||
format: (n: number) => `${Math.round(100 * n)}%`,
|
||||
toText: (n: number) => String(+(n * 1e2).toFixed(0)),
|
||||
toNum: (n: string) => parseFloat(n) * 1e-2
|
||||
},
|
||||
{
|
||||
label: "Hatch price",
|
||||
value: p0,
|
||||
setter: _setP0,
|
||||
min: 0.01,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
unit: "$",
|
||||
prefix: "$",
|
||||
toText: (n: number) => String(+n.toFixed(2)),
|
||||
toNum: (n: string) => parseFloat(n),
|
||||
format: (n: number) => `$${n}`
|
||||
},
|
||||
{
|
||||
label: "Post-hatch price",
|
||||
value: p1,
|
||||
setter: setP1,
|
||||
min: p0 || 0.1,
|
||||
max: Number((maxReturnRate * p0).toFixed(2)),
|
||||
step: 0.01,
|
||||
unit: "$",
|
||||
prefix: "$",
|
||||
toText: (n: number) => String(+n.toFixed(2)),
|
||||
toNum: (n: string) => parseFloat(n),
|
||||
format: (n: number) => `$${n}`
|
||||
},
|
||||
{
|
||||
label: "Exit tribute",
|
||||
value: wFee,
|
||||
setter: setWFee,
|
||||
min: 0,
|
||||
max: 0.1,
|
||||
step: 0.001,
|
||||
unit: "%",
|
||||
suffix: "%",
|
||||
format: (n: number) => `${+(100 * n).toFixed(1)}%`,
|
||||
toText: (n: number) => String(+(n * 1e2).toFixed(1)),
|
||||
toNum: (n: string) => parseFloat(n) * 1e-2
|
||||
}
|
||||
];
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
|
|
@ -227,6 +88,7 @@ export default function InputParams({
|
|||
step,
|
||||
prefix,
|
||||
suffix,
|
||||
secondaryColor,
|
||||
format,
|
||||
toText,
|
||||
toNum
|
||||
|
|
@ -253,7 +115,7 @@ export default function InputParams({
|
|||
sanitizeInput(
|
||||
toNum ? toNum(e.target.value) : parseFloat(e.target.value)
|
||||
);
|
||||
setParentCurveParams();
|
||||
onChangeCommited();
|
||||
}}
|
||||
InputProps={{
|
||||
inputComponent: NumberFormatCustom,
|
||||
|
|
@ -269,12 +131,14 @@ export default function InputParams({
|
|||
|
||||
<Grid item xs={4}>
|
||||
<PrettoSlider
|
||||
className={classes.slider}
|
||||
className={`${classes.slider} ${
|
||||
secondaryColor ? classes.secondaryColor : ""
|
||||
}`}
|
||||
valueLabelDisplay="auto"
|
||||
aria-label={label}
|
||||
defaultValue={value}
|
||||
onChange={(_, newValue) => sanitizeInput(Number(newValue))}
|
||||
onChangeCommitted={setParentCurveParams}
|
||||
onChangeCommitted={onChangeCommited}
|
||||
value={value}
|
||||
min={min}
|
||||
max={max}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import { withStyles } from "@material-ui/core/styles";
|
||||
import Slider from "@material-ui/core/Slider";
|
||||
|
||||
export default withStyles({
|
||||
root: {
|
||||
height: 8
|
||||
},
|
||||
thumb: {
|
||||
height: 24,
|
||||
width: 24,
|
||||
backgroundColor: "#fff",
|
||||
border: "2px solid currentColor",
|
||||
marginTop: -8,
|
||||
marginLeft: -12,
|
||||
"&:focus,&:hover,&$active": {
|
||||
boxShadow: "inherit"
|
||||
}
|
||||
},
|
||||
active: {},
|
||||
valueLabel: {
|
||||
left: "calc(-50% + 4px)"
|
||||
},
|
||||
track: {
|
||||
height: 8,
|
||||
borderRadius: 4
|
||||
},
|
||||
rail: {
|
||||
height: 8,
|
||||
borderRadius: 4
|
||||
},
|
||||
markLabel: {
|
||||
top: 30
|
||||
}
|
||||
})(Slider);
|
||||
|
|
@ -10,9 +10,25 @@ import {
|
|||
ResponsiveContainer,
|
||||
Tooltip
|
||||
} from "recharts";
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||
import { useTheme } from "@material-ui/styles";
|
||||
import { linspace } from "./utils";
|
||||
|
||||
const keyHorizontal = "x";
|
||||
const keyVerticalLeft = "Price (DAI/token)";
|
||||
const keyVerticalRight = "Total exit tributes (DAI)";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
tooltip: {
|
||||
border: "1px solid #313d47",
|
||||
backgroundColor: "#384b59",
|
||||
padding: theme.spacing(1),
|
||||
color: "#c7ccd2"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
function PriceSimulationChart({
|
||||
priceTimeseries,
|
||||
withdrawFeeTimeseries,
|
||||
|
|
@ -30,10 +46,6 @@ function PriceSimulationChart({
|
|||
// returnF - Return factor (.)
|
||||
// wFee - friction coefficient (.)
|
||||
|
||||
const keyHorizontal = "x";
|
||||
const keyVerticalLeft = "Price (DAI / token)";
|
||||
const keyVerticalRight = "Total exit tributes (DAI)";
|
||||
|
||||
const data = [];
|
||||
for (let t = 0; t < priceTimeseries.length; t++) {
|
||||
data.push({
|
||||
|
|
@ -46,6 +58,7 @@ function PriceSimulationChart({
|
|||
// Chart components
|
||||
|
||||
const theme: any = useTheme();
|
||||
const classes = useStyles();
|
||||
|
||||
function renderColorfulLegendText(value: string) {
|
||||
return <span style={{ color: theme.palette.text.secondary }}>{value}</span>;
|
||||
|
|
@ -67,6 +80,35 @@ function PriceSimulationChart({
|
|||
);
|
||||
}
|
||||
|
||||
function CustomTooltip({ active, payload, label }: any) {
|
||||
if (active) {
|
||||
const price = payload[0].value;
|
||||
const exit = payload[1].value;
|
||||
const weekNum = label;
|
||||
const toolTipData: string[][] = [
|
||||
["Price", price.toFixed(2), "DAI/tk"],
|
||||
["Exit t.", formatter(exit), "DAI"],
|
||||
["Week", weekNum, ""]
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={classes.tooltip}>
|
||||
<table>
|
||||
<tbody>
|
||||
{toolTipData.map(([name, value, unit]) => (
|
||||
<tr key={name}>
|
||||
<td>{name}</td>
|
||||
<td>{value}</td>
|
||||
<td>{unit}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ResponsiveContainer debounce={1}>
|
||||
<AreaChart
|
||||
|
|
@ -115,7 +157,7 @@ function PriceSimulationChart({
|
|||
stroke={theme.palette.text.secondary}
|
||||
/>
|
||||
|
||||
<Tooltip formatter={value => Number(value)} />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
|
||||
<Area
|
||||
isAnimationActive={false}
|
||||
|
|
@ -146,8 +188,9 @@ function PriceSimulationChart({
|
|||
yAxisId="right"
|
||||
type="monotone"
|
||||
dataKey={keyVerticalRight}
|
||||
stroke={theme.palette.secondary.main}
|
||||
fill={theme.palette.secondary.main}
|
||||
stroke={theme.palette.secondary.dark}
|
||||
fill={theme.palette.secondary.dark}
|
||||
fillOpacity="0.8"
|
||||
/>
|
||||
|
||||
{/* <ReferenceLine
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { InputFieldInterface, CurveParamsInterface } from "./types";
|
||||
import InputParams from "./InputParams";
|
||||
|
||||
export default function CurveDesignInputParams({
|
||||
curveParams,
|
||||
setCurveParams
|
||||
}: {
|
||||
curveParams: CurveParamsInterface;
|
||||
setCurveParams(newCurveParams: any): void;
|
||||
}) {
|
||||
const [d0, setD0] = useState(3e6); // Initial raise, d0 (DAI)
|
||||
|
||||
useEffect(() => {
|
||||
setD0(curveParams.d0);
|
||||
}, [curveParams]);
|
||||
|
||||
function setParentCurveParams() {
|
||||
setCurveParams((params: CurveParamsInterface) => ({
|
||||
...params,
|
||||
d0
|
||||
}));
|
||||
}
|
||||
|
||||
const inputFields: InputFieldInterface[] = [
|
||||
{
|
||||
label: "Initial raise",
|
||||
value: d0,
|
||||
setter: setD0,
|
||||
min: 0.1e6,
|
||||
max: 10e6,
|
||||
step: 0.1e6,
|
||||
unit: "$M",
|
||||
prefix: "$",
|
||||
suffix: "M",
|
||||
format: (n: number) => `$${+(n * 1e-6).toFixed(1)}M`,
|
||||
toText: (n: number) => String(+(n * 1e-6).toFixed(1)),
|
||||
toNum: (n: string) => Math.floor(parseFloat(n) * 1e6),
|
||||
secondaryColor: true
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<InputParams
|
||||
inputFields={inputFields}
|
||||
onChangeCommited={setParentCurveParams}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
@ -10,10 +10,25 @@ import {
|
|||
ResponsiveContainer,
|
||||
Tooltip
|
||||
} from "recharts";
|
||||
import { createStyles, makeStyles, Theme } from "@material-ui/core/styles";
|
||||
import { getLinspaceTicks } from "./utils";
|
||||
import { getInitialParams } from "./math";
|
||||
import { getInitialParams, getPriceR } from "./math";
|
||||
import { useTheme } from "@material-ui/styles";
|
||||
|
||||
const keyHorizontal = "x";
|
||||
const keyVertical = "Supply (tokens) / Reserve (DAI)";
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
tooltip: {
|
||||
border: "1px solid #313d47",
|
||||
backgroundColor: "#384b59",
|
||||
padding: theme.spacing(1),
|
||||
color: "#c7ccd2"
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
function SupplyVsDemandChart({
|
||||
theta,
|
||||
d0,
|
||||
|
|
@ -35,21 +50,23 @@ function SupplyVsDemandChart({
|
|||
const {
|
||||
k, // Invariant power kappa (.)
|
||||
R0, // Initial reserve (DAI)
|
||||
S0 // initial supply of tokens (token)
|
||||
S0, // initial supply of tokens (token)
|
||||
V0 // invariant coef
|
||||
} = getInitialParams({
|
||||
d0,
|
||||
theta,
|
||||
p0,
|
||||
p1
|
||||
});
|
||||
const S_of_R = (R: number) => S0 * (R / R0) ** (1 / k);
|
||||
const R0_round = Math.round(R0);
|
||||
const S_of_R = (R: number) => S0 * (R / R0_round) ** (1 / k);
|
||||
|
||||
// Function setup
|
||||
const f = S_of_R;
|
||||
const from = 0;
|
||||
const to = 4 * R0;
|
||||
const to = 4 * R0_round;
|
||||
const steps = 100 + 1; // Add 1 for the ticks to match
|
||||
const step = (to - from) / steps;
|
||||
const step = Math.round((to - from) / (steps - 1));
|
||||
|
||||
/**
|
||||
* Prettify the result converting 1000000 to 1M
|
||||
|
|
@ -68,12 +85,9 @@ function SupplyVsDemandChart({
|
|||
: // No scale
|
||||
[1, ""];
|
||||
|
||||
const keyHorizontal = "x";
|
||||
const keyVertical = "Supply (tokens) / Reserve (DAI)";
|
||||
|
||||
const data = [];
|
||||
for (let i = 0; i < steps; i++) {
|
||||
const x = from + step * i;
|
||||
const x = Math.round(from + step * i);
|
||||
data.push({
|
||||
[keyHorizontal]: x,
|
||||
[keyVertical]: f(x)
|
||||
|
|
@ -83,6 +97,7 @@ function SupplyVsDemandChart({
|
|||
// Chart components
|
||||
|
||||
const theme: any = useTheme();
|
||||
const classes = useStyles();
|
||||
|
||||
const formatter = (n: number) =>
|
||||
(+(n / scaling).toPrecision(2)).toLocaleString();
|
||||
|
|
@ -105,6 +120,34 @@ function SupplyVsDemandChart({
|
|||
);
|
||||
}
|
||||
|
||||
function CustomTooltip({ active, payload, label }: any) {
|
||||
if (active) {
|
||||
const supply = payload[0].value;
|
||||
const reserve = label;
|
||||
const price = getPriceR({ R: reserve, V0, k });
|
||||
const toolTipData: string[][] = [
|
||||
["Supply", formatter(supply) + unit, "tokens"],
|
||||
["Reserve", formatter(reserve) + unit, "DAI"],
|
||||
["Price", price.toFixed(2), "DAI/token"]
|
||||
];
|
||||
return (
|
||||
<div className={classes.tooltip}>
|
||||
<table>
|
||||
<tbody>
|
||||
{toolTipData.map(([name, value, unit]) => (
|
||||
<tr key={name}>
|
||||
<td>{name}</td>
|
||||
<td>{value}</td>
|
||||
<td>{unit}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
} else return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<ResponsiveContainer debounce={1}>
|
||||
<AreaChart
|
||||
|
|
@ -136,7 +179,7 @@ function SupplyVsDemandChart({
|
|||
domain={[0, f(to)]}
|
||||
stroke={theme.palette.text.secondary}
|
||||
/>
|
||||
<Tooltip formatter={value => formatter(Number(value))} />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Area
|
||||
isAnimationActive={false}
|
||||
type="monotone"
|
||||
|
|
@ -145,7 +188,7 @@ function SupplyVsDemandChart({
|
|||
fill={theme.palette.primary.main}
|
||||
/>
|
||||
<ReferenceLine
|
||||
x={R0}
|
||||
x={R0_round}
|
||||
stroke={theme.palette.primary.main}
|
||||
strokeDasharray="9 0"
|
||||
label={<ReferenceLabel />}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,9 @@ const theme = createMuiTheme({
|
|||
main: "#2ecd79"
|
||||
},
|
||||
secondary: {
|
||||
main: "#116be0"
|
||||
main: "#116be0",
|
||||
light: "#0f8bff",
|
||||
dark: "#116be0"
|
||||
},
|
||||
error: {
|
||||
main: red.A400
|
||||
|
|
|
|||
|
|
@ -0,0 +1,23 @@
|
|||
export interface InputFieldInterface {
|
||||
label: string;
|
||||
value: number;
|
||||
setter(newValue: any): void;
|
||||
min: number;
|
||||
max: number;
|
||||
step: number;
|
||||
unit?: string;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
secondaryColor?: boolean;
|
||||
toText?(value: number): string;
|
||||
toNum?(value: string): number;
|
||||
format(value: number): string;
|
||||
}
|
||||
|
||||
export interface CurveParamsInterface {
|
||||
d0: number;
|
||||
theta: number;
|
||||
p0: number;
|
||||
p1: number;
|
||||
wFee: number;
|
||||
}
|
||||
Loading…
Reference in New Issue