Skip to content

Commit

Permalink
Add service fee claim page (#733)
Browse files Browse the repository at this point in the history
* add service fees on claim page

* add success amount

* update usehandleBurnRedeem hook

* clean utils

* move logic to initClaim.tsx

* clean

* rename amount to receive

* add outputAmount check in succesClaim

* refacto getAmountToReceive and edit tests

* refactor getAmountToreceive

* remove undefined from success claim props

* add comments

* refactor input and output

* add outputAmount to success page

* clean bridgeRedeemLayout

* fix changeAmount fn

* Revert "fix changeAmount fn"

This reverts commit 13c2648.

* clean changeAmount fn

* set inputs undefined

* exp => inputAmount to bigint

* update ui kit with npm link, PR #459

* fix retrievePercent

* fix Amount

* fix tests

* rename variable

* rename var + fix component

* fix claim page wwhen failing to parse 1,000 to bigint

* remove comment

* prevent crashing from parsing a string with , seperator

* seperate send from received

* refactor getAmountReceived()

* refactor getAmountReceived() p2

* clean claim page

* rename amount in BridgeRedeemLayout.tsx

* compare struct equal and fix test

* rename _outputAmount

---------

Co-authored-by: Nathan Seva <[email protected]>
  • Loading branch information
pivilartisant and Thykof authored Jun 12, 2024
1 parent b8e9a13 commit 91f2d81
Show file tree
Hide file tree
Showing 36 changed files with 329 additions and 270 deletions.
53 changes: 23 additions & 30 deletions jest/__tests__/getAmountToReceive.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { formatFTAmount } from '@massalabs/react-ui-kit';
import { parseUnits } from 'viem';
import { getAmountToReceive, serviceFeeToPercent } from '../../src/utils/utils';

Expand All @@ -7,61 +6,55 @@ describe('should calculate service fees', () => {
jest.clearAllMocks();
});

test('should return 0.01% of 0.004', () => {
const amount = '0.004';
test('should return 0.004 - a 0.1% service fee', () => {
const serviceFee = 10n;
const decimals = 6;
const result = getAmountToReceive(amount, serviceFee, decimals);
expect(result).toBe('0.003996');
const amount = parseUnits('0.004', decimals);
const result = getAmountToReceive(amount, serviceFee);
expect(result).toBe(3996n);
});

test('should return input amount when service fee is 0n', () => {
const amount = '100';
const serviceFee = 0n;
const decimals = 6;
const result = getAmountToReceive(amount, serviceFee, decimals);
const amount = parseUnits('100', decimals);
const result = getAmountToReceive(amount, serviceFee);
expect(result).toBe(amount);
});

test('should return 0.01% of 100', () => {
const amount = '100';
test('should return 100 - 0.1% of service fees', () => {
const serviceFee = 10n;
const decimals = 6;
const result = getAmountToReceive(amount, serviceFee, decimals);
expect(result).toBe('99.900000');
const amount = parseUnits('100', decimals);
const result = getAmountToReceive(amount, serviceFee);
expect(result).toBe(99900000n);
});

test('should return 0.02% of 5618.897000', () => {
const amount = '5618.897000';
test('should return 5618.897000 - 0.02% of service fee', () => {
const serviceFee = 20n;
const decimals = 6;
const result = getAmountToReceive(amount, serviceFee, decimals);
expect(result).toBe('5,607.659206');
const amount = parseUnits('5618.897000', decimals);
const result = getAmountToReceive(amount, serviceFee);
expect(result).toBe(5607659206n);
});

test('should return 0.02% of 101299120121.128893', () => {
const amount = '101299120121.128893';
test('should return 101299120121.128893 - 0.02% of service fees', () => {
const serviceFee = 20n;
const decimals = 6;
const result = getAmountToReceive(amount, serviceFee, decimals);
expect(result).toBe('101,096,521,880.886640');
const amount = parseUnits('101299120121.128893', decimals);
const result = getAmountToReceive(amount, serviceFee);
expect(result).toBe(101096521880886636n);
});

test('should calculate 0.02% of MAX SAFE INT', () => {
const amount = Number.MAX_SAFE_INTEGER.toString();
const serviceFee = 20n;
const decimals = 18;
const result = getAmountToReceive(amount, serviceFee, decimals);
const amount = parseUnits(Number.MAX_SAFE_INTEGER.toString(), decimals);
const result = getAmountToReceive(amount, serviceFee);

const _amount = parseUnits(amount, decimals);
const redeemFee = (_amount * serviceFee) / 10000n;
const expectedReceivedAmount = _amount - redeemFee;
const expected = formatFTAmount(
expectedReceivedAmount,
decimals,
).amountFormattedFull;

expect(result).toBe(expected);
const redeemFee = (amount * serviceFee) / 10000n;
const expectedReceivedAmount = amount - redeemFee;
expect(result).toBe(expectedReceivedAmount);
});

describe('serviceFeeToPercent', () => {
Expand Down
10 changes: 5 additions & 5 deletions jest/__tests__/handleApproveRedeem.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ describe('handleApproveRedeem', () => {
});

test('should increaseAllowance and approve redeem', async () => {
const amount = U256_MAX.toString();
const amount = U256_MAX;
const opId = 'opId';
smartContractsMock.callSmartContract.mockResolvedValueOnce(opId);
smartContractsMock.getOperationStatus.mockResolvedValueOnce(
Expand All @@ -37,7 +37,7 @@ describe('handleApproveRedeem', () => {
});

test('should not increaseAllowance and show success of redeem approval', async () => {
const amount = '1';
const amount = 1n;

const result = await handleApproveRedeem(amount);

Expand All @@ -62,7 +62,7 @@ describe('handleApproveRedeem', () => {
new Error('error'),
);

const amount = U256_MAX.toString();
const amount = U256_MAX;

const result = await handleApproveRedeem(amount);

Expand Down Expand Up @@ -96,7 +96,7 @@ describe('handleApproveRedeem', () => {
),
);

const amount = U256_MAX.toString();
const amount = U256_MAX;

const result = await handleApproveRedeem(amount);

Expand Down Expand Up @@ -124,7 +124,7 @@ describe('handleApproveRedeem', () => {
.fn()
.mockRejectedValueOnce(new Error(TIMEOUT));

const amount = U256_MAX.toString();
const amount = U256_MAX;

const result = await handleApproveRedeem(amount);

Expand Down
2 changes: 1 addition & 1 deletion jest/__tests__/retrievePercent.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ describe('retrievePercent', () => {
test('', () => {
expect(retrievePercent('1000', '998')).toBe('0.2%');
expect(retrievePercent('10000', '9998')).toBe('0.02%');
expect(retrievePercent('1', '1')).toBe('100%');
expect(retrievePercent('1', '1')).toBe('0%');
expect(retrievePercent('10000000000', '1')).toBe('99.99%');
// minimal value in
expect(retrievePercent('0', '0')).toBe('0%');
Expand Down
9 changes: 4 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"big.js": "^6.2.1",
"currency.js": "^2.0.4",
"delay": "^6.0.0",
"dot-object": "^2.1.5",
"esbuild": "0.17.19",
"localforage": "^1.10.0",
"lottie-react": "^2.4.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ export function EvmConnectButton(): JSX.Element {
formatAmount(
balanceData.value.toString(),
balanceData.decimals,
).amountFormattedFull
).full
} ${balanceData.symbol}`
) : (
<FetchingLine />
Expand Down
7 changes: 2 additions & 5 deletions src/components/ConnectWalletPopup/MassaWallets/MASBalance.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,7 @@ export function MASBalance() {
});
}, [connectedAccount, setBalance]);

const { amountFormattedFull } = formatAmount(
fromMAS(balance?.candidateBalance || '0').toString(),
9,
);
const { full } = formatAmount(fromMAS(balance?.candidateBalance || '0'), 9);

const isBalanceZero = balance?.candidateBalance === '0';

Expand All @@ -46,7 +43,7 @@ export function MASBalance() {
<FetchingLine />
) : (
<>
{amountFormattedFull} {MASSA_TOKEN}
{full} {MASSA_TOKEN}
{renderCustomTooltip && <CustomInfoTag />}
</>
)}
Expand Down
4 changes: 2 additions & 2 deletions src/components/ServiceFeeTooltip/ServiceFeeTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ import { FiInfo } from 'react-icons/fi';
import Intl from '@/i18n/i18n';

export interface ServiceFeeTooltipProps {
inputAmount: string;
inputAmount?: string;
outputAmount?: string;
serviceFee: string;
symbol: string;
}

export function ServiceFeeTooltip(props: ServiceFeeTooltipProps) {
const { inputAmount, outputAmount = '-', serviceFee, symbol } = props;
const { inputAmount = '-', outputAmount = '-', serviceFee, symbol } = props;

function ServiceFeeTooltipBody() {
return (
Expand Down
8 changes: 8 additions & 0 deletions src/const/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,11 @@ export const WAIT_STATUS_TIMEOUT = 300_000;
export const STATUS_POLL_INTERVAL_MS = 1000;

export const TIMEOUT = 'timeout';

// Service fees object to be used in claim page
export const CHAIN_ID_TO_SERVICE_FEE: Record<number, bigint> = {
[mainnet.id]: 0n,
[sepolia.id]: 20n,
[bsc.id]: 0n,
[bscTestnet.id]: 10n,
};
6 changes: 2 additions & 4 deletions src/custom/bridge/handlers/handleApproveRedeem.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { toast } from '@massalabs/react-ui-kit';
import { parseUnits } from 'viem';
import { TIMEOUT, U256_MAX } from '../../../const/const';
import Intl from '../../../i18n/i18n';
import { useTokenStore } from '../../../store/tokenStore';
Expand All @@ -11,16 +10,15 @@ import {
isRejectedByUser,
} from '@/utils/error';

export async function handleApproveRedeem(amount: string) {
export async function handleApproveRedeem(amount: bigint) {
const { setApprove, setBox } = useGlobalStatusesStore.getState();
try {
const { selectedToken } = useTokenStore.getState();
setApprove(Status.Loading);

if (!selectedToken) throw new Error('Token not selected');

const _amount = parseUnits(amount, selectedToken.decimals);
if (selectedToken.allowance < _amount) {
if (selectedToken.allowance < amount) {
await increaseAllowance(U256_MAX);
}

Expand Down
6 changes: 2 additions & 4 deletions src/custom/bridge/handlers/validateTransaction.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { parseUnits } from 'viem';
import Intl from '@/i18n/i18n';
import {
useGlobalStatusesStore,
Expand All @@ -18,7 +17,6 @@ export function validate(tokenBalanceEVM: any) {
return false;
}

const _amount = parseUnits(amount, selectedToken.decimals);
let _balance;

if (massaToEvm) {
Expand All @@ -27,12 +25,12 @@ export function validate(tokenBalanceEVM: any) {
_balance = tokenBalanceEVM;
}

if (_amount <= 0n) {
if (amount <= 0n) {
setAmountError(Intl.t('index.approve.error.invalid-amount'));
return false;
}

if (_balance < _amount) {
if (_balance < amount) {
setAmountError(Intl.t('index.approve.error.insufficient-funds'));
return false;
}
Expand Down
12 changes: 5 additions & 7 deletions src/custom/bridge/useBridgeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ import { BurnState } from '@/utils/const';

export function useBridgeUtils() {
const { reset } = useGlobalStatusesStore();
const {
setInputAmount: setAmount,
resetTxIDs,
setBurnState,
} = useOperationStore();
const { setInputAmount, setOutputAmount, resetTxIDs, setBurnState } =
useOperationStore();

const closeLoadingBox = useCallback(() => {
reset();
setAmount('');
setInputAmount(undefined);
setOutputAmount(undefined);
resetTxIDs();
setBurnState(BurnState.INIT);
}, [reset, setAmount, resetTxIDs, setBurnState]);
}, [reset, setInputAmount, setOutputAmount, resetTxIDs, setBurnState]);

return { closeLoadingBox };
}
5 changes: 1 addition & 4 deletions src/custom/bridge/useBurn.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { useCallback } from 'react';
import { Args, EOperationStatus, MAX_GAS_CALL } from '@massalabs/massa-web3';
import { parseUnits } from 'viem';
import { useAccount } from 'wagmi';
import { handleBurnError } from './handlers/handleTransactionErrors';
import { ForwardingRequest } from '../serializable/request';
Expand All @@ -27,15 +26,13 @@ export function useBurn() {
if (!massaClient) throw new Error('Massa client not found');
if (!selectedToken) throw new Error('Token not selected');

const amt = parseUnits(amount, selectedToken.decimals);

const tokenPair = new TokenPair(
selectedToken.massaToken,
selectedToken.evmToken,
selectedToken.chainId,
);

const request = new ForwardingRequest(amt, evmAddress, tokenPair);
const request = new ForwardingRequest(amount, evmAddress, tokenPair);

try {
const callData = {
Expand Down
Loading

0 comments on commit 91f2d81

Please sign in to comment.