Skip to content

Commit

Permalink
allow up to max 2 decimals for percentages to avoid loss of precision
Browse files Browse the repository at this point in the history
  • Loading branch information
ps1dr3x committed Oct 2, 2023
1 parent 1959b05 commit a1a27e4
Show file tree
Hide file tree
Showing 6 changed files with 54 additions and 14 deletions.
13 changes: 12 additions & 1 deletion src/core/calculateAmounts.ts
Expand Up @@ -6,11 +6,22 @@ import {
} from "../typing";

// Used to calculate WEI amounts
// Allow for up to 2 decimal places (percentage) to avoid loss of precision
export const calculatePercentageInt = (
percentage: number,
amount: bigint,
): bigint => {
return (amount * BigInt(Math.round(percentage * 1e18))) / BigInt(1e20);
const scaleFactor = 1e2;

if (Math.round(percentage * scaleFactor) !== percentage * scaleFactor) {
throw new Error(
"Percentage values with more than 2 decimal places are not allowed (to avoid loss of precision).",
);
}

const scaledPercentage = BigInt(Math.round(percentage * scaleFactor));
const result = (amount * scaledPercentage) / (BigInt(scaleFactor) * 100n);
return result;
};

// Used to calculate percentages (of percentages)
Expand Down
1 change: 1 addition & 0 deletions src/helpers/index.ts
Expand Up @@ -4,6 +4,7 @@ export { displayChallengePeriod } from "./displayChallengePeriod";
export { formatAmountToUSD } from "./formatAmountToUSD";
export { percentageToBips } from "./percentageToBips";
export { bipsToPercentage } from "./bipsToPercentage";
export { roundPercentage } from "./roundPercentage";
export { isSameAddress } from "./isSameAddress";
export { toDate } from "./toDate";
export { getExchangeRates } from "./getExchangeRates";
Expand Down
18 changes: 18 additions & 0 deletions src/helpers/roundPercentage.ts
@@ -0,0 +1,18 @@
/**
* Round a percentage to max 2 decimals.
* If amount > 100, returns 100
* If amount < 0, returns 0
*/
export const roundPercentage = (amount: number) => {
if (amount > 100) {
return 100;
}

if (amount < 0) {
return 0;
}

amount = Math.round(Number(amount) * 100) / 100;

return amount;
};
13 changes: 8 additions & 5 deletions src/ui/internal/modals/AddApproveArbitrator.tsx
Expand Up @@ -17,7 +17,7 @@ import {
} from "../../../typing";
import { useModalStates } from "../hooks/useModalStates";
import { ScopedModal } from "../components";
import { BUYER, SELLER } from "../../../helpers";
import { BUYER, SELLER, roundPercentage } from "../../../helpers";
import { ModalAction } from "../components/Modal";
import { useModalCloseHandler } from "../hooks/useModalCloseHandler";
import { useEscrowData } from "ui/internal/hooks/useEscrowData";
Expand Down Expand Up @@ -189,6 +189,12 @@ export const AddApproveArbitrator = ({
}
};

const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
event.target.value = String(roundPercentage(Number(event.target.value)));
setArbitratorFee(event.target.value);
setFocus("arbitratorFee");
};

const ModalBody = () => {
if (!escrowData) return null;

Expand All @@ -214,10 +220,7 @@ export const AddApproveArbitrator = ({
name="arbitratorFee"
id="arbitratorFee"
label="Fee"
onChange={(event) => {
setArbitratorFee(event.target.value);
setFocus("arbitratorFee");
}}
onChange={handleInputChange}
value={arbitratorFee}
min="0"
max="100"
Expand Down
13 changes: 9 additions & 4 deletions src/ui/internal/modals/Arbitrate.tsx
@@ -1,11 +1,12 @@
import React, { ChangeEvent } from "react";
import React from "react";
import {
InputText,
Button,
Stack,
FormattedPercentageAmountAdornment,
ScopedModal,
} from "../../../ui/internal/components";
import { roundPercentage } from "../../../helpers/roundPercentage";
import { arbitrate } from "../../../core";
import { toast } from "../notification/toast";
import { IArbitrateModalProps } from "../../../typing";
Expand Down Expand Up @@ -99,16 +100,20 @@ export const Arbitrate = ({
});
};

const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {
const handleInputChange = (
event: React.ChangeEvent<HTMLInputElement & { name: "buyer" | "seller" }>,
) => {
event.target.value = String(roundPercentage(Number(event.target.value)));

if (event.target.name === "seller") {
setSellerValue(event.target.value);
setBuyerValue(String(100 - Number(event.target.value)));
setFocus("seller");
} else {
setSellerValue(String(100 - Number(event.target.value)));
setBuyerValue(event.target.value);
setFocus("buyer");
}

setFocus(event.target.name);
};

const ModalBody = () => {
Expand Down
10 changes: 6 additions & 4 deletions src/ui/internal/modals/SettlementOffer.tsx
Expand Up @@ -11,7 +11,7 @@ import { Button } from "../../../ui/internal/components/Button";
import styled from "styled-components";
import { offerSettlement } from "../../../core/offerSettlement";
import { toast } from "../notification/toast";
import { SELLER, BUYER } from "../../../helpers";
import { SELLER, BUYER, roundPercentage } from "../../../helpers";
import { FormattedPercentageAmountAdornment } from "../../../ui/internal/components/FormattedPercentageAmountAdornment";
import { renderModal } from "../config/render";
import { ApproveSettlementModal } from "./ApproveSettlement";
Expand Down Expand Up @@ -133,9 +133,11 @@ export function SettlementOfferModal({
return ["Buyer should get back", "You should receive"];
}, [escrowData]);

const handleChange = (
const handleInputChange = (
event: React.ChangeEvent<HTMLInputElement & { name: "buyer" | "seller" }>,
) => {
event.target.value = String(roundPercentage(Number(event.target.value)));

if (event.target.name === "seller") {
setSellerValue(event.target.value);
setBuyerValue(String(100 - Number(event.target.value)));
Expand Down Expand Up @@ -269,7 +271,7 @@ export function SettlementOfferModal({
key="buyer"
label={labelBuyer}
placeholder="0"
onChange={handleChange}
onChange={handleInputChange}
value={buyerValue}
min="0"
max="100"
Expand Down Expand Up @@ -302,7 +304,7 @@ export function SettlementOfferModal({
min="0"
max="100"
type="number"
onChange={handleChange}
onChange={handleInputChange}
adornmentStart={{
content: <AdornmentContent>%</AdornmentContent>,
}}
Expand Down

0 comments on commit a1a27e4

Please sign in to comment.