Skip to content

Commit ed10df0

Browse files
author
Vitor Hugo
committed
add tests and fix
1 parent 72adb2b commit ed10df0

File tree

2 files changed

+154
-6
lines changed

2 files changed

+154
-6
lines changed
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
import { NumberFormatValues } from "react-number-format";
2+
3+
import { toSmartContractDecimals } from "@taikai/dappkit/dist/src/utils/numbers";
4+
import { fireEvent } from "@testing-library/dom";
5+
import BigNumber from "bignumber.js";
6+
7+
import CreateBountyTokenAmount, {
8+
ZeroNumberFormatValues,
9+
} from "components/bounty/create-bounty/token-amount/controller";
10+
11+
import { Network } from "interfaces/network";
12+
import { DistributionsProps } from "interfaces/proposal";
13+
import { Token } from "interfaces/token";
14+
15+
import { render } from "__tests__/utils/custom-render";
16+
17+
jest.mock("x-hooks/use-bepro", () => () => ({}));
18+
19+
const mockCurrentToken: Token = {
20+
address: "0x1234567890123456789012345678901234567890",
21+
name: "Mock Token",
22+
symbol: "MOCK",
23+
};
24+
25+
const mockCurrentNetwork: Network = {
26+
id: 1,
27+
name: "Mock Network",
28+
updatedAt: new Date(),
29+
createdAt: new Date(),
30+
description: "Mock Description",
31+
networkAddress: "0x1234567890123456789012345678901234567890",
32+
creatorAddress: "0x1234567890123456789012345678901234567890",
33+
openBounties: 0,
34+
totalBounties: 0,
35+
allowCustomTokens: false,
36+
councilMembers: [],
37+
banned_domains: [],
38+
closeTaskAllowList: [],
39+
allow_list: [],
40+
mergeCreatorFeeShare: 0.05,
41+
proposerFeeShare: 0.5,
42+
chain: {
43+
chainId: 1,
44+
chainRpc: "https://mock-rpc.com",
45+
name: "Mock Chain",
46+
chainName: "Mock Chain",
47+
chainShortName: "MOCK",
48+
chainCurrencySymbol: "MOCK",
49+
chainCurrencyDecimals: "18",
50+
chainCurrencyName: "Mock Token",
51+
blockScanner: "https://mock-scanner.com",
52+
registryAddress: "0x1234567890123456789012345678901234567890",
53+
eventsApi: "https://mock-events.com",
54+
isDefault: true,
55+
closeFeePercentage: 10,
56+
cancelFeePercentage: 1.0,
57+
networkCreationFeePercentage: 0.5,
58+
},
59+
};
60+
61+
describe("TokenAmountController", () => {
62+
beforeEach(() => {
63+
jest.clearAllMocks();
64+
});
65+
66+
it("fuzzes total input and ensures internal adjusted total is divisible by 100 in contract units", () => {
67+
let executions = 0;
68+
69+
let issueAmount = ZeroNumberFormatValues;
70+
let previewAmount = ZeroNumberFormatValues;
71+
72+
const setPreviewAmount = jest.fn((value: NumberFormatValues) => {
73+
previewAmount = value;
74+
});
75+
const updateIssueAmount = jest.fn((value: NumberFormatValues) => {
76+
issueAmount = value;
77+
});
78+
79+
while (executions < 100) {
80+
const decimals = Math.floor(Math.random() * 13) + 6;
81+
const randomValue = parseFloat((Math.random() * 499999 + 1).toFixed(decimals));
82+
83+
const result = render(<CreateBountyTokenAmount
84+
currentToken={mockCurrentToken}
85+
updateCurrentToken={jest.fn()}
86+
addToken={jest.fn()}
87+
canAddCustomToken={true}
88+
defaultToken={mockCurrentToken}
89+
userAddress="0x1234567890123456789012345678901234567890"
90+
customTokens={[]}
91+
tokenBalance={new BigNumber(1)}
92+
issueAmount={issueAmount}
93+
updateIssueAmount={updateIssueAmount}
94+
isFunders={true}
95+
decimals={decimals}
96+
isFunding={false}
97+
needValueValidation={false}
98+
previewAmount={previewAmount}
99+
distributions={{} as DistributionsProps}
100+
currentNetwork={mockCurrentNetwork}
101+
setPreviewAmount={setPreviewAmount}
102+
setDistributions={jest.fn()}
103+
sethasAmountError={jest.fn()}
104+
/>);
105+
106+
const totalAmountInput = result.getAllByTestId("total-amount-input")[0];
107+
108+
const valueString = randomValue.toString();
109+
110+
fireEvent.change(totalAmountInput, { target: { value: valueString } });
111+
112+
result.rerender(<CreateBountyTokenAmount
113+
currentToken={mockCurrentToken}
114+
updateCurrentToken={jest.fn()}
115+
addToken={jest.fn()}
116+
canAddCustomToken={true}
117+
defaultToken={mockCurrentToken}
118+
userAddress="0x1234567890123456789012345678901234567890"
119+
customTokens={[]}
120+
tokenBalance={new BigNumber(1)}
121+
issueAmount={issueAmount}
122+
updateIssueAmount={updateIssueAmount}
123+
isFunders={true}
124+
decimals={decimals}
125+
isFunding={false}
126+
needValueValidation={false}
127+
previewAmount={previewAmount}
128+
distributions={{} as DistributionsProps}
129+
currentNetwork={mockCurrentNetwork}
130+
setPreviewAmount={setPreviewAmount}
131+
setDistributions={jest.fn()}
132+
sethasAmountError={jest.fn()}
133+
/>);
134+
135+
const newValueContract = toSmartContractDecimals(issueAmount.value, decimals);
136+
137+
expect(Number(BigInt(newValueContract) % BigInt(100))).toBe(0);
138+
139+
jest.clearAllMocks();
140+
result.unmount();
141+
142+
executions += 1;
143+
}
144+
});
145+
});

components/bounty/create-bounty/token-amount/controller.tsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {useEffect, useState} from "react";
22
import {NumberFormatValues} from "react-number-format";
33

4-
import { fromSmartContractDecimals, toSmartContractDecimals } from "@taikai/dappkit";
4+
import { fromSmartContractDecimals, toSmartContractDecimals } from "@taikai/dappkit/dist/src/utils/numbers";
55
import BigNumber from "bignumber.js";
66
import {useDebouncedCallback} from "use-debounce";
77

@@ -15,7 +15,7 @@ import {useUserStore} from "x-hooks/stores/user/user.store";
1515

1616
import CreateBountyTokenAmountView from "./view";
1717

18-
const ZeroNumberFormatValues = {
18+
export const ZeroNumberFormatValues = {
1919
value: "",
2020
formattedValue: "",
2121
floatValue: 0,
@@ -102,8 +102,8 @@ export default function CreateBountyTokenAmount({
102102
}
103103

104104
const handleNumberFormat = (v: BigNumber) => ({
105-
value: v.decimalPlaces(5, 0).toFixed(),
106-
floatValue: v.toNumber(),
105+
value: v.decimalPlaces(Math.min(10, decimals), 0).toFixed(),
106+
floatValue: +v.decimalPlaces(Math.min(10, decimals), 0).toFixed(),
107107
formattedValue: v.decimalPlaces(Math.min(10, decimals), 0).toFixed()
108108
});
109109

@@ -191,12 +191,15 @@ export default function CreateBountyTokenAmount({
191191
const rewardValue = BigNumber(calculateRewardAmountGivenTotalAmount(totalAmount.toNumber()));
192192
setPreviewAmount(handleNumberFormat(rewardValue));
193193

194+
if (totalAmount.toFixed() !== value.toString()) {
195+
updateIssueAmount(handleNumberFormat(totalAmount));
196+
}
197+
194198
if (rewardValue.isLessThan(BigNumber(currentToken?.minimum))) {
195199
setInputError("bounty:errors.exceeds-minimum-amount");
196200
sethasAmountError(true);
197201
}
198202
}
199-
200203
setDistributions(_distributions);
201204
}
202205

@@ -236,8 +239,8 @@ export default function CreateBountyTokenAmount({
236239
setInputError("");
237240
sethasAmountError(false);
238241
}
239-
debouncedDistributionsUpdater(values.value, type);
240242
setType(handleNumberFormat(BigNumber(values.value)));
243+
debouncedDistributionsUpdater(values.value, type);
241244
}
242245
}
243246

0 commit comments

Comments
 (0)