Skip to content

Commit

Permalink
feat: added dynamic feeAmount parameter to fungible and non-fungible …
Browse files Browse the repository at this point in the history
…token create with custom fee method (#700)

* feat: added feeAmount to create fungible and non-fungible with fee method

Signed-off-by: Logan Nguyen <[email protected]>

* fix: fixed unit tests to adapt new feeAmount parameter

Signed-off-by: Logan Nguyen <[email protected]>

* feat: updated System Contract DApp UI to adapt feeAmount parameter

Signed-off-by: Logan Nguyen <[email protected]>

* chore: renamed feeTokenAmount to feeAmount

Signed-off-by: Logan Nguyen <[email protected]>

---------

Signed-off-by: Logan Nguyen <[email protected]>
  • Loading branch information
quiet-node authored Mar 7, 2024
1 parent 8974d28 commit 9a18ac0
Show file tree
Hide file tree
Showing 9 changed files with 111 additions and 37 deletions.

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 feeAmount?: 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,
feeAmount?: number
): Promise<ISmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand Down Expand Up @@ -114,6 +117,7 @@ export const createHederaFungibleToken = async (
initialTotalSupply,
maxSupply,
decimals,
feeAmount,
keyRes.hederaTokenKeys,
{
value: ethers.parseEther(msgValue),
Expand Down Expand Up @@ -175,6 +179,8 @@ export const createHederaFungibleToken = async (
*
* @param feeTokenAddress?: ethers.AddressLike
*
* @param feeAmount?: 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,
feeAmount?: number
): Promise<ISmartContractExecutionResult> => {
// sanitize params
let sanitizeErr;
Expand Down Expand Up @@ -224,6 +231,7 @@ export const createHederaNonFungibleToken = async (
symbol,
memo,
maxSupply,
feeAmount,
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;
feeAmount?: 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,
feeAmount,
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(feeAmount) <= 0) {
sanitizeErr = 'Custom fee amount must be positive';
}
// 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: '',
feeAmount: '',
freezeStatus: false,
};
const [paramValues, setParamValues] = useState<any>(initialParamValues);
Expand Down Expand Up @@ -128,6 +129,7 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
maxSupply,
initSupply,
freezeStatus,
feeAmount,
feeTokenAddress,
} = paramValues;

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

Expand All @@ -168,7 +171,8 @@ const FungibleTokenCreate = ({ baseContract }: PageProps) => {
treasury,
keys,
feeValue,
withCustomFee ? feeTokenAddress : undefined
withCustomFee ? feeTokenAddress : undefined,
withCustomFee ? Number(feeAmount) : 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={'feeAmount'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeAmount']}
paramKey={(htsTokenCreateParamFields as any)['feeAmount'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeAmount'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeAmount'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeAmount'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeAmount'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeAmount'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeAmount'].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: '',
feeAmount: '',
feeTokenAddress: '',
};
const [paramValues, setParamValues] = useState<any>(initialParamValues);
Expand Down Expand Up @@ -112,7 +113,7 @@ 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, feeAmount } = paramValues;

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

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

// turn is loading off
Expand Down Expand Up @@ -248,18 +251,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={'feeAmount'}
handleInputOnChange={handleInputOnChange}
paramValue={paramValues['feeAmount']}
paramKey={(htsTokenCreateParamFields as any)['feeAmount'].paramKey}
paramType={(htsTokenCreateParamFields as any)['feeAmount'].inputType}
paramSize={(htsTokenCreateParamFields as any)['feeAmount'].inputSize}
explanation={(htsTokenCreateParamFields as any)['feeAmount'].explanation}
paramClassName={(htsTokenCreateParamFields as any)['feeAmount'].inputClassname}
paramPlaceholder={(htsTokenCreateParamFields as any)['feeAmount'].inputPlaceholder}
paramFocusColor={(htsTokenCreateParamFields as any)['feeAmount'].inputFocusBorderColor}
/>
</>
)}

{/* keys */}
Expand All @@ -281,7 +299,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',
},
feeAmount: {
...HEDERA_SHARED_PARAM_INPUT_FIELDS,
inputType: 'number',
paramKey: 'feeAmount',
inputPlaceholder: 'The fee amount...',
explanation: 'represents the number of units to assess as a fee',
},
customFee: {
paramKey: 'customFee',
explanation: {
Expand Down
3 changes: 3 additions & 0 deletions test/hts-precompile/token-create/tokenCreateCustomContract.js
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

0 comments on commit 9a18ac0

Please sign in to comment.