Skip to content

Commit

Permalink
fix:[IGSGS-7] Formats Smart Checkout results (#1868)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwhardwick authored Jun 5, 2024
1 parent 2f2089d commit 0932bfe
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 16 deletions.
1 change: 1 addition & 0 deletions packages/checkout/sdk/src/env/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { NetworkDetails, NetworkMap } from '../types';
export const ENV_DEVELOPMENT = 'development' as Environment;

export const DEFAULT_TOKEN_DECIMALS = 18;
export const DEFAULT_TOKEN_FORMATTING_DECIMALS = 6;

export const NATIVE = 'native';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
} from '../indexer/fetchL1Representation';
import { DEFAULT_TOKEN_DECIMALS } from '../../../env';
import { isNativeToken } from '../../../tokens';
import { isMatchingAddress } from '../../../utils/utils';
import { formatSmartCheckoutAmount, isMatchingAddress } from '../../../utils/utils';

export const hasSufficientL1Eth = (
tokenBalanceResult: TokenBalanceResult,
Expand Down Expand Up @@ -92,7 +92,7 @@ const constructBridgeFundingRoute = (
type: itemType,
fundsRequired: {
amount: bridgeRequirement.amount,
formattedAmount: bridgeRequirement.formattedAmount,
formattedAmount: formatSmartCheckoutAmount(bridgeRequirement.formattedAmount),
},
userBalance: {
balance: balance.balance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { BridgeRequirement } from '../bridge/bridgeRoute';
import { DexQuote, DexQuotes } from '../types';
import { INDEXER_ETH_ROOT_CONTRACT_ADDRESS, L1ToL2TokenAddressMapping } from '../indexer/fetchL1Representation';
import { BalanceCheckResult } from '../../balanceCheck/types';
import { isMatchingAddress } from '../../../utils/utils';
import { formatSmartCheckoutAmount, isMatchingAddress } from '../../../utils/utils';

// The dex will return all the fees which is in a particular token (currently always IMX)
// If any of the fees are in the same token that is trying to be swapped (e.g. trying to swap IMX)
Expand Down Expand Up @@ -145,7 +145,7 @@ export const constructBridgeRequirements = (

bridgeRequirements.push({
amount: amountToBridge,
formattedAmount: utils.formatUnits(amountToBridge, l1balance.token.decimals),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(amountToBridge, l1balance.token.decimals)),
// L2 address is used for the bridge requirement as the bridge route uses the indexer to find L1 address
l2address,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
import { BalanceERC20Requirement, BalanceNativeRequirement, BalanceRequirement } from '../../balanceCheck/types';
import { allowListCheckForOnRamp } from '../../allowList';
import { isNativeToken } from '../../../tokens';
import { isMatchingAddress } from '../../../utils/utils';
import { formatSmartCheckoutAmount, isMatchingAddress } from '../../../utils/utils';

export const onRampRoute = async (
config: CheckoutConfiguration,
Expand Down Expand Up @@ -42,7 +42,7 @@ export const onRampRoute = async (
type: isNativeToken(required.token.address) ? ItemType.NATIVE : ItemType.ERC20,
fundsRequired: {
amount: delta.balance,
formattedAmount: delta.formattedBalance,
formattedAmount: formatSmartCheckoutAmount(delta.formattedBalance),
},
userBalance: {
balance: current.balance,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
} from '../../../types';
import { quoteFetcher } from './quoteFetcher';
import { HttpClient } from '../../../api/http';
import { formatSmartCheckoutAmount } from '../../../utils/utils';

jest.mock('../../../config/remoteConfigFetcher');
jest.mock('./quoteFetcher');
Expand Down Expand Up @@ -236,7 +237,7 @@ describe('swapRoute', () => {
type: ItemType.ERC20,
fundsRequired: {
amount: BigNumber.from(1),
formattedAmount: utils.formatUnits(BigNumber.from(1), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(1), 18)),
},
userBalance: {
balance: BigNumber.from(10),
Expand All @@ -258,6 +259,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapGasFee: {
Expand All @@ -268,6 +270,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapFees: [{
Expand All @@ -279,6 +282,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
}],
},
Expand Down Expand Up @@ -367,7 +371,7 @@ describe('swapRoute', () => {
type: ItemType.ERC20,
fundsRequired: {
amount: BigNumber.from(1),
formattedAmount: utils.formatUnits(BigNumber.from(1), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(1), 18)),
},
userBalance: {
balance: BigNumber.from(10),
Expand All @@ -389,6 +393,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapGasFee: {
Expand All @@ -399,6 +404,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapFees: [{
Expand All @@ -410,6 +416,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
}],
},
Expand Down Expand Up @@ -510,7 +517,7 @@ describe('swapRoute', () => {
type: ItemType.ERC20,
fundsRequired: {
amount: BigNumber.from(1),
formattedAmount: utils.formatUnits(BigNumber.from(1), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(1), 18)),
},
userBalance: {
balance: BigNumber.from(10),
Expand All @@ -532,6 +539,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapGasFee: {
Expand All @@ -542,6 +550,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapFees: [{
Expand All @@ -553,6 +562,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
}],
},
Expand All @@ -564,7 +574,7 @@ describe('swapRoute', () => {
type: ItemType.ERC20,
fundsRequired: {
amount: BigNumber.from(1),
formattedAmount: utils.formatUnits(BigNumber.from(1), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(1), 18)),
},
userBalance: {
balance: BigNumber.from(10),
Expand All @@ -586,6 +596,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapGasFee: {
Expand All @@ -596,6 +607,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
},
swapFees: [{
Expand All @@ -607,6 +619,7 @@ describe('swapRoute', () => {
decimals: 18,
name: 'IMX',
symbol: 'IMX',
address: undefined,
},
}],
},
Expand Down Expand Up @@ -1165,7 +1178,7 @@ describe('swapRoute', () => {
type: ItemType.NATIVE,
fundsRequired: {
amount: BigNumber.from(100),
formattedAmount: utils.formatUnits(BigNumber.from(100), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(100), 18)),
},
userBalance: {
balance: BigNumber.from(100),
Expand Down Expand Up @@ -1222,7 +1235,7 @@ describe('swapRoute', () => {
type: ItemType.ERC20,
fundsRequired: {
amount: BigNumber.from(100),
formattedAmount: utils.formatUnits(BigNumber.from(100), 18),
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(BigNumber.from(100), 18)),
},
userBalance: {
balance: BigNumber.from(100),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { BalanceCheckResult, BalanceRequirement } from '../../balanceCheck/types
import { TokenBalanceResult } from '../types';
import { quoteFetcher } from './quoteFetcher';
import { isNativeToken } from '../../../tokens';
import { isMatchingAddress } from '../../../utils/utils';
import { formatSmartCheckoutAmount, isMatchingAddress } from '../../../utils/utils';

const constructFees = (
approvalGasFee: Amount | null | undefined,
Expand Down Expand Up @@ -105,10 +105,10 @@ export const constructSwapRoute = (
type,
fundsRequired: {
amount: fundsRequired,
formattedAmount: utils.formatUnits(
formattedAmount: formatSmartCheckoutAmount(utils.formatUnits(
fundsRequired,
userBalance.token.decimals,
),
)),
},
userBalance: {
balance: userBalance.balance,
Expand Down
19 changes: 18 additions & 1 deletion packages/checkout/sdk/src/utils/utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChainId } from '../types';
import { isMatchingAddress, isZkEvmChainId } from './utils';
import { formatSmartCheckoutAmount, isMatchingAddress, isZkEvmChainId } from './utils';

describe('utils', () => {
it('should return true if addresses are the same', () => {
Expand Down Expand Up @@ -38,4 +38,21 @@ describe('utils', () => {
expect(chainId).toBeFalsy();
});
});

describe('formatSmartCheckoutAmount', () => {
const formatTokenAmountPatterns = [
{ amount: '0.1234567', expected: '0.123457' },
{ amount: '0.1234561', expected: '0.123457' },
{ amount: '0.1234560', expected: '0.123456' },
{ amount: '0.1234', expected: '0.1234' },
{ amount: '120.100001', expected: '120.100001' },
{ amount: '120.1000011', expected: '120.100002' },
{ amount: '120.1000019', expected: '120.100002' },
{ amount: '120.10000101', expected: '120.100002' },
{ amount: '0.000000000000000001', expected: '0.000001' },
];
it.each(formatTokenAmountPatterns)('.formatTokenAmount($amount)', ({ amount, expected }) => {
expect(formatSmartCheckoutAmount(amount)).toEqual(expected);
});
});
});
32 changes: 32 additions & 0 deletions packages/checkout/sdk/src/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { DEFAULT_TOKEN_FORMATTING_DECIMALS } from '../env/constants';
import { ChainId } from '../types';

export const isMatchingAddress = (addressA: string = '', addressB: string = '') => (
Expand All @@ -7,3 +8,34 @@ export const isMatchingAddress = (addressA: string = '', addressB: string = '')
export const isZkEvmChainId = (chainId: ChainId) => chainId === ChainId.IMTBL_ZKEVM_DEVNET
|| chainId === ChainId.IMTBL_ZKEVM_TESTNET
|| chainId === ChainId.IMTBL_ZKEVM_MAINNET;

const trimRoundUpDecimals = (s: string, maxDecimals: number): string => {
const pointIndex = s.indexOf('.');
const extraDecimals = s.substring(pointIndex + maxDecimals + 1);
if (extraDecimals && parseFloat(extraDecimals) >= 1) {
const trimmedDecimals = s.substring(0, pointIndex + maxDecimals + 1);
const increment = 1 / (10 ** maxDecimals);
return (parseFloat(trimmedDecimals) + increment).toString();
}
return parseFloat(s.substring(0, pointIndex + maxDecimals + 1)).toString();
};

/**
* Rounds up a token amount to a set number of decimals, so it can be handled by Swap, Bridge, OnRamp Widgets.
* Widgets can only handle formatted values of 6 (DEFAULT_TOKEN_FORMATTING_DECIMALS) decimals.
* @param amount
* @param maxDecimals
* @returns
*/
export const formatSmartCheckoutAmount = (
amount: string,
maxDecimals: number = DEFAULT_TOKEN_FORMATTING_DECIMALS,
) => {
// Only float numbers will be handled by this function
const pointIndex = amount.indexOf('.');
if (pointIndex === -1) return amount;

const formattedAmount = trimRoundUpDecimals(amount, maxDecimals);

return formattedAmount;
};

0 comments on commit 0932bfe

Please sign in to comment.