Skip to content

Commit

Permalink
feat: dev UI wip
Browse files Browse the repository at this point in the history
  • Loading branch information
danielattilasimon committed Jun 21, 2021
1 parent 23f85ed commit 0620755
Show file tree
Hide file tree
Showing 7 changed files with 200 additions and 12 deletions.
27 changes: 21 additions & 6 deletions packages/dev-frontend/src/components/Trove/Adjusting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
Difference
} from "@liquity/lib-base";
import { useLiquitySelector } from "@liquity/lib-react";

import { useStableTroveChange } from "../../hooks/useStableTroveChange";
import { ActionDescription } from "../ActionDescription";
import { useMyTransactionState } from "../Transaction";
import { TroveAction } from "./TroveAction";
Expand All @@ -19,6 +21,7 @@ import { InfoIcon } from "../InfoIcon";
import { LoadingOverlay } from "../LoadingOverlay";
import { CollateralRatio } from "./CollateralRatio";
import { EditableRow, StaticRow } from "./Editor";
import { ExpensiveTroveChangeWarning, GasEstimationState } from "./ExpensiveTroveChangeWarning";
import {
selectForTroveChangeValidation,
validateTroveChange
Expand Down Expand Up @@ -118,10 +121,6 @@ export const Adjusting: React.FC = () => {
setNetDebt(trove.netDebt);
}, [trove.collateral, trove.netDebt]);

if (trove.status !== "open") {
return null;
}

const isDirty = !collateral.eq(trove.collateral) || !netDebt.eq(trove.netDebt);
const isDebtIncrease = netDebt.gt(trove.netDebt);
const debtIncreaseAmount = isDebtIncrease ? netDebt.sub(trove.netDebt) : Decimal.ZERO;
Expand All @@ -147,10 +146,17 @@ export const Adjusting: React.FC = () => {
validationContext
);

const stableTroveChange = useStableTroveChange(troveChange);
const [gasEstimationState, setGasEstimationState] = useState<GasEstimationState>({ type: "idle" });

const isTransactionPending =
transactionState.type === "waitingForApproval" ||
transactionState.type === "waitingForConfirmation";

if (trove.status !== "open") {
return null;
}

return (
<Card>
<Heading>
Expand Down Expand Up @@ -252,16 +258,25 @@ export const Adjusting: React.FC = () => {
</ActionDescription>
)}

<ExpensiveTroveChangeWarning
troveChange={stableTroveChange}
maxBorrowingRate={maxBorrowingRate}
borrowingFeeDecayToleranceMinutes={60}
gasEstimationState={gasEstimationState}
setGasEstimationState={setGasEstimationState}
/>

<Flex variant="layout.actions">
<Button variant="cancel" onClick={handleCancelPressed}>
Cancel
</Button>

{troveChange ? (
{stableTroveChange ? (
<TroveAction
transactionId={TRANSACTION_ID}
change={troveChange}
change={stableTroveChange}
maxBorrowingRate={maxBorrowingRate}
borrowingFeeDecayToleranceMinutes={60}
>
Confirm
</TroveAction>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { useEffect } from "react";

import { Decimal, TroveChange } from "@liquity/lib-base";
import { PopulatedEthersLiquityTransaction } from "@liquity/lib-ethers";

import { useLiquity } from "../../hooks/LiquityContext";
import { Warning } from "../Warning";

export type GasEstimationState =
| { type: "idle" | "inProgress" }
| { type: "complete"; populatedTx: PopulatedEthersLiquityTransaction };

type ExpensiveTroveChangeWarningParams = {
troveChange?: Exclude<TroveChange<Decimal>, { type: "invalidCreation" }>;
maxBorrowingRate: Decimal;
borrowingFeeDecayToleranceMinutes: number;
gasEstimationState: GasEstimationState;
setGasEstimationState: (newState: GasEstimationState) => void;
};

export const ExpensiveTroveChangeWarning: React.FC<ExpensiveTroveChangeWarningParams> = ({
troveChange,
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes,
gasEstimationState,
setGasEstimationState
}) => {
const { liquity } = useLiquity();

useEffect(() => {
if (troveChange && troveChange.type !== "closure") {
setGasEstimationState({ type: "inProgress" });

let cancelled = false;

const timeoutId = setTimeout(async () => {
const populatedTx = await (troveChange.type === "creation"
? liquity.populate.openTrove(troveChange.params, {
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes
})
: liquity.populate.adjustTrove(troveChange.params, {
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes
}));

if (!cancelled) {
setGasEstimationState({ type: "complete", populatedTx });
console.log(
"Estimated TX cost: " +
Decimal.from(`${populatedTx.rawPopulatedTransaction.gasLimit}`).prettify(0)
);
}
}, 333);

return () => {
clearTimeout(timeoutId);
cancelled = true;
};
} else {
setGasEstimationState({ type: "idle" });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [troveChange]);

if (
troveChange &&
gasEstimationState.type === "complete" &&
gasEstimationState.populatedTx.gasHeadroom !== undefined &&
gasEstimationState.populatedTx.gasHeadroom >= 200000
) {
return troveChange.type === "creation" ? (
<Warning>
The cost of opening a Trove in this collateral ratio range is high. It is recommended to
choose a slightly different collateral ratio.
</Warning>
) : (
<Warning>
The cost of adjusting a Trove into this collateral ratio range is high. It is recommended to
choose a slightly different collateral ratio.
</Warning>
);
}

return null;
};
25 changes: 22 additions & 3 deletions packages/dev-frontend/src/components/Trove/Opening.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from "react";
import { Flex, Button, Box, Card, Heading } from "theme-ui";
import { Flex, Button, Box, Card, Heading, Spinner } from "theme-ui";
import {
LiquityStoreState,
Decimal,
Expand All @@ -9,6 +9,8 @@ import {
Percent
} from "@liquity/lib-base";
import { useLiquitySelector } from "@liquity/lib-react";

import { useStableTroveChange } from "../../hooks/useStableTroveChange";
import { ActionDescription } from "../ActionDescription";
import { useMyTransactionState } from "../Transaction";
import { TroveAction } from "./TroveAction";
Expand All @@ -19,6 +21,7 @@ import { InfoIcon } from "../InfoIcon";
import { LoadingOverlay } from "../LoadingOverlay";
import { CollateralRatio } from "./CollateralRatio";
import { EditableRow, StaticRow } from "./Editor";
import { ExpensiveTroveChangeWarning, GasEstimationState } from "./ExpensiveTroveChangeWarning";
import {
selectForTroveChangeValidation,
validateTroveChange
Expand Down Expand Up @@ -67,6 +70,9 @@ export const Opening: React.FC = () => {
validationContext
);

const stableTroveChange = useStableTroveChange(troveChange);
const [gasEstimationState, setGasEstimationState] = useState<GasEstimationState>({ type: "idle" });

const transactionState = useMyTransactionState(TRANSACTION_ID);
const isTransactionPending =
transactionState.type === "waitingForApproval" ||
Expand Down Expand Up @@ -188,16 +194,29 @@ export const Opening: React.FC = () => {
</ActionDescription>
)}

<ExpensiveTroveChangeWarning
troveChange={stableTroveChange}
maxBorrowingRate={maxBorrowingRate}
borrowingFeeDecayToleranceMinutes={60}
gasEstimationState={gasEstimationState}
setGasEstimationState={setGasEstimationState}
/>

<Flex variant="layout.actions">
<Button variant="cancel" onClick={handleCancelPressed}>
Cancel
</Button>

{troveChange ? (
{gasEstimationState.type === "inProgress" ? (
<Button disabled>
<Spinner size="24px" sx={{ color: "background" }} />
</Button>
) : stableTroveChange ? (
<TroveAction
transactionId={TRANSACTION_ID}
change={troveChange}
change={stableTroveChange}
maxBorrowingRate={maxBorrowingRate}
borrowingFeeDecayToleranceMinutes={60}
>
Confirm
</TroveAction>
Expand Down
14 changes: 11 additions & 3 deletions packages/dev-frontend/src/components/Trove/TroveAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,31 @@ type TroveActionProps = {
transactionId: string;
change: Exclude<TroveChange<Decimal>, { type: "invalidCreation" }>;
maxBorrowingRate: Decimal;
borrowingFeeDecayToleranceMinutes: number;
};

export const TroveAction: React.FC<TroveActionProps> = ({
children,
transactionId,
change,
maxBorrowingRate
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes
}) => {
const { liquity } = useLiquity();

const [sendTransaction] = useTransactionFunction(
transactionId,
change.type === "creation"
? liquity.send.openTrove.bind(liquity.send, change.params, maxBorrowingRate)
? liquity.send.openTrove.bind(liquity.send, change.params, {
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes
})
: change.type === "closure"
? liquity.send.closeTrove.bind(liquity.send)
: liquity.send.adjustTrove.bind(liquity.send, change.params, maxBorrowingRate)
: liquity.send.adjustTrove.bind(liquity.send, change.params, {
maxBorrowingRate,
borrowingFeeDecayToleranceMinutes
})
);

return <Button onClick={sendTransaction}>{children}</Button>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export const TroveManager: React.FC<TroveManagerProps> = ({ collateral, debt })
transactionId={`${transactionIdPrefix}${validChange.type}`}
change={validChange}
maxBorrowingRate={maxBorrowingRate}
borrowingFeeDecayToleranceMinutes={60}
>
Confirm
</TroveAction>
Expand Down
27 changes: 27 additions & 0 deletions packages/dev-frontend/src/components/Warning.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Box, Flex, Text } from "theme-ui";

import { Icon } from "./Icon";

export const Warning: React.FC = ({ children }) => (
<Box
sx={{
display: "flex",
flexDirection: "column",
justifyContent: "space-around",

mb: [2, 3],
p: 3,

border: 1,
borderRadius: "8px",
borderColor: "warning",
boxShadow: 2
// bg: "rgba(46, 182, 234, 0.05)"
}}
>
<Flex sx={{ alignItems: "center" }}>
<Icon name="exclamation-triangle" size="lg" />
<Text sx={{ ml: 2 }}>{children}</Text>
</Flex>
</Box>
);
32 changes: 32 additions & 0 deletions packages/dev-frontend/src/hooks/useStableTroveChange.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { useEffect, useState } from "react";
import { Decimal, TroveChange } from "@liquity/lib-base";

type ValidTroveChange = Exclude<TroveChange<Decimal>, { type: "invalidCreation" }>;

const paramsEq = (a?: Decimal, b?: Decimal) => (a && b ? a.eq(b) : !a && !b);

const equals = (a: ValidTroveChange, b: ValidTroveChange): boolean => {
return (
a.type === b.type &&
paramsEq(a.params.borrowLUSD, b.params.borrowLUSD) &&
paramsEq(a.params.repayLUSD, b.params.repayLUSD) &&
paramsEq(a.params.depositCollateral, b.params.depositCollateral) &&
paramsEq(a.params.withdrawCollateral, b.params.withdrawCollateral)
);
};

export const useStableTroveChange = (
troveChange: ValidTroveChange | undefined
): ValidTroveChange | undefined => {
const [stableTroveChange, setStableTroveChange] = useState(troveChange);

useEffect(() => {
if (!!stableTroveChange !== !!troveChange) {
setStableTroveChange(troveChange);
} else if (stableTroveChange && troveChange && !equals(stableTroveChange, troveChange)) {
setStableTroveChange(troveChange);
}
}, [stableTroveChange, troveChange]);

return stableTroveChange;
};

0 comments on commit 0620755

Please sign in to comment.