diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3916f4e7..145377da 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -35,7 +35,7 @@ jobs: - name: Prepare Hiero Solo id: solo - uses: hiero-ledger/hiero-solo-action@fbca3e7a99ce9aa8a250563a81187abe115e0dad # v0.16.0 + uses: hiero-ledger/hiero-solo-action@4d42a74e8e644a2753f3bb7a2afa429305375b14 # v0.17.0 with: installMirrorNode: true hieroVersion: v0.66.0 diff --git a/hiero-enterprise-base/src/main/java/com/openelements/hiero/base/data/Contract.java b/hiero-enterprise-base/src/main/java/com/openelements/hiero/base/data/Contract.java index 201d92fa..06b2a464 100644 --- a/hiero-enterprise-base/src/main/java/com/openelements/hiero/base/data/Contract.java +++ b/hiero-enterprise-base/src/main/java/com/openelements/hiero/base/data/Contract.java @@ -2,7 +2,7 @@ import com.hedera.hashgraph.sdk.AccountId; import com.hedera.hashgraph.sdk.ContractId; -import com.hedera.hashgraph.sdk.PublicKey; +import com.hedera.hashgraph.sdk.Key; import java.time.Instant; import java.util.Objects; import org.jspecify.annotations.NonNull; @@ -11,7 +11,7 @@ /** Represents a smart contract on the Hiero network. */ public record Contract( @NonNull ContractId contractId, - @Nullable PublicKey adminKey, + @Nullable Key adminKey, @Nullable AccountId autoRenewAccount, int autoRenewPeriod, @NonNull Instant createdTimestamp, diff --git a/hiero-enterprise-spring/src/main/java/com/openelements/hiero/spring/implementation/MirrorNodeJsonConverterImpl.java b/hiero-enterprise-spring/src/main/java/com/openelements/hiero/spring/implementation/MirrorNodeJsonConverterImpl.java index c4afeee8..e86f7c87 100644 --- a/hiero-enterprise-spring/src/main/java/com/openelements/hiero/spring/implementation/MirrorNodeJsonConverterImpl.java +++ b/hiero-enterprise-spring/src/main/java/com/openelements/hiero/spring/implementation/MirrorNodeJsonConverterImpl.java @@ -3,6 +3,8 @@ import com.fasterxml.jackson.databind.JsonNode; import com.hedera.hashgraph.sdk.AccountId; import com.hedera.hashgraph.sdk.ContractId; +import com.hedera.hashgraph.sdk.DelegateContractId; +import com.hedera.hashgraph.sdk.Key; import com.hedera.hashgraph.sdk.PublicKey; import com.hedera.hashgraph.sdk.TokenId; import com.hedera.hashgraph.sdk.TokenSupplyType; @@ -39,6 +41,7 @@ import java.math.BigInteger; import java.time.Instant; import java.util.Base64; +import java.util.HexFormat; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -730,10 +733,21 @@ private Stream jsonArrayToStream(@NonNull final JsonNode node) { try { final ContractId contractId = ContractId.fromString(node.get("contract_id").asText()); - final PublicKey adminKey = - node.get("admin_key").isNull() - ? null - : PublicKey.fromString(node.get("admin_key").get("key").asText()); + final Key adminKey; + + if (node.get("admin_key").isNull()) { + adminKey = null; + } else { + final String keyType = node.get("admin_key").get("_type").asText(); + final String key = node.get("admin_key").get("key").asText(); + + if (keyType.equals("ProtobufEncoded")) { + adminKey = parseProtoBufEncodedKey(key); + } else { + adminKey = PublicKey.fromString(key); + } + } + final AccountId autoRenewAccount = node.get("auto_renew_account").isNull() ? null @@ -769,9 +783,14 @@ private Stream jsonArrayToStream(@NonNull final JsonNode node) { final Instant fromTimestamp = Instant.ofEpochSecond(node.get("timestamp").get("from").asLong()); final Instant toTimestamp = Instant.ofEpochSecond(node.get("timestamp").get("to").asLong()); - final String bytecode = node.get("bytecode").isNull() ? null : node.get("bytecode").asText(); + final String bytecode = + (!node.has("bytecode") || node.get("bytecode").isNull()) + ? null + : node.get("bytecode").asText(); final String runtimeBytecode = - node.get("runtime_bytecode").isNull() ? null : node.get("runtime_bytecode").asText(); + (!node.has("runtime_bytecode") || node.get("runtime_bytecode").isNull()) + ? null + : node.get("runtime_bytecode").asText(); return Optional.of( new Contract( @@ -832,4 +851,26 @@ private Stream jsonArrayToStream(@NonNull final JsonNode node) { .map(optional -> optional.get()) .toList(); } + + private @NonNull Key parseProtoBufEncodedKey(@NonNull String key) throws Exception { + Objects.requireNonNull(key, "key must not be null"); + final byte[] bytes = HexFormat.of().parseHex(key); + final com.hedera.hashgraph.sdk.proto.Key protoKey = + com.hedera.hashgraph.sdk.proto.Key.parseFrom(bytes); + + return switch (protoKey.getKeyCase()) { + case ED25519 -> PublicKey.fromBytesED25519(protoKey.getEd25519().toByteArray()); + + case ECDSA_SECP256K1 -> PublicKey.fromBytesECDSA(protoKey.getECDSASecp256K1().toByteArray()); + + case CONTRACTID -> ContractId.fromBytes(protoKey.getContractID().toByteArray()); + + case DELEGATABLE_CONTRACT_ID -> + DelegateContractId.fromBytes(protoKey.getDelegatableContractId().toByteArray()); + + default -> + throw new IllegalArgumentException( + "Unsupported protobuf key type: " + protoKey.getKeyCase()); + }; + } }