diff --git a/src/sdk/main/include/CustomFractionalFee.h b/src/sdk/main/include/CustomFractionalFee.h index 4b14a5f9..aaf9db46 100644 --- a/src/sdk/main/include/CustomFractionalFee.h +++ b/src/sdk/main/include/CustomFractionalFee.h @@ -87,7 +87,6 @@ class CustomFractionalFee : public CustomFeeBase * @param denominator The desired denominator of the fractional amount of the transferred units to assess as a part of * this CustomFractionalFee. * @return A reference to this CustomFractionalFee object, with the newly-set denominator. - * @throws std::invalid_argument If the input denominator is 0. */ CustomFractionalFee& setDenominator(const int64_t& denominator); diff --git a/src/sdk/main/include/CustomRoyaltyFee.h b/src/sdk/main/include/CustomRoyaltyFee.h index 2e331f0e..dd8c3d1e 100644 --- a/src/sdk/main/include/CustomRoyaltyFee.h +++ b/src/sdk/main/include/CustomRoyaltyFee.h @@ -87,7 +87,6 @@ class CustomRoyaltyFee : public CustomFeeBase * @param denominator The desired denominator of the fractional amount of the transferred units to assess as a part of * this CustomRoyaltyFee. * @return A reference to this CustomRoyaltyFee object, with the newly-set denominator. - * @throws std::invalid_argument If the input denominator is 0. */ CustomRoyaltyFee& setDenominator(const int64_t& denominator); diff --git a/src/sdk/main/include/FeeAssessmentMethod.h b/src/sdk/main/include/FeeAssessmentMethod.h index 8765ea80..4b47cbe0 100644 --- a/src/sdk/main/include/FeeAssessmentMethod.h +++ b/src/sdk/main/include/FeeAssessmentMethod.h @@ -20,6 +20,7 @@ #ifndef HEDERA_SDK_CPP_FEE_ASSESSMENT_METHOD_H_ #define HEDERA_SDK_CPP_FEE_ASSESSMENT_METHOD_H_ +#include #include namespace Hedera @@ -46,11 +47,19 @@ enum class FeeAssessmentMethod /** * Map of FeeAssessmentMethod to its corresponding string. */ -const std::unordered_map gFeeAssessmentMethodToString = { +const std::unordered_map gFeeAssessmentMethodToString = { {FeeAssessmentMethod::INCLUSIVE, "INCLUSIVE"}, { FeeAssessmentMethod::EXCLUSIVE, "EXCLUSIVE"} }; +/** + * Map of FeeAssessmentMethod string representation to its corresponding enum value. + */ +[[maybe_unused]] const std::unordered_map gStringToFeeAssessmentMethod = { + {"INCLUSIVE", FeeAssessmentMethod::INCLUSIVE}, + { "EXCLUSIVE", FeeAssessmentMethod::EXCLUSIVE} +}; + } // namespace Hedera #endif // HEDERA_SDK_CPP_FEE_ASSESSMENT_METHOD_H_ diff --git a/src/sdk/main/src/CustomFractionalFee.cc b/src/sdk/main/src/CustomFractionalFee.cc index 78fc90a2..a6bf631d 100644 --- a/src/sdk/main/src/CustomFractionalFee.cc +++ b/src/sdk/main/src/CustomFractionalFee.cc @@ -87,11 +87,6 @@ CustomFractionalFee& CustomFractionalFee::setNumerator(const int64_t& numerator) //----- CustomFractionalFee& CustomFractionalFee::setDenominator(const int64_t& denominator) { - if (denominator == 0LL) - { - throw std::invalid_argument("Denominator cannot be 0"); - } - mDenominator = denominator; return *this; } diff --git a/src/sdk/main/src/CustomRoyaltyFee.cc b/src/sdk/main/src/CustomRoyaltyFee.cc index 437ad57c..7f730fc9 100644 --- a/src/sdk/main/src/CustomRoyaltyFee.cc +++ b/src/sdk/main/src/CustomRoyaltyFee.cc @@ -91,11 +91,6 @@ CustomRoyaltyFee& CustomRoyaltyFee::setNumerator(const int64_t& numerator) //----- CustomRoyaltyFee& CustomRoyaltyFee::setDenominator(const int64_t& denominator) { - if (denominator == 0LL) - { - throw std::invalid_argument("Denominator cannot be 0"); - } - mDenominator = denominator; return *this; } diff --git a/src/sdk/tests/unit/CustomFractionalFeeUnitTests.cc b/src/sdk/tests/unit/CustomFractionalFeeUnitTests.cc index f0029c3b..b1da7eb8 100644 --- a/src/sdk/tests/unit/CustomFractionalFeeUnitTests.cc +++ b/src/sdk/tests/unit/CustomFractionalFeeUnitTests.cc @@ -175,16 +175,6 @@ TEST_F(CustomFractionalFeeUnitTests, GetSetDenominator) EXPECT_EQ(customFractionalFee.getDenominator(), getTestDenominator()); } -//----- -TEST_F(CustomFractionalFeeUnitTests, CannotSetDenominatorToZero) -{ - // Given - CustomFractionalFee customFractionalFee; - - // When / Then - EXPECT_THROW(customFractionalFee.setDenominator(0LL), std::invalid_argument); -} - //----- TEST_F(CustomFractionalFeeUnitTests, GetSetMinimumAmount) { diff --git a/src/sdk/tests/unit/CustomRoyaltyFeeUnitTests.cc b/src/sdk/tests/unit/CustomRoyaltyFeeUnitTests.cc index b0198da9..1381aeff 100644 --- a/src/sdk/tests/unit/CustomRoyaltyFeeUnitTests.cc +++ b/src/sdk/tests/unit/CustomRoyaltyFeeUnitTests.cc @@ -157,16 +157,6 @@ TEST_F(CustomRoyaltyFeeUnitTests, GetSetDenominator) EXPECT_EQ(customRoyaltyFee.getDenominator(), getTestDenominator()); } -//----- -TEST_F(CustomRoyaltyFeeUnitTests, CannotSetDenominatorToZero) -{ - // Given - CustomRoyaltyFee customRoyaltyFee; - - // When / Then - EXPECT_THROW(customRoyaltyFee.setDenominator(0LL), std::invalid_argument); -} - //----- TEST_F(CustomRoyaltyFeeUnitTests, GetSetFallbackFee) { diff --git a/src/sdk/tests/unit/FeeAssessmentMethodUnitTests.cc b/src/sdk/tests/unit/FeeAssessmentMethodUnitTests.cc index 6acddedb..cc8bad63 100644 --- a/src/sdk/tests/unit/FeeAssessmentMethodUnitTests.cc +++ b/src/sdk/tests/unit/FeeAssessmentMethodUnitTests.cc @@ -33,6 +33,6 @@ TEST_F(FeeAssessmentMethodUnitTests, FeeAssessmentMethodToString) // Given / When / Then ASSERT_TRUE(gFeeAssessmentMethodToString.find(FeeAssessmentMethod::INCLUSIVE) != gFeeAssessmentMethodToString.end()); ASSERT_TRUE(gFeeAssessmentMethodToString.find(FeeAssessmentMethod::EXCLUSIVE) != gFeeAssessmentMethodToString.end()); - EXPECT_STRCASEEQ(gFeeAssessmentMethodToString.at(FeeAssessmentMethod::INCLUSIVE), "INCLUSIVE"); - EXPECT_STRCASEEQ(gFeeAssessmentMethodToString.at(FeeAssessmentMethod::EXCLUSIVE), "EXCLUSIVE"); + EXPECT_EQ(gFeeAssessmentMethodToString.at(FeeAssessmentMethod::INCLUSIVE), "INCLUSIVE"); + EXPECT_EQ(gFeeAssessmentMethodToString.at(FeeAssessmentMethod::EXCLUSIVE), "EXCLUSIVE"); } \ No newline at end of file diff --git a/src/tck/include/CommonTransactionParams.h b/src/tck/include/CommonTransactionParams.h index 56ddd1d3..f8e0613c 100644 --- a/src/tck/include/CommonTransactionParams.h +++ b/src/tck/include/CommonTransactionParams.h @@ -37,7 +37,7 @@ namespace Hedera::TCK { /** - * Struct the contains the common parameters of a Transaction. + * Struct that contains the common parameters of a Transaction. */ struct CommonTransactionParams { diff --git a/src/tck/include/CustomFeeSerializer.h b/src/tck/include/CustomFeeSerializer.h new file mode 100644 index 00000000..559848a5 --- /dev/null +++ b/src/tck/include/CustomFeeSerializer.h @@ -0,0 +1,346 @@ +/*- + * + * Hedera C++ SDK + * + * Copyright (C) 2020 - 2024 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. + * + */ +#ifndef HEDERA_TCK_CPP_CUSTOM_FEE_SERIALIZER_H_ +#define HEDERA_TCK_CPP_CUSTOM_FEE_SERIALIZER_H_ + +#include "AccountId.h" +#include "CustomFee.h" +#include "CustomFeeBase.h" +#include "CustomFixedFee.h" +#include "CustomFractionalFee.h" +#include "CustomRoyaltyFee.h" +#include "JsonRpcException.h" + +#include + +namespace nlohmann +{ +/** + * JSON serializer template specialization required to convert CustomFee arguments properly. + */ +template<> +struct [[maybe_unused]] adl_serializer> +{ + /** + * Convert a CustomFee to a JSON object. + * + * @param jsonTo The JSON object to fill with the CustomFee. + * @param fee The CustomFee with which to fill the JSON object. + */ + static void to_json(json& jsonTo, const std::shared_ptr& fee) + { + jsonTo["feeCollectorAccountId"] = fee->getFeeCollectorAccountId().toString(); + jsonTo["feeCollectorsExempt"] = fee->getAllCollectorsAreExempt(); + + if (const std::shared_ptr fixedFee = std::dynamic_pointer_cast(fee); + fixedFee) + { + jsonTo["fixedFee"] = { + {"amount", fixedFee->getAmount()} + }; + if (fixedFee->getDenominatingTokenId().has_value()) + { + jsonTo["fixedFee"]["denominatingTokenId"] = fixedFee->getDenominatingTokenId()->toString(); + } + } + + else if (const std::shared_ptr fractionalFee = + std::dynamic_pointer_cast(fee); + fractionalFee) + { + std::string assessmentMethod = Hedera::gFeeAssessmentMethodToString.at(fractionalFee->getAssessmentMethod()); + std::transform(assessmentMethod.begin(), + assessmentMethod.end(), + assessmentMethod.begin(), + [](unsigned char c) { return std::tolower(c); }); + jsonTo["fractionalFee"] = { + {"numerator", fractionalFee->getNumerator() }, + { "denominator", fractionalFee->getDenominator() }, + { "minimumAmount", fractionalFee->getMinimumAmount()}, + { "maximumAmount", fractionalFee->getMaximumAmount()}, + { "assessmentMethod", assessmentMethod } + }; + } + + else + { + const std::shared_ptr royaltyFee = + std::dynamic_pointer_cast(fee); + + jsonTo["royaltyFee"] = { + {"numerator", royaltyFee->getNumerator() }, + { "denominator", royaltyFee->getDenominator()} + }; + + if (royaltyFee->getFallbackFee().has_value()) + { + jsonTo["royaltyFee"]["fallbackFee"] = { + {"amount", royaltyFee->getFallbackFee()->getAmount()} + }; + if (royaltyFee->getFallbackFee()->getDenominatingTokenId().has_value()) + { + jsonTo["royaltyFee"]["fallbackFee"]["denominatingTokenId"] = + royaltyFee->getFallbackFee()->getDenominatingTokenId()->toString(); + } + } + } + } + + /** + * Convert a JSON object to a CustomFee. + * + * @param jsonFrom The JSON object with which to fill the CustomFee. + * @param fee The CustomFee to fill with the JSON object. + */ + static void from_json(const json& jsonFrom, std::shared_ptr& fee) + { + if (!jsonFrom.contains("feeCollectorAccountId")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: feeCollectorAccountId is REQUIRED."); + } + + if (!jsonFrom["feeCollectorAccountId"].is_string()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: feeCollectorAccountId MUST be a string."); + } + + const Hedera::AccountId feeCollectorAccountId = + Hedera::AccountId::fromString(jsonFrom["feeCollectorAccountId"].get()); + + if (!jsonFrom.contains("feeCollectorsExempt")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: feeCollectorsExempt is REQUIRED."); + } + + if (!jsonFrom["feeCollectorsExempt"].is_boolean()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: feeCollectorsExempt MUST be a boolean."); + } + + const bool feeCollectorsExempt = jsonFrom["feeCollectorsExempt"].get(); + + if (jsonFrom.contains("fixedFee")) + { + auto fixedFee = std::make_shared(); + fixedFee->setFeeCollectorAccountId(feeCollectorAccountId); + fixedFee->setAllCollectorsAreExempt(feeCollectorsExempt); + + if (!jsonFrom["fixedFee"].contains("amount")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: amount is REQUIRED for fixedFee fee types."); + } + + if (!jsonFrom["fixedFee"]["amount"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: amount MUST be an int64."); + } + + fixedFee->setAmount(jsonFrom["fixedFee"]["amount"].get()); + + if (jsonFrom["fixedFee"].contains("denominatingTokenId")) + { + if (!jsonFrom["fixedFee"]["denominatingTokenId"].is_string()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominatingTokenId MUST be a string."); + } + + fixedFee->setDenominatingTokenId( + Hedera::TokenId::fromString(jsonFrom["fixedFee"]["denominatingTokenId"].get())); + } + + fee = fixedFee; + } + + else if (jsonFrom.contains("fractionalFee")) + { + auto fractionalFee = std::make_shared(); + fractionalFee->setFeeCollectorAccountId(feeCollectorAccountId); + fractionalFee->setAllCollectorsAreExempt(feeCollectorsExempt); + + if (!jsonFrom["fractionalFee"].contains("numerator")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: numerator is REQUIRED for fractionalFee fee types."); + } + + if (!jsonFrom["fractionalFee"]["numerator"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: numerator MUST be an int64."); + } + + fractionalFee->setNumerator(jsonFrom["fractionalFee"]["numerator"].get()); + + if (!jsonFrom["fractionalFee"].contains("denominator")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominator is REQUIRED for fractionalFee fee types."); + } + + if (!jsonFrom["fractionalFee"]["denominator"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominator MUST be an int64."); + } + + fractionalFee->setDenominator(jsonFrom["fractionalFee"]["denominator"].get()); + + if (!jsonFrom["fractionalFee"].contains("minimumAmount")) + { + throw Hedera::TCK::JsonRpcException( + Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: minimumAmount is REQUIRED for fractionalFee fee types."); + } + + if (!jsonFrom["fractionalFee"]["minimumAmount"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: minimumAmount MUST be an int64."); + } + + fractionalFee->setMinimumAmount(jsonFrom["fractionalFee"]["minimumAmount"].get()); + + if (!jsonFrom["fractionalFee"].contains("maximumAmount")) + { + throw Hedera::TCK::JsonRpcException( + Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: maximumAmount is REQUIRED for fractionalFee fee types."); + } + + if (!jsonFrom["fractionalFee"]["maximumAmount"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: maximumAmount MUST be an int64."); + } + + fractionalFee->setMaximumAmount(jsonFrom["fractionalFee"]["maximumAmount"].get()); + + if (!jsonFrom["fractionalFee"].contains("assessmentMethod")) + { + throw Hedera::TCK::JsonRpcException( + Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: assessmentMethod is REQUIRED for fractionalFee fee types."); + } + + if (!jsonFrom["fractionalFee"]["assessmentMethod"].is_string()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: assessmentMethod MUST be a string."); + } + + std::string assessmentMethod = jsonFrom["fractionalFee"]["assessmentMethod"].get(); + std::transform(assessmentMethod.begin(), + assessmentMethod.end(), + assessmentMethod.begin(), + [](unsigned char c) { return std::toupper(c); }); + fractionalFee->setAssessmentMethod(Hedera::gStringToFeeAssessmentMethod.at(assessmentMethod)); + + fee = fractionalFee; + } + + else if (jsonFrom.contains("royaltyFee")) + { + auto royaltyFee = std::make_shared(); + royaltyFee->setFeeCollectorAccountId(feeCollectorAccountId); + royaltyFee->setAllCollectorsAreExempt(feeCollectorsExempt); + + if (!jsonFrom["royaltyFee"].contains("numerator")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: numerator is REQUIRED for royaltyFee fee types."); + } + + if (!jsonFrom["royaltyFee"]["numerator"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: numerator MUST be an int64."); + } + + royaltyFee->setNumerator(jsonFrom["royaltyFee"]["numerator"].get()); + + if (!jsonFrom["royaltyFee"].contains("denominator")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominator is REQUIRED for royaltyFee fee types."); + } + + if (!jsonFrom["royaltyFee"]["denominator"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominator MUST be an int64."); + } + + royaltyFee->setDenominator(jsonFrom["royaltyFee"]["denominator"].get()); + + if (jsonFrom["royaltyFee"].contains("fallbackFee")) + { + Hedera::CustomFixedFee fallbackFee; + + if (!jsonFrom["royaltyFee"]["fallbackFee"].contains("amount")) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: amount is REQUIRED for a fallback fee."); + } + + if (!jsonFrom["royaltyFee"]["fallbackFee"]["amount"].is_number_integer()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: amount MUST be an int64."); + } + + fallbackFee.setAmount(jsonFrom["royaltyFee"]["fallbackFee"]["amount"].get()); + + if (jsonFrom["royaltyFee"]["fallbackFee"].contains("denominatingTokenId")) + { + if (!jsonFrom["royaltyFee"]["fallbackFee"]["denominatingTokenId"].is_string()) + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: denominatingTokenId MUST be a string."); + } + + fallbackFee.setDenominatingTokenId(Hedera::TokenId::fromString( + jsonFrom["royaltyFee"]["fallbackFee"]["denominatingTokenId"].get())); + } + + royaltyFee->setFallbackFee(fallbackFee); + } + + fee = royaltyFee; + } + + else + { + throw Hedera::TCK::JsonRpcException(Hedera::TCK::JsonErrorType::INVALID_PARAMS, + "invalid parameters: fee MUST contain one of fixedFee, fractionalFee, or " + "royaltyFee."); + } + } +}; + +} // namespace nlohmann + +#endif // HEDERA_TCK_CPP_CUSTOM_FEE_PARAMS_H_ diff --git a/src/tck/include/JsonTypeMapper.h b/src/tck/include/JsonTypeMapper.h index 241c4cdb..52b675d9 100644 --- a/src/tck/include/JsonTypeMapper.h +++ b/src/tck/include/JsonTypeMapper.h @@ -20,6 +20,7 @@ #ifndef HEDERA_TCK_CPP_JSON_TYPE_MAPPER_H_ #define HEDERA_TCK_CPP_JSON_TYPE_MAPPER_H_ +#include "CustomFeeSerializer.h" #include "JsonErrorType.h" #include "JsonRpcException.h" diff --git a/src/tck/include/SdkClient.h b/src/tck/include/SdkClient.h index f8ae9ef2..1cb23289 100644 --- a/src/tck/include/SdkClient.h +++ b/src/tck/include/SdkClient.h @@ -21,6 +21,7 @@ #define HEDERA_TCK_CPP_SDK_CLIENT_H_ #include "CommonTransactionParams.h" +#include "CustomFee.h" #include "KeyHelper.h" #include @@ -58,6 +59,64 @@ nlohmann::json createAccount(const std::optional& key, const std::optional& alias, const std::optional& commonTxParams); +/** + * Create a token. + * + * @param name The name of the new token. + * @param symbol The symbol of the new token. + * @param decimals The number of decimal places by which the new token will be divisible. + * @param initialSupply The number of tokens to put into circulation upon creation. + * @param treasureAccountId The ID of the account which will act as the new token's treasury and will receive the + * specified initial supply of the new token. + * @param adminKey The key which can perform update/delete operations on the new token. + * @param kycKey The key which can grant/revoke KYC on an account for transactions of the new token. + * @param freezeKey The key which can freeze/unfreeze an account for transactions of the new token. + * @param wipeKey The key which can wipe the balance of the new token from an account. + * @param supplyKey The key which can change the supply of the new token. + * @param freezeDefault Should accounts initially be frozen with respect to the new token? + * @param expirationTime The time at which the new token should expire. + * @param autoRenewAccountId The ID of the account that should be charged to renew the new token's expiration. + * @param autoRenewPeriod The interval at which the auto renew account will be charged to extend the new token's + * expiration. + * @param memo The memo associated with the token. + * @param tokenType The type of the new token. + * @param supplyType The supply type of the new token. + * @param maxSupply The maximum amount of the new token that can be in circulation (for fungible types) or + * minted (for NFTs). + * @param feeScheduleKey The key which can change the new token's fee schedule. + * @param customFees The fees to be assessed during a transfer of the new token. + * @param pauseKey The key which can pause/unpause the new token. + * @param metadata The metadata of the new token. + * @param metadataKey The key which can change the metadata of the new token and/or individual NFTs of the new + * token class. + * @param commonTxParams Any parameters common to all transaction types. + * @return A JSON response containing the created token ID and the status of the token creation. + */ +nlohmann::json createToken(const std::optional& name, + const std::optional& symbol, + const std::optional& decimals, + const std::optional& initialSupply, + const std::optional& treasuryAccountId, + const std::optional& adminKey, + const std::optional& kycKey, + const std::optional& freezeKey, + const std::optional& wipeKey, + const std::optional& supplyKey, + const std::optional& freezeDefault, + const std::optional& expirationTime, + const std::optional& autoRenewAccountId, + const std::optional& autoRenewPeriod, + const std::optional& memo, + const std::optional& tokenType, + const std::optional& supplyType, + const std::optional& maxSupply, + const std::optional& feeScheduleKey, + const std::optional>>& customFees, + const std::optional& pauseKey, + const std::optional& metadata, + const std::optional& metadataKey, + const std::optional& commonTxParams); + /** * Delete an account. * diff --git a/src/tck/src/SdkClient.cc b/src/tck/src/SdkClient.cc index 9b5a9eb7..177374df 100644 --- a/src/tck/src/SdkClient.cc +++ b/src/tck/src/SdkClient.cc @@ -25,9 +25,14 @@ #include "Client.h" #include "EvmAddress.h" #include "HbarUnit.h" +#include "JsonErrorType.h" +#include "JsonRpcException.h" #include "KeyHelper.h" #include "PrivateKey.h" #include "Status.h" +#include "TokenCreateTransaction.h" +#include "TokenSupplyType.h" +#include "TokenType.h" #include "TransactionReceipt.h" #include "TransactionResponse.h" #include "impl/HexConverter.h" @@ -65,7 +70,7 @@ nlohmann::json SdkClient::createAccount(const std::optional& key, const std::optional& commonTxParams) { AccountCreateTransaction accountCreateTransaction; - accountCreateTransaction.setGrpcDeadline(std::chrono::seconds(DEFAULT_TCK_REQUEST_TIMEOUT)); + accountCreateTransaction.setGrpcDeadline(DEFAULT_TCK_REQUEST_TIMEOUT); if (key.has_value()) { @@ -129,6 +134,176 @@ nlohmann::json SdkClient::createAccount(const std::optional& key, }; } +//----- +nlohmann::json SdkClient::createToken(const std::optional& name, + const std::optional& symbol, + const std::optional& decimals, + const std::optional& initialSupply, + const std::optional& treasuryAccountId, + const std::optional& adminKey, + const std::optional& kycKey, + const std::optional& freezeKey, + const std::optional& wipeKey, + const std::optional& supplyKey, + const std::optional& freezeDefault, + const std::optional& expirationTime, + const std::optional& autoRenewAccountId, + const std::optional& autoRenewPeriod, + const std::optional& memo, + const std::optional& tokenType, + const std::optional& supplyType, + const std::optional& maxSupply, + const std::optional& feeScheduleKey, + const std::optional>>& customFees, + const std::optional& pauseKey, + const std::optional& metadata, + const std::optional& metadataKey, + const std::optional& commonTxParams) +{ + TokenCreateTransaction tokenCreateTransaction; + tokenCreateTransaction.setGrpcDeadline(DEFAULT_TCK_REQUEST_TIMEOUT); + + if (name.has_value()) + { + tokenCreateTransaction.setTokenName(name.value()); + } + + if (symbol.has_value()) + { + tokenCreateTransaction.setTokenSymbol(symbol.value()); + } + + if (decimals.has_value()) + { + tokenCreateTransaction.setDecimals(decimals.value()); + } + + if (initialSupply.has_value()) + { + tokenCreateTransaction.setInitialSupply(initialSupply.value()); + } + + if (treasuryAccountId.has_value()) + { + tokenCreateTransaction.setTreasuryAccountId(AccountId::fromString(treasuryAccountId.value())); + } + + if (adminKey.has_value()) + { + tokenCreateTransaction.setAdminKey(getHederaKey(adminKey.value())); + } + + if (kycKey.has_value()) + { + tokenCreateTransaction.setKycKey(getHederaKey(kycKey.value())); + } + + if (freezeKey.has_value()) + { + tokenCreateTransaction.setFreezeKey(getHederaKey(freezeKey.value())); + } + + if (wipeKey.has_value()) + { + tokenCreateTransaction.setWipeKey(getHederaKey(wipeKey.value())); + } + + if (supplyKey.has_value()) + { + tokenCreateTransaction.setSupplyKey(getHederaKey(supplyKey.value())); + } + + if (freezeDefault.has_value()) + { + tokenCreateTransaction.setFreezeDefault(freezeDefault.value()); + } + + if (expirationTime.has_value()) + { + tokenCreateTransaction.setExpirationTime(std::chrono::system_clock::from_time_t(0) + + std::chrono::seconds(expirationTime.value())); + } + + if (autoRenewAccountId.has_value()) + { + tokenCreateTransaction.setAutoRenewAccountId(AccountId::fromString(autoRenewAccountId.value())); + } + + if (autoRenewPeriod.has_value()) + { + tokenCreateTransaction.setAutoRenewPeriod(std::chrono::seconds(autoRenewPeriod.value())); + } + + if (memo.has_value()) + { + tokenCreateTransaction.setTokenMemo(memo.value()); + } + + if (tokenType.has_value()) + { + if (tokenType.value() != "ft" && tokenType.value() != "nft") + { + throw JsonRpcException(JsonErrorType::INVALID_PARAMS, "invalid params: tokenType MUST be one of ft or nft."); + } + + tokenCreateTransaction.setTokenType(tokenType.value() == "ft" ? TokenType::FUNGIBLE_COMMON + : TokenType::NON_FUNGIBLE_UNIQUE); + } + + if (supplyType.has_value()) + { + if (supplyType.value() != "infinite" && supplyType.value() != "finite") + { + throw JsonRpcException(JsonErrorType::INVALID_PARAMS, + "invalid params: supplyType MUST be one of infinite or finite."); + } + + tokenCreateTransaction.setSupplyType(supplyType.value() == "finite" ? TokenSupplyType::FINITE + : TokenSupplyType::INFINITE); + } + + if (maxSupply.has_value()) + { + tokenCreateTransaction.setMaxSupply(maxSupply.value()); + } + + if (feeScheduleKey.has_value()) + { + tokenCreateTransaction.setFeeScheduleKey(getHederaKey(feeScheduleKey.value())); + } + + if (customFees.has_value()) + { + tokenCreateTransaction.setCustomFees(customFees.value()); + } + + if (pauseKey.has_value()) + { + tokenCreateTransaction.setPauseKey(getHederaKey(pauseKey.value())); + } + + if (metadata.has_value()) + { + tokenCreateTransaction.setMetadata(internal::HexConverter::hexToBytes(metadata.value())); + } + + if (metadataKey.has_value()) + { + tokenCreateTransaction.setMetadataKey(getHederaKey(metadataKey.value())); + } + + if (commonTxParams.has_value()) + { + commonTxParams->fillOutTransaction(tokenCreateTransaction, mClient); + } + + const TransactionReceipt txReceipt = tokenCreateTransaction.execute(mClient).getReceipt(mClient); + return { + {"tokenId", txReceipt.mTokenId->toString() }, + { "status", gStatusToString.at(txReceipt.mStatus)} + }; +} + //----- nlohmann::json SdkClient::deleteAccount(const std::optional& deleteAccountId, const std::optional& transferAccountId, diff --git a/src/tck/src/main.cc b/src/tck/src/main.cc index 7b21aacf..0cac00db 100644 --- a/src/tck/src/main.cc +++ b/src/tck/src/main.cc @@ -44,6 +44,32 @@ int main(int argc, char** argv) "declineStakingReward", "alias", "commonTransactionParams" }); + tckServer.add("createToken", + getHandle(&SdkClient::createToken), + { "name", + "symbol", + "decimals", + "initialSupply", + "treasuryAccountId", + "adminKey", + "kycKey", + "freezeKey", + "wipeKey", + "supplyKey", + "freezeDefault", + "expirationTime", + "autoRenewAccountId", + "autoRenewPeriod", + "memo", + "tokenType", + "supplyType", + "maxSupply", + "feeScheduleKey", + "customFees", + "pauseKey", + "metadata", + "metadataKey", + "commonTransactionParams" }); tckServer.add("deleteAccount", getHandle(&SdkClient::deleteAccount), { "deleteAccountId", "transferAccountId", "commonTransactionParams" });