diff --git a/test/crypto-service/test_DeleteAccount.js b/test/crypto-service/test_DeleteAccount.js deleted file mode 100644 index 9742076..0000000 --- a/test/crypto-service/test_DeleteAccount.js +++ /dev/null @@ -1,103 +0,0 @@ -import {JSONRPCRequest} from "../../client.js"; -import consensusInfoClient from "../../consensusInfoClient.js"; -import {assert} from "chai"; -import {setOperator} from "../../setup_Tests.js"; -let newAccountId; -let newAccountPrivateKey; -let newAccountBal; - -let recipientAccountId; -let recipientPrivateKey; -let recipientInitialBal; -let recipientFinalBal; -/** - * Test delete account and compare results with js SDK - * Two test accounts will be created -- - * 'newAccount' -- will be the account that is eventually deleted - * 'recipientAccount' -- will receive closing balance of newAccount - */ - describe('#deleteAccount()', function () { - this.timeout(30000); - - before(async function generateAccountId() { - await setOperator(process.env.OPERATOR_ACCOUNT_ID, process.env.OPERATOR_ACCOUNT_PRIVATE_KEY) - }); - after(async function () { - await JSONRPCRequest("reset") - }); - - it('should create newAccount via JSON-RPC server', async function () { - // Generate new private & public key - newAccountPrivateKey = await JSONRPCRequest("generatePrivateKey", {}) - let newPublicKey = await JSONRPCRequest("generatePublicKey", { - "privateKey": newAccountPrivateKey - }); - //CreateAccount with the JSON-RPC - let response = await JSONRPCRequest("createAccount", { - "publicKey": newPublicKey - }) - newAccountId = response.accountId; - }); - - it('should create recipientAccount via JSON-RPC server', async function () { - // Generate new private & public key - recipientPrivateKey = await JSONRPCRequest("generatePrivateKey", {}) - let recipientPublicKey = await JSONRPCRequest("generatePublicKey", { - "privateKey": recipientPrivateKey - }); - //CreateAccount with the JSON-RPC - let response = await JSONRPCRequest("createAccount", { - "publicKey": recipientPublicKey - }); - recipientAccountId = response.accountId; - - }); - - it('should get initial balance of newAccount', async function () { - let accountBalance = await consensusInfoClient.getBalance(newAccountId); - newAccountBal = BigInt(Number(accountBalance.hbars._valueInTinybar)); - }); - - it('should get initial balance of recipientAccount', async function () { - let accountBalance = await consensusInfoClient.getBalance(recipientAccountId); - recipientInitialBal = BigInt(Number(accountBalance.hbars._valueInTinybar)); - }); - - it('should delete newAccount and transfer its balance to recipientAccount', async function () { - // Delete newly created account via the JSON-RPC - console.log("\nDeleting account " + newAccountId); - await JSONRPCRequest("deleteAccount", { - "accountId": newAccountId, - "accountKey": newAccountPrivateKey, - "recipientId": recipientAccountId - }) - }); - /** - * Further tests for newAccountId will throw failed precheck error: ACCOUNT_DELETED - * Instead -> test for transfer of newAccount's closing balance to recipientAccount - */ - it('check that recipientAccount received closing balance', async function () { - let accountBalance = await consensusInfoClient.getBalance(recipientAccountId); - recipientFinalBal = BigInt(Number(accountBalance.hbars._valueInTinybar)); - - // Check if recipient's balance was successfully increased by amount of deleted account's balance - assert.strictEqual(recipientFinalBal, newAccountBal +recipientInitialBal, - "new recipientAccount bal is its initial bal + the deleted account's closing bal " - ); - }) - - it('test that newAccount is deleted', async function () { - /** - * the account has been marked as deleted - * ACCOUNT_DELETED = 72; - **/ - try { - console.log("\nTry to enquire on account " + newAccountId); - await consensusInfoClient.getAccountInfo(newAccountId); - } catch (err) { - assert.equal(err.status.toString(), "ACCOUNT_DELETED"); - return - } - assert.fail("Should throw an error") - }) -}); diff --git a/test/crypto-service/test_accountDeleteTransaction.js b/test/crypto-service/test_accountDeleteTransaction.js new file mode 100644 index 0000000..4ac8f32 --- /dev/null +++ b/test/crypto-service/test_accountDeleteTransaction.js @@ -0,0 +1,321 @@ +import { JSONRPCRequest } from "../../client.js"; +import consensusInfoClient from "../../consensusInfoClient.js"; +import { assert } from "chai"; +import { setOperator } from "../../setup_Tests.js"; + +describe("AccountDeleteTransaction", function () { + // Tests should not take longer than 30 seconds to fully execute. + this.timeout(30000); + + // An account is created for each test. These hold the information for that account. + let accountPrivateKey, accountId; + + beforeEach(async function () { + // Initialize the network and operator. + await setOperator(process.env.OPERATOR_ACCOUNT_ID, process.env.OPERATOR_ACCOUNT_PRIVATE_KEY); + + // Generate a private key. + let response = await JSONRPCRequest("generateKey", { + type: "ed25519PrivateKey" + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + accountPrivateKey = response.key; + + // Create an account using the generated private key. + response = await JSONRPCRequest("createAccount", { + key: accountPrivateKey + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + accountId = response.accountId; + }); + afterEach(async function () { + await JSONRPCRequest("reset"); + }); + + describe("Delete Account Id", async function () { + it("(#1) Deletes an account with no transfer account", async function () { + try { + // Attempt to delete the account without a transfer account. The network should respond with an ACCOUNT_ID_DOES_NOT_EXIST status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch (err) { + assert.equal(err.data.status, "ACCOUNT_ID_DOES_NOT_EXIST"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#2) Deletes an account with no delete account", async function () { + try { + // Attempt to delete the account without a delete account. The network should respond with an ACCOUNT_ID_DOES_NOT_EXIST status. + const response = await JSONRPCRequest("deleteAccount", { + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch (err) { + assert.equal(err.data.status, "ACCOUNT_ID_DOES_NOT_EXIST"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#3) Deletes an admin account", async function () { + try { + // Attempt to delete an admin account. The network should respond with an ENTITY_NOT_ALLOWED_TO_DELETE status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: "0.0.2", + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch(err) { + assert.equal(err.data.status, "ENTITY_NOT_ALLOWED_TO_DELETE"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#4) Deletes an account that doesn't exist", async function () { + try { + // Attempt to delete an account that doesn't exist. The network should respond with an INVALID_ACCOUNT_ID status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: "123.456.789", + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch(err) { + assert.equal(err.data.status, "INVALID_ACCOUNT_ID"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#5) Deletes an account that was already deleted", async function () { + // Delete the account first. + var response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + + try { + // Attempt to delete the account again. The network should respond with an ACCOUNT_DELETED status. + response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + } catch(err) { + assert.equal(err.data.status, "ACCOUNT_DELETED"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#6) Deletes an account without signing with the account's private key", async function () { + try { + // Attempt to delete the account without signing with the account's private key. The network should respond with an INVALID_SIGNATURE status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch(err) { + assert.equal(err.data.status, "INVALID_SIGNATURE"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#7) Deletes an account but signs with an incorrect private key", async function () { + // Generate a private key. + let key = await JSONRPCRequest("generateKey", { + type: "ed25519PrivateKey" + }); + if (key.status === "NOT_IMPLEMENTED") this.skip(); + + try { + // Attempt to delete the account and sign with an incorrect private key. The network should respond with an INVALID_SIGNATURE status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + key.key + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch(err) { + assert.equal(err.data.status, "INVALID_SIGNATURE"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + }); + + describe("Transfer Account Id", async function () { + it("(#1) Deletes an account with a valid transfer account", async function () { + // Attempt to delete the account and transfer its funds to the operator account. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }) + if (response.status === "NOT_IMPLEMENTED") this.skip(); + + // Only look at the consensus node here because the mirror node data can be populated yet still take a couple seconds to fully update. + // AccountInfoQuery throws if the account is deleted, so catch that and verify the status code maps correctly. + try { + let _ = await consensusInfoClient.getAccountInfo(accountId); + } catch (err) { + assert.equal(err.status._code, 72); // 72 maps to ACCOUNT_DELETED + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#2) Deletes an account with a transfer account that is the deleted account", async function () { + try { + // Attempt to delete the account with a transfer account that is the deleted account. The network should respond with an TRANSFER_ACCOUNT_SAME_AS_DELETE_ACCOUNT status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: accountId, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch (err) { + assert.equal(err.data.status, "TRANSFER_ACCOUNT_SAME_AS_DELETE_ACCOUNT"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#3) Deletes an account with a transfer account that is invalid/doesn't exist", async function () { + try { + // Attempt to delete the account with a transfer account that is the deleted account. The network should respond with an INVALID_TRANSFER_ACCOUNT_ID status. + const response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: "123.456.789", + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + } catch (err) { + assert.equal(err.data.status, "INVALID_TRANSFER_ACCOUNT_ID"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + + it("(#4) Deletes an account with a transfer account that is a deleted account", async function () { + // Generate a key. + var response = await JSONRPCRequest("generateKey", { + type: "ecdsaSecp256k1PrivateKey" + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + let key = response.key + + // Create an account with the key. + response = await JSONRPCRequest("createAccount", { + key: key + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + let deletedAccountId = response.accountId; + + // Delete the account. + response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: deletedAccountId, + transferAccountId: process.env.OPERATOR_ACCOUNT_ID, + commonTransactionParams: { + signers: [ + key + ] + } + }); + if (response.status === "NOT_IMPLEMENTED") this.skip(); + + try { + // Attempt to delete the account with the deleted account as the transfer account. The network should respond with an ACCOUNT_DELETED status. + response = await JSONRPCRequest("deleteAccount", { + deleteAccountId: accountId, + transferAccountId: deletedAccountId, + commonTransactionParams: { + signers: [ + accountPrivateKey + ] + } + }); + } catch(err) { + assert.equal(err.data.status, "ACCOUNT_DELETED"); + return; + } + + // The test failed, no error was thrown. + assert.fail("Should throw an error"); + }); + }); + + return Promise.resolve(); +});