Skip to content

Commit

Permalink
Merge branch 'dev' into feat(web)/desktop-navbar-and-responsiveness
Browse files Browse the repository at this point in the history
  • Loading branch information
kemuru authored Sep 4, 2023
2 parents d0612bc + 6b6eaf4 commit fbe85a3
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 44 deletions.
58 changes: 42 additions & 16 deletions contracts/scripts/keeperBot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ import hre = require("hardhat");
const { ethers } = hre;
const MAX_DRAW_ITERATIONS = 30;
const MAX_EXECUTE_ITERATIONS = 20;
const MAX_DELAYED_STAKES_ITERATIONS = 50;
const WAIT_FOR_RNG_DURATION = 5 * 1000; // 5 seconds
const ITERATIONS_COOLDOWN_PERIOD = 20 * 1000; // 20 seconds
const HIGH_GAS_LIMIT = { gasLimit: 50000000 }; // 50M gas
const ITERATIONS_COOLDOWN_PERIOD = 10 * 1000; // 10 seconds
const HIGH_GAS_LIMIT = { gasLimit: 50_000_000 }; // 50M gas
const HEARTBEAT_URL = env.optionalNoDefault("HEARTBEAT_URL_KEEPER_BOT");
const SUBGRAPH_URL = env.require("SUBGRAPH_URL");
const MAX_JURORS_PER_DISPUTE = 1000; // Skip disputes with more than this number of jurors
Expand Down Expand Up @@ -219,7 +220,7 @@ const drawJurors = async (dispute: { id: string; currentRoundIndex: string }, it
try {
await core.callStatic.draw(dispute.id, iterations, HIGH_GAS_LIMIT);
} catch (e) {
logger.info(`Draw: will fail for ${dispute.id}, skipping`);
logger.error(`Draw: will fail for ${dispute.id}, skipping`);
return success;
}
try {
Expand All @@ -241,7 +242,7 @@ const executeRepartitions = async (dispute: { id: string; currentRoundIndex: str
try {
await core.callStatic.execute(dispute.id, dispute.currentRoundIndex, iterations, HIGH_GAS_LIMIT);
} catch (e) {
logger.info(`Execute: will fail for ${dispute.id}, skipping`);
logger.error(`Execute: will fail for ${dispute.id}, skipping`);
return success;
}
try {
Expand All @@ -260,7 +261,7 @@ const executeRuling = async (dispute: { id: string }) => {
try {
await core.callStatic.executeRuling(dispute.id);
} catch (e) {
logger.info(`ExecuteRuling: will fail for ${dispute.id}, skipping`);
logger.error(`ExecuteRuling: will fail for ${dispute.id}, skipping`);
return success;
}
try {
Expand Down Expand Up @@ -290,7 +291,7 @@ const withdrawAppealContribution = async (
contribution.choice
);
} catch (e) {
logger.info(
logger.warn(
`WithdrawFeesAndRewards: will fail for dispute #${disputeId}, round #${roundId}, choice ${contribution.choice} and beneficiary ${contribution.contributor.id}, skipping`
);
return success;
Expand Down Expand Up @@ -323,6 +324,40 @@ const withdrawAppealContribution = async (
return success;
};

const executeDelayedStakes = async () => {
const { sortition } = await getContracts();

// delayedStakes = 1 + delayedStakeWriteIndex - delayedStakeReadIndex
const delayedStakesRemaining = BigNumber.from(1)
.add(await sortition.delayedStakeWriteIndex())
.sub(await sortition.delayedStakeReadIndex());

const delayedStakes = delayedStakesRemaining.lt(MAX_DELAYED_STAKES_ITERATIONS)
? delayedStakesRemaining
: BigNumber.from(MAX_DELAYED_STAKES_ITERATIONS);

if (delayedStakes.eq(0)) {
logger.info("No delayed stakes to execute");
return true;
}
logger.info(`Executing ${delayedStakes} delayed stakes, ${delayedStakesRemaining} remaining`);
let success = false;
try {
await sortition.callStatic.executeDelayedStakes(delayedStakes);
} catch (e) {
logger.error(`executeDelayedStakes: will fail because of ${JSON.stringify(e)}`);
return success;
}
try {
const gas = (await sortition.estimateGas.executeDelayedStakes(delayedStakes)).mul(150).div(100); // 50% extra gas
const tx = await (await sortition.executeDelayedStakes(delayedStakes, { gasLimit: gas })).wait();
logger.info(`executeDelayedStakes txID: ${tx?.transactionHash}`);
} catch (e) {
handleError(e);
}
return success;
};

const getMissingJurors = async (dispute: { id: string; currentRoundIndex: string }) => {
const { core } = await getContracts();
const { nbVotes, drawnJurors } = await core.getRoundInfo(dispute.id, dispute.currentRoundIndex);
Expand Down Expand Up @@ -594,18 +629,9 @@ async function main() {
// ----------------------------------------------- //
// EXECUTE DELAYED STAKES //
// ----------------------------------------------- //
// delayedStakes = 1 + delayedStakeWriteIndex - delayedStakeReadIndex
const delayedStakes = BigNumber.from(1)
.add(await sortition.delayedStakeWriteIndex())
.sub(await sortition.delayedStakeReadIndex());

if (await isPhaseStaking()) {
if (delayedStakes.gt(0)) {
logger.info("Executing delayed stakes");
await sortition.executeDelayedStakes(delayedStakes);
} else {
logger.info("No delayed stakes to execute");
}
await executeDelayedStakes();
}

await sendHeartbeat();
Expand Down
1 change: 1 addition & 0 deletions cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"repartitions",
"solhint",
"typechain",
"uncommify",
"Unslashed",
"viem",
"wagmi"
Expand Down
57 changes: 57 additions & 0 deletions web/src/components/NumberInputField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useState } from "react";
import styled from "styled-components";
import { Field } from "@kleros/ui-components-library";

const Container = styled.div`
width: 100%;
height: fit-content;
`;

const StyledField = styled(Field)`
width: 100%;
height: fit-content;
`;

interface INumberInputField {
placeholder?: string;
message?: string;
value?: string;
onChange?: (value: string) => void;
formatter?: (value: string) => string;
}

export const NumberInputField: React.FC<INumberInputField> = ({ placeholder, message, value, onChange, formatter }) => {
const [isEditing, setIsEditing] = useState(false);

const toggleEditing = () => {
setIsEditing(!isEditing);
};

return (
<Container>
{isEditing ? (
<StyledField
type="number"
value={value}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
onChange?.(event.target.value);
}}
placeholder={placeholder}
message={message}
variant="info"
onBlur={toggleEditing}
/>
) : (
<StyledField
type="text"
value={formatter ? formatter(value ?? "0") : value}
placeholder={placeholder}
message={message}
variant="info"
onFocus={toggleEditing}
readOnly
/>
)}
</Container>
);
};
27 changes: 14 additions & 13 deletions web/src/pages/Courts/CourtDetails/StakePanel/InputDisplay.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import React, { useState } from "react";
import styled from "styled-components";
import { useParams } from "react-router-dom";
import { formatEther } from "viem";
import { useDebounce } from "react-use";
import { useAccount } from "wagmi";
import { Field } from "@kleros/ui-components-library";
import { NumberInputField } from "components/NumberInputField";
import { useParsedAmount } from "hooks/useParsedAmount";
import { useCourtDetails } from "hooks/queries/useCourtDetails";
import { useKlerosCoreGetJurorBalance, usePnkBalanceOf } from "hooks/contracts/generated";
import StakeWithdrawButton, { ActionType } from "./StakeWithdrawButton";
import { formatPNK, roundNumberDown } from "utils/format";
import { isUndefined } from "utils/index";
import { commify, uncommify } from "utils/commify";
import { EnsureChain } from "components/EnsureChain";

const StyledField = styled(Field)`
const StyledField = styled(NumberInputField)`
width: 100%;
height: fit-content;
`;
Expand Down Expand Up @@ -53,7 +54,7 @@ const InputDisplay: React.FC<IInputDisplay> = ({
}) => {
const [debouncedAmount, setDebouncedAmount] = useState("");
useDebounce(() => setDebouncedAmount(amount), 500, [amount]);
const parsedAmount = useParsedAmount(debouncedAmount);
const parsedAmount = useParsedAmount(uncommify(debouncedAmount));

const { id } = useParams();
const { data: courtDetails } = useCourtDetails(id);
Expand All @@ -63,13 +64,13 @@ const InputDisplay: React.FC<IInputDisplay> = ({
args: [address ?? "0x"],
watch: true,
});
const parsedBalance = formatEther(balance ?? 0n);
const parsedBalance = formatPNK(balance ?? 0n, 0, true);
const { data: jurorBalance } = useKlerosCoreGetJurorBalance({
enabled: !isUndefined(address),
args: [address, id],
watch: true,
});
const parsedStake = formatEther(jurorBalance?.[0] || 0n);
const parsedStake = formatPNK(jurorBalance?.[0] || 0n, 0, true);
const isStaking = action === ActionType.stake;

return (
Expand All @@ -87,21 +88,21 @@ const InputDisplay: React.FC<IInputDisplay> = ({
</LabelArea>
<InputArea>
<StyledField
type="number"
value={amount}
value={uncommify(amount)}
onChange={(e) => {
setAmount(e.target.value);
setAmount(e);
}}
placeholder={isStaking ? "Amount to stake" : "Amount to withdraw"}
message={
isStaking
? `You need to stake at least ${formatEther(courtDetails?.court.minStake ?? 0n)} PNK. ` +
? `You need to stake at least ${formatPNK(courtDetails?.court.minStake ?? 0n, 3)} PNK. ` +
"You may need two transactions, one to increase allowance, the other to stake."
: `You need to either withdraw all or keep at least ${formatEther(
courtDetails?.court.minStake ?? 0n
: `You need to either withdraw all or keep at least ${formatPNK(
courtDetails?.court.minStake ?? 0n,
3
)} PNK.`
}
variant="info"
formatter={(number: string) => commify(roundNumberDown(Number(number)))}
/>
<EnsureChain>
<StakeWithdrawButton
Expand Down
3 changes: 2 additions & 1 deletion web/src/pages/Courts/CourtDetails/Stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import styled from "styled-components";
import { useParams } from "react-router-dom";
import { useCourtDetails, CourtDetailsQuery } from "queries/useCourtDetails";
import { useCoinPrice } from "hooks/useCoinPrice";
import { formatETH, formatPNK, formatUnitsWei, formatUSD, isUndefined } from "utils/index";
import { formatETH, formatPNK, formatUnitsWei, formatUSD } from "utils/format";
import { isUndefined } from "utils/index";
import { calculateSubtextRender } from "utils/calculateSubtextRender";
import { CoinIds } from "consts/coingecko";
import StatDisplay, { IStatDisplay } from "components/StatDisplay";
Expand Down
3 changes: 2 additions & 1 deletion web/src/pages/Home/CourtOverview/Stats.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import EthereumIcon from "svgs/icons/ethereum.svg";
import PNKRedistributedIcon from "svgs/icons/redistributed-pnk.svg";
import JurorIcon from "svgs/icons/user.svg";
import BalanceIcon from "svgs/icons/law-balance.svg";
import { formatETH, formatPNK, formatUnitsWei, formatUSD, isUndefined } from "utils/index";
import { formatETH, formatPNK, formatUnitsWei, formatUSD } from "utils/format";
import { isUndefined } from "utils/index";
import { calculateSubtextRender } from "utils/calculateSubtextRender";
import { CoinIds } from "consts/coingecko";
import { useHomePageContext, HomePageQuery, HomePageQueryDataPoints } from "hooks/useHomePageContext";
Expand Down
4 changes: 4 additions & 0 deletions web/src/utils/commify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ export function commify(value: string | number): string {

return negative + formatted.join(",") + suffix;
}

export function uncommify(value: string): string {
return value.replace(/,/g, "");
}
23 changes: 23 additions & 0 deletions web/src/utils/format.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { formatEther, formatUnits } from "viem";
import { commify } from "./commify";

export const roundNumberDown = (value: number, fractionDigits = 0) => {
const factor = 10 ** fractionDigits;
return Math.floor(value * factor) / factor;
};

export const formatUnitsWei = (value: bigint) => formatUnits(value, 18);

export const formatValue = (value: string, fractionDigits, roundDown) => {
let units = Number(value);
if (roundDown) units = roundNumberDown(units, fractionDigits);
return commify(units.toFixed(fractionDigits));
};

export const formatPNK = (value: bigint, fractionDigits = 0, roundDown = false) =>
formatValue(formatUnitsWei(value), fractionDigits, roundDown);

export const formatETH = (value: bigint, fractionDigits = 4, roundDown = false) =>
formatValue(formatEther(value), fractionDigits, roundDown);

export const formatUSD = (value: number, fractionDigits = 2) => "$" + commify(Number(value).toFixed(fractionDigits));
13 changes: 0 additions & 13 deletions web/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
import { formatEther, formatUnits } from "viem";
import { commify } from "./commify";

export const isUndefined = (maybeObject: any): maybeObject is undefined => typeof maybeObject === "undefined";

export const formatUnitsWei = (value: bigint) => formatUnits(value, 18);

export const formatPNK = (value: bigint, fractionDigits = 0) =>
commify(Number(formatUnitsWei(value)).toFixed(fractionDigits));

export const formatETH = (value: bigint, fractionDigits = 4) =>
commify(Number(formatEther(value)).toFixed(fractionDigits));

export const formatUSD = (value: number, fractionDigits = 2) => "$" + commify(Number(value).toFixed(fractionDigits));

0 comments on commit fbe85a3

Please sign in to comment.