Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/maven.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,14 @@ jobs:

- name: Prepare Hiero Solo
id: solo
uses: hiero-ledger/hiero-solo-action@692b186bd2e4c8d46b9deb1c067dc6ddcf0abcd7 # v0.18.0
uses: hiero-ledger/hiero-solo-action@328bc84c3b00a990a151418144fd682a4eb76ea6 # v0.19.0
with:
installMirrorNode: true
hieroVersion: v0.66.0
mirrorNodeVersion: v0.138.0
mirrorNodePortRest: 5551
mirrorNodePortGrpc: 5600
mirrorNodePortWeb3Rest: 8545
soloVersion: 0.46.1

- name: Wait for Mirror Node
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.hedera.hashgraph.sdk.AccountId;
import com.hedera.hashgraph.sdk.Hbar;
import com.hedera.hashgraph.sdk.PrivateKey;
import java.util.List;
import java.util.Objects;
import org.hiero.base.data.Account;
import org.hiero.base.data.HookDetails;
import org.jspecify.annotations.NonNull;

/**
Expand Down Expand Up @@ -134,4 +136,30 @@ default Hbar getAccountBalance(@NonNull String accountId) throws HieroException
* @throws HieroException if the balance could not be retrieved
*/
@NonNull Hbar getOperatorAccountBalance() throws HieroException;

/** Adds a hook to an account. */
default void addHook(@NonNull Account account, @NonNull HookDetails hookDetails)
throws HieroException {
Objects.requireNonNull(account, "account must not be null");
Objects.requireNonNull(hookDetails, "hookDetails must not be null");
updateHooks(account, List.of(hookDetails), List.of());
}

/** Deletes a hook from an account. */
default void deleteHook(@NonNull Account account, long hookId) throws HieroException {
Objects.requireNonNull(account, "account must not be null");
if (hookId < 0) {
throw new IllegalArgumentException("hookId must be non-negative");
}
updateHooks(account, List.of(), List.of(hookId));
}

/** Updates account hooks by creating and/or deleting hooks. */
default void updateHooks(
@NonNull Account account,
@NonNull List<HookDetails> hooksToCreate,
@NonNull List<Long> hookIdsToDelete)
throws HieroException {
throw new UnsupportedOperationException("Account hook management is not implemented yet.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.hiero.base.data;

import com.hedera.hashgraph.sdk.ContractId;
import com.hedera.hashgraph.sdk.EvmHookStorageUpdate;
import com.hedera.hashgraph.sdk.HookExtensionPoint;
import com.hedera.hashgraph.sdk.Key;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

/**
* High-level representation of a hook to attach to an account.
*
* @param extensionPoint the extension point where the hook should be attached
* @param hookId unique identifier of the hook on the owning entity
* @param evmHookContractId contract implementing the hook logic
* @param initialStorageUpdates initial EVM storage updates to apply on hook creation
* @param adminKey optional key used to authorize management operations for this hook
*/
public record HookDetails(
@NonNull HookExtensionPoint extensionPoint,
long hookId,
@NonNull ContractId evmHookContractId,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also include List<EvmHookStorageUpdate> to adds an EVM hook with initial storage updates.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, updated.

@NonNull List<EvmHookStorageUpdate> initialStorageUpdates,
@Nullable Key adminKey) {

public HookDetails {
Objects.requireNonNull(extensionPoint, "extensionPoint must not be null");
Objects.requireNonNull(evmHookContractId, "evmHookContractId must not be null");
Objects.requireNonNull(initialStorageUpdates, "initialStorageUpdates must not be null");
initialStorageUpdates.forEach(
update -> Objects.requireNonNull(update, "initialStorageUpdates must not contain null"));
initialStorageUpdates = List.copyOf(initialStorageUpdates);
if (hookId < 0) {
throw new IllegalArgumentException("hookId must be non-negative");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
import org.hiero.base.protocol.data.AccountCreateResult;
import org.hiero.base.protocol.data.AccountDeleteRequest;
import org.hiero.base.protocol.data.AccountDeleteResult;
import org.hiero.base.protocol.data.AccountHookUpdateRequest;
import org.hiero.base.protocol.data.AccountHookUpdateResult;
import org.hiero.base.protocol.data.AccountUpdateRequest;
import org.hiero.base.protocol.data.AccountUpdateResult;
import org.hiero.base.protocol.data.ContractCallRequest;
Expand Down Expand Up @@ -177,6 +179,19 @@ public interface ProtocolLayerClient {
@NonNull AccountDeleteResult executeAccountDeleteTransaction(
@NonNull AccountDeleteRequest request) throws HieroException;

/**
* Executes an account hook update transaction.
*
* @param request the request containing hooks to create and hooks to delete on an account
* @return the result of the account hook update transaction
* @throws HieroException if the transaction could not be executed
*/
@NonNull
default AccountHookUpdateResult executeAccountHookUpdateTransaction(
@NonNull AccountHookUpdateRequest request) throws HieroException {
throw new UnsupportedOperationException("Account hook update transaction is not implemented.");
}

/**
* Executes an account update transaction.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package org.hiero.base.protocol.data;

import com.hedera.hashgraph.sdk.Hbar;
import java.time.Duration;
import java.util.List;
import java.util.Objects;
import org.hiero.base.data.Account;
import org.hiero.base.data.HookDetails;
import org.jspecify.annotations.NonNull;

public record AccountHookUpdateRequest(
@NonNull Hbar maxTransactionFee,
@NonNull Duration transactionValidDuration,
@NonNull Account account,
@NonNull List<HookDetails> hooksToCreate,
@NonNull List<Long> hooksToDelete)
implements TransactionRequest {

public AccountHookUpdateRequest {
Objects.requireNonNull(maxTransactionFee, "maxTransactionFee is required");
Objects.requireNonNull(transactionValidDuration, "transactionValidDuration is required");
Objects.requireNonNull(account, "account is required");
Objects.requireNonNull(hooksToCreate, "hooksToCreate is required");
Objects.requireNonNull(hooksToDelete, "hooksToDelete is required");
if (maxTransactionFee.toTinybars() < 0) {
throw new IllegalArgumentException("maxTransactionFee must be non-negative");
}
if (transactionValidDuration.isNegative() || transactionValidDuration.isZero()) {
throw new IllegalArgumentException("transactionValidDuration must be positive");
}
hooksToDelete.forEach(
hookId -> {
Objects.requireNonNull(hookId, "hooksToDelete must not contain null values");
if (hookId < 0) {
throw new IllegalArgumentException("hook IDs in hooksToDelete must be non-negative");
}
});
}

@NonNull
public static AccountHookUpdateRequest addHook(
@NonNull Account account, @NonNull HookDetails hookToCreate) {
Objects.requireNonNull(hookToCreate, "hookToCreate is required");
return new AccountHookUpdateRequest(
DEFAULT_MAX_TRANSACTION_FEE,
DEFAULT_TRANSACTION_VALID_DURATION,
account,
List.of(hookToCreate),
List.of());
}

@NonNull
public static AccountHookUpdateRequest deleteHook(@NonNull Account account, long hookIdToDelete) {
if (hookIdToDelete < 0) {
throw new IllegalArgumentException("hookIdToDelete must be non-negative");
}
return new AccountHookUpdateRequest(
DEFAULT_MAX_TRANSACTION_FEE,
DEFAULT_TRANSACTION_VALID_DURATION,
account,
List.of(),
List.of(hookIdToDelete));
}

@NonNull
public static AccountHookUpdateRequest of(
@NonNull Account account,
@NonNull List<HookDetails> hooksToCreate,
@NonNull List<Long> hooksToDelete) {
return new AccountHookUpdateRequest(
DEFAULT_MAX_TRANSACTION_FEE,
DEFAULT_TRANSACTION_VALID_DURATION,
account,
hooksToCreate,
hooksToDelete);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.hiero.base.protocol.data;

import com.hedera.hashgraph.sdk.Hbar;
import com.hedera.hashgraph.sdk.Status;
import com.hedera.hashgraph.sdk.TransactionId;
import java.time.Instant;
import java.util.Objects;
import org.jspecify.annotations.NonNull;

public record AccountHookUpdateResult(
@NonNull TransactionId transactionId,
@NonNull Status status,
@NonNull byte[] transactionHash,
@NonNull Instant consensusTimestamp,
@NonNull Hbar transactionFee)
implements TransactionRecord {

public AccountHookUpdateResult {
Objects.requireNonNull(transactionId, "transactionId must not be null");
Objects.requireNonNull(status, "status must not be null");
Objects.requireNonNull(transactionHash, "transactionHash must not be null");
Objects.requireNonNull(consensusTimestamp, "consensusTimestamp must not be null");
Objects.requireNonNull(transactionFee, "transactionFee must not be null");
if (transactionFee.toTinybars() < 0) {
throw new IllegalArgumentException("transactionFee must be non-negative");
}
}
}
Loading