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

feat: added dynamic feeAmount parameter to fungible and non-fungible token create with custom fee method #700

Merged
Show file tree
Hide file tree
Changes from 3 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

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ contract TokenCreateCustomContract is HederaTokenService, ExpiryHelper, KeyHelpe
int64 initialTotalSupply,
int64 maxSupply,
int32 decimals,
int64 feeAmount,
IHederaTokenService.TokenKey[] memory keys
) public payable {
IHederaTokenService.Expiry memory expiry = IHederaTokenService.Expiry(
Expand All @@ -61,7 +62,7 @@ contract TokenCreateCustomContract is HederaTokenService, ExpiryHelper, KeyHelpe
);

IHederaTokenService.FixedFee[] memory fixedFees = new IHederaTokenService.FixedFee[](1);
fixedFees[0] = IHederaTokenService.FixedFee(1, fixedFeeTokenAddress, false, false, treasury);
fixedFees[0] = IHederaTokenService.FixedFee(feeAmount, fixedFeeTokenAddress, false, false, treasury);

IHederaTokenService.FractionalFee[] memory fractionalFees = new IHederaTokenService.FractionalFee[](1);
fractionalFees[0] = IHederaTokenService.FractionalFee(4, 5, 10, 30, false, treasury);
Expand Down Expand Up @@ -110,6 +111,7 @@ contract TokenCreateCustomContract is HederaTokenService, ExpiryHelper, KeyHelpe
string memory symbol,
string memory memo,
int64 maxSupply,
int64 feeAmount,
IHederaTokenService.TokenKey[] memory keys
) public payable {
IHederaTokenService.Expiry memory expiry = IHederaTokenService.Expiry(
Expand All @@ -121,7 +123,7 @@ contract TokenCreateCustomContract is HederaTokenService, ExpiryHelper, KeyHelpe
);

IHederaTokenService.FixedFee[] memory fixedFees = new IHederaTokenService.FixedFee[](1);
fixedFees[0] = IHederaTokenService.FixedFee(1, fixedFeeTokenAddress, false, false, treasury);
fixedFees[0] = IHederaTokenService.FixedFee(feeAmount, fixedFeeTokenAddress, false, false, treasury);

IHederaTokenService.RoyaltyFee[] memory royaltyFees = new IHederaTokenService.RoyaltyFee[](1);
royaltyFees[0] = IHederaTokenService.RoyaltyFee(4, 5, 10, fixedFeeTokenAddress, false, treasury);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe('createHederaFungibleToken test suite', () => {
const initialSupply = 900000000; // 9 WHBAR
const metadata = ['Zeus', 'Athena', 'Apollo'];
const msgValue = '20000000000000000000'; // 20 hbar
const feeAmount = 1000; // 20 hbar
const recipient = '0x34810E139b451e0a4c67d5743E956Ac8990842A8';
const contractId = '0xbdcdf69052c9fc01e38377d05cc83c28ee43f24a';
const feeTokenAddress = '0x00000000000000000000000000000000000006Ab';
Expand Down Expand Up @@ -161,7 +162,8 @@ describe('createHederaFungibleToken test suite', () => {
contractId,
inputKeys,
msgValue,
feeTokenAddress
feeTokenAddress,
feeAmount
);

expect(txRes.err).toBeNull;
Expand Down Expand Up @@ -342,7 +344,8 @@ describe('createHederaFungibleToken test suite', () => {
contractId,
inputKeys,
msgValue,
feeTokenAddress
feeTokenAddress,
feeAmount
);

expect(txRes.err).toBeNull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ import { TNetworkName } from '@/types/common';
*
* @param feeTokenAddress?: string
*
* @param feeTokenAmount?: number
*
* @return Promise<ISmartContractExecutionResult>
*
* @see https://github.com/hashgraph/hedera-smart-contracts/blob/main/contracts/hts-precompile/IHederaTokenService.sol#L136
Expand All @@ -73,7 +75,8 @@ export const createHederaFungibleToken = async (
treasury: string,
inputKeys: ICommonKeyObject[],
msgValue: string,
feeTokenAddress?: string
feeTokenAddress?: string,
feeTokenAmount?: number
Copy link
Contributor

Choose a reason for hiding this comment

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

small nit, should we use feeAmount to be consistent with the rest of the PR?

Copy link
Member Author

@quiet-node quiet-node Mar 6, 2024

Choose a reason for hiding this comment

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

Gotcha I don't know why I left it as feeTokenAmount! Good catch thanks! Pushed in the fix!

): Promise<ISmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand Down Expand Up @@ -114,6 +117,7 @@ export const createHederaFungibleToken = async (
initialTotalSupply,
maxSupply,
decimals,
feeTokenAmount,
keyRes.hederaTokenKeys,
{
value: ethers.parseEther(msgValue),
Expand Down Expand Up @@ -175,6 +179,8 @@ export const createHederaFungibleToken = async (
*
* @param feeTokenAddress?: ethers.AddressLike
*
* @param feeTokenAmount?: number
*
* @return Promise<ISmartContractExecutionResult>
*
* @see https://github.com/hashgraph/hedera-smart-contracts/blob/main/contracts/hts-precompile/IHederaTokenService.sol#L136
Expand All @@ -189,7 +195,8 @@ export const createHederaNonFungibleToken = async (
treasury: ethers.AddressLike,
inputKeys: ICommonKeyObject[],
msgValue: string,
feeTokenAddress?: ethers.AddressLike
feeTokenAddress?: ethers.AddressLike,
feeTokenAmount?: number
): Promise<ISmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand Down Expand Up @@ -224,6 +231,7 @@ export const createHederaNonFungibleToken = async (
symbol,
memo,
maxSupply,
feeTokenAmount,
keyRes.hederaTokenKeys,
{
value: ethers.parseEther(msgValue),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ interface ParamsProps {
spenderAddress?: string;
withCustomFee?: boolean;
accountAddress?: string;
feeTokenAmount?: number;
serialNumbers?: number[];
receiverAddress?: string;
feeTokenAddress?: string;
Expand All @@ -47,8 +48,8 @@ interface ParamsProps {
autoRenewAccount?: string;
tokenAddresses?: string[];
recipientAddress?: string;
associatingAddress?: string;
tokenAddressToMint?: string;
associatingAddress?: string;
hederaTokenAddress?: string;
fungibleReceivers?: string[];
nonFungibleReceivers?: string[];
Expand Down Expand Up @@ -101,6 +102,7 @@ export const handleSanitizeHederaFormInputs = ({
senderAddress,
withCustomFee,
serialNumbers,
feeTokenAmount,
spenderAddress,
accountAddress,
tokenAddresses,
Expand Down Expand Up @@ -133,6 +135,8 @@ export const handleSanitizeHederaFormInputs = ({
sanitizeErr = 'Invalid denomination token ID';
} else if (!isAddress(treasury)) {
sanitizeErr = 'Invalid treasury account address';
} else if (withCustomFee && Number(feeTokenAmount) <= 0) {
sanitizeErr = 'Custom fee amount must be positive';
Copy link
Contributor

Choose a reason for hiding this comment

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

not sure if applicable, should we also validate if the number if too big?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice input! Though I think we can address it in another PR.

}
// sanitize keys
if (!sanitizeErr && keys) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
maxSupply: '',
initSupply: '',
feeTokenAddress: '',
feeTokenAmount: '',
freezeStatus: false,
};
const [paramValues, setParamValues] = useState<any>(initialParamValues);
Expand Down Expand Up @@ -128,6 +129,7 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
maxSupply,
initSupply,
freezeStatus,
feeTokenAmount,
feeTokenAddress,
} = paramValues;

Expand All @@ -143,6 +145,7 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
maxSupply,
initSupply,
withCustomFee,
feeTokenAmount,
feeTokenAddress,
});

Expand All @@ -168,7 +171,8 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
treasury,
keys,
feeValue,
withCustomFee ? feeTokenAddress : undefined
withCustomFee ? feeTokenAddress : undefined,
withCustomFee ? Number(feeTokenAmount) : undefined
);

// turn is loading off
Expand Down Expand Up @@ -318,18 +322,33 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {

{/* fee token address */}
{withCustomFee && (
<SharedFormInputField
param={'feeTokenAddress'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAddress']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAddress'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAddress'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputFocusBorderColor}
/>
<>
<SharedFormInputField
param={'feeTokenAddress'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAddress']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAddress'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAddress'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputFocusBorderColor}
/>

<SharedFormInputField
param={'feeTokenAmount'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAmount']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAmount'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAmount'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputFocusBorderColor}
/>
</>
)}

{/* treasury */}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {
treasury: '',
feeValue: '',
maxSupply: '',
feeTokenAmount: '',
feeTokenAddress: '',
};
const [paramValues, setParamValues] = useState<any>(initialParamValues);
Expand Down Expand Up @@ -112,7 +113,8 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {

/** @dev handle invoking the API to interact with smart contract and create non fungible token */
const handleCreatingNonFungibleToken = async () => {
const { name, symbol, memo, maxSupply, treasury, feeTokenAddress, feeValue } = paramValues;
const { name, symbol, memo, maxSupply, treasury, feeTokenAddress, feeValue, feeTokenAmount } =
paramValues;

// sanitize params
const sanitizeErr = handleSanitizeHederaFormInputs({
Expand All @@ -124,6 +126,7 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {
treasury,
maxSupply,
withCustomFee,
feeTokenAmount,
feeTokenAddress,
});

Expand All @@ -146,7 +149,8 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {
treasury,
keys,
feeValue,
withCustomFee ? feeTokenAddress : undefined
withCustomFee ? feeTokenAddress : undefined,
withCustomFee ? Number(feeTokenAmount) : undefined
);

// turn is loading off
Expand Down Expand Up @@ -248,18 +252,33 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {

{/* fee token address */}
{withCustomFee && (
<SharedFormInputField
param={'feeTokenAddress'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAddress']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAddress'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAddress'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputFocusBorderColor}
/>
<>
<SharedFormInputField
param={'feeTokenAddress'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAddress']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAddress'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAddress'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAddress'].inputFocusBorderColor}
/>

<SharedFormInputField
param={'feeTokenAmount'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeTokenAmount']}
paramKey={(htsTokenCreateParamFields as any)['feeTokenAmount'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeTokenAmount'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeTokenAmount'].inputFocusBorderColor}
/>
</>
)}

{/* keys */}
Expand All @@ -281,7 +300,7 @@ const NonFungibleTokenCreate = ({ baseContract }: PageProps) => {
feeType={'SERVICE'}
paramValues={paramValues.feeValue}
placeHolder={'Service fee...'}
executeBtnTitle={'Create Fungible Token'}
executeBtnTitle={'Create Non Fungible Token'}
handleInputOnChange={handleInputOnChange}
explanation={
'Represents the fee in HBAR directly paid to the contract system of the Hedera Token Service'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ export const htsTokenCreateParamFields = {
inputPlaceholder: 'The denomination token ID...',
explanation: 'represents the ID of token that is used for fixed fee denomination',
},
feeTokenAmount: {
...HEDERA_SHARED_PARAM_INPUT_FIELDS,
inputType: 'number',
paramKey: 'feeTokenAmount',
inputPlaceholder: 'The fee amount...',
explanation: 'represents the number of units to assess as a fee',
},
customFee: {
paramKey: 'customFee',
explanation: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ describe('TokenCreateCustomContract Test Suite', () => {
const initialSupply = 900000000; // 9 WHBAR
const maxSupply = 30000000000; // 300 WHBAR
const decimals = 8;
const feeAmount = 1000n;
const freezeDefaultStatus = false;
let keys, signers, fixedFeeTokenAddress, tokenCreateCustomContract;

Expand Down Expand Up @@ -133,6 +134,7 @@ describe('TokenCreateCustomContract Test Suite', () => {
initialSupply,
maxSupply,
decimals,
feeAmount,
keys,
{
value: '35000000000000000000',
Expand Down Expand Up @@ -179,6 +181,7 @@ describe('TokenCreateCustomContract Test Suite', () => {
tokenSymbol,
tokenMemo,
maxSupply,
feeAmount,
keys,
{
value: '20000000000000000000',
Expand Down
Loading