Skip to content

Commit f97b454

Browse files
Merge pull request #204 from OpenElements/implement-contract-repo
feat: create ContractRepository interface, implementation
2 parents ab28b3d + f04f9d7 commit f97b454

File tree

13 files changed

+539
-19
lines changed

13 files changed

+539
-19
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.openelements.hiero.base.data;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.ContractId;
5+
import com.hedera.hashgraph.sdk.PublicKey;
6+
import java.time.Instant;
7+
import java.util.Objects;
8+
import org.jspecify.annotations.NonNull;
9+
import org.jspecify.annotations.Nullable;
10+
11+
/**
12+
* Represents a smart contract on the Hiero network.
13+
*/
14+
public record Contract(
15+
@NonNull ContractId contractId,
16+
@Nullable PublicKey adminKey,
17+
@Nullable AccountId autoRenewAccount,
18+
int autoRenewPeriod,
19+
@NonNull Instant createdTimestamp,
20+
boolean deleted,
21+
@Nullable Instant expirationTimestamp,
22+
@Nullable String fileId,
23+
@Nullable String evmAddress,
24+
@Nullable String memo,
25+
@Nullable Integer maxAutomaticTokenAssociations,
26+
@Nullable Long nonce,
27+
@Nullable String obtainerId,
28+
boolean permanentRemoval,
29+
@Nullable String proxyAccountId,
30+
@NonNull Instant fromTimestamp,
31+
@NonNull Instant toTimestamp,
32+
@Nullable String bytecode,
33+
@Nullable String runtimeBytecode
34+
) {
35+
public Contract {
36+
Objects.requireNonNull(contractId, "contractId must not be null");
37+
Objects.requireNonNull(createdTimestamp, "createdTimestamp must not be null");
38+
Objects.requireNonNull(fromTimestamp, "fromTimestamp must not be null");
39+
Objects.requireNonNull(toTimestamp, "toTimestamp must not be null");
40+
}
41+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.openelements.hiero.base.data;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
6+
/**
7+
* Basic {@link Page} implementation backed by an in-memory list.
8+
*
9+
* @param <T> element type for the page
10+
*/
11+
public final class SinglePage<T> implements Page<T> {
12+
13+
private final List<T> data;
14+
15+
public SinglePage(final List<T> data) {
16+
this.data = List.copyOf(Objects.requireNonNull(data, "data must not be null"));
17+
}
18+
19+
@Override
20+
public int getPageIndex() {
21+
return 0;
22+
}
23+
24+
@Override
25+
public int getSize() {
26+
return data.size();
27+
}
28+
29+
@Override
30+
public List<T> getData() {
31+
return data;
32+
}
33+
34+
@Override
35+
public boolean hasNext() {
36+
return false;
37+
}
38+
39+
@Override
40+
public Page<T> next() {
41+
throw new IllegalStateException("No next page");
42+
}
43+
44+
@Override
45+
public Page<T> first() {
46+
return this;
47+
}
48+
49+
@Override
50+
public boolean isFirst() {
51+
return true;
52+
}
53+
}
54+

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/implementation/AbstractMirrorNodeClient.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package com.openelements.hiero.base.implementation;
22

33
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.ContractId;
45
import com.hedera.hashgraph.sdk.TokenId;
56
import com.hedera.hashgraph.sdk.TopicId;
67
import com.openelements.hiero.base.HieroException;
8+
import com.openelements.hiero.base.data.Contract;
9+
import com.openelements.hiero.base.data.Nft;
10+
import com.openelements.hiero.base.data.NftMetadata;
711
import com.openelements.hiero.base.data.AccountInfo;
812
import com.openelements.hiero.base.data.ExchangeRates;
913
import com.openelements.hiero.base.data.NetworkFee;
1014
import com.openelements.hiero.base.data.NetworkStake;
1115
import com.openelements.hiero.base.data.NetworkSupplies;
12-
import com.openelements.hiero.base.data.Nft;
13-
import com.openelements.hiero.base.data.NftMetadata;
16+
import com.openelements.hiero.base.data.Page;
1417
import com.openelements.hiero.base.data.TokenInfo;
1518
import com.openelements.hiero.base.data.TransactionInfo;
1619
import com.openelements.hiero.base.data.Topic;
@@ -105,4 +108,17 @@ public final Optional<TopicMessage> queryTopicMessageBySequenceNumber(TopicId to
105108
throw new UnsupportedOperationException("Not yet implemented");
106109
}
107110

111+
@Override
112+
public @NonNull Page<Contract> queryContracts() throws HieroException {
113+
final JSON json = getRestClient().queryContracts();
114+
return getJsonConverter().toContractPage(json);
115+
}
116+
117+
@Override
118+
public @NonNull Optional<Contract> queryContractById(@NonNull final ContractId contractId) throws HieroException {
119+
Objects.requireNonNull(contractId, "contractId must not be null");
120+
final JSON json = getRestClient().queryContractById(contractId);
121+
return getJsonConverter().toContract(json);
122+
}
123+
108124
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.openelements.hiero.base.implementation;
2+
3+
import com.hedera.hashgraph.sdk.ContractId;
4+
import com.openelements.hiero.base.HieroException;
5+
import com.openelements.hiero.base.data.Contract;
6+
import com.openelements.hiero.base.data.Page;
7+
import com.openelements.hiero.base.mirrornode.ContractRepository;
8+
import com.openelements.hiero.base.mirrornode.MirrorNodeClient;
9+
import java.util.Objects;
10+
import java.util.Optional;
11+
import org.jspecify.annotations.NonNull;
12+
13+
/**
14+
* Implementation of ContractRepository that uses MirrorNodeClient to query contract data.
15+
*/
16+
public class ContractRepositoryImpl implements ContractRepository {
17+
18+
private final MirrorNodeClient mirrorNodeClient;
19+
20+
/**
21+
* Creates a new ContractRepositoryImpl with the given MirrorNodeClient.
22+
*
23+
* @param mirrorNodeClient the mirror node client to use for queries
24+
*/
25+
public ContractRepositoryImpl(@NonNull final MirrorNodeClient mirrorNodeClient) {
26+
this.mirrorNodeClient = Objects.requireNonNull(mirrorNodeClient, "mirrorNodeClient must not be null");
27+
}
28+
29+
@NonNull
30+
@Override
31+
public Page<Contract> findAll() throws HieroException {
32+
return mirrorNodeClient.queryContracts();
33+
}
34+
35+
@NonNull
36+
@Override
37+
public Optional<Contract> findById(@NonNull final ContractId contractId) throws HieroException {
38+
return mirrorNodeClient.queryContractById(contractId);
39+
}
40+
}

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/implementation/MirrorNodeJsonConverter.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
import com.openelements.hiero.base.data.Balance;
1313
import com.openelements.hiero.base.data.Topic;
1414
import com.openelements.hiero.base.data.TopicMessage;
15+
import com.openelements.hiero.base.data.Contract;
16+
import com.openelements.hiero.base.data.Page;
1517

1618
import java.util.List;
1719
import java.util.Optional;
1820
import org.jspecify.annotations.NonNull;
1921

2022
public interface MirrorNodeJsonConverter<JSON> {
21-
2223
@NonNull
2324
Optional<Nft> toNft(@NonNull JSON json);
2425

@@ -59,4 +60,13 @@ public interface MirrorNodeJsonConverter<JSON> {
5960

6061
@NonNull
6162
List<TopicMessage> toTopicMessages(JSON json);
63+
64+
@NonNull
65+
Optional<Contract> toContract(@NonNull JSON json);
66+
67+
@NonNull
68+
Page<Contract> toContractPage(@NonNull JSON json);
69+
70+
@NonNull
71+
List<Contract> toContracts(@NonNull JSON json);
6272
}

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/implementation/MirrorNodeRestClient.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.openelements.hiero.base.implementation;
22

33
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.ContractId;
45
import com.hedera.hashgraph.sdk.TokenId;
56
import com.hedera.hashgraph.sdk.TopicId;
67
import com.openelements.hiero.base.HieroException;
@@ -68,4 +69,15 @@ default JSON queryTopicMessageBySequenceNumber(TopicId topicId, long sequenceNum
6869

6970
@NonNull
7071
JSON doGetCall(@NonNull String path) throws HieroException;
72+
73+
@NonNull
74+
default JSON queryContracts() throws HieroException {
75+
return doGetCall("/api/v1/contracts");
76+
}
77+
78+
@NonNull
79+
default JSON queryContractById(@NonNull final ContractId contractId) throws HieroException {
80+
Objects.requireNonNull(contractId, "contractId must not be null");
81+
return doGetCall("/api/v1/contracts/" + contractId);
82+
}
7183
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.openelements.hiero.base.mirrornode;
2+
3+
import com.hedera.hashgraph.sdk.ContractId;
4+
import com.openelements.hiero.base.HieroException;
5+
import com.openelements.hiero.base.data.Contract;
6+
import com.openelements.hiero.base.data.Page;
7+
import java.util.Objects;
8+
import java.util.Optional;
9+
import org.jspecify.annotations.NonNull;
10+
11+
/**
12+
* Interface for interacting with smart contracts on a Hiero network. This interface provides methods for searching for contracts.
13+
*/
14+
public interface ContractRepository {
15+
16+
/**
17+
* Return all contracts.
18+
*
19+
* @return first page of contracts
20+
* @throws HieroException if the search fails
21+
*/
22+
@NonNull
23+
Page<Contract> findAll() throws HieroException;
24+
25+
/**
26+
* Return a contract by its contract ID.
27+
*
28+
* @param contractId id of the contract
29+
* @return {@link Optional} containing the found contract or null
30+
* @throws HieroException if the search fails
31+
*/
32+
@NonNull
33+
Optional<Contract> findById(@NonNull ContractId contractId) throws HieroException;
34+
35+
/**
36+
* Return a contract by its contract ID.
37+
*
38+
* @param contractId id of the contract
39+
* @return {@link Optional} containing the found contract or null
40+
* @throws HieroException if the search fails
41+
*/
42+
@NonNull
43+
default Optional<Contract> findById(@NonNull String contractId) throws HieroException {
44+
Objects.requireNonNull(contractId, "contractId must not be null");
45+
return findById(ContractId.fromString(contractId));
46+
}
47+
48+
}

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/mirrornode/MirrorNodeClient.java

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.openelements.hiero.base.mirrornode;
22

33
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.ContractId;
45
import com.hedera.hashgraph.sdk.TokenId;
56
import com.hedera.hashgraph.sdk.TopicId;
67
import com.openelements.hiero.base.HieroException;
78
import com.openelements.hiero.base.data.AccountInfo;
89
import com.openelements.hiero.base.data.Balance;
10+
import com.openelements.hiero.base.data.Contract;
911
import com.openelements.hiero.base.data.ExchangeRates;
1012
import com.openelements.hiero.base.data.NetworkFee;
1113
import com.openelements.hiero.base.data.NetworkStake;
@@ -143,7 +145,7 @@ default Optional<Nft> queryNftsByTokenIdAndSerial(@NonNull String tokenId, long
143145
*/
144146
@NonNull
145147
default Optional<Nft> queryNftsByAccountAndTokenIdAndSerial(@NonNull AccountId accountId, @NonNull TokenId tokenId,
146-
long serialNumber) throws HieroException {
148+
long serialNumber) throws HieroException {
147149
Objects.requireNonNull(accountId, "newAccountId must not be null");
148150
return queryNftsByTokenIdAndSerial(tokenId, serialNumber)
149151
.filter(nft -> Objects.equals(nft.owner(), accountId));
@@ -160,7 +162,7 @@ default Optional<Nft> queryNftsByAccountAndTokenIdAndSerial(@NonNull AccountId a
160162
*/
161163
@NonNull
162164
default Optional<Nft> queryNftsByAccountAndTokenIdAndSerial(@NonNull String accountId, @NonNull String tokenId,
163-
long serialNumber) throws HieroException {
165+
long serialNumber) throws HieroException {
164166
Objects.requireNonNull(accountId, "accountId must not be null");
165167
Objects.requireNonNull(tokenId, "tokenId must not be null");
166168
return queryNftsByAccountAndTokenIdAndSerial(AccountId.fromString(accountId), TokenId.fromString(tokenId),
@@ -459,4 +461,37 @@ default Optional<TopicMessage> queryTopicMessageBySequenceNumber(String topicId,
459461

460462
@NonNull
461463
Page<NftMetadata> findAllNftTypes();
464+
465+
/**
466+
* Queries all contracts.
467+
*
468+
* @return the contracts
469+
* @throws HieroException if an error occurs
470+
*/
471+
@NonNull
472+
Page<Contract> queryContracts() throws HieroException;
473+
474+
/**
475+
* Queries a contract by its contract ID.
476+
*
477+
* @param contractId the contract ID
478+
* @return the contract information
479+
* @throws HieroException if an error occurs
480+
*/
481+
@NonNull
482+
Optional<Contract> queryContractById(@NonNull ContractId contractId) throws HieroException;
483+
484+
/**
485+
* Queries a contract by its contract ID.
486+
*
487+
* @param contractId the contract ID
488+
* @return the contract information
489+
* @throws HieroException if an error occurs
490+
*/
491+
@NonNull
492+
default Optional<Contract> queryContractById(@NonNull String contractId) throws HieroException {
493+
Objects.requireNonNull(contractId, "contractId must not be null");
494+
return queryContractById(ContractId.fromString(contractId));
495+
}
496+
462497
}

hiero-enterprise-microprofile/src/main/java/com/openelements/hiero/microprofile/ClientProvider.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
import com.openelements.hiero.base.implementation.SmartContractClientImpl;
1919
import com.openelements.hiero.base.implementation.TokenRepositoryImpl;
2020
import com.openelements.hiero.base.implementation.TransactionRepositoryImpl;
21+
import com.openelements.hiero.base.implementation.ContractRepositoryImpl;
2122
import com.openelements.hiero.base.mirrornode.AccountRepository;
2223
import com.openelements.hiero.base.mirrornode.MirrorNodeClient;
2324
import com.openelements.hiero.base.mirrornode.NetworkRepository;
2425
import com.openelements.hiero.base.mirrornode.NftRepository;
2526
import com.openelements.hiero.base.mirrornode.TokenRepository;
2627
import com.openelements.hiero.base.mirrornode.TransactionRepository;
28+
import com.openelements.hiero.base.mirrornode.ContractRepository;
2729
import com.openelements.hiero.base.protocol.ProtocolLayerClient;
2830
import com.openelements.hiero.base.verification.ContractVerificationClient;
2931
import com.openelements.hiero.microprofile.implementation.ContractVerificationClientImpl;
@@ -159,4 +161,11 @@ TransactionRepository createTransactionRepository(@NonNull final MirrorNodeClien
159161
TokenRepository createTokenRepository(@NonNull final MirrorNodeClient mirrorNodeClient) {
160162
return new TokenRepositoryImpl(mirrorNodeClient);
161163
}
164+
165+
@NonNull
166+
@Produces
167+
@ApplicationScoped
168+
ContractRepository createContractRepository(@NonNull final MirrorNodeClient mirrorNodeClient) {
169+
return new ContractRepositoryImpl(mirrorNodeClient);
170+
}
162171
}

0 commit comments

Comments
 (0)