Skip to content

Commit 4f457b8

Browse files
committed
Calculation before minting.
1 parent 58b5694 commit 4f457b8

File tree

1 file changed

+84
-28
lines changed

1 file changed

+84
-28
lines changed

web/src/app/[cat]/InteractionClient.tsx

Lines changed: 84 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -148,43 +148,68 @@ export default function InteractionClient() {
148148
}
149149
}, []);
150150

151-
// Function to calculate user amount after fees
152-
// Simple math: if fee is 0.5%, then userAmount = mintAmount * 0.995
151+
// PRECISION IMPROVEMENT: Using BigInt arithmetic for exact 18-decimal precision
152+
// Function to calculate user amount after fees using precise BigInt arithmetic
153+
// Matches smart contract: feeAmount = (amount * 500) / 100000; userAmount = amount - feeAmount
153154
const calculateUserAmountAfterFees = useCallback((amount: string) => {
154155
if (!amount || isNaN(Number(amount)) || Number(amount) <= 0) {
155156
setUserAmountAfterFees(0);
156157
return;
157158
}
158159

159-
const mintAmount = Number(amount);
160-
161-
// Simple calculation: userAmount = mintAmount * (1 - 0.005)
162-
const userAmount = mintAmount * 0.995;
163-
164-
// Round to 6 decimal places for better UX
165-
const roundedUserAmount = Math.round(userAmount * 1000000) / 1000000;
166-
167-
setUserAmountAfterFees(roundedUserAmount);
160+
try {
161+
// Convert to BigInt with 18 decimals for precise calculation
162+
const amountBigInt = parseUnits(amount, decimals);
163+
164+
// Smart contract constants: clowderFee = 500, denominator = 100000
165+
const clowderFee = BigInt(500);
166+
const denominator = BigInt(100000);
167+
168+
// Calculate fee: (amount * 500) / 100000
169+
const feeAmountBigInt = (amountBigInt * clowderFee) / denominator;
170+
171+
// Calculate user amount: amount - fee
172+
const userAmountBigInt = amountBigInt - feeAmountBigInt;
173+
174+
// Convert back to number for display (maintaining precision)
175+
const userAmountNumber = Number(formatUnits(userAmountBigInt, decimals));
176+
177+
setUserAmountAfterFees(userAmountNumber);
178+
} catch (error) {
179+
console.error('Error calculating user amount after fees:', error);
180+
setUserAmountAfterFees(0);
181+
}
168182
}, []);
169183

170-
// Function to calculate mint amount needed to achieve desired receive amount
171-
// Simple math: if fee is 0.5%, then receiveAmount = mintAmount * 0.995
172-
// Therefore: mintAmount = receiveAmount / 0.995
184+
// PRECISION IMPROVEMENT: Reverse calculation also uses precise BigInt arithmetic
185+
// Function to calculate mint amount needed to achieve desired receive amount using precise BigInt arithmetic
186+
// Reverse calculation: if userAmount = amount - (amount * 500) / 100000, then amount = userAmount * 100000 / (100000 - 500)
173187
const calculateMintAmountFromReceive = useCallback((desiredReceiveAmount: string) => {
174188
if (!desiredReceiveAmount || isNaN(Number(desiredReceiveAmount)) || Number(desiredReceiveAmount) <= 0) {
175189
setCalculatedMintAmount(0);
176190
return;
177191
}
178192

179-
const receiveAmount = Number(desiredReceiveAmount);
180-
181-
// Simple calculation: mintAmount = receiveAmount / (1 - 0.005)
182-
const mintAmount = receiveAmount / 0.995;
183-
184-
// Round to 6 decimal places for better UX
185-
const roundedMintAmount = Math.round(mintAmount * 1000000) / 1000000;
186-
187-
setCalculatedMintAmount(roundedMintAmount);
193+
try {
194+
// Convert to BigInt with 18 decimals for precise calculation
195+
const receiveAmountBigInt = parseUnits(desiredReceiveAmount, decimals);
196+
197+
// Smart contract constants: clowderFee = 500, denominator = 100000
198+
const clowderFee = BigInt(500);
199+
const denominator = BigInt(100000);
200+
201+
// Calculate mint amount: receiveAmount * denominator / (denominator - clowderFee)
202+
// This gives us: receiveAmount * 100000 / (100000 - 500) = receiveAmount * 100000 / 99500
203+
const mintAmountBigInt = (receiveAmountBigInt * denominator) / (denominator - clowderFee);
204+
205+
// Convert back to number for display (maintaining precision)
206+
const mintAmountNumber = Number(formatUnits(mintAmountBigInt, decimals));
207+
208+
setCalculatedMintAmount(mintAmountNumber);
209+
} catch (error) {
210+
console.error('Error calculating mint amount from receive:', error);
211+
setCalculatedMintAmount(0);
212+
}
188213
}, []);
189214

190215
// Add new state for transaction signing
@@ -1289,14 +1314,30 @@ export default function InteractionClient() {
12891314
type="number"
12901315
placeholder="Enter amount to mint"
12911316
value={mintAmount}
1292-
onChange={(e) => setMintAmount(Math.min(Number(e.target.value), tokenDetails.maxMintableAmount).toString())}
1317+
onChange={(e) => {
1318+
const inputValue = e.target.value;
1319+
if (inputValue === '' || inputValue === '.') {
1320+
setMintAmount(inputValue);
1321+
} else {
1322+
const numValue = Number(inputValue);
1323+
if (!isNaN(numValue) && numValue >= 0) {
1324+
// Only limit to max mintable amount if it exceeds the limit
1325+
if (numValue <= tokenDetails.maxMintableAmount) {
1326+
setMintAmount(inputValue);
1327+
} else {
1328+
setMintAmount(tokenDetails.maxMintableAmount.toString());
1329+
}
1330+
}
1331+
}
1332+
}}
12931333
className="h-10 text-sm bg-white/60 dark:bg-[#2a1a00] border-2 border-gray-200 dark:border-yellow-400/20 text-gray-600 dark:text-yellow-200"
12941334
/>
12951335
<Button
12961336
type="button"
12971337
onClick={() => {
12981338
const safeMaxAmount = Math.max(0, tokenDetails.maxMintableAmount);
1299-
setMintAmount(safeMaxAmount.toFixed(6));
1339+
// Maintain full precision for input, but limit displayed decimals for UX
1340+
setMintAmount(safeMaxAmount.toString());
13001341
}}
13011342
disabled={tokenDetails.maxMintableAmount === 0}
13021343
className="h-10 px-3 text-sm bg-gray-500 dark:bg-gray-600 hover:bg-gray-600 dark:hover:bg-gray-700 text-white rounded-xl whitespace-nowrap"
@@ -1349,9 +1390,24 @@ export default function InteractionClient() {
13491390
<Button
13501391
type="button"
13511392
onClick={() => {
1352-
// Set a reasonable max receive amount (slightly less than max mintable due to fees)
1353-
const safeMaxReceiveAmount = Math.max(0, tokenDetails.maxMintableAmount * 0.99);
1354-
setReceiveAmount(safeMaxReceiveAmount.toFixed(6));
1393+
// Calculate precise max receive amount using exact smart contract fee calculation
1394+
const maxMintableAmount = tokenDetails.maxMintableAmount;
1395+
if (maxMintableAmount > 0) {
1396+
try {
1397+
const amountBigInt = parseUnits(maxMintableAmount.toString(), decimals);
1398+
const clowderFee = BigInt(500);
1399+
const denominator = BigInt(100000);
1400+
const feeAmountBigInt = (amountBigInt * clowderFee) / denominator;
1401+
const maxReceiveAmountBigInt = amountBigInt - feeAmountBigInt;
1402+
const maxReceiveAmount = formatUnits(maxReceiveAmountBigInt, decimals);
1403+
setReceiveAmount(maxReceiveAmount);
1404+
} catch (error) {
1405+
console.error('Error calculating max receive amount:', error);
1406+
setReceiveAmount('0');
1407+
}
1408+
} else {
1409+
setReceiveAmount('0');
1410+
}
13551411
}}
13561412
disabled={tokenDetails.maxMintableAmount === 0}
13571413
className="h-10 px-3 text-sm bg-gray-500 dark:bg-gray-600 hover:bg-gray-600 dark:hover:bg-gray-700 text-white rounded-xl whitespace-nowrap"

0 commit comments

Comments
 (0)