Skip to content

Commit

Permalink
Merge pull request #4121 from CrocSwap/fix-exponential-token-qty-inpu…
Browse files Browse the repository at this point in the history
…t-bugs

allow exponential token quantity input
  • Loading branch information
benwolski authored Sep 17, 2024
2 parents 4b00655 + db32209 commit 61a072d
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 69 deletions.
3 changes: 2 additions & 1 deletion src/App/hooks/useHandleRangeButtonMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ export function useHandleRangeButtonMessage(
} else if (
(tokenAmount === '0' ||
tokenAmount === '0.00' ||
tokenAmount === '') &&
tokenAmount === '' ||
parseFloat(tokenAmount) < 0) &&
!isTokenInputDisabled
) {
rangeButtonErrorMessage = 'Enter an Amount';
Expand Down
21 changes: 17 additions & 4 deletions src/components/Form/TokenInputQuantity.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,25 @@ function TokenInputQuantity(props: propsIF) {

const onChange = (event: ChangeEvent<HTMLInputElement>) => {
let inputStringNoCommas = event.target.value
.replace(/,/g, '.')
.replace(/\s+/g, '');
.replace(/,/g, '.') // Replace commas with dots
.replace(/\s+/g, ''); // Remove any spaces

if (inputStringNoCommas === '.') inputStringNoCommas = '0.';

const inputStringNoUnfinishedExponent = isNaN(+inputStringNoCommas)
? inputStringNoCommas.replace(
/e[+-]?(?!\d)/gi, // Match 'e', 'e-' or 'e+' only if NOT followed by a number
'',
)
: inputStringNoCommas;

const isPrecisionGreaterThanDecimals =
precisionOfInput(inputStringNoCommas) > token.decimals;
if (inputStringNoCommas === '.') inputStringNoCommas = '0.';
if (!isPrecisionGreaterThanDecimals && !isNaN(+inputStringNoCommas)) {

if (
!isPrecisionGreaterThanDecimals &&
!isNaN(+inputStringNoUnfinishedExponent)
) {
handleTokenInputEvent(inputStringNoCommas);
setDisplayValue(inputStringNoCommas);
}
Expand Down
40 changes: 36 additions & 4 deletions src/components/Swap/SwapTokenInput/SwapTokenInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ import { PoolContext } from '../../../contexts/PoolContext';
import { TradeTableContext } from '../../../contexts/TradeTableContext';
import { TradeTokenContext } from '../../../contexts/TradeTokenContext';
import { FlexContainer } from '../../../styled/Common';
import { truncateDecimals } from '../../../ambient-utils/dataLayer';
import {
precisionOfInput,
truncateDecimals,
} from '../../../ambient-utils/dataLayer';
import { linkGenMethodsIF, useLinkGen } from '../../../utils/hooks/useLinkGen';
import { formatTokenInput } from '../../../utils/numbers';
import TokenInputWithWalletBalance from '../../Form/TokenInputWithWalletBalance';
Expand Down Expand Up @@ -152,7 +155,7 @@ function SwapTokenInput(props: propsIF) {
input: string,
sellToken: boolean,
): Promise<number | undefined> {
if (isNaN(parseFloat(input)) || parseFloat(input) === 0 || !crocEnv) {
if (isNaN(parseFloat(input)) || parseFloat(input) <= 0 || !crocEnv) {
setIsLiquidityInsufficient(false);

return undefined;
Expand All @@ -175,10 +178,24 @@ function SwapTokenInput(props: propsIF) {
});
}
if (sellToken) {
let precisionForTruncation = 6;

const rawTokenBQty = impact?.buyQty ? parseFloat(impact.buyQty) : 0;

// find the largest precision that doesn't exceed the token's decimal places
while (
precisionOfInput(
rawTokenBQty.toPrecision(precisionForTruncation),
) > tokenB.decimals &&
precisionForTruncation > 1
) {
precisionForTruncation--;
}
const truncatedTokenBQty = rawTokenBQty
? rawTokenBQty < 2
? rawTokenBQty.toPrecision(6)
? rawTokenBQty
.toPrecision(precisionForTruncation)
.replace(/\.?0+$/, '')
: truncateDecimals(rawTokenBQty, rawTokenBQty < 100 ? 3 : 2)
: '';

Expand All @@ -188,12 +205,27 @@ function SwapTokenInput(props: propsIF) {
setIsBuyLoading(false);
}
} else {
let precisionForTruncation = 6;

const rawTokenAQty = impact?.sellQty
? parseFloat(impact.sellQty)
: 0;

// find the largest precision that doesn't exceed the token's decimal places
while (
precisionOfInput(
rawTokenAQty.toPrecision(precisionForTruncation),
) > tokenA.decimals &&
precisionForTruncation > 1
) {
precisionForTruncation--;
}

const truncatedTokenAQty = rawTokenAQty
? rawTokenAQty < 2
? rawTokenAQty.toPrecision(6)
? rawTokenAQty
.toPrecision(precisionForTruncation)
.replace(/\.?0+$/, '')
: truncateDecimals(rawTokenAQty, rawTokenAQty < 100 ? 3 : 2)
: '';

Expand Down
59 changes: 56 additions & 3 deletions src/components/Trade/Limit/LimitTokenInput/LimitTokenInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import { PoolContext } from '../../../../contexts/PoolContext';
import { TradeTableContext } from '../../../../contexts/TradeTableContext';
import { TradeTokenContext } from '../../../../contexts/TradeTokenContext';
import { FlexContainer } from '../../../../styled/Common';
import { truncateDecimals } from '../../../../ambient-utils/dataLayer';
import {
precisionOfInput,
truncateDecimals,
} from '../../../../ambient-utils/dataLayer';
import {
limitParamsIF,
linkGenMethodsIF,
Expand Down Expand Up @@ -155,9 +158,34 @@ function LimitTokenInput(props: propsIF) {
);
}

let precisionForTruncation = 6;

const fixedTokenBQty = parseFloat(
rawTokenBQty.toFixed(tokenB.decimals),
);

const precisionOfTruncatedTokenBQty = precisionOfInput(
fixedTokenBQty.toPrecision(precisionForTruncation),
);

// find the largest precision that doesn't exceed the token's decimal places
while (
precisionOfTruncatedTokenBQty > tokenB.decimals &&
precisionForTruncation > 1
) {
precisionForTruncation--;
}

const truncatedTokenBQtyIsZero =
fixedTokenBQty.toPrecision(precisionForTruncation) === '0.00000';

const truncatedTokenBQty = rawTokenBQty
? rawTokenBQty < 2
? rawTokenBQty.toPrecision(6)
? truncatedTokenBQtyIsZero
? '0'
: fixedTokenBQty
.toPrecision(precisionForTruncation)
.replace(/\.?0+$/, '') // Remove trailing zeros
: truncateDecimals(rawTokenBQty, 2)
: '';

Expand Down Expand Up @@ -220,9 +248,34 @@ function LimitTokenInput(props: propsIF) {
fromDisplayQty(formattedRawTokenAQty, tokenA.decimals),
);
}
let precisionForTruncation = 6;

const fixedTokenAQty = parseFloat(
rawTokenAQty.toFixed(tokenA.decimals),
);

const precisionOfTruncatedTokenAQty = precisionOfInput(
fixedTokenAQty.toPrecision(precisionForTruncation),
);

// find the largest precision that doesn't exceed the token's decimal places
while (
precisionOfTruncatedTokenAQty > tokenA.decimals &&
precisionForTruncation > 1
) {
precisionForTruncation--;
}

const truncatedTokenAQtyIsZero =
fixedTokenAQty.toPrecision(precisionForTruncation) === '0.00000';

const truncatedTokenAQty = rawTokenAQty
? rawTokenAQty < 2
? rawTokenAQty.toPrecision(6)
? truncatedTokenAQtyIsZero
? '0'
: fixedTokenAQty
.toPrecision(precisionForTruncation)
.replace(/\.?0+$/, '')
: truncateDecimals(rawTokenAQty, 2)
: '';

Expand Down
57 changes: 45 additions & 12 deletions src/pages/platformAmbient/Trade/Limit/Limit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,30 @@ export default function Limit() {
const [tokenBInputQty, setTokenBInputQty] = useState<string>(
!isTokenAPrimary ? primaryQuantity : '',
);

const tokenAInputQtyNoExponentString = useMemo(() => {
return tokenAInputQty.includes('e')
? toDisplayQty(
fromDisplayQty(tokenAInputQty || '0', tokenA.decimals),
tokenA.decimals,
)
: tokenAInputQty;
}, [tokenAInputQty, tokenA.decimals]);

const tokenBInputQtyNoExponentString = useMemo(() => {
try {
return tokenBInputQty.includes('e')
? toDisplayQty(
fromDisplayQty(tokenBInputQty || '0', tokenB.decimals),
tokenB.decimals,
)
: tokenBInputQty;
} catch (error) {
console.log({ error });
return tokenBInputQty;
}
}, [tokenBInputQty, tokenB.decimals]);

const [isWithdrawFromDexChecked, setIsWithdrawFromDexChecked] =
useState(false);
const [isSaveAsDexSurplusChecked, setIsSaveAsDexSurplusChecked] = useState(
Expand Down Expand Up @@ -187,14 +211,17 @@ export default function Limit() {
: quoteTokenDexBalance;
const tokenASurplusMinusTokenARemainderNum =
fromDisplayQty(tokenADexBalance || '0', tokenA.decimals) -
fromDisplayQty(tokenAInputQty || '0', tokenA.decimals);
fromDisplayQty(tokenAInputQtyNoExponentString || '0', tokenA.decimals);
const isTokenADexSurplusSufficient =
tokenASurplusMinusTokenARemainderNum >= 0;
const tokenAQtyCoveredByWalletBalance = isWithdrawFromDexChecked
? tokenASurplusMinusTokenARemainderNum < 0
? tokenASurplusMinusTokenARemainderNum * -1n
: 0n
: fromDisplayQty(tokenAInputQty || '0', tokenA.decimals);
: fromDisplayQty(
tokenAInputQtyNoExponentString || '0',
tokenA.decimals,
);
const isTokenAAllowanceSufficient =
tokenAAllowance === undefined
? true
Expand Down Expand Up @@ -493,11 +520,14 @@ export default function Limit() {

useEffect(() => {
handleLimitButtonMessage(
fromDisplayQty(tokenAInputQty || '0', tokenA.decimals),
fromDisplayQty(
tokenAInputQtyNoExponentString || '0',
tokenA.decimals,
),
);
}, [
isOrderValid,
tokenAInputQty,
tokenAInputQtyNoExponentString,
isPoolInitialized,
poolPriceNonDisplay,
limitTick,
Expand Down Expand Up @@ -601,8 +631,8 @@ export default function Limit() {
const sellToken = tokenA.address;
const buyToken = tokenB.address;

const sellQty = tokenAInputQty;
const buyQty = tokenBInputQty;
const sellQty = tokenAInputQtyNoExponentString;
const buyQty = tokenBInputQtyNoExponentString;

const qty = isTokenAPrimary ? sellQty : buyQty;
const type = isTokenAPrimary ? 'sell' : 'buy';
Expand Down Expand Up @@ -898,8 +928,8 @@ export default function Limit() {

const percentDiffUsdValue =
usdValueTokenA && usdValueTokenB
? ((usdValueTokenB * parseFloat(tokenBInputQty) -
usdValueTokenA * parseFloat(tokenAInputQty)) /
? ((usdValueTokenB * parseFloat(tokenBInputQtyNoExponentString) -
usdValueTokenA * parseFloat(tokenAInputQtyNoExponentString)) /
(usdValueTokenA * parseFloat(tokenAInputQty))) *
100
: 0;
Expand All @@ -921,7 +951,10 @@ export default function Limit() {
set: setTokenAInputQty,
}}
tokenBInputQty={{
value: tokenBInputQty,
value:
tokenBInputQtyNoExponentString !== '0.0'
? tokenBInputQty
: '0',
set: setTokenBInputQty,
}}
isSaveAsDexSurplusChecked={isSaveAsDexSurplusChecked}
Expand Down Expand Up @@ -964,8 +997,8 @@ export default function Limit() {
<ConfirmLimitModal
onClose={handleModalClose}
initiateLimitOrderMethod={sendLimitOrder}
tokenAInputQty={tokenAInputQty}
tokenBInputQty={tokenBInputQty}
tokenAInputQty={tokenAInputQtyNoExponentString}
tokenBInputQty={tokenBInputQtyNoExponentString}
insideTickDisplayPrice={endDisplayPrice}
newLimitOrderTransactionHash={
newLimitOrderTransactionHash
Expand Down Expand Up @@ -1029,7 +1062,7 @@ export default function Limit() {
isPoolInitialized &&
!isTokenAAllowanceSufficient &&
isTokenAWalletBalanceSufficient &&
parseFloat(tokenAInputQty) > 0 ? (
parseFloat(tokenAInputQtyNoExponentString) > 0 ? (
<Button
idForDOM='approve_limit_order_button'
style={{ textTransform: 'none' }}
Expand Down
Loading

0 comments on commit 61a072d

Please sign in to comment.