Skip to content

Commit 7ec0eb0

Browse files
committed
Token & NFT support
1 parent 5b89c88 commit 7ec0eb0

33 files changed

+1243
-47
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,13 @@ The following services are available in spring and microprofile:
9696
- `com.openelements.hedera.base.FileClient`: to interact with Hedera files
9797
- `com.openelements.hedera.base.SmartContractClient`: to interact with Hedera smart contracts
9898
- `com.openelements.hedera.base.ContractVerificationClient`: to verify smart contracts
99+
- `com.openelements.hedera.base.NftClient`: to interact with Hedera NFTs
100+
- `com.openelements.hedera.base.NftRepository`: to query NFTs
101+
102+
Next to that the following low-level services are available:
103+
99104
- `com.openelements.hedera.base.protocol.ProtocolLayerClient`: to interact with the Hedera protocol layer
105+
- `com.openelements.hedera.base.mirrornode.MirrorNodeClient`: to query the Hedera mirror node
100106

101107
## Built the project
102108

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.openelements.hedera.base;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.TokenId;
5+
6+
public record Nft(TokenId tokenId, long serial, AccountId owner, byte[] metadata) {
7+
8+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.openelements.hedera.base;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.Key;
5+
import com.hedera.hashgraph.sdk.PrivateKey;
6+
import com.hedera.hashgraph.sdk.TokenId;
7+
import edu.umd.cs.findbugs.annotations.NonNull;
8+
import java.util.List;
9+
import java.util.stream.Stream;
10+
11+
public interface NftClient {
12+
13+
@NonNull
14+
TokenId createNftType(String name, String symbol) throws HederaException;
15+
16+
@NonNull
17+
TokenId createNftType(String name, String symbol, PrivateKey supplierKey) throws HederaException;
18+
19+
@NonNull
20+
TokenId createNftType(String name, String symbol, AccountId treasuryAccountId, PrivateKey treasuryKey) throws HederaException;
21+
22+
@NonNull
23+
TokenId createNftType(String name, String symbol, AccountId treasuryAccountId, PrivateKey treasuryKey, PrivateKey supplierKey) throws HederaException;
24+
25+
void associateNft(TokenId tokenId, AccountId accountId, PrivateKey accountKey) throws HederaException;
26+
27+
long mintNft(TokenId tokenId, String metadata) throws HederaException;
28+
29+
long mintNft(TokenId tokenId, String metadata, PrivateKey supplyKey) throws HederaException;
30+
31+
@NonNull
32+
List<Long> mintNfts(TokenId tokenId, List<String> metadata) throws HederaException;
33+
34+
@NonNull
35+
List<Long> mintNfts(TokenId tokenId, List<String> metadata, PrivateKey supplyKey) throws HederaException;
36+
37+
void transferNft(TokenId tokenId, long serialNumber, AccountId fromAccountId, PrivateKey fromAccountKey, AccountId toAccountId) throws HederaException;
38+
39+
void transferNfts(TokenId tokenId, List<Long> serialNumber, AccountId fromAccountId, PrivateKey fromAccountKey, AccountId toAccountId) throws HederaException;
40+
41+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package com.openelements.hedera.base;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.TokenId;
5+
import edu.umd.cs.findbugs.annotations.NonNull;
6+
import java.util.List;
7+
import java.util.Optional;
8+
9+
public interface NftRepository {
10+
11+
@NonNull
12+
List<Nft> findByOwner(@NonNull AccountId owner) throws HederaException;
13+
14+
@NonNull
15+
List<Nft> findByType(@NonNull TokenId tokenId) throws HederaException;
16+
17+
@NonNull
18+
Optional<Nft> findByTypeAndSerial(@NonNull TokenId tokenId, long serialNumber) throws HederaException;
19+
20+
@NonNull
21+
List<Nft> findByOwnerAndType(@NonNull AccountId owner, @NonNull TokenId tokenId) throws HederaException;
22+
23+
@NonNull
24+
Optional<Nft> findByOwnerAndTypeAndSerial(@NonNull AccountId owner, @NonNull TokenId tokenId, long serialNumber) throws HederaException;
25+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package com.openelements.hedera.base.implementation;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.Key;
5+
import com.hedera.hashgraph.sdk.PrivateKey;
6+
import com.hedera.hashgraph.sdk.TokenId;
7+
import com.hedera.hashgraph.sdk.TokenType;
8+
import com.openelements.hedera.base.HederaException;
9+
import com.openelements.hedera.base.NftClient;
10+
import com.openelements.hedera.base.protocol.ProtocolLayerClient;
11+
import com.openelements.hedera.base.protocol.TokenAssociateRequest;
12+
import com.openelements.hedera.base.protocol.TokenCreateRequest;
13+
import com.openelements.hedera.base.protocol.TokenCreateResult;
14+
import com.openelements.hedera.base.protocol.TokenMintRequest;
15+
import com.openelements.hedera.base.protocol.TokenMintResult;
16+
import com.openelements.hedera.base.protocol.TokenTransferRequest;
17+
import edu.umd.cs.findbugs.annotations.NonNull;
18+
import java.util.Collections;
19+
import java.util.List;
20+
import java.util.Objects;
21+
22+
public class NftClientImpl implements NftClient {
23+
24+
private final ProtocolLayerClient client;
25+
26+
private final AccountId adminAccount;
27+
28+
private final PrivateKey adminSupplyKey;
29+
30+
public NftClientImpl(@NonNull final ProtocolLayerClient client, @NonNull final AccountId adminAccount, @NonNull final PrivateKey adminSupplyKey) {
31+
this.client = Objects.requireNonNull(client, "client must not be null");
32+
this.adminAccount = Objects.requireNonNull(adminAccount, "adminAccount must not be null");
33+
this.adminSupplyKey = Objects.requireNonNull(adminSupplyKey, "adminSupplyKey must not be null");
34+
}
35+
36+
@Override
37+
public TokenId createNftType(@NonNull final String name, @NonNull final String symbol) throws HederaException{
38+
return createNftType(name, symbol, adminAccount, adminSupplyKey);
39+
}
40+
41+
42+
@Override
43+
public TokenId createNftType(@NonNull final String name, @NonNull final String symbol, @NonNull final PrivateKey supplierKey) throws HederaException {
44+
return createNftType(name, symbol, adminAccount, adminSupplyKey, supplierKey);
45+
}
46+
47+
@Override
48+
public TokenId createNftType(@NonNull final String name, @NonNull final String symbol, @NonNull final AccountId treasuryAccountId, @NonNull final PrivateKey treasuryKey) throws HederaException {
49+
return createNftType(name, symbol, treasuryAccountId, treasuryKey, adminSupplyKey);
50+
}
51+
52+
@Override
53+
public TokenId createNftType(@NonNull final String name, @NonNull final String symbol, @NonNull final AccountId treasuryAccountId, @NonNull final PrivateKey treasuryKey,
54+
@NonNull final PrivateKey supplierKey) throws HederaException {
55+
final TokenCreateRequest request = TokenCreateRequest.of(name, symbol, treasuryAccountId, treasuryKey, TokenType.NON_FUNGIBLE_UNIQUE, supplierKey);
56+
final TokenCreateResult tokenCreateResult = client.executeTokenCreateTransaction(request);
57+
return tokenCreateResult.tokenId();
58+
}
59+
60+
@Override
61+
public void associateNft(@NonNull final TokenId tokenId, @NonNull final AccountId accountId, @NonNull final PrivateKey accountKey) throws HederaException {
62+
final TokenAssociateRequest request = TokenAssociateRequest.of(tokenId, accountId, accountKey);
63+
client.executeTokenAssociateTransaction(request);
64+
}
65+
66+
@Override
67+
public long mintNft(@NonNull final TokenId tokenId, @NonNull final String metadata) throws HederaException {
68+
return mintNft(tokenId, metadata, adminSupplyKey);
69+
}
70+
71+
@Override
72+
public List<Long> mintNfts(@NonNull final TokenId tokenId, @NonNull final List<String> metadata) throws HederaException {
73+
return mintNfts(tokenId, metadata, adminSupplyKey);
74+
}
75+
76+
@Override
77+
public long mintNft(@NonNull final TokenId tokenId, @NonNull final String metadata, @NonNull final PrivateKey supplyKey) throws HederaException {
78+
final TokenMintRequest request = TokenMintRequest.of(tokenId, supplyKey, metadata);
79+
final TokenMintResult tokenMintResult = client.executeMintTokenTransaction(request);
80+
final List<Long> serials = tokenMintResult.serials();
81+
if(serials.size() != 1) {
82+
throw new HederaException("Expected 1 serial number, but got " + serials.size());
83+
}
84+
return serials.get(0);
85+
}
86+
87+
@Override
88+
public List<Long> mintNfts(@NonNull final TokenId tokenId, @NonNull final List<String> metadata, @NonNull final PrivateKey supplyKey) throws HederaException {
89+
final TokenMintRequest request = TokenMintRequest.of(tokenId, supplyKey, metadata);
90+
final TokenMintResult result = client.executeMintTokenTransaction(request);
91+
return Collections.unmodifiableList(result.serials());
92+
}
93+
94+
@Override
95+
public void transferNft(@NonNull final TokenId tokenId, final long serialNumber, @NonNull final AccountId fromAccountId, @NonNull final PrivateKey fromAccountKey,
96+
@NonNull final AccountId toAccountId) throws HederaException {
97+
transferNfts(tokenId, List.of(serialNumber), fromAccountId, fromAccountKey, toAccountId);
98+
}
99+
100+
@Override
101+
public void transferNfts(@NonNull final TokenId tokenId, @NonNull final List<Long> serialNumber, @NonNull final AccountId fromAccountId,
102+
@NonNull final PrivateKey fromAccountKey, @NonNull final AccountId toAccountId) throws HederaException {
103+
final TokenTransferRequest request = TokenTransferRequest.of(tokenId, serialNumber, fromAccountId, toAccountId, fromAccountKey);
104+
client.executeTransferTransactionForNft(request);
105+
}
106+
107+
108+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package com.openelements.hedera.base.implementation;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.TokenId;
5+
import com.openelements.hedera.base.HederaException;
6+
import com.openelements.hedera.base.Nft;
7+
import com.openelements.hedera.base.NftRepository;
8+
import com.openelements.hedera.base.mirrornode.MirrorNodeClient;
9+
import edu.umd.cs.findbugs.annotations.NonNull;
10+
import java.util.List;
11+
import java.util.Objects;
12+
import java.util.Optional;
13+
14+
public class NftRepositoryImpl implements NftRepository {
15+
16+
private final MirrorNodeClient mirrorNodeClient;
17+
18+
public NftRepositoryImpl(@NonNull final MirrorNodeClient mirrorNodeClient) {
19+
this.mirrorNodeClient = Objects.requireNonNull(mirrorNodeClient, "mirrorNodeClient must not be null");
20+
}
21+
22+
@NonNull
23+
@Override
24+
public List<Nft> findByOwner(@NonNull final AccountId owner) throws HederaException {
25+
return mirrorNodeClient.queryNftsByAccount(owner);
26+
}
27+
28+
@NonNull
29+
@Override
30+
public List<Nft> findByType(@NonNull final TokenId tokenId) throws HederaException {
31+
return mirrorNodeClient.queryNftsByTokenId(tokenId);
32+
}
33+
34+
@NonNull
35+
@Override
36+
public Optional<Nft> findByTypeAndSerial(@NonNull final TokenId tokenId, final long serialNumber) throws HederaException {
37+
return mirrorNodeClient.queryNftsByTokenIdAndSerial(tokenId, serialNumber);
38+
}
39+
40+
@NonNull
41+
@Override
42+
public List<Nft> findByOwnerAndType(@NonNull final AccountId owner, @NonNull final TokenId tokenId) throws HederaException {
43+
return mirrorNodeClient.queryNftsByAccountAndTokenId(owner, tokenId);
44+
}
45+
46+
@NonNull
47+
@Override
48+
public Optional<Nft> findByOwnerAndTypeAndSerial(@NonNull final AccountId owner, @NonNull final TokenId tokenId,
49+
final long serialNumber) throws HederaException {
50+
return mirrorNodeClient.queryNftsByAccountAndTokenIdAndSerial(owner, tokenId, serialNumber);
51+
}
52+
}

0 commit comments

Comments
 (0)