diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ea5e71022..082c9a78d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -164,30 +164,30 @@ jobs: if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task test:integration:codecov - - name: Stop the local node - id: stop-local-node - if: ${{ steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} - run: ${{ env.CG_EXEC }} npx @hashgraph/hedera-local stop - - name: Build @hashgraph/cryptography working-directory: packages/cryptography - if: ${{ steps.build-sdk.conclusion == 'success' && steps.stop-local-node.conclusion == 'success' && !cancelled() && always() }} + if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task build - name: Unit Test @hashgraph/cryptography working-directory: packages/cryptography - if: ${{ steps.build-sdk.conclusion == 'success' && steps.stop-local-node.conclusion == 'success' && !cancelled() && always() }} + if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task test:unit - name: Codecov @hashgraph/cryptography working-directory: packages/cryptography - if: ${{ steps.build-sdk.conclusion == 'success' && steps.stop-local-node.conclusion == 'success' && !cancelled() && always() }} + if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task test:unit:codecov - name: Unit Test @hashgraph/sdk - if: ${{ steps.build-sdk.conclusion == 'success' && steps.stop-local-node.conclusion == 'success' && steps.playwright-deps.conclusion == 'success' && !cancelled() && always() }} + if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && steps.playwright-deps.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task test:unit - name: Codecov @hashgraph/sdk - if: ${{ steps.build-sdk.conclusion == 'success' && steps.stop-local-node.conclusion == 'success' && !cancelled() && always() }} + if: ${{ steps.build-sdk.conclusion == 'success' && steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} run: ${{ env.CG_EXEC }} task test:unit:codecov + + - name: Stop the local node + id: stop-local-node + if: ${{ steps.start-local-node.conclusion == 'success' && !cancelled() && always() }} + run: ${{ env.CG_EXEC }} npx @hashgraph/hedera-local stop \ No newline at end of file diff --git a/src/Executable.js b/src/Executable.js index 9d8140d64..419445597 100644 --- a/src/Executable.js +++ b/src/Executable.js @@ -34,6 +34,7 @@ import HttpError from "./http/HttpError.js"; * @typedef {import("./Signer.js").Signer} Signer * @typedef {import("./PublicKey.js").default} PublicKey * @typedef {import("./logger/Logger.js").default} Logger + * @typedef {import("./LedgerId.js").default} LedgerId */ /** @@ -134,6 +135,20 @@ export default class Executable { * @type {Logger | null} */ this._logger = null; + + /** + * List of mirror network nodes with which execution will be attempted. + * @protected + * @type {string[]} + */ + this._mirrorNetworkNodes = []; + + /** + * Current LedgerId of the network with which execution will be attempted. + * @protected + * @type {LedgerId | null} + */ + this._ledgerId = null; } /** @@ -511,6 +526,14 @@ export default class Executable { * @returns {Promise} */ async execute(client, requestTimeout) { + // Set list of mirror network nodes with + // which execution will be attempted + this._mirrorNetworkNodes = client.mirrorNetwork; + + // Set current LedgerId of the network with + // which execution will be attempted + this._ledgerId = client.ledgerId; + // If the logger on the request is not set, use the logger in client // (if set, otherwise do not use logger) this._logger = diff --git a/src/Status.js b/src/Status.js index c9f3dae99..0febc8673 100644 --- a/src/Status.js +++ b/src/Status.js @@ -651,6 +651,18 @@ export default class Status { return "INVALID_GRPC_CERTIFICATE"; case Status.InvalidMaxAutoAssociations: return "INVALID_MAX_AUTO_ASSOCIATIONS"; + case Status.MaxNodesCreated: + return "MAX_NODES_CREATED"; + case Status.IpFqdnCannotBeSetForSameEndpoint: + return "IP_FQDN_CANNOT_BE_SET_FOR_SAME_ENDPOINT"; + case Status.GossipEndpointCannotHaveFqdn: + return "GOSSIP_ENDPOINT_CANNOT_HAVE_FQDN"; + case Status.FqdnSizeTooLarge: + return "FQDN_SIZE_TOO_LARGE"; + case Status.InvalidEndpoint: + return "INVALID_ENDPOINT"; + case Status.GossipEndpointsExceededLimit: + return "GOSSIP_ENDPOINTS_EXCEEDED_LIMIT"; default: return `UNKNOWN (${this._code})`; } @@ -1273,6 +1285,18 @@ export default class Status { return Status.InvalidGrpcCertificate; case 346: return Status.InvalidMaxAutoAssociations; + case 347: + return Status.MaxNodesCreated; + case 348: + return Status.IpFqdnCannotBeSetForSameEndpoint; + case 349: + return Status.GossipEndpointCannotHaveFqdn; + case 350: + return Status.FqdnSizeTooLarge; + case 351: + return Status.InvalidEndpoint; + case 352: + return Status.GossipEndpointsExceededLimit; default: throw new Error( `(BUG) Status.fromCode() does not handle code: ${code}`, @@ -2855,3 +2879,33 @@ Status.InvalidGrpcCertificate = new Status(345); * The most common cause for this error is a value less than `-1`. */ Status.InvalidMaxAutoAssociations = new Status(346); + +/** + * The maximum number of nodes allowed in the address book have been created. + */ +Status.MaxNodesCreated = new Status(347); + +/** + * In ServiceEndpoint, domain_name and ipAddressV4 are mutually exclusive + */ +Status.IpFqdnCannotBeSetForSameEndpoint = new Status(348); + +/** + * Fully qualified domain name is not allowed in gossip_endpoint + */ +Status.GossipEndpointCannotHaveFqdn = new Status(349); + +/** + * In ServiceEndpoint, domain_name size too large + */ +Status.FqdnSizeTooLarge = new Status(350); + +/** + * ServiceEndpoint is invalid + */ +Status.InvalidEndpoint = new Status(351); + +/** + * The number of gossip endpoints exceeds the limit + */ +Status.GossipEndpointsExceededLimit = new Status(352); \ No newline at end of file diff --git a/src/account/AccountBalance.js b/src/account/AccountBalance.js index 3a7ae31a2..4fe031fac 100644 --- a/src/account/AccountBalance.js +++ b/src/account/AccountBalance.js @@ -54,18 +54,8 @@ export default class AccountBalance { */ this.hbars = props.hbars; - /** - * @deprecated - Use the mirror node API https://docs.hedera.com/guides/docs/mirror-node-api/rest-api#api-v1-accounts instead - * @readonly - */ - // eslint-disable-next-line deprecation/deprecation this.tokens = props.tokens; - /** - * @deprecated - Use the mirror node API https://docs.hedera.com/guides/docs/mirror-node-api/rest-api#api-v1-accounts instead - * @readonly - */ - // eslint-disable-next-line deprecation/deprecation this.tokenDecimals = props.tokenDecimals; Object.freeze(this); diff --git a/src/account/AccountBalanceQuery.js b/src/account/AccountBalanceQuery.js index 6b75557cd..467162da7 100644 --- a/src/account/AccountBalanceQuery.js +++ b/src/account/AccountBalanceQuery.js @@ -22,6 +22,8 @@ import Query, { QUERY_REGISTRY } from "../query/Query.js"; import AccountId from "./AccountId.js"; import ContractId from "../contract/ContractId.js"; import AccountBalance from "./AccountBalance.js"; +import MirrorNodeService from "../network/MirrorNodeService.js"; +import MirrorNodeGateway from "../network/MirrorNodeGateway.js"; /** * @namespace proto @@ -31,6 +33,7 @@ import AccountBalance from "./AccountBalance.js"; * @typedef {import("@hashgraph/proto").proto.IResponseHeader} HashgraphProto.proto.IResponseHeader * @typedef {import("@hashgraph/proto").proto.ICryptoGetAccountBalanceQuery} HashgraphProto.proto.ICryptoGetAccountBalanceQuery * @typedef {import("@hashgraph/proto").proto.ICryptoGetAccountBalanceResponse} HashgraphProto.proto.ICryptoGetAccountBalanceResponse + * @typedef {import("@hashgraph/proto").proto.ITokenBalance} HashgraphProto.proto.ITokenBalance */ /** @@ -69,6 +72,13 @@ export default class AccountBalanceQuery extends Query { */ this._contractId = null; + /** + * @private + * @description Delay in ms if is necessary to wait for the mirror node to update the account balance + * @type {number} + */ + this._timeout = 0; + if (props.accountId != null) { this.setAccountId(props.accountId); } @@ -149,6 +159,16 @@ export default class AccountBalanceQuery extends Query { return this; } + /** + * + * @param {number} timeout + * @returns {this} + */ + setTimeout(timeout) { + this._timeout = timeout; + return this; + } + /** * @protected * @override @@ -210,13 +230,56 @@ export default class AccountBalanceQuery extends Query { */ // eslint-disable-next-line @typescript-eslint/no-unused-vars _mapResponse(response, nodeAccountId, request) { - const cryptogetAccountBalance = - /** @type {HashgraphProto.proto.ICryptoGetAccountBalanceResponse} */ ( - response.cryptogetAccountBalance + return new Promise((resolve, reject) => { + const mirrorNodeGateway = MirrorNodeGateway.forNetwork( + this._mirrorNetworkNodes, + this._ledgerId, ); - return Promise.resolve( - AccountBalance._fromProtobuf(cryptogetAccountBalance), - ); + const mirrorNodeService = new MirrorNodeService(mirrorNodeGateway); + + const cryptogetAccountBalanceFromConsensusNode = + /** @type {HashgraphProto.proto.ICryptoGetAccountBalanceResponse} */ ( + response.cryptogetAccountBalance + ); + + if (cryptogetAccountBalanceFromConsensusNode.accountID) { + const accountIdFromConsensusNode = AccountId._fromProtobuf( + cryptogetAccountBalanceFromConsensusNode.accountID, + ); + + mirrorNodeService + .setTimeout(this._timeout) + .getTokenBalancesForAccount( + accountIdFromConsensusNode.num.toString(), + ) + .then( + ( + /** @type {HashgraphProto.proto.ITokenBalance[]} */ tokenBalances, + ) => { + if ( + cryptogetAccountBalanceFromConsensusNode?.tokenBalances && + tokenBalances + ) { + // Reset the array to avoid duplicates + cryptogetAccountBalanceFromConsensusNode.tokenBalances.length = 0; + // Add the token balances from the mirror node to the response from the consensus node + cryptogetAccountBalanceFromConsensusNode.tokenBalances.push( + ...tokenBalances, + ); + + resolve( + AccountBalance._fromProtobuf( + cryptogetAccountBalanceFromConsensusNode, + ), + ); + } + }, + ) + .catch((error) => { + reject(error); + }); + } + }); } /** diff --git a/src/account/AccountInfoQuery.js b/src/account/AccountInfoQuery.js index db3d627e2..595c9dfcd 100644 --- a/src/account/AccountInfoQuery.js +++ b/src/account/AccountInfoQuery.js @@ -23,6 +23,8 @@ import AccountId from "./AccountId.js"; import AccountInfo from "./AccountInfo.js"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import Hbar from "../Hbar.js"; +import MirrorNodeService from "../network/MirrorNodeService.js"; +import MirrorNodeGateway from "../network/MirrorNodeGateway.js"; /** * @namespace proto @@ -33,11 +35,13 @@ import Hbar from "../Hbar.js"; * @typedef {import("@hashgraph/proto").proto.CryptoGetInfoResponse.IAccountInfo} HashgraphProto.proto.CryptoGetInfoResponse.IAccountInfo * @typedef {import("@hashgraph/proto").proto.ICryptoGetInfoQuery} HashgraphProto.proto.ICryptoGetInfoQuery * @typedef {import("@hashgraph/proto").proto.ICryptoGetInfoResponse} HashgraphProto.proto.ICryptoGetInfoResponse + * @typedef {import("@hashgraph/proto").proto.ITokenRelationship} HashgraphProto.proto.ITokenRelationship */ /** * @typedef {import("../channel/Channel.js").default} Channel * @typedef {import("../client/Client.js").default<*, *>} Client + * @typedef {import("../account/TokenRelationship.js").default} TokenRelationship */ /** @@ -56,9 +60,17 @@ export default class AccountInfoQuery extends Query { * @type {?AccountId} */ this._accountId = null; + if (props.accountId != null) { this.setAccountId(props.accountId); } + + /** + * @private + * @description Delay in ms if is necessary to wait for the mirror node to update the account info + * @type {number} + */ + this._timeout = 0; } /** @@ -110,6 +122,16 @@ export default class AccountInfoQuery extends Query { } } + /** + * + * @param {number} timeout + * @returns {this} + */ + setTimeout(timeout) { + this._timeout = timeout; + return this; + } + /** * @override * @internal @@ -156,18 +178,60 @@ export default class AccountInfoQuery extends Query { */ // eslint-disable-next-line @typescript-eslint/no-unused-vars _mapResponse(response, nodeAccountId, request) { - const info = - /** @type {HashgraphProto.proto.ICryptoGetInfoResponse} */ ( - response.cryptoGetInfo + return new Promise((resolve, reject) => { + const mirrorNodeGateway = MirrorNodeGateway.forNetwork( + this._mirrorNetworkNodes, + this._ledgerId, ); - return Promise.resolve( - AccountInfo._fromProtobuf( - /** @type {HashgraphProto.proto.CryptoGetInfoResponse.IAccountInfo} */ ( - info.accountInfo - ), - ), - ); + const mirrorNodeService = new MirrorNodeService(mirrorNodeGateway); + + const accountInfoFromConsensusNode = + /** @type {HashgraphProto.proto.ICryptoGetInfoResponse} */ ( + response.cryptoGetInfo + ); + + if ( + accountInfoFromConsensusNode.accountInfo && + accountInfoFromConsensusNode.accountInfo.accountID + ) { + const accountIdFromConsensusNode = AccountId._fromProtobuf( + accountInfoFromConsensusNode.accountInfo.accountID, + ); + + mirrorNodeService + .setTimeout(this._timeout) + .getTokenRelationshipsForAccount( + accountIdFromConsensusNode.num.toString(), + ) + .then((tokensRelationships) => { + if ( + accountInfoFromConsensusNode.accountInfo + ?.tokenRelationships && + tokensRelationships + ) { + // Reset the array to avoid duplicates + accountInfoFromConsensusNode.accountInfo.tokenRelationships.length = 0; + + // Add the token relationships from the mirror node to the response from the consensus node + accountInfoFromConsensusNode.accountInfo.tokenRelationships.push( + ...tokensRelationships, + ); + } + + resolve( + AccountInfo._fromProtobuf( + /** @type {HashgraphProto.proto.CryptoGetInfoResponse.IAccountInfo} */ ( + accountInfoFromConsensusNode.accountInfo + ), + ), + ); + }) + .catch((error) => { + reject(error); + }); + } + }); } /** diff --git a/src/account/TokenRelationship.js b/src/account/TokenRelationship.js index 095205710..3c69ac820 100644 --- a/src/account/TokenRelationship.js +++ b/src/account/TokenRelationship.js @@ -41,6 +41,7 @@ export default class TokenRelationship { * @param {boolean | null} props.isKycGranted * @param {boolean | null} props.isFrozen * @param {boolean | null} props.automaticAssociation + * @param {number | null} props.decimals */ constructor(props) { /** @@ -53,8 +54,12 @@ export default class TokenRelationship { /** * The Symbol of the token * - * @readonly + * @deprecated - Not supported by consensus nodes (from hedera-services tag v0.50.x). + * Although the Mirror Node REST APIs still contain this feature, there is no straightforward way of integration, + * leading to this field being deprecated. + * Can be extracted from TokenInfo class. */ + // eslint-disable-next-line deprecation/deprecation this.symbol = props.symbol; /** @@ -73,13 +78,19 @@ export default class TokenRelationship { this.isKycGranted = props.isKycGranted; /** - * The Freeze status of the account (FreezeNotApplicable, Frozen or Unfrozen). If the token - * does not have Freeze key, FreezeNotApplicable is returned + * Tokens divide into 10^decimals pieces * * @readonly */ this.isFrozen = props.isFrozen; + /** + Tokens divide into 10^decimals pieces + * + * @readonly + */ + this.decimals = props.decimals; + /** * Specifies if the relationship is created implicitly. False : explicitly associated, True : * implicitly associated. @@ -119,6 +130,8 @@ export default class TokenRelationship { : Long.ZERO, isKycGranted, isFrozen, + decimals: + relationship.decimals != null ? relationship.decimals : null, automaticAssociation: relationship.automaticAssociation != null ? relationship.automaticAssociation @@ -132,12 +145,14 @@ export default class TokenRelationship { _toProtobuf() { return { tokenId: this.tokenId._toProtobuf(), + // eslint-disable-next-line deprecation/deprecation symbol: this.symbol, balance: this.balance, kycStatus: this.isKycGranted == null ? 0 : this.isKycGranted ? 1 : 2, freezeStatus: this.isFrozen == null ? 0 : this.isFrozen ? 1 : 2, automaticAssociation: this.automaticAssociation, + decimals: this.decimals, }; } } diff --git a/src/client/ManagedNetwork.js b/src/client/ManagedNetwork.js index ab795846e..31cd9e2d0 100644 --- a/src/client/ManagedNetwork.js +++ b/src/client/ManagedNetwork.js @@ -325,11 +325,9 @@ export default class ManagedNetwork { newNetwork.set(node.getKey(), newNetworkNodes); } - // console.log(JSON.stringify(newNodes, null, 2)); this._nodes = newNodes; this._healthyNodes = newHealthyNodes; this._network = newNetwork; - this._ledgerId = null; return this; } diff --git a/src/client/NodeClient.js b/src/client/NodeClient.js index e28577b5a..4685e929c 100644 --- a/src/client/NodeClient.js +++ b/src/client/NodeClient.js @@ -107,6 +107,10 @@ export default class NodeClient extends Client { this.setMirrorNetwork(MirrorNetwork.PREVIEWNET); break; + case "local-node": + this.setMirrorNetwork(MirrorNetwork.LOCAL_NODE); + break; + default: this.setMirrorNetwork([props.mirrorNetwork]); break; diff --git a/src/contract/ContractInfoQuery.js b/src/contract/ContractInfoQuery.js index 27648c16f..c7dcfb311 100644 --- a/src/contract/ContractInfoQuery.js +++ b/src/contract/ContractInfoQuery.js @@ -23,6 +23,8 @@ import ContractId from "./ContractId.js"; import ContractInfo from "./ContractInfo.js"; // eslint-disable-next-line @typescript-eslint/no-unused-vars import Hbar from "../Hbar.js"; +import MirrorNodeGateway from "../network/MirrorNodeGateway.js"; +import MirrorNodeService from "../network/MirrorNodeService.js"; /** * @namespace proto @@ -57,6 +59,14 @@ export default class ContractInfoQuery extends Query { * @private */ this._contractId = null; + + /** + * @private + * @description Delay in ms if is necessary to wait for the mirror node to update the contract info + * @type {number} + */ + this._timeout = 0; + if (props.contractId != null) { this.setContractId(props.contractId); } @@ -102,6 +112,16 @@ export default class ContractInfoQuery extends Query { return this; } + /** + * + * @param {number} timeout + * @returns {this} + */ + setTimeout(timeout) { + this._timeout = timeout; + return this; + } + /** * @param {Client} client */ @@ -157,18 +177,55 @@ export default class ContractInfoQuery extends Query { */ // eslint-disable-next-line @typescript-eslint/no-unused-vars _mapResponse(response, nodeAccountId, request) { - const info = - /** @type {HashgraphProto.proto.IContractGetInfoResponse} */ ( - response.contractGetInfo + return new Promise((resolve, reject) => { + const mirrorNodeGateway = MirrorNodeGateway.forNetwork( + this._mirrorNetworkNodes, + this._ledgerId, ); + const mirrorNodeService = new MirrorNodeService(mirrorNodeGateway); - return Promise.resolve( - ContractInfo._fromProtobuf( - /** @type {HashgraphProto.proto.ContractGetInfoResponse.IContractInfo} */ ( - info.contractInfo - ), - ), - ); + const info = + /** @type {HashgraphProto.proto.IContractGetInfoResponse} */ ( + response.contractGetInfo + ); + + if (info.contractInfo && info.contractInfo.contractID) { + const contractIdFromConsensusNode = ContractId._fromProtobuf( + info.contractInfo.contractID, + ); + + mirrorNodeService + .setTimeout(this._timeout) + .getTokenRelationshipsForAccount( + contractIdFromConsensusNode.num.toString(), + ) + .then((tokensRelationships) => { + if ( + info.contractInfo?.tokenRelationships && + tokensRelationships + ) { + // Reset the array to avoid duplicates + info.contractInfo.tokenRelationships.length = 0; + + // Add the token relationships from the mirror node to the response from the consensus node + info.contractInfo.tokenRelationships.push( + ...tokensRelationships, + ); + } + + resolve( + ContractInfo._fromProtobuf( + /** @type {HashgraphProto.proto.ContractGetInfoResponse.IContractInfo} */ ( + info.contractInfo + ), + ), + ); + }) + .catch((error) => { + reject(error); + }); + } + }); } /** diff --git a/src/exports.js b/src/exports.js index e1c8e448f..77b37de84 100644 --- a/src/exports.js +++ b/src/exports.js @@ -49,6 +49,8 @@ export { default as AccountRecordsQuery } from "./account/AccountRecordsQuery.js export { default as AccountStakersQuery } from "./account/AccountStakersQuery.js"; export { default as AccountUpdateTransaction } from "./account/AccountUpdateTransaction.js"; export { default as AddressBookQuery } from "./network/AddressBookQuery.js"; +export { default as MirrorNodeGateway } from "./network/MirrorNodeGateway.js"; +export { default as MirrorNodeRouter } from "./network/MirrorNodeRouter.js"; export { default as AssessedCustomFee } from "./token/AssessedCustomFee.js"; export { default as ContractByteCodeQuery } from "./contract/ContractByteCodeQuery.js"; export { default as ContractCallQuery } from "./contract/ContractCallQuery.js"; diff --git a/src/network/MirrorNodeGateway.js b/src/network/MirrorNodeGateway.js new file mode 100644 index 000000000..db6f056b0 --- /dev/null +++ b/src/network/MirrorNodeGateway.js @@ -0,0 +1,115 @@ +/*- + * ‌ + * Hedera JavaScript SDK + * ​ + * Copyright (C) 2020 - 2023 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +import axios from "axios"; +import MirrorNodeRouter from "./MirrorNodeRouter.js"; + +/** + * @typedef {import("../contract/ContractId.js").default} ContractId + * @typedef {import("../account/AccountId.js").default} AccountId + * @typedef {import("../LedgerId.js").default} LedgerId + * / +/** + * @namespace proto + * @typedef {import("@hashgraph/proto").proto.IQuery} HashgraphProto.proto.IQuery + */ + +/** + * @typedef MirrorNodeTokenResponse + * @property {boolean} automatic_association + * @property {number} balance + * @property {string} created_timestamp + * @property {number} decimals + * @property {string} token_id + * @property {string} freeze_status + * @property {string} kyc_status + */ + +export const ACCOUNTS_ROUTE = "/accounts/%s"; +export const CONTRACT_ROUTE = "/contracts/%s"; +export const ACCOUNT_TOKENS_ROUTE = "/accounts/%s/tokens"; + +export default class MirrorNodeGateway { + /** + * @param {object} props + * @param {string} props.mirrorNodeUrl + */ + constructor(props) { + /** + * @type {string} + */ + this._mirrorNodeUrl = props.mirrorNodeUrl; + } + + /** + * Set mirror node url + * @param {string} mirrorNodeUrl + */ + static setMirrorNodeUrl(mirrorNodeUrl) { + this._mirrorNodeUrl = mirrorNodeUrl; + } + + /** + * @param {string[]} mirrorNetworkNodes + * @param {?LedgerId} ledgerId + * @returns {MirrorNodeGateway} + */ + static forNetwork(mirrorNetworkNodes, ledgerId) { + const mirrorNodeUrl = MirrorNodeRouter.getMirrorNodeUrl( + mirrorNetworkNodes, + ledgerId, + ); + + return new MirrorNodeGateway({ mirrorNodeUrl }); + } + + /** + * @internal + * @param {string} url + * @returns {Promise} + */ + static executeRequest(url) { + return new Promise((resolve, reject) => { + axios + .get(url) + .then((response) => resolve(response)) + .catch((error) => reject(error)); + }); + } + + /** + * @internal + * @param {string} idOrAliasOrEvmAddress + * @returns {Promise} + */ + getAccountTokens(idOrAliasOrEvmAddress) { + var apiUrl = MirrorNodeRouter.buildApiUrl( + this._mirrorNodeUrl, + ACCOUNT_TOKENS_ROUTE, + idOrAliasOrEvmAddress, + ); + + return new Promise((resolve, reject) => { + MirrorNodeGateway.executeRequest(apiUrl) + .then((response) => resolve(response)) + .catch((error) => reject(error)); + }); + } +} diff --git a/src/network/MirrorNodeRouter.js b/src/network/MirrorNodeRouter.js new file mode 100644 index 000000000..4347c024f --- /dev/null +++ b/src/network/MirrorNodeRouter.js @@ -0,0 +1,87 @@ +/*- + * ‌ + * Hedera JavaScript SDK + * ​ + * Copyright (C) 2020 - 2023 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ + +/** + * @typedef {import("../contract/ContractId.js").default} ContractId + * @typedef {import("../account/AccountId.js").default} AccountId + * @typedef {import("../LedgerId.js").default} LedgerId + * / +/** + * @namespace proto + * @typedef {import("@hashgraph/proto").proto.IQuery} HashgraphProto.proto.IQuery + */ +/** + * Layer between the SDK and the Mirror Node + */ + +const API_VERSION = "/api/v1"; +const HTTP = "http://"; +const HTTPS = "https://"; +const LOCAL_NODE_PORT = "5551"; + +export default class MirrorNodeRouter { + /** + * Set mirror node url + * @param {string[]} mirrorNetworkNodes + * @param {LedgerId | null} ledgerId + * @returns {string} + */ + static getMirrorNodeUrl(mirrorNetworkNodes, ledgerId) { + let path; + let mirrorNodeAddress; + + mirrorNodeAddress = mirrorNetworkNodes.map((a) => + a.substring(0, a.indexOf(":")), + )[0]; + + if (mirrorNodeAddress.length == 0) { + throw new Error("Mirror address not found!"); + } + + if (ledgerId != null && !ledgerId.isLocalNode()) { + path = HTTPS + mirrorNodeAddress.toString(); + } else { + // local node case + path = HTTP + mirrorNodeAddress.toString() + ":" + LOCAL_NODE_PORT; + } + + return path; + } + + /** + * + * @param {string} route + * @param {string} id + * @returns {string} + */ + static _getRoute = (route, id) => { + return route.replace("%s", id); + }; + + /** + * @param {string} mirrorNodeUrl + * @param {string} route + * @param {string} id + * @returns {string} + */ + static buildApiUrl(mirrorNodeUrl, route, id) { + return mirrorNodeUrl + API_VERSION + this._getRoute(route, id); + } +} diff --git a/src/network/MirrorNodeService.js b/src/network/MirrorNodeService.js new file mode 100644 index 000000000..74e4a27f0 --- /dev/null +++ b/src/network/MirrorNodeService.js @@ -0,0 +1,205 @@ +/*- + * ‌ + * Hedera JavaScript SDK + * ​ + * Copyright (C) 2020 - 2023 Hedera Hashgraph, LLC + * ​ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ‍ + */ +/** + * @namespace proto + * @typedef {import("@hashgraph/proto").proto.ITokenBalance} HashgraphProto.proto.ITokenBalance + * @typedef {import("@hashgraph/proto").proto.ITokenRelationship} HashgraphProto.proto.ITokenRelationship + * @typedef {import("@hashgraph/proto").proto.TokenKycStatus} HashgraphProto.proto.TokenKycStatus + * @typedef {import("@hashgraph/proto").proto.TokenFreezeStatus} HashgraphProto.proto.TokenFreezeStatus + */ +import TokenId from "../token/TokenId.js"; +import Long from "long"; +import * as hashgraphProto from "@hashgraph/proto"; + +/** + * @typedef MirrorNodeTokenResponse + * @property {boolean} automatic_association + * @property {number} balance + * @property {string} created_timestamp + * @property {number} decimals + * @property {string} token_id + * @property {string} freeze_status + * @property {string} kyc_status + */ + +/** + * @typedef {import("./MirrorNodeGateway.js").default} MirrorNodeGateway + */ + +/** + * @enum {string} + */ +export const TokenFreezeStatusEnum = { + NOT_APPLICABLE: "NOT_APPLICABLE", + FROZEN: "FROZEN", + UNFROZEN: "UNFROZEN", +}; +/** + * @enum {string} + */ +export const TokenKeyStatusEnum = { + NOT_APPLICABLE: "NOT_APPLICABLE", + GRANTED: "GRANTED", + REVOKED: "REVOKED", +}; + +export default class MirrorNodeService { + /** + * @param {MirrorNodeGateway} mirrorNodeGateway + */ + constructor(mirrorNodeGateway) { + /** + * @private + * @type {MirrorNodeGateway} + */ + this._mirrorNodeGateway = mirrorNodeGateway; + + /** + * @private + * @type {number} + */ + this._timeout = 0; + } + + /** + * @param {string} idOrAliasOrEvmAddress + * @returns {Promise} + */ + async getTokenBalancesForAccount(idOrAliasOrEvmAddress) { + return new Promise((resolve, reject) => { + setTimeout(() => { + this._mirrorNodeGateway + .getAccountTokens(idOrAliasOrEvmAddress) + .then( + ( + /** @type {import("axios").AxiosResponse<{ tokens: MirrorNodeTokenResponse[] }>} */ response, + ) => { + /** @type {HashgraphProto.proto.ITokenBalance[]} */ + const tokenBalances = response.data.tokens.map( + ( + /** @type {MirrorNodeTokenResponse} */ token, + ) => ({ + tokenId: TokenId.fromString( + token.token_id, + )._toProtobuf(), + balance: Long.fromNumber(token.balance), + decimals: token.decimals, + }), + ); + + resolve(tokenBalances); + }, + ) + .catch((error) => reject(error)); + }, this._timeout); + }); + } + + /** + * @param {string} idOrAliasOrEvmAddress + * @returns {Promise} + */ + getTokenRelationshipsForAccount(idOrAliasOrEvmAddress) { + return new Promise((resolve, reject) => { + setTimeout(() => { + this._mirrorNodeGateway + .getAccountTokens(idOrAliasOrEvmAddress) + .then( + ( + /** @type {import("axios").AxiosResponse<{ tokens: MirrorNodeTokenResponse[] }>} */ response, + ) => { + /** @type {HashgraphProto.proto.ITokenRelationship[]} */ + const tokenRelationships = response.data.tokens.map( + ( + /** @type {MirrorNodeTokenResponse} */ token, + ) => ({ + tokenId: TokenId.fromString( + token.token_id, + )._toProtobuf(), + balance: Long.fromNumber(token.balance), + decimals: token.decimals, + kycStatus: this.getTokenKycStatusFrom( + token.kyc_status, + ), + freezeStatus: this.getTokenFreezeStatusFrom( + token.freeze_status, + ), + automaticAssociation: + token.automatic_association, + }), + ); + + resolve(tokenRelationships); + }, + ) + .catch((error) => { + reject(error); + }); + }, this._timeout); + }); + } + + /** + * + * @param {string} status + * @returns {HashgraphProto.proto.TokenKycStatus} + */ + getTokenKycStatusFrom(status) { + switch (status) { + case TokenKeyStatusEnum.NOT_APPLICABLE: + return hashgraphProto.proto.TokenKycStatus.KycNotApplicable; + case TokenKeyStatusEnum.GRANTED: + return hashgraphProto.proto.TokenKycStatus.Granted; + case TokenKeyStatusEnum.REVOKED: + return hashgraphProto.proto.TokenKycStatus.Revoked; + default: + throw new Error(`Invalid token KYC status: ${status}`); + } + } + + /** + * + * @param {string} status + * @returns {HashgraphProto.proto.TokenFreezeStatus} + */ + getTokenFreezeStatusFrom(status) { + switch (status) { + case TokenFreezeStatusEnum.NOT_APPLICABLE: + return hashgraphProto.proto.TokenFreezeStatus + .FreezeNotApplicable; + case TokenFreezeStatusEnum.FROZEN: + return hashgraphProto.proto.TokenFreezeStatus.Frozen; + case TokenFreezeStatusEnum.UNFROZEN: + return hashgraphProto.proto.TokenFreezeStatus.Unfrozen; + default: + throw new Error(`Invalid token freeze status: ${status}`); + } + } + + /** + * + * @param {number} timeout + * @returns {this} + */ + setTimeout(timeout) { + this._timeout = timeout; + return this; + } +} diff --git a/test/integration/AccountBalanceIntegrationTest.js b/test/integration/AccountBalanceIntegrationTest.js index f2be8c9ca..a97d22d9f 100644 --- a/test/integration/AccountBalanceIntegrationTest.js +++ b/test/integration/AccountBalanceIntegrationTest.js @@ -1,6 +1,7 @@ import { AccountBalanceQuery, Status, + TokenCreateTransaction, // TokenCreateTransaction, } from "../../src/exports.js"; import IntegrationTestEnv, { @@ -28,10 +29,8 @@ describe("AccountBalanceQuery", function () { expect(balance.hbars.toTinybars().compare(0)).to.be.equal(1); }); - // TODO(2023-11-01 NK) - test is consistently failing and should be enabled once fixed. - // eslint-disable-next-line mocha/no-skipped-tests - xit("can connect to previewnet with TLS", async function () { - this.timeout(30000); + it("can connect to previewnet with TLS", async function () { + this.timeout(120000); if (skipTestDueToNodeJsVersion(16)) { return; } @@ -41,15 +40,18 @@ describe("AccountBalanceQuery", function () { )) { expect(address.endsWith(":50212")).to.be.true; - await new AccountBalanceQuery() + const balance = await new AccountBalanceQuery() + .setTimeout(3000) .setAccountId(nodeAccountId) .setMaxAttempts(10) .execute(clientPreviewNet); + + expect(balance.hbars).to.not.be.null; } }); it("can connect to testnet with TLS", async function () { - this.timeout(30000); + this.timeout(120000); if (skipTestDueToNodeJsVersion(16)) { return; @@ -60,10 +62,13 @@ describe("AccountBalanceQuery", function () { )) { expect(address.endsWith(":50212")).to.be.true; - await new AccountBalanceQuery() + const balance = await new AccountBalanceQuery() + .setTimeout(3000) .setAccountId(nodeAccountId) .setMaxAttempts(10) .execute(clientTestnet); + + expect(balance.hbars).to.not.be.null; } }); @@ -85,32 +90,28 @@ describe("AccountBalanceQuery", function () { } }); - /** - * - * @description The test is temporarily commented because AccountBalanceQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should reflect token with no keys", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setTreasuryAccountId(operatorId) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // const balances = await new AccountBalanceQuery() - // .setAccountId(env.operatorId) - // .execute(env.client); - - // expect(balances.tokens.get(token).toInt()).to.be.equal(0); - // }); + it("should reflect token with no keys", async function () { + this.timeout(30000); + + const operatorId = env.operatorId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setTreasuryAccountId(operatorId) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + const balances = await new AccountBalanceQuery() + .setTimeout(3000) + .setAccountId(env.operatorId) + .execute(env.client); + + expect(balances.tokens.get(token).toInt()).to.be.equal(0); + }); after(async function () { clientPreviewNet.close(); diff --git a/test/integration/AccountCreateIntegrationTest.js b/test/integration/AccountCreateIntegrationTest.js index 2f150ada4..4212b000c 100644 --- a/test/integration/AccountCreateIntegrationTest.js +++ b/test/integration/AccountCreateIntegrationTest.js @@ -35,6 +35,7 @@ describe("AccountCreate", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); @@ -76,6 +77,7 @@ describe("AccountCreate", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setNodeAccountIds([response.nodeId]) .setAccountId(account) .execute(env.client); @@ -117,6 +119,7 @@ describe("AccountCreate", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); @@ -173,6 +176,7 @@ describe("AccountCreate", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setNodeAccountIds([response.nodeId]) .setAccountId(account) .execute(env.client); @@ -218,6 +222,7 @@ describe("AccountCreate", function () { expect(accountId).to.not.be.null; const info = await new AccountInfoQuery() + .setTimeout(3000) .setNodeAccountIds([txAccountCreate.nodeId]) .setAccountId(accountId) .execute(env.client); @@ -255,6 +260,7 @@ describe("AccountCreate", function () { expect(accountId).to.not.be.null; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(accountId) .execute(env.client); @@ -296,6 +302,7 @@ describe("AccountCreate", function () { expect(accountId).to.not.be.null; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(accountId) .execute(env.client); @@ -369,6 +376,7 @@ describe("AccountCreate", function () { expect(accountId).to.not.be.null; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(accountId) .execute(env.client); @@ -447,6 +455,7 @@ describe("AccountCreate", function () { expect(accountId).to.not.be.null; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(accountId) .execute(env.client); diff --git a/test/integration/AccountDeleteIntegrationTest.js b/test/integration/AccountDeleteIntegrationTest.js index abea8abd2..dde84807f 100644 --- a/test/integration/AccountDeleteIntegrationTest.js +++ b/test/integration/AccountDeleteIntegrationTest.js @@ -33,6 +33,7 @@ describe("AccountDelete", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); diff --git a/test/integration/AccountInfoIntegrationTest.js b/test/integration/AccountInfoIntegrationTest.js index ea6cfbbd5..34f455117 100644 --- a/test/integration/AccountInfoIntegrationTest.js +++ b/test/integration/AccountInfoIntegrationTest.js @@ -5,7 +5,7 @@ import { Hbar, PrivateKey, Status, - // TokenCreateTransaction, + TokenCreateTransaction, TransactionId, } from "../../src/exports.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; @@ -86,6 +86,7 @@ describe("AccountInfo", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); @@ -154,38 +155,34 @@ describe("AccountInfo", function () { } }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should reflect token with no keys", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setTreasuryAccountId(operatorId) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // const info = await new AccountInfoQuery() - // .setAccountId(operatorId) - // .execute(env.client); - - // const relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.null; - // expect(relationship.isFrozen).to.be.null; - // }); + it("should reflect token with no keys", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setTreasuryAccountId(operatorId) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + const info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(operatorId) + .execute(env.client); + + const relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.null; + expect(relationship.isFrozen).to.be.null; + }); it("should be error with no account ID", async function () { this.timeout(120000); diff --git a/test/integration/AccountUpdateIntegrationTest.js b/test/integration/AccountUpdateIntegrationTest.js index bcc9bb7de..cc987ae17 100644 --- a/test/integration/AccountUpdateIntegrationTest.js +++ b/test/integration/AccountUpdateIntegrationTest.js @@ -39,6 +39,7 @@ describe("AccountUpdate", function () { const account = receipt.accountId; let info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); diff --git a/test/integration/ClientIntegrationTest.js b/test/integration/ClientIntegrationTest.js index 204faaa38..7cb3ec9a2 100644 --- a/test/integration/ClientIntegrationTest.js +++ b/test/integration/ClientIntegrationTest.js @@ -21,47 +21,6 @@ describe("ClientIntegration", function () { clientPreviewNet = Client.forPreviewnet(); }); - it("should error when invalid network on entity ID", async function () { - this.timeout(120000); - - if (env.client.ledgerId == null) { - return; - } - - let err = false; - - let network; - switch (env.client.ledgerId.toString()) { - case "mainnet": - network = "testnet"; - break; - case "testnet": - network = "previewnet"; - break; - case "previewnet": - network = "mainnet"; - break; - default: - throw new Error( - `(BUG) operator network is unrecognized value: ${env.client.ledgerId.toString()}`, - ); - } - - const accountId = AccountId.withNetwork(3, network); - - try { - await new AccountInfoQuery() - .setAccountId(accountId) - .execute(env.client); - } catch (error) { - err = true; - } - - if (!err) { - throw new Error("query did not error"); - } - }); - it("can execute with sign on demand", async function () { this.timeout(120000); @@ -81,9 +40,11 @@ describe("ClientIntegration", function () { const account = receipt.accountId; const info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); + expect(info).to.not.be.null; expect(info.accountId.toString()).to.be.equal(account.toString()); expect(info.isDeleted).to.be.false; expect(info.key.toString()).to.be.equal(key.publicKey.toString()); @@ -122,7 +83,7 @@ describe("ClientIntegration", function () { }); it("can pingAll", async function () { - this.timeout(120000); + this.timeout(300000); await env.client.pingAll(); }); @@ -139,32 +100,17 @@ describe("ClientIntegration", function () { expect(error).to.be.an("Error"); }); - // TODO(2023-11-01 NK) - test is consistently failing and should be enabled once fixed. - // eslint-disable-next-line mocha/no-skipped-tests - xit("can set network name on custom network", async function () { - this.timeout(120000); - expect(clientTestnet.ledgerId).to.be.equal(LedgerId.TESTNET); - expect(clientPreviewNet.ledgerId).to.be.equal(LedgerId.PREVIEWNET); - - await clientTestnet.setNetwork(clientPreviewNet.network); - - expect(clientTestnet.ledgerId).to.be.null; - - clientTestnet.setLedgerId("previewnet"); - - expect(clientTestnet.ledgerId).to.be.equal(LedgerId.PREVIEWNET); - }); - it("can use same proxies of one node", async function () { - this.timeout(100000); + this.timeout(300000); let nodes = { "0.testnet.hedera.com:50211": new AccountId(3), "34.94.106.61:50211": new AccountId(3), "50.18.132.211:50211": new AccountId(3), - "138.91.142.219:50211": new AccountId(3), }; - const clientForNetwork = Client.forNetwork(nodes); + const clientForNetwork = Client.forNetwork(nodes) + .setLedgerId(LedgerId.TESTNET) + .setMirrorNetwork("testnet.mirrornode.hedera.com:443"); await clientForNetwork.pingAll(); }); @@ -190,6 +136,64 @@ describe("ClientIntegration", function () { expect(env.client.defaultMaxQueryPayment).to.be.equal(value); }); + /** + * @summary + * The last two tests must be in the exact order as + * they are now and always be the last tests in the suite. + * The client is initialized once before all the tests in the suite + * and when we manipulate the ledger id of the network + * this will affect the other tests. + */ + + it("should error when invalid network on entity ID", async function () { + this.timeout(120000); + + if (env.client.ledgerId == null) { + return; + } + + switch (env.client.ledgerId.toString()) { + case "mainnet": + env.client.setLedgerId(LedgerId.TESTNET); + break; + case "testnet": + env.client.setLedgerId(LedgerId.PREVIEWNET); + break; + case "previewnet": + env.client.setLedgerId(LedgerId.LOCAL_NODE); + break; + case "local-node": + env.client.setLedgerId(LedgerId.MAINNET); + break; + default: + throw new Error( + `(BUG) operator network is unrecognized value: ${env.client.ledgerId.toString()}`, + ); + } + + const accountId = new AccountId(3); + let err; + + try { + await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(accountId) + .execute(env.client); + } catch (error) { + err = error; + } + + expect(err).to.not.be.null; + }); + + it("can set network name on custom network", async function () { + this.timeout(120000); + + env.client.setLedgerId("previewnet"); + + expect(env.client.ledgerId).to.be.equal(LedgerId.PREVIEWNET); + }); + after(async function () { await env.close(); clientTestnet.close(); diff --git a/test/integration/ContractCreateIntegrationTest.js b/test/integration/ContractCreateIntegrationTest.js index 6e00e2c6b..627a364f2 100644 --- a/test/integration/ContractCreateIntegrationTest.js +++ b/test/integration/ContractCreateIntegrationTest.js @@ -58,6 +58,7 @@ describe("ContractCreate", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); diff --git a/test/integration/ContractDeleteIntegrationTest.js b/test/integration/ContractDeleteIntegrationTest.js index 7b10b278f..e31b032d0 100644 --- a/test/integration/ContractDeleteIntegrationTest.js +++ b/test/integration/ContractDeleteIntegrationTest.js @@ -58,6 +58,7 @@ describe("ContractDelete", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); @@ -179,6 +180,7 @@ describe("ContractDelete", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); diff --git a/test/integration/ContractFunctionParametersIntegrationTest.js b/test/integration/ContractFunctionParametersIntegrationTest.js index 990919d2a..b7ca08978 100644 --- a/test/integration/ContractFunctionParametersIntegrationTest.js +++ b/test/integration/ContractFunctionParametersIntegrationTest.js @@ -132,7 +132,6 @@ describe("ContractFunctionParameters", function () { const fileCreateSubmit = await fileCreateSign.execute(env.client); const fileCreateRx = await fileCreateSubmit.getReceipt(env.client); const bytecodeFileId = fileCreateRx.fileId; - console.log(`- The bytecode file ID is: ${bytecodeFileId} \n`); //Append contents to the file const fileAppendTx = new FileAppendTransaction() @@ -142,11 +141,7 @@ describe("ContractFunctionParameters", function () { .freezeWith(env.client); const fileAppendSign = await fileAppendTx.sign(env.operatorKey); const fileAppendSubmit = await fileAppendSign.execute(env.client); - const fileAppendRx = await fileAppendSubmit.getReceipt(env.client); - console.log( - "Status of file append is", - fileAppendRx.status.toString(10), - ); + await fileAppendSubmit.getReceipt(env.client); // Instantiate the contract instance const contractTx = new ContractCreateTransaction() @@ -165,9 +160,6 @@ describe("ContractFunctionParameters", function () { //Get the smart contract ID newContractId = contractReceipt.contractId; - - //Log the smart contract ID - console.log("The smart contract ID is " + newContractId); }); bitSizes.forEach((bitSize) => { @@ -1018,7 +1010,6 @@ describe("ContractFunctionParameters", function () { const contractCreateRecord = await contractCreate.getRecord(env.client); const nonces = contractCreateRecord.contractFunctionResult.contractNonces; - console.log(`contractNonces: ${JSON.stringify(nonces)}`); const contractId = contractCreateRecord.receipt.contractId; const contractAnonce = nonces.find( @@ -1038,19 +1029,13 @@ describe("ContractFunctionParameters", function () { .setContractId(contractId) .execute(env.client); - const contractDeleteResult = await contractDeleteTx.getReceipt( - env.client, - ); - console.log( - `contractDelete status: ${contractDeleteResult.status.toString()}`, - ); + await contractDeleteTx.getReceipt(env.client); const fileDeleteTx = await new FileDeleteTransaction() .setFileId(fileId) .execute(env.client); - const fileDeleteResult = await fileDeleteTx.getReceipt(env.client); - console.log(`fileDelete status: ${fileDeleteResult.status.toString()}`); + await fileDeleteTx.getReceipt(env.client); }); after(async function () { diff --git a/test/integration/ContractInfoIntegrationTest.js b/test/integration/ContractInfoIntegrationTest.js index d38a6e7d4..4af8e4ef0 100644 --- a/test/integration/ContractInfoIntegrationTest.js +++ b/test/integration/ContractInfoIntegrationTest.js @@ -19,6 +19,7 @@ describe("ContractInfo", function () { before(async function () { env = await IntegrationTestEnv.new(); }); + it("should be executable", async function () { this.timeout(120000); @@ -57,6 +58,7 @@ describe("ContractInfo", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); @@ -126,6 +128,7 @@ describe("ContractInfo", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); diff --git a/test/integration/ContractUpdateIntegrationTest.js b/test/integration/ContractUpdateIntegrationTest.js index af2310ace..323fa6a5b 100644 --- a/test/integration/ContractUpdateIntegrationTest.js +++ b/test/integration/ContractUpdateIntegrationTest.js @@ -59,6 +59,7 @@ describe("ContractUpdate", function () { let contract = receipt.contractId; let info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(1)) .execute(env.client); @@ -85,6 +86,7 @@ describe("ContractUpdate", function () { ).getReceipt(env.client); info = await new ContractInfoQuery() + .setTimeout(3000) .setContractId(contract) .setQueryPayment(new Hbar(5)) .execute(env.client); diff --git a/test/integration/CustomFeesIntegrationTest.js b/test/integration/CustomFeesIntegrationTest.js index 46f7eae79..65456c3ca 100644 --- a/test/integration/CustomFeesIntegrationTest.js +++ b/test/integration/CustomFeesIntegrationTest.js @@ -1397,7 +1397,6 @@ describe("CustomFees", function () { .execute(env.client) ).getReceipt(env.client); } catch (error) { - console.log(error); err = error .toString() .includes(Status.CustomFeeChargingExceededMaxAccountAmounts); diff --git a/test/integration/GetCostIntegrationTest.js b/test/integration/GetCostIntegrationTest.js index a27f533fc..92af3913b 100644 --- a/test/integration/GetCostIntegrationTest.js +++ b/test/integration/GetCostIntegrationTest.js @@ -22,6 +22,7 @@ describe("GetCost", function () { .getCost(env.client); await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(operatorId) .setQueryPayment(cost) .execute(env.client); @@ -39,6 +40,7 @@ describe("GetCost", function () { .getCost(env.client); await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(operatorId) .setQueryPayment(cost) .execute(env.client); @@ -56,6 +58,7 @@ describe("GetCost", function () { .getCost(env.client); await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(operatorId) .setQueryPayment(cost) .execute(env.client); @@ -72,6 +75,7 @@ describe("GetCost", function () { .execute(env.client); await new AccountBalanceQuery() + .setTimeout(3000) .setAccountId(operatorId) .setQueryPayment(new Hbar(0)) .execute(env.client); @@ -88,6 +92,7 @@ describe("GetCost", function () { .execute(env.client); await new AccountBalanceQuery() + .setTimeout(3000) .setAccountId(operatorId) .setQueryPayment(new Hbar(0)) .execute(env.client); diff --git a/test/integration/ScheduleCreateIntegrationTest.js b/test/integration/ScheduleCreateIntegrationTest.js index a1c4e3cc6..55ee83bfa 100644 --- a/test/integration/ScheduleCreateIntegrationTest.js +++ b/test/integration/ScheduleCreateIntegrationTest.js @@ -123,12 +123,10 @@ describe("ScheduleCreate", function () { key3.publicKey, ); - const balance = await new AccountBalanceQuery() + await new AccountBalanceQuery() .setAccountId(operatorId) .execute(env.client); - console.log(`Balances of the new account: ${balance.toString()}`); - const response = await new AccountCreateTransaction() .setInitialBalance(new Hbar(10)) .setKey(keyList) diff --git a/test/integration/TokenAllowancesIntegrationTest.js b/test/integration/TokenAllowancesIntegrationTest.js index c5474e41a..de53ee9e9 100644 --- a/test/integration/TokenAllowancesIntegrationTest.js +++ b/test/integration/TokenAllowancesIntegrationTest.js @@ -156,10 +156,7 @@ describe("TokenAllowances", function () { const approveRx = await receiverApproveTx.execute(env.client); - const approveReceipt = await approveRx.getReceipt(env.client); - console.log( - `Approve spender allowance - status: ${approveReceipt.status}`, - ); + await approveRx.getReceipt(env.client); let err = false; const onBehalfOfTransactionId = @@ -227,8 +224,7 @@ describe("TokenAllowances", function () { .freezeWith(env.client); const fileAppendSign = await fileAppendTx.sign(env.operatorKey); const fileAppendSubmit = await fileAppendSign.execute(env.client); - const fileAppendRx = await fileAppendSubmit.getReceipt(env.client); - console.log("Status of file append is", fileAppendRx.status.toString()); + await fileAppendSubmit.getReceipt(env.client); // Instantiate the contract instance const contractTx = await new ContractCreateTransaction() @@ -249,8 +245,6 @@ describe("TokenAllowances", function () { //Get the smart contract ID const contractId = contractReceipt.contractId; - console.log("Contract ID is:", contractId.toString()); - //Associate Token with Contract const tokenAssociateTransactionWithContract = await new TokenAssociateTransaction() @@ -262,12 +256,7 @@ describe("TokenAllowances", function () { await tokenAssociateTransactionWithContract.sign(env.operatorKey); const txResponseAssociatedTokenWithContract = await signedTxForAssociateTokenWithContract.execute(env.client); - const txReceipt2 = - await txResponseAssociatedTokenWithContract.getReceipt(env.client); - console.log( - "The associate token to contract transaction consensus is", - txReceipt2.status.toString(), - ); + await txResponseAssociatedTokenWithContract.getReceipt(env.client); //Associate Token with Receiver const tokenAssociateTransactionWithContract1 = @@ -280,12 +269,7 @@ describe("TokenAllowances", function () { await tokenAssociateTransactionWithContract1.sign(receiverKey); const txResponseAssociatedTokenWithContract1 = await signedTxForAssociateTokenWithContract1.execute(env.client); - const txReceipt21 = - await txResponseAssociatedTokenWithContract1.getReceipt(env.client); - console.log( - "The associate token to receiver transaction consensus is", - txReceipt21.status.toString(), - ); + await txResponseAssociatedTokenWithContract1.getReceipt(env.client); // Give `spender` allowance for Token const receiverApproveTx = @@ -298,10 +282,7 @@ describe("TokenAllowances", function () { const approveRx = await receiverApproveTx.execute(env.client); - const approveReceipt = await approveRx.getReceipt(env.client); - console.log( - `Approve spender allowance - status: ${approveReceipt.status}`, - ); + await approveRx.getReceipt(env.client); // Get Allowances const checkAllowance = new ContractExecuteTransaction() @@ -324,8 +305,6 @@ describe("TokenAllowances", function () { .execute(env.client); const allowanceSize = recQuery.contractFunctionResult.getUint256(0); - console.log(`Contract has an allowance of ${allowanceSize}`); - expect(allowanceSize.toNumber()).to.equal(100); }); diff --git a/test/integration/TokenAssociateIntegrationTest.js b/test/integration/TokenAssociateIntegrationTest.js index 020813a07..8a4323397 100644 --- a/test/integration/TokenAssociateIntegrationTest.js +++ b/test/integration/TokenAssociateIntegrationTest.js @@ -1,9 +1,9 @@ import { - // AccountBalanceQuery, - // AccountCreateTransaction, - // AccountInfoQuery, - // Hbar, - // PrivateKey, + AccountBalanceQuery, + AccountCreateTransaction, + AccountInfoQuery, + Hbar, + PrivateKey, Status, TokenAssociateTransaction, TokenCreateTransaction, @@ -17,71 +17,70 @@ describe("TokenAssociate", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountBalanceQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // const balances = await new AccountBalanceQuery() - // .setAccountId(account) - // .execute(env.client); - - // expect(balances.tokens.get(token).toInt()).to.be.equal(0); - - // const info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // const relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.false; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + const tokenDecimal = 3; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(tokenDecimal) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + const balances = await new AccountBalanceQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + expect(balances.tokens.get(token).toInt()).to.be.equal(0); + + const info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + const relationship = info.tokenRelationships.get(token); + + expect(relationship.decimals).to.be.equal(tokenDecimal); + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.false; + }); it("should be executable even when no token IDs are set", async function () { this.timeout(120000); diff --git a/test/integration/TokenBurnIntegrationTest.js b/test/integration/TokenBurnIntegrationTest.js index 5c7fae214..ca8b4749a 100644 --- a/test/integration/TokenBurnIntegrationTest.js +++ b/test/integration/TokenBurnIntegrationTest.js @@ -4,7 +4,7 @@ import { TokenCreateTransaction, TokenSupplyType, TokenType, - // AccountBalanceQuery, + AccountBalanceQuery, } from "../../src/exports.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; @@ -65,57 +65,53 @@ describe("TokenBurn", function () { } }); - /** - * - * @description The test is temporarily commented because AccountBalanceQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should not error when amount is not set", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - - // const response = await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client); - - // const token = (await response.getReceipt(env.client)).tokenId; - - // let err = false; - - // try { - // await ( - // await new TokenBurnTransaction() - // .setTokenId(token) - // .execute(env.client) - // ).getReceipt(env.client); - // } catch (error) { - // err = error; - // } - - // const accountBalance = await new AccountBalanceQuery() - // .setAccountId(operatorId) - // .execute(env.client); - - // expect( - // accountBalance.tokens._map.get(token.toString()).toNumber(), - // ).to.be.equal(1000000); - - // if (err) { - // throw new Error("token burn did error"); - // } - // }); + it("should not error when amount is not set", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + + const response = await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client); + + const token = (await response.getReceipt(env.client)).tokenId; + + let err = false; + + try { + await ( + await new TokenBurnTransaction() + .setTokenId(token) + .execute(env.client) + ).getReceipt(env.client); + } catch (error) { + err = error; + } + + const accountBalance = await new AccountBalanceQuery() + .setTimeout(3000) + .setAccountId(operatorId) + .execute(env.client); + + expect( + accountBalance.tokens._map.get(token.toString()).toNumber(), + ).to.be.equal(1000000); + + if (err) { + throw new Error("token burn did error"); + } + }); it("cannot burn token with invalid metadata", async function () { this.timeout(120000); diff --git a/test/integration/TokenDissociateIntegrationTest.js b/test/integration/TokenDissociateIntegrationTest.js index 5b1e29414..4d68f7141 100644 --- a/test/integration/TokenDissociateIntegrationTest.js +++ b/test/integration/TokenDissociateIntegrationTest.js @@ -1,8 +1,8 @@ import { - // AccountBalanceQuery, + AccountBalanceQuery, AccountCreateTransaction, - // AccountInfoQuery, - // Hbar, + AccountInfoQuery, + Hbar, PrivateKey, Status, TokenAssociateTransaction, @@ -23,93 +23,92 @@ describe("TokenDissociate", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountBalanceQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // let balances = await new AccountBalanceQuery() - // .setAccountId(account) - // .execute(env.client); - - // expect(balances.tokens.get(token).toInt()).to.be.equal(0); - - // let info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // const relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.false; - - // await ( - // await ( - // await new TokenDissociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // balances = await new AccountBalanceQuery() - // .setAccountId(account) - // .execute(env.client); - - // expect(balances.tokens.get(token)).to.be.null; - - // info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // expect(info.tokenRelationships.get(token)).to.be.null; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + let balances = await new AccountBalanceQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + expect(balances.tokens.get(token).toInt()).to.be.equal(0); + + let info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + const relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.false; + + await ( + await ( + await new TokenDissociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + balances = await new AccountBalanceQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + expect(balances.tokens.get(token)).to.be.null; + + info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + expect(info.tokenRelationships.get(token)).to.be.null; + }); it("should be executable even when no token IDs are set", async function () { this.timeout(120000); diff --git a/test/integration/TokenFreezeIntegrationTest.js b/test/integration/TokenFreezeIntegrationTest.js index f35aed9b6..e629eb14e 100644 --- a/test/integration/TokenFreezeIntegrationTest.js +++ b/test/integration/TokenFreezeIntegrationTest.js @@ -1,10 +1,10 @@ import { AccountCreateTransaction, - // AccountInfoQuery, + AccountInfoQuery, Hbar, PrivateKey, Status, - // TokenAssociateTransaction, + TokenAssociateTransaction, TokenCreateTransaction, TokenFreezeTransaction, } from "../../src/exports.js"; @@ -17,75 +17,71 @@ describe("TokenFreeze", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await ( - // await new TokenFreezeTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // const info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // const relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.true; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await ( + await new TokenFreezeTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + const info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + const relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.true; + }); it("should be executable with no tokens set", async function () { this.timeout(120000); diff --git a/test/integration/TokenGrantKycIntegrationTest.js b/test/integration/TokenGrantKycIntegrationTest.js index 2fa40851b..3157eb7c4 100644 --- a/test/integration/TokenGrantKycIntegrationTest.js +++ b/test/integration/TokenGrantKycIntegrationTest.js @@ -1,10 +1,10 @@ import { AccountCreateTransaction, - // AccountInfoQuery, + AccountInfoQuery, Hbar, PrivateKey, Status, - // TokenAssociateTransaction, + TokenAssociateTransaction, TokenCreateTransaction, TokenGrantKycTransaction, } from "../../src/exports.js"; @@ -17,75 +17,71 @@ describe("TokenGrantKyc", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await ( - // await new TokenGrantKycTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // const info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // const relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.true; - // expect(relationship.isFrozen).to.be.false; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await ( + await new TokenGrantKycTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + const info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + const relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.true; + expect(relationship.isFrozen).to.be.false; + }); it("should be executable even when no token IDs are set", async function () { this.timeout(120000); diff --git a/test/integration/TokenRevokeKycIntegrationTest.js b/test/integration/TokenRevokeKycIntegrationTest.js index d1023d9fa..92cb0eb1d 100644 --- a/test/integration/TokenRevokeKycIntegrationTest.js +++ b/test/integration/TokenRevokeKycIntegrationTest.js @@ -1,12 +1,12 @@ import { AccountCreateTransaction, - // AccountInfoQuery, + AccountInfoQuery, Hbar, PrivateKey, Status, - // TokenAssociateTransaction, + TokenAssociateTransaction, TokenCreateTransaction, - // TokenGrantKycTransaction, + TokenGrantKycTransaction, TokenRevokeKycTransaction, } from "../../src/exports.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; @@ -18,97 +18,94 @@ describe("TokenRevokeKyc", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await ( - // await new TokenGrantKycTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // let info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // let relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.true; - // expect(relationship.isFrozen).to.be.false; - - // await ( - // await ( - // await new TokenRevokeKycTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.false; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await ( + await new TokenGrantKycTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + let info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + let relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.true; + expect(relationship.isFrozen).to.be.false; + + await ( + await ( + await new TokenRevokeKycTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.false; + }); it("should be executable even when no token IDs are set", async function () { this.timeout(120000); diff --git a/test/integration/TokenTransferIntegrationTest.js b/test/integration/TokenTransferIntegrationTest.js index 4ee2605ba..ebb424130 100644 --- a/test/integration/TokenTransferIntegrationTest.js +++ b/test/integration/TokenTransferIntegrationTest.js @@ -340,6 +340,7 @@ describe("TokenTransfer", function () { const account = receipt.accountId; let info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); @@ -356,6 +357,7 @@ describe("TokenTransfer", function () { ).getReceipt(env.client); info = await new AccountInfoQuery() + .setTimeout(3000) .setAccountId(account) .execute(env.client); diff --git a/test/integration/TokenUnfreezeIntegrationTest.js b/test/integration/TokenUnfreezeIntegrationTest.js index ec4390e8f..f1d94f9fa 100644 --- a/test/integration/TokenUnfreezeIntegrationTest.js +++ b/test/integration/TokenUnfreezeIntegrationTest.js @@ -1,12 +1,12 @@ import { AccountCreateTransaction, - // AccountInfoQuery, + AccountInfoQuery, Hbar, PrivateKey, Status, - // TokenAssociateTransaction, + TokenAssociateTransaction, TokenCreateTransaction, - // TokenFreezeTransaction, + TokenFreezeTransaction, TokenUnfreezeTransaction, } from "../../src/exports.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; @@ -18,97 +18,94 @@ describe("TokenUnfreeze", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await ( - // await new TokenFreezeTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // let info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // let relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.true; - - // await ( - // await ( - // await new TokenUnfreezeTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.false; - // expect(relationship.isFrozen).to.be.false; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await ( + await new TokenFreezeTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + let info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + let relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.true; + + await ( + await ( + await new TokenUnfreezeTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.false; + expect(relationship.isFrozen).to.be.false; + }); it("should be executable even when no token IDs are set", async function () { this.timeout(120000); diff --git a/test/integration/TokenWipeIntegrationTest.js b/test/integration/TokenWipeIntegrationTest.js index f31d05bc7..6f4945157 100644 --- a/test/integration/TokenWipeIntegrationTest.js +++ b/test/integration/TokenWipeIntegrationTest.js @@ -1,6 +1,6 @@ import { AccountCreateTransaction, - // AccountInfoQuery, + AccountInfoQuery, Hbar, PrivateKey, Status, @@ -8,7 +8,7 @@ import { TokenCreateTransaction, TokenGrantKycTransaction, TokenWipeTransaction, - // TransferTransaction, + TransferTransaction, Transaction, } from "../../src/exports.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; @@ -21,102 +21,99 @@ describe("TokenWipe", function () { env = await IntegrationTestEnv.new(); }); - /** - * - * @description The test is temporarily commented because AccountInfoQuery does a query to the consensus node which was deprecated. - * @todo Uncomment a test when the new query to the mirror node is implemented as it described here https://github.com/hashgraph/hedera-sdk-reference/issues/144 - */ - // it("should be executable", async function () { - // this.timeout(120000); - - // const operatorId = env.operatorId; - // const operatorKey = env.operatorKey.publicKey; - // const key = PrivateKey.generateED25519(); - - // const response = await new AccountCreateTransaction() - // .setKey(key) - // .setInitialBalance(new Hbar(2)) - // .execute(env.client); - - // const account = (await response.getReceipt(env.client)).accountId; - - // const token = ( - // await ( - // await new TokenCreateTransaction() - // .setTokenName("ffff") - // .setTokenSymbol("F") - // .setDecimals(3) - // .setInitialSupply(1000000) - // .setTreasuryAccountId(operatorId) - // .setAdminKey(operatorKey) - // .setKycKey(operatorKey) - // .setFreezeKey(operatorKey) - // .setWipeKey(operatorKey) - // .setSupplyKey(operatorKey) - // .setFreezeDefault(false) - // .execute(env.client) - // ).getReceipt(env.client) - // ).tokenId; - - // await ( - // await ( - // await new TokenAssociateTransaction() - // .setTokenIds([token]) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await ( - // await new TokenGrantKycTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .freezeWith(env.client) - // .sign(key) - // ).execute(env.client) - // ).getReceipt(env.client); - - // await ( - // await new TransferTransaction() - // .addTokenTransfer(token, account, 10) - // .addTokenTransfer(token, env.operatorId, -10) - // .execute(env.client) - // ).getReceipt(env.client); - - // let info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // let relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(10); - // expect(relationship.isKycGranted).to.be.true; - // expect(relationship.isFrozen).to.be.false; - - // await ( - // await new TokenWipeTransaction() - // .setTokenId(token) - // .setAccountId(account) - // .setAmount(10) - // .execute(env.client) - // ).getReceipt(env.client); - - // info = await new AccountInfoQuery() - // .setAccountId(account) - // .execute(env.client); - - // relationship = info.tokenRelationships.get(token); - - // expect(relationship).to.be.not.null; - // expect(relationship.tokenId.toString()).to.be.equal(token.toString()); - // expect(relationship.balance.toInt()).to.be.equal(0); - // expect(relationship.isKycGranted).to.be.true; - // expect(relationship.isFrozen).to.be.false; - // }); + it("should be executable", async function () { + this.timeout(120000); + + const operatorId = env.operatorId; + const operatorKey = env.operatorKey.publicKey; + const key = PrivateKey.generateED25519(); + + const response = await new AccountCreateTransaction() + .setKey(key) + .setInitialBalance(new Hbar(2)) + .execute(env.client); + + const account = (await response.getReceipt(env.client)).accountId; + + const token = ( + await ( + await new TokenCreateTransaction() + .setTokenName("ffff") + .setTokenSymbol("F") + .setDecimals(3) + .setInitialSupply(1000000) + .setTreasuryAccountId(operatorId) + .setAdminKey(operatorKey) + .setKycKey(operatorKey) + .setFreezeKey(operatorKey) + .setWipeKey(operatorKey) + .setSupplyKey(operatorKey) + .setFreezeDefault(false) + .execute(env.client) + ).getReceipt(env.client) + ).tokenId; + + await ( + await ( + await new TokenAssociateTransaction() + .setTokenIds([token]) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await ( + await new TokenGrantKycTransaction() + .setTokenId(token) + .setAccountId(account) + .freezeWith(env.client) + .sign(key) + ).execute(env.client) + ).getReceipt(env.client); + + await ( + await new TransferTransaction() + .addTokenTransfer(token, account, 10) + .addTokenTransfer(token, env.operatorId, -10) + .execute(env.client) + ).getReceipt(env.client); + + let info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + let relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(10); + expect(relationship.isKycGranted).to.be.true; + expect(relationship.isFrozen).to.be.false; + + await ( + await new TokenWipeTransaction() + .setTokenId(token) + .setAccountId(account) + .setAmount(10) + .execute(env.client) + ).getReceipt(env.client); + + info = await new AccountInfoQuery() + .setTimeout(3000) + .setAccountId(account) + .execute(env.client); + + relationship = info.tokenRelationships.get(token); + + expect(relationship).to.be.not.null; + expect(relationship.tokenId.toString()).to.be.equal(token.toString()); + expect(relationship.balance.toInt()).to.be.equal(0); + expect(relationship.isKycGranted).to.be.true; + expect(relationship.isFrozen).to.be.false; + }); it("should error when token ID is not set", async function () { this.timeout(120000); diff --git a/test/integration/TopicMessageIntegrationTest.js b/test/integration/TopicMessageIntegrationTest.js index 4090da658..1ba1b352d 100644 --- a/test/integration/TopicMessageIntegrationTest.js +++ b/test/integration/TopicMessageIntegrationTest.js @@ -7,6 +7,7 @@ import { } from "../../src/exports.js"; import { bigContents } from "./contents.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; +import { wait } from "../../src/util.js"; describe("TopicMessage", function () { let env; @@ -22,7 +23,7 @@ describe("TopicMessage", function () { const operatorKey = env.operatorKey.publicKey; // Skip this test if we do not have a mirror network - if (env.client.mirrorNetwork.length == 0) { + if (env.client && env.client.mirrorNetwork.length == 0) { return; } @@ -33,24 +34,8 @@ describe("TopicMessage", function () { .execute(env.client); const topic = (await response.getReceipt(env.client)).topicId; - - let finished = false; const contents = "Hello from Hedera SDK JS"; - const handle = new TopicMessageQuery() - .setTopicId(topic) - .setStartTime(0) - .setLimit(1) - .setCompletionHandler(() => { - finished = true; - }) - // eslint-disable-next-line no-unused-vars - .subscribe(env.client, (_) => { - // Do nothing - }); - - const startTime = Date.now(); - await ( await new TopicMessageSubmitTransaction() .setTopicId(topic) @@ -58,9 +43,24 @@ describe("TopicMessage", function () { .execute(env.client) ).getReceipt(env.client); - while (!finished && Date.now() < startTime + 45000) { + let finished = false; + let listener = null; + let endTime = Date.now() + 50000; + + await wait(3000); + + const handle = new TopicMessageQuery() + .setTopicId(topic) + .setStartTime(0) + .setEndTime(Date.now()) + .subscribe(env.client, null, (res) => { + finished = true; + listener = res; + }); + + while (!finished && Date.now() < endTime) { //NOSONAR - await new Promise((resolved) => setTimeout(resolved, 2000)); + await new Promise((resolved) => setTimeout(resolved, 5000)); } await ( @@ -71,9 +71,10 @@ describe("TopicMessage", function () { handle.unsubscribe(); - if (!finished) { - throw new Error("Failed to receive message in 30s"); - } + expect(listener).to.not.be.null; + expect(Buffer.from(listener.contents).toString("utf8")).to.be.eql( + contents, + ); }); it("should be executable with large message", async function () { diff --git a/test/integration/TopicMessageQueryTest.js b/test/integration/TopicMessageQueryTest.js index 83153d0b2..a359745b3 100644 --- a/test/integration/TopicMessageQueryTest.js +++ b/test/integration/TopicMessageQueryTest.js @@ -3,6 +3,7 @@ import { TopicCreateTransaction, TopicMessageSubmitTransaction, } from "../../src/exports.js"; +import { wait } from "../../src/util.js"; import IntegrationTestEnv from "./client/NodeIntegrationTestEnv.js"; describe("TopicMessageQuery", function () { @@ -43,15 +44,18 @@ describe("TopicMessageQuery", function () { ).getReceipt(env.client); let finished = false; + let listener = null; let endTime = Date.now() + 50000; + await wait(3000); + new TopicMessageQuery() .setTopicId(topic) - // .setStartTime(0) - // .setLimit(1) - // eslint-disable-next-line no-unused-vars - .subscribe(env, (_) => { + .setStartTime(0) + .setEndTime(Date.now()) + .subscribe(env.client, null, (res) => { finished = true; + listener = res; }); while (!finished && Date.now() < endTime) { @@ -59,9 +63,10 @@ describe("TopicMessageQuery", function () { await new Promise((resolved) => setTimeout(resolved, 5000)); } - if (!finished) { - throw new Error("Did not receive message from query"); - } + expect(listener).to.not.be.null; + expect(Buffer.from(listener.contents).toString("utf8")).to.be.eql( + contents, + ); }); after(async function () { diff --git a/test/integration/TransactionRecordIntegrationTest.js b/test/integration/TransactionRecordIntegrationTest.js index a33eb0fdf..567d61ea4 100644 --- a/test/integration/TransactionRecordIntegrationTest.js +++ b/test/integration/TransactionRecordIntegrationTest.js @@ -29,7 +29,6 @@ describe("TransactionRecord", function () { const fileCreateSubmit = await fileCreateSign.execute(env.client); const fileCreateRx = await fileCreateSubmit.getReceipt(env.client); const bytecodeFileId = fileCreateRx.fileId; - console.log(`- The bytecode file ID is: ${bytecodeFileId} \n`); //Append contents to the file const fileAppendTx = new FileAppendTransaction() @@ -39,8 +38,7 @@ describe("TransactionRecord", function () { .freezeWith(env.client); const fileAppendSign = await fileAppendTx.sign(privateKey); const fileAppendSubmit = await fileAppendSign.execute(env.client); - const fileAppendRx = await fileAppendSubmit.getReceipt(env.client); - console.log("Status of file append is", fileAppendRx.status.toString()); + await fileAppendSubmit.getReceipt(env.client); // Instantiate the contract instance const contractTx = await new ContractCreateTransaction() @@ -60,9 +58,6 @@ describe("TransactionRecord", function () { //Get the smart contract ID const newContractId = contractReceipt.contractId; - //Log the smart contract ID - console.log("The smart contract ID is " + newContractId); - const contractExecuteTx = new ContractExecuteTransaction() .setContractId(newContractId) .setGas(750000) diff --git a/test/integration/client/BaseIntegrationTestEnv.js b/test/integration/client/BaseIntegrationTestEnv.js index 5a0c4d0c9..0c5b5dc11 100644 --- a/test/integration/client/BaseIntegrationTestEnv.js +++ b/test/integration/client/BaseIntegrationTestEnv.js @@ -74,9 +74,7 @@ export default class BaseIntegrationTestEnv { options.env.HEDERA_NETWORK == "localhost") || options.env.HEDERA_NETWORK == "local-node" ) { - client = options.client.forNetwork({ - "127.0.0.1:50211": new AccountId(3), - }); + client = options.client.forLocalNode(); } else if (options.env.CONFIG_FILE != null) { client = await options.client.fromConfigFile( options.env.CONFIG_FILE diff --git a/test/unit/AccountInfoMocking.js b/test/unit/AccountInfoMocking.js index 6366938f3..eca2b8587 100644 --- a/test/unit/AccountInfoMocking.js +++ b/test/unit/AccountInfoMocking.js @@ -49,8 +49,13 @@ describe("AccountInfoMocking", function () { let servers; afterEach(function () { - client.close(); - servers.close(); + if (client != null) { + client.close(); + } + + if (servers != null) { + servers.close(); + } }); it("payment transaction is correctly constructed", async function () { @@ -137,6 +142,8 @@ describe("AccountInfoMocking", function () { errorName = error.name; } + console.log(errorName); + expect(errorName).to.be.eql("MaxQueryPaymentExceededError"); }); diff --git a/test/unit/ContractCreateFlowMocking.js b/test/unit/ContractCreateFlowMocking.js index 77ecec5f3..4bf9ebebe 100644 --- a/test/unit/ContractCreateFlowMocking.js +++ b/test/unit/ContractCreateFlowMocking.js @@ -14,8 +14,13 @@ describe("ContractCreateFlowMocking", function () { let wallet; afterEach(function () { - client.close(); - servers.close(); + if (client != null) { + client.close(); + } + + if (servers != null) { + servers.close(); + } }); it("signs all transactions", async function () { diff --git a/test/unit/EthereumFlowMocking.js b/test/unit/EthereumFlowMocking.js index 04591319d..44badc66a 100644 --- a/test/unit/EthereumFlowMocking.js +++ b/test/unit/EthereumFlowMocking.js @@ -32,8 +32,13 @@ describe("EthereumFlowMocking", function () { let servers; afterEach(function () { - client.close(); - servers.close(); + if (client != null) { + client.close(); + } + + if (servers != null) { + servers.close(); + } }); it("doesn't truncate ethereum data if it's not long enough", async function () { diff --git a/test/unit/MirrorNodeService.js b/test/unit/MirrorNodeService.js new file mode 100644 index 000000000..4e10066c4 --- /dev/null +++ b/test/unit/MirrorNodeService.js @@ -0,0 +1,43 @@ +import MirrorNodeService, { + TokenKeyStatusEnum, + TokenFreezeStatusEnum, +} from "../../src/network/MirrorNodeService.js"; +import * as HashgraphProto from "@hashgraph/proto"; +import { expect } from "chai"; + +describe("MirrorNodeService", function () { + let mirrorNodeService; + + before(function () { + mirrorNodeService = new MirrorNodeService(); + }); + + it("should return the set timeout value", async function () { + mirrorNodeService.setTimeout(1000); + expect(mirrorNodeService._timeout).to.be.eql(1000); + }); + + it("getTokenFreezeStatusFrom helper function", async function () { + const statuses = Object.values(TokenFreezeStatusEnum); + + for (let i; i < statuses.length; i++) { + const freezeStatus = mirrorNodeService.getTokenFreezeStatusFrom( + statuses[i], + ); + expect(freezeStatus).to.be.eql( + HashgraphProto.proto.TokenFreezeStatus[i], + ); + } + }); + + it("getTokenKycStatusFrom helper function", async function () { + const statuses = Object.values(TokenKeyStatusEnum); + + for (let i; i < statuses.length; i++) { + const kycStatus = mirrorNodeService.getTokenKycStatusFrom( + statuses[i], + ); + expect(kycStatus).to.be.eql(HashgraphProto.proto.TokenKycStatus[i]); + } + }); +}); diff --git a/test/unit/Mocker.js b/test/unit/Mocker.js index 1b97d504f..0d20c183f 100644 --- a/test/unit/Mocker.js +++ b/test/unit/Mocker.js @@ -5,6 +5,7 @@ import { Client, Wallet, LocalProvider, + LedgerId, } from "../../src/index.js"; import * as grpc from "@grpc/grpc-js"; import * as loader from "@grpc/proto-loader"; @@ -424,7 +425,7 @@ class GrpcServers { * @returns {this} */ addServer(responses) { - const address = `0.0.0.0:${50213 + this._index}`; + const address = `127.0.0.1:${1111 + this._index}`; const nodeAccountId = `0.0.${3 + this._index}`; const server = new GrpcServer(PROTOS).addResponses(responses); @@ -453,6 +454,7 @@ class GrpcServers { return new Client({ network, scheduleNetworkUpdate: false }) .setMirrorNetwork(Object.keys(network)) + .setLedgerId(LedgerId.LOCAL_NODE) .setNodeMinBackoff(0) .setNodeMaxBackoff(0) .setNodeMinReadmitPeriod(0) diff --git a/test/unit/TopicMessageMocking.js b/test/unit/TopicMessageMocking.js index 4bf6b101f..8da95bef9 100644 --- a/test/unit/TopicMessageMocking.js +++ b/test/unit/TopicMessageMocking.js @@ -28,8 +28,13 @@ describe("TopicMessageMocking", function () { let handle; afterEach(function () { - client.close(); - servers.close(); + if (client != null) { + client.close(); + } + + if (servers != null) { + servers.close(); + } if (handle != null) { handle.unsubscribe(); diff --git a/test/unit/TransactionReceipt.js b/test/unit/TransactionReceipt.js index 35507c1bc..733f50a88 100644 --- a/test/unit/TransactionReceipt.js +++ b/test/unit/TransactionReceipt.js @@ -152,7 +152,6 @@ describe("TransactionReceipt", function () { const receipt = new TransactionReceipt({ status, }); - console.log(JSON.stringify(receipt)); const expectedJSON = `{"status":"OK","accountId":null,"filedId":null,"contractId":null,"topicId":null,"tokenId":null,"scheduleId":null,"exchangeRate":null,"topicSequenceNumber":null,"topicRunningHash":null,"totalSupply":null,"scheduledTransactionId":null,"serials":[],"duplicates":[],"children":[]}`; const expectedJSONParsed = JSON.parse(expectedJSON); diff --git a/test/unit/TransactionReceiptMocking.js b/test/unit/TransactionReceiptMocking.js index 26c9cfd95..fc79bb760 100644 --- a/test/unit/TransactionReceiptMocking.js +++ b/test/unit/TransactionReceiptMocking.js @@ -39,8 +39,13 @@ describe("TransactionReceiptMocking", function () { let servers; afterEach(function () { - client.close(); - servers.close(); + if (client != null) { + client.close(); + } + + if (servers != null) { + servers.close(); + } }); it("should error with max attempts", async function () { diff --git a/test/unit/TransactionRecord.js b/test/unit/TransactionRecord.js index 8db5cf2ca..f448a3404 100644 --- a/test/unit/TransactionRecord.js +++ b/test/unit/TransactionRecord.js @@ -77,8 +77,6 @@ describe("TransactionRecord", function () { tokenTransfersList: [tokenTransfer], }); - console.log(JSON.stringify(newRecord)); - const expectedJSON = JSON.parse( `{"receipt":{"status":"SUCCESS","accountId":"0.0.1246","filedId":null,"contractId":null,"topicId":null,"tokenId":null,"scheduleId":null,"exchangeRate":{"hbars":1,"cents":12,"expirationTime":"1963-11-25T17:31:44.000Z","exchangeRateInCents":12},"topicSequenceNumber":"0","topicRunningHash":"","totalSupply":"0","scheduledTransactionId":null,"serials":[],"duplicates":[],"children":[]},"transactionHash":"cac44f2db045ba441f3fbc295217f2eb0f956293d28b3401578f6160e66f4e47ea87952d91c4b1cb5bda6447823b979a","consensusTimestamp":"2022-06-18T02:54:43.839Z","transactionId":"0.0.1157@1655520872.507983896","transactionMemo":"test","transactionFee":"41694270","transfers":[{"accountId":"0.0.5","amount":"1071080","isApproved":false},{"accountId":"0.0.98","amount":"32498552","isApproved":false},{"accountId":"0.0.800","amount":"4062319","isApproved":false},{"accountId":"0.0.801","amount":"4062319","isApproved":false},{"accountId":"0.0.1157","amount":"-1041694270","isApproved":false},{"accountId":"0.0.1246","amount":"1000000000","isApproved":false}],"tokenTransfers":{"0.0.123":{"0.0.1246":"789"}},"tokenTransfersList":[{"tokenId":"0.0.123","accountId":"0.0.1246","amount":"789"}],"scheduleRef":"0.0.123","assessedCustomFees":[{"feeCollectorAccountId":"0.0.1246","tokenId":"0.0.123","amount":"789","payerAccountIds":["0.0.1246"]}],"nftTransfers":{"0.0.123":[{"sender":"0.0.1246","recipient":"0.0.1246","serial":123,"isApproved":true}]},"automaticTokenAssociations":[{"accountId":"0.0.1246","tokenId":"0.0.123"}],"parentConsensusTimestamp":"2022-06-18T02:54:43.839Z","aliasKey":"302a300506032b6570032100d7366c45e4d2f1a6c1d9af054f5ef8edc0b8d3875ba5d08a7f2e81ee8876e9e8","duplicates":[],"children":[],"ethereumHash":"01020304","paidStakingRewards":[{"accountId":"0.0.5","amount":"1071080","isApproved":false},{"accountId":"0.0.98","amount":"32498552","isApproved":false},{"accountId":"0.0.800","amount":"4062319","isApproved":false},{"accountId":"0.0.801","amount":"4062319","isApproved":false},{"accountId":"0.0.1157","amount":"-1041694270","isApproved":false},{"accountId":"0.0.1246","amount":"1000000000","isApproved":false}],"prngBytes":"01020304","prngNumber":123,"evmAddress":"deadbeef"}`, ); diff --git a/test/unit/TransactionResponse.js b/test/unit/TransactionResponse.js index 3f4b2cb05..9ea90c1b3 100644 --- a/test/unit/TransactionResponse.js +++ b/test/unit/TransactionResponse.js @@ -14,8 +14,6 @@ describe("TransactionResponse", function () { transactionId: TransactionId.fromString("0.0.12@13.000000014"), }); - console.log(JSON.stringify(response)); - const expectedJSON = `{"nodeId":"0.0.3","transactionHash":"010203","transactionId":"0.0.12@13.000000014"}`; const expectedJSONParsed = JSON.parse(expectedJSON);