diff --git a/examples/build.gradle.kts b/examples/build.gradle.kts index e8a43b94e..53b542199 100644 --- a/examples/build.gradle.kts +++ b/examples/build.gradle.kts @@ -27,6 +27,11 @@ mainModuleInfo { runtimeOnly("org.slf4j.simple") } +dependencies { + implementation("org.bouncycastle:bcpkix-jdk18on:1.78.1") + implementation("org.bouncycastle:bcprov-jdk18on:1.78.1") +} + dependencies.constraints { implementation("com.hedera.hashgraph:sdk:2.45.0") implementation("com.hedera.hashgraph:sdk-full:2.45.0") diff --git a/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java b/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java index c601ca056..a27c41d4e 100644 --- a/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java +++ b/examples/src/main/java/com/hedera/hashgraph/sdk/examples/MirrorNodeContractQueriesExample.java @@ -25,21 +25,16 @@ import com.hedera.hashgraph.sdk.ContractCallQuery; import com.hedera.hashgraph.sdk.ContractCreateTransaction; import com.hedera.hashgraph.sdk.ContractFunctionParameters; -import com.hedera.hashgraph.sdk.FileCreateTransaction; -import com.hedera.hashgraph.sdk.FileId; import com.hedera.hashgraph.sdk.Hbar; import com.hedera.hashgraph.sdk.MirrorNodeContractCallQuery; import com.hedera.hashgraph.sdk.MirrorNodeContractEstimateGasQuery; -import com.hedera.hashgraph.sdk.MirrorNodeContractQuery; import com.hedera.hashgraph.sdk.PrivateKey; -import com.hedera.hashgraph.sdk.PublicKey; -import com.hedera.hashgraph.sdk.TransactionReceipt; -import com.hedera.hashgraph.sdk.TransactionResponse; import com.hedera.hashgraph.sdk.logger.LogLevel; import com.hedera.hashgraph.sdk.logger.Logger; import io.github.cdimascio.dotenv.Dotenv; import java.nio.charset.StandardCharsets; import java.util.Objects; +import org.bouncycastle.util.encoders.Hex; public class MirrorNodeContractQueriesExample { /* @@ -48,32 +43,33 @@ public class MirrorNodeContractQueriesExample { */ /** - * Operator's account ID. - * Used to sign and pay for operations on Hedera. + * Operator's account ID. Used to sign and pay for operations on Hedera. */ - private static final AccountId OPERATOR_ID = AccountId.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_ID"))); + private static final AccountId OPERATOR_ID = AccountId.fromString( + Objects.requireNonNull(Dotenv.load().get("OPERATOR_ID"))); /** * Operator's private key. */ - private static final PrivateKey OPERATOR_KEY = PrivateKey.fromString(Objects.requireNonNull(Dotenv.load().get("OPERATOR_KEY"))); + private static final PrivateKey OPERATOR_KEY = PrivateKey.fromString( + Objects.requireNonNull(Dotenv.load().get("OPERATOR_KEY"))); /** - * HEDERA_NETWORK defaults to testnet if not specified in dotenv file. - * Network can be: localhost, testnet, previewnet or mainnet. + * HEDERA_NETWORK defaults to testnet if not specified in dotenv file. Network can be: localhost, testnet, + * previewnet or mainnet. */ private static final String HEDERA_NETWORK = Dotenv.load().get("HEDERA_NETWORK", "testnet"); /** - * SDK_LOG_LEVEL defaults to SILENT if not specified in dotenv file. - * Log levels can be: TRACE, DEBUG, INFO, WARN, ERROR, SILENT. + * SDK_LOG_LEVEL defaults to SILENT if not specified in dotenv file. Log levels can be: TRACE, DEBUG, INFO, WARN, + * ERROR, SILENT. *
- * Important pre-requisite: set simple logger log level to same level as the SDK_LOG_LEVEL, - * for example via VM options: -Dorg.slf4j.simpleLogger.log.com.hedera.hashgraph=trace + * Important pre-requisite: set simple logger log level to same level as the SDK_LOG_LEVEL, for example via VM + * options: -Dorg.slf4j.simpleLogger.log.com.hedera.hashgraph=trace */ private static final String SDK_LOG_LEVEL = Dotenv.load().get("SDK_LOG_LEVEL", "SILENT"); - private static final String SMART_CONTRACT_BYTECODE = "608060405234801561001057600080fd5b506040516104d73803806104d78339818101604052602081101561003357600080fd5b810190808051604051939291908464010000000082111561005357600080fd5b90830190602082018581111561006857600080fd5b825164010000000081118282018810171561008257600080fd5b82525081516020918201929091019080838360005b838110156100af578181015183820152602001610097565b50505050905090810190601f1680156100dc5780820380516001836020036101000a031916815260200191505b506040525050600080546001600160a01b0319163317905550805161010890600190602084019061010f565b50506101aa565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061015057805160ff191683800117855561017d565b8280016001018555821561017d579182015b8281111561017d578251825591602001919060010190610162565b5061018992915061018d565b5090565b6101a791905b808211156101895760008155600101610193565b90565b61031e806101b96000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063368b87721461004657806341c0e1b5146100ee578063ce6d41de146100f6575b600080fd5b6100ec6004803603602081101561005c57600080fd5b81019060208101813564010000000081111561007757600080fd5b82018360208201111561008957600080fd5b803590602001918460018302840111640100000000831117156100ab57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550610173945050505050565b005b6100ec6101a2565b6100fe6101ba565b6040805160208082528351818301528351919283929083019185019080838360005b83811015610138578181015183820152602001610120565b50505050905090810190601f1680156101655780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000546001600160a01b0316331461018a5761019f565b805161019d906001906020840190610250565b505b50565b6000546001600160a01b03163314156101b85733ff5b565b60018054604080516020601f600260001961010087891615020190951694909404938401819004810282018101909252828152606093909290918301828280156102455780601f1061021a57610100808354040283529160200191610245565b820191906000526020600020905b81548152906001019060200180831161022857829003601f168201915b505050505090505b90565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f1061029157805160ff19168380011785556102be565b828001600101855582156102be579182015b828111156102be5782518255916020019190600101906102a3565b506102ca9291506102ce565b5090565b61024d91905b808211156102ca57600081556001016102d456fea264697066735822122084964d4c3f6bc912a9d20e14e449721012d625aa3c8a12de41ae5519752fc89064736f6c63430006000033"; + private static final String SMART_CONTRACT_BYTECODE = "6080604052348015600e575f80fd5b5061014e8061001c5f395ff3fe608060405234801561000f575f80fd5b5060043610610029575f3560e01c8063ce6d41de1461002d575b5f80fd5b61003561004b565b60405161004291906100f8565b60405180910390f35b60606040518060400160405280600581526020017f68656c6c6f000000000000000000000000000000000000000000000000000000815250905090565b5f81519050919050565b5f82825260208201905092915050565b8281835e5f83830152505050565b5f601f19601f8301169050919050565b5f6100ca82610088565b6100d48185610092565b93506100e48185602086016100a2565b6100ed816100b0565b840191505092915050565b5f6020820190508181035f83015261011081846100c0565b90509291505056fea264697066735822122073f43039f9146f50acc1b1f6e211c2588bf825fa9fef2178482dd5c63009edcc64736f6c634300081a0033"; public static void main(String[] args) throws Exception { System.out.println("Mirror Node contract queries Example Start!"); @@ -88,36 +84,18 @@ public static void main(String[] args) throws Exception { // Attach logger to the SDK Client. client.setLogger(new Logger(LogLevel.valueOf(SDK_LOG_LEVEL))); - var operatorPublicKey = OPERATOR_KEY.getPublicKey(); - /* * Step 1: * Create the contract */ - System.out.println("Creating new file..."); - TransactionResponse fileCreateTxResponse = new FileCreateTransaction() - // Use the same key as the operator to "own" this file. - .setKeys(operatorPublicKey) - .setContents(SMART_CONTRACT_BYTECODE) - // The default max fee of 1 Hbar is not enough to create a file (starts around ~1.1 Hbar). - .setMaxTransactionFee(Hbar.from(2)) - .execute(client); - - TransactionReceipt fileCreateTxReceipt = fileCreateTxResponse.getReceipt(client); - FileId newFileId = fileCreateTxReceipt.fileId; - - Objects.requireNonNull(newFileId); - System.out.println("Created new file with ID: " + newFileId); - var response = new ContractCreateTransaction() - .setAdminKey(client.getOperatorPublicKey()) - .setGas(200000) - .setConstructorParameters(new ContractFunctionParameters().addString("Hello from Hedera.")) - .setBytecodeFileId(newFileId) + .setGas(200_000) + .setBytecode(Hex.decode(SMART_CONTRACT_BYTECODE)) .setContractMemo("Simple contract with string field") .execute(client); var contractId = Objects.requireNonNull(response.getReceipt(client).contractId); + System.out.println("Created new contract with ID: " + contractId); /* * Step 3: @@ -165,9 +143,27 @@ public static void main(String[] args) throws Exception { .setFunction("getMessage") .execute(client); - System.out.println("Simulation result: " + decodeABIHexString(simulationResult)); + // Decode the result since it's coming in ABI Hex format from the Mirror Node + var decodedResult = decodeABIHexString(simulationResult); + System.out.println("Simulation result: " + decodedResult); System.out.println("Contract call result: " + result.getString(0)); } + + /** + * Decodes a hex-encoded ABI (Application Binary Interface) string into a UTF-8 string. + *
+ * The function assumes the input follows the ABI encoding standard for dynamic data. Specifically, it parses the + * length of the dynamic data and extracts the corresponding substring. + *
+ * The structure of the input hex string is as follows: - The first 64 characters represent metadata, such as + * offsets and other header information. - Characters from index 64 to 128 encode the length of the dynamic data in + * bytes. - Characters from index 128 onward represent the actual dynamic data. + *
+ * This method removes the `0x` prefix if present, parses the length, and decodes the dynamic data into UTF-8. + * + * @param hex the hex string to decode, which follows the ABI encoding standard + * @return the decoded UTF-8 string + */ private static String decodeABIHexString(String hex) { // Trim 0x at the beginning if (hex.startsWith("0x")) { diff --git a/examples/src/main/java/module-info.java b/examples/src/main/java/module-info.java index dba574aac..b94bba8ae 100644 --- a/examples/src/main/java/module-info.java +++ b/examples/src/main/java/module-info.java @@ -27,4 +27,5 @@ requires static java.annotation; requires com.google.protobuf; + requires org.bouncycastle.provider; }