From 47a08efcc9fb06bcf1d42fe9ffd36b26a6a78286 Mon Sep 17 00:00:00 2001 From: Simeon Nakov <simeon.nakov@limechain.tech> Date: Fri, 31 Jan 2025 18:55:58 +0200 Subject: [PATCH] requested changes from PR Signed-off-by: Simeon Nakov <simeon.nakov@limechain.tech> --- test/constants.js | 2 + .../hrc-904/AirdropContract.js | 167 +++++++++++------- .../hedera-token-service/utils.js | 58 ++++++ 3 files changed, 161 insertions(+), 66 deletions(-) diff --git a/test/constants.js b/test/constants.js index ebfc0b517..dba50a54b 100644 --- a/test/constants.js +++ b/test/constants.js @@ -216,6 +216,7 @@ const GAS_LIMIT_5_000_000 = { gasLimit: 5_000_000 }; const GAS_LIMIT_10_000_000 = { gasLimit: 10_000_000 }; const GAS_LIMIT_800000 = { gasLimit: 800000 }; const GAS_LIMIT_8000000 = { gasLimit: 8000000 }; +const ONE_HBAR = ethers.parseEther('1'); const TOKEN_NAME = 'tokenName'; const TOKEN_SYMBOL = 'tokenSymbol'; const TOKEN_URL = 'tokenUrl'; @@ -254,4 +255,5 @@ module.exports = { GWEI, HTS_SYSTEM_CONTRACT_ID, HAS_SYSTEM_CONTRACT_ID, + ONE_HBAR, }; diff --git a/test/system-contracts/hedera-token-service/hrc-904/AirdropContract.js b/test/system-contracts/hedera-token-service/hrc-904/AirdropContract.js index b0cad7efa..681f739ef 100644 --- a/test/system-contracts/hedera-token-service/hrc-904/AirdropContract.js +++ b/test/system-contracts/hedera-token-service/hrc-904/AirdropContract.js @@ -33,60 +33,7 @@ describe('HIP904 AirdropContract Test Suite', function () { let signers; let owner; let accounts; - - async function setupToken() { - const tokenAddress = - await utils.createFungibleTokenWithSECP256K1AdminKeyWithoutKYC( - tokenCreateContract, - owner, - utils.getSignerCompressedPublicKey() - ); - - await utils.updateTokenKeysViaHapi(tokenAddress, [ - await airdropContract.getAddress(), - await tokenCreateContract.getAddress(), - ]); - - await utils.associateToken( - tokenCreateContract, - tokenAddress, - Constants.Contract.TokenCreateContract - ); - - return tokenAddress; - } - - async function setupNft() { - const nftTokenAddress = - await utils.createNonFungibleTokenWithSECP256K1AdminKeyWithoutKYC( - tokenCreateContract, - owner, - utils.getSignerCompressedPublicKey() - ); - - await utils.updateTokenKeysViaHapi( - nftTokenAddress, - [ - await airdropContract.getAddress(), - await tokenCreateContract.getAddress(), - ], - true, - true, - false, - true, - true, - true, - false - ); - - await utils.associateToken( - tokenCreateContract, - nftTokenAddress, - Constants.Contract.TokenCreateContract - ); - - return nftTokenAddress; - } + let contractAddresses; before(async function () { signers = await ethers.getSigners(); @@ -103,19 +50,32 @@ describe('HIP904 AirdropContract Test Suite', function () { owner = signers[0].address; accounts = signers.slice(1, 3).map((s) => s.address); - await utils.updateAccountKeysViaHapi([ + contractAddresses = [ await airdropContract.getAddress(), await tokenCreateContract.getAddress(), - ]); + ]; + await utils.updateAccountKeysViaHapi(contractAddresses); - tokenAddress = await setupToken(); - nftTokenAddress = await setupNft(); + tokenAddress = await utils.setupToken( + tokenCreateContract, + owner, + contractAddresses + ); + nftTokenAddress = await utils.setupNft( + tokenCreateContract, + owner, + contractAddresses + ); }); it('should airdrop a fungible token (FT) to a single account', async function () { const ftAmount = BigInt(1); const receiver = signers[1].address; - const tokenAddress = await setupToken(); + const tokenAddress = await utils.setupToken( + tokenCreateContract, + owner, + contractAddresses + ); const initialBalance = await erc20Contract.balanceOf( tokenAddress, @@ -162,7 +122,11 @@ describe('HIP904 AirdropContract Test Suite', function () { it('should airdrop fungible token (FT) to a single account using distribute', async function () { const ftAmount = BigInt(1); const receiver = signers[1].address; - const tokenAddress = await setupToken(); + const tokenAddress = await utils.setupToken( + tokenCreateContract, + owner, + contractAddresses + ); const initialBalance = await erc20Contract.balanceOf( tokenAddress, @@ -187,7 +151,11 @@ describe('HIP904 AirdropContract Test Suite', function () { it('should airdrop fungible tokens (FT) to multiple accounts', async function () { const ftAmount = BigInt(1); - const tokenAddress = await setupToken(); + const tokenAddress = await utils.setupToken( + tokenCreateContract, + owner, + contractAddresses + ); const getBalances = async () => Promise.all( @@ -234,8 +202,14 @@ describe('HIP904 AirdropContract Test Suite', function () { expect(nftOwner).to.equal(receiver); }); + // TODO: Test skipped due to missing error code support in services implementation + // See: https://github.com/hashgraph/hedera-services/issues/17409 it.skip('should airdrop non-fungible tokens (NFT) to multiple accounts', async function () { - const nftTokenAddress = await setupNft(); + const nftTokenAddress = await utils.setupNft( + tokenCreateContract, + owner, + contractAddresses + ); const serials = []; serials.push( await utils.mintNFTToAddress(tokenCreateContract, nftTokenAddress) @@ -269,7 +243,9 @@ describe('HIP904 AirdropContract Test Suite', function () { const tokens = []; // Every accountAmount counts as 1 transfer so 5x2=10 for (let i = 0; i < 5; i++) { - tokens.push(await setupToken()); + tokens.push( + await utils.setupToken(tokenCreateContract, owner, contractAddresses) + ); } for (let i = 0; i < accounts.length; i++) { const tx = await airdropContract.multipleFtAirdrop( @@ -292,7 +268,11 @@ describe('HIP904 AirdropContract Test Suite', function () { const tokens = []; const serials = []; for (let i = 0; i < count; i++) { - const tokenAddress = await setupNft(); + const tokenAddress = await utils.setupNft( + tokenCreateContract, + owner, + contractAddresses + ); const serial = await utils.mintNFTToAddress( tokenCreateContract, tokenAddress @@ -400,7 +380,11 @@ describe('HIP904 AirdropContract Test Suite', function () { const nftTokens = []; const nftSerials = []; for (let i = 0; i < 11; i++) { - const tokenAddress = await setupNft(); + const tokenAddress = await utils.setupNft( + tokenCreateContract, + owner, + contractAddresses + ); const serial = await utils.mintNFTToAddress( tokenCreateContract, tokenAddress @@ -432,7 +416,9 @@ describe('HIP904 AirdropContract Test Suite', function () { const ftAmount = BigInt(1); const tokens = []; for (let i = 0; i < 6; i++) { - tokens.push(await setupToken()); + tokens.push( + await utils.setupToken(tokenCreateContract, airdropContract, owner) + ); } const tx = await airdropContract.multipleFtAirdrop( tokens, @@ -447,4 +433,53 @@ describe('HIP904 AirdropContract Test Suite', function () { expect(error.shortMessage).to.eq('transaction execution reverted'); } }); + + it('should handle airdrop to account with no available association slots', async function () { + const ftAmount = BigInt(1); + const receiver = ethers.Wallet.createRandom().connect(ethers.provider); + await signers[0].sendTransaction({ + to: receiver.address, + value: ethers.parseEther('100'), + }); + const IHRC904AccountFacade = new ethers.Interface( + (await hre.artifacts.readArtifact('IHRC904AccountFacade')).abi + ); + + walletIHRC904AccountFacade = new ethers.Contract( + receiver.address, + IHRC904AccountFacade, + receiver + ); + + const disableAutoAssociations = + await walletIHRC904AccountFacade.setUnlimitedAutomaticAssociations( + false, + { + gasLimit: 2_000_000, + } + ); + await disableAutoAssociations.wait(); + + const tx = await airdropContract.tokenAirdrop( + tokenAddress, + signers[0].address, + receiver.address, + ftAmount, + { + gasLimit: 2_000_000, + value: Constants.ONE_HBAR, + } + ); + await tx.wait(); + + const responseCode = await utils.getHTSResponseCode(tx.hash); + expect(responseCode).to.eq('22'); + + // The airdrop will be pending, so the balance should still be 0 + const balance = await erc20Contract.balanceOf( + tokenAddress, + receiver.address + ); + expect(balance).to.equal(0n); + }); }); diff --git a/test/system-contracts/hedera-token-service/utils.js b/test/system-contracts/hedera-token-service/utils.js index 5b028849d..77ae009c6 100644 --- a/test/system-contracts/hedera-token-service/utils.js +++ b/test/system-contracts/hedera-token-service/utils.js @@ -1000,6 +1000,64 @@ class Utils { ); return BigInt(precompileAction.result_data).toString(); } + + static async setupNft(tokenCreateContract, owner, contractAddresses) { + const nftTokenAddress = + await this.createNonFungibleTokenWithSECP256K1AdminKeyWithoutKYC( + tokenCreateContract, + owner, + this.getSignerCompressedPublicKey() + ); + + await this.updateTokenKeysViaHapi( + nftTokenAddress, + contractAddresses, + true, + true, + false, + true, + true, + true, + false + ); + + await this.associateToken( + tokenCreateContract, + nftTokenAddress, + Constants.Contract.TokenCreateContract + ); + + return nftTokenAddress; + } + + static async setupToken(tokenCreateContract, owner, contractAddresses) { + const tokenAddress = + await this.createFungibleTokenWithSECP256K1AdminKeyWithoutKYC( + tokenCreateContract, + owner, + this.getSignerCompressedPublicKey() + ); + + await this.updateTokenKeysViaHapi( + tokenAddress, + contractAddresses, + true, + true, + false, + true, + true, + true, + false + ); + + await this.associateToken( + tokenCreateContract, + tokenAddress, + Constants.Contract.TokenCreateContract + ); + + return tokenAddress; + } } module.exports = Utils;