Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dapp-feat: TransferMultiTokens feature complete (#319) #384

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ import {
import { Contract } from 'ethers';

describe('TokenTransferContract test suite', () => {
const quantity = 369;
const responseCode = 22;
const gasLimit = 1000000;
const invalidSender = '0xabc';
const nonFungibleAmounts = [3, 6, 9];
const fungibleAmounts = [-18, 3, 6, 9];
const senderA = '0xDd7fCb7c2ee96A79B1e201d25F5E43d6a0cED5e6';
const senderB = '0x0851072d7bB726305032Eff23CB8fd22eB74c85B';
const receiverA = '0x7a35433804d8Cd070d98d66C6E9b45c6C32C3CDD';
Expand Down Expand Up @@ -116,7 +119,8 @@ describe('TokenTransferContract test suite', () => {
baseContract as unknown as Contract,
hederaTokenAddress,
[senderA, senderB],
[3, 6, 9]
fungibleAmounts,
gasLimit
);

expect(txRes.err).toBeNull;
Expand All @@ -129,7 +133,8 @@ describe('TokenTransferContract test suite', () => {
baseContract as unknown as Contract,
'0xabc',
[senderA, senderB],
[3, 6, 9]
fungibleAmounts,
gasLimit
);

expect(txRes.err).toBe('Invalid token address');
Expand All @@ -142,7 +147,8 @@ describe('TokenTransferContract test suite', () => {
baseContract as unknown as Contract,
hederaTokenAddress,
[senderA, '0xabc'],
[3, 6, 9]
fungibleAmounts,
gasLimit
);

expect(txRes.err).toBe(`${invalidSender} is an invalid accountID`);
Expand All @@ -155,7 +161,8 @@ describe('TokenTransferContract test suite', () => {
baseContract as unknown as Contract,
hederaTokenAddress,
[senderA, senderB],
[-3, 6, 9]
[-9, -3, 6],
gasLimit
);

expect(txRes.err).toBe(`-3 is an invalid amount`);
Expand All @@ -171,7 +178,8 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
[senderA, senderB],
[receiverA, receiverB],
[3, 6, 9]
nonFungibleAmounts,
gasLimit
);

expect(txRes.err).toBeNull;
Expand All @@ -185,7 +193,8 @@ describe('TokenTransferContract test suite', () => {
'0xabc',
[senderA, senderB],
[receiverA, receiverB],
[3, 6, 9]
nonFungibleAmounts,
gasLimit
);

expect(txRes.err).toBe('Invalid token address');
Expand All @@ -199,7 +208,8 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
[senderA, '0xabc'],
[receiverA, receiverB],
[3, 6, 9]
nonFungibleAmounts,
gasLimit
);

expect(txRes.err).toBe(`${invalidSender} is an invalid sender accountID`);
Expand All @@ -213,7 +223,8 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
[senderA, senderB],
[receiverA, '0xabc'],
[3, 6, 9]
nonFungibleAmounts,
gasLimit
);

expect(txRes.err).toBe(`${invalidSender} is an invalid receiver accountID`);
Expand All @@ -227,7 +238,8 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
[senderA, senderB],
[receiverA, receiverB],
[-3, 6, 9]
[-3, 6, 9],
gasLimit
);

expect(txRes.err).toBe(`-3 is an invalid serial number`);
Expand All @@ -244,7 +256,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -253,14 +265,14 @@ describe('TokenTransferContract test suite', () => {
expect(txRes.transactionHash).toBe(txHash);
});

it('should execute transferSingleToken with API === "NON_FUNGIBLE" then return a successful response code', async () => {
it('should execute transferSingleToken with API === "NFT" then return a successful response code', async () => {
const txRes = await transferSingleToken(
baseContract as unknown as Contract,
'NON_FUNGIBLE',
'NFT',
hederaTokenAddress,
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -276,7 +288,7 @@ describe('TokenTransferContract test suite', () => {
'0xabc',
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -292,7 +304,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
'0xabc',
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -308,7 +320,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
'0xabc',
369,
quantity,
gasLimit
);

Expand All @@ -324,7 +336,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
receiverB,
-369,
quantity * -1,
gasLimit
);

Expand All @@ -342,7 +354,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -358,7 +370,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -374,7 +386,7 @@ describe('TokenTransferContract test suite', () => {
'0xabc',
senderA,
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -390,7 +402,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
'0xabc',
receiverA,
369,
quantity,
gasLimit
);

Expand All @@ -406,7 +418,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
'0xabc',
369,
quantity,
gasLimit
);

Expand All @@ -422,7 +434,7 @@ describe('TokenTransferContract test suite', () => {
hederaTokenAddress,
senderA,
receiverB,
-369,
quantity * -1,
gasLimit
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,16 @@ export const transferCrypto = async (
*
* @param amount: number[]
*
* @param gasLimit: number
*
* @return Promise Promise<SmartContractExecutionResult>
*/
export const transferFungibleTokens = async (
baseContract: Contract,
hederaTokenAddress: string,
accountIDs: string[],
amounts: number[]
amounts: number[],
gasLimit: number
): Promise<SmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand All @@ -95,7 +98,7 @@ export const transferFungibleTokens = async (
});
}
if (!sanitizeErr) {
amounts.some((amount) => {
amounts.slice(1).some((amount) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you taking only the 1st element?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh the amounts.slice(1) actually helps skipping the first element of the array in the loop. The reason is that the initial item in the amounts array represents the totalInputAmount multiplied by -1, ensuring that the sum of the amounts can equal 0. For instance, if a client inputs 2 amounts, 100 and 200, the amounts array would be [-300, 100, 200]. This is why, when sanitizing the parameter, we only need to check on the amounts provided by the client.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, a short comment with this context on top of this line to help readers

if (amount < 0) {
sanitizeErr = `${amount} is an invalid amount`;
return true;
Expand All @@ -109,7 +112,9 @@ export const transferFungibleTokens = async (

// invoking contract methods
try {
const tx = await baseContract.transferTokensPublic(hederaTokenAddress, accountIDs, amounts);
const tx = await baseContract.transferTokensPublic(hederaTokenAddress, accountIDs, amounts, {
gasLimit,
});

return await handleContractResponse(tx);
} catch (err: any) {
Expand All @@ -133,14 +138,17 @@ export const transferFungibleTokens = async (
*
* @param serialNumbers: number[]
*
* @param gasLimit: number
*
* @return Promise<SmartContractExecutionResult>
*/
export const transferNonFungibleTokens = async (
baseContract: Contract,
hederaTokenAddress: string,
senders: string[],
receivers: string[],
serialNumbers: number[]
serialNumbers: number[],
gasLimit: number
): Promise<SmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand Down Expand Up @@ -182,7 +190,8 @@ export const transferNonFungibleTokens = async (
hederaTokenAddress,
senders,
receivers,
serialNumbers
serialNumbers,
{ gasLimit }
);

return await handleContractResponse(tx);
Expand All @@ -205,7 +214,7 @@ export const transferNonFungibleTokens = async (
*
* @param baseContract: ethers.Contract
*
* @param API: "FUNGIBLE" | "NON_FUNGIBLE" | 'FUNGIBLE_FROM' | 'NFT_FROM'
* @param API: "FUNGIBLE" | "NFT" | 'FUNGIBLE_FROM' | 'NFT_FROM'
*
* @param hederaTokenAddress: string
*
Expand All @@ -219,7 +228,7 @@ export const transferNonFungibleTokens = async (
*/
export const transferSingleToken = async (
baseContract: Contract,
API: 'FUNGIBLE' | 'NON_FUNGIBLE' | 'FUNGIBLE_FROM' | 'NFT_FROM',
API: 'FUNGIBLE' | 'NFT' | 'FUNGIBLE_FROM' | 'NFT_FROM',
hederaTokenAddress: string,
sender: string,
receiver: string,
Expand Down Expand Up @@ -257,7 +266,7 @@ export const transferSingleToken = async (
);
break;

case 'NON_FUNGIBLE':
case 'NFT':
transactionResult = await baseContract.transferNFTPublic(
hederaTokenAddress,
sender,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ import { ReactNode, useEffect, useState } from 'react';
import { balanceOf } from '@/api/hedera/erc20-interactions';
import { getBalancesFromLocalStorage } from '@/api/localStorage';
import { CommonErrorToast } from '@/components/toast/CommonToast';
import { HEDERA_BRANDING_COLORS } from '@/utils/common/constants';
import HederaCommonTextField from '@/components/common/HederaCommonTextField';
import { HEDERA_BRANDING_COLORS, HEDERA_CHAKRA_INPUT_BOX_SIZES } from '@/utils/common/constants';
import {
Popover,
PopoverContent,
Expand Down Expand Up @@ -209,7 +209,7 @@ const BalanceOf = ({ baseContract }: PageProps) => {
<div className="flex gap-12 items-center w-[580px]">
{/* method */}
<HederaCommonTextField
size={'md'}
size={HEDERA_CHAKRA_INPUT_BOX_SIZES.medium}
value={accountAddress}
title={'Balance of'}
explanation={'Returns the amount of tokens owned by account.'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,22 @@ import Link from 'next/link';
import { AiOutlineMinus } from 'react-icons/ai';
import { Dispatch, SetStateAction } from 'react';
import { Tooltip, Select, Input } from '@chakra-ui/react';
import { HEDERA_BRANDING_COLORS } from '@/utils/common/constants';
import { convertCalmelCaseFunctionName } from '@/utils/common/helpers';
import {
HEDERA_BRANDING_COLORS,
HEDERA_CHAKRA_INPUT_BOX_SIZES,
HEDERA_CHAKRA_INPUT_BOX_SHARED_CLASSNAME,
} from '@/utils/common/constants';
import {
CommonKeyObject,
IHederaTokenServiceKeyType,
IHederaTokenServiceKeyValueType,
} from '@/types/contract-interactions/HTS';
import {
handleAddingOrRemovingKeys,
handleUpdateKeyValue,
handleKeyTypeOnChange,
handleAddingOrRemovingKeys,
handleKeyValueTypeOnChange,
handleUpdateKeyValue,
} from '../methods/signingKeys';

/** @dev shared component presenting signing keys*/
Expand Down Expand Up @@ -152,9 +156,9 @@ export const SharedSigningKeysComponent = ({
? 'ID of a smart contract instance...'
: `${key.keyValueType.split('_')[0].toUpperCase()} compressed public key...`
}
size={'md'}
size={HEDERA_CHAKRA_INPUT_BOX_SIZES.medium}
focusBorderColor={HEDERA_BRANDING_COLORS.purple}
className={'w-full border-white/30'}
className={HEDERA_CHAKRA_INPUT_BOX_SHARED_CLASSNAME}
/>
)}
</div>
Expand Down
Loading