Skip to content

Commit ecd14fd

Browse files
committed
added dissociateNft() and dissociateToken() for nft and fungibletoken client
Signed-off-by: Manish Dait <[email protected]>
1 parent 20ff854 commit ecd14fd

File tree

12 files changed

+412
-1
lines changed

12 files changed

+412
-1
lines changed

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/FungibleTokenClient.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
import com.hedera.hashgraph.sdk.PrivateKey;
55
import com.hedera.hashgraph.sdk.TokenId;
66
import com.openelements.hiero.base.data.Account;
7+
8+
import java.util.List;
79
import java.util.Objects;
810
import org.jspecify.annotations.NonNull;
911

@@ -230,6 +232,69 @@ default void associateToken(@NonNull TokenId tokenId, @NonNull Account account)
230232
associateToken(tokenId, account.accountId(), account.privateKey());
231233
}
232234

235+
/**
236+
* Dissociate an account with token.
237+
*
238+
* @param tokenId the ID of the token
239+
* @param accountId the accountId
240+
* @param accountKey the account privateKey
241+
* @throws HieroException if the account could not be associated with the token
242+
*/
243+
void dissociateToken(@NonNull TokenId tokenId, @NonNull AccountId accountId, @NonNull PrivateKey accountKey)
244+
throws HieroException;
245+
246+
/**
247+
* Dissociate an account with token.
248+
*
249+
* @param tokenId the ID of the token
250+
* @param accountId the accountId
251+
* @param accountKey the account privateKey
252+
* @throws HieroException if the account could not be associated with the token
253+
*/
254+
default void dissociateToken(@NonNull String tokenId, @NonNull String accountId, @NonNull String accountKey)
255+
throws HieroException {
256+
Objects.requireNonNull(tokenId, "tokenId must not be null");
257+
Objects.requireNonNull(accountId, "accountId must not be null");
258+
Objects.requireNonNull(accountKey, "accountKey must not be null");
259+
dissociateToken(TokenId.fromString(tokenId), AccountId.fromString(accountId), PrivateKey.fromString(accountKey));
260+
};
261+
262+
/**
263+
* Dissociate an account with token.
264+
*
265+
* @param tokenId the ID of the token
266+
* @param account the account
267+
* @throws HieroException if the account could not be associated with the token
268+
*/
269+
default void dissociateToken(@NonNull TokenId tokenId, @NonNull Account account) throws HieroException {
270+
Objects.requireNonNull(account, "accountId must not be null");
271+
dissociateToken(tokenId, account.accountId(), account.privateKey());
272+
};
273+
274+
/**
275+
* Dissociate an account with token.
276+
*
277+
* @param tokenIds list of the ID of the token
278+
* @param accountId the accountId
279+
* @param accountKey the account privateKey
280+
* @throws HieroException if the account could not be associated with the token
281+
*/
282+
void dissociateToken(@NonNull List<TokenId> tokenIds, @NonNull AccountId accountId, @NonNull PrivateKey accountKey)
283+
throws HieroException;
284+
285+
/**
286+
* Dissociate an account with token.
287+
*
288+
* @param tokenIds list of the ID of the token
289+
* @param account the account
290+
* @throws HieroException if the account could not be associated with the token
291+
*/
292+
default void dissociateToken(@NonNull List<TokenId> tokenIds, @NonNull Account account) throws HieroException {
293+
Objects.requireNonNull(account, "accountId must not be null");
294+
dissociateToken(tokenIds, account.accountId(), account.privateKey());
295+
};
296+
297+
233298
/**
234299
* Mint a Token.
235300
*

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/NftClient.java

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import java.util.List;
88
import java.util.Objects;
99
import java.util.Set;
10+
11+
import com.openelements.hiero.base.data.Token;
1012
import org.jspecify.annotations.NonNull;
1113

1214
/**
@@ -203,6 +205,68 @@ default void associateNft(@NonNull TokenId tokenId, @NonNull Account account) th
203205
associateNft(tokenId, account.accountId(), account.privateKey());
204206
}
205207

208+
/**
209+
* Dissociate an account with an NFT type.
210+
*
211+
* @param tokenId the ID of the NFT type
212+
* @param accountId the accountId
213+
* @param accountKey the account privateKey
214+
* @throws HieroException if the account could not be associated with the NFT type
215+
*/
216+
void dissociateNft(@NonNull TokenId tokenId, @NonNull AccountId accountId, @NonNull PrivateKey accountKey)
217+
throws HieroException;
218+
219+
/**
220+
* Dissociate an account with an NFT type.
221+
*
222+
* @param tokenId the ID of the NFT type
223+
* @param accountId the accountId
224+
* @param accountKey the account privateKey
225+
* @throws HieroException if the account could not be associated with the NFT type
226+
*/
227+
default void dissociateNft(@NonNull String tokenId, @NonNull String accountId, @NonNull String accountKey)
228+
throws HieroException {
229+
Objects.requireNonNull(tokenId, "tokenId must not be null");
230+
Objects.requireNonNull(accountId, "accountId must not be null");
231+
Objects.requireNonNull(accountKey, "accountKey must not be null");
232+
dissociateNft(TokenId.fromString(tokenId), AccountId.fromString(accountId), PrivateKey.fromString(accountKey));
233+
};
234+
235+
/**
236+
* Dissociate an account with an NFT type.
237+
*
238+
* @param tokenId the ID of the NFT type
239+
* @param account the account
240+
* @throws HieroException if the account could not be associated with the NFT type
241+
*/
242+
default void dissociateNft(@NonNull TokenId tokenId, @NonNull Account account) throws HieroException {
243+
Objects.requireNonNull(account, "accountId must not be null");
244+
dissociateNft(tokenId, account.accountId(), account.privateKey());
245+
};
246+
247+
/**
248+
* Dissociate an account with an NFT type.
249+
*
250+
* @param tokenIds the List of ID for NFT type
251+
* @param accountId the accountId
252+
* @param accountKey the account privateKey
253+
* @throws HieroException if the account could not be associated with the NFT type
254+
*/
255+
void dissociateNft(@NonNull List<TokenId> tokenIds, @NonNull AccountId accountId, @NonNull PrivateKey accountKey)
256+
throws HieroException;
257+
258+
/**
259+
* Dissociate an account with an NFT type.
260+
*
261+
* @param tokenIds the List of ID for NFT type
262+
* @param account the account
263+
* @throws HieroException if the account could not be associated with the NFT type
264+
*/
265+
default void dissociateNft(@NonNull List<TokenId> tokenIds, @NonNull Account account) throws HieroException {
266+
Objects.requireNonNull(account, "accountId must not be null");
267+
dissociateNft(tokenIds, account.accountId(), account.privateKey());
268+
};
269+
206270
/**
207271
* Mint a new NFT of the given type. The NFT is minted by the operator account. The operator account is used as
208272
* supply account for the NFT.

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
import com.hedera.hashgraph.sdk.TokenType;
88
import com.openelements.hiero.base.HieroException;
99
import com.openelements.hiero.base.data.Account;
10-
import com.openelements.hiero.base.protocol.*;
10+
import com.openelements.hiero.base.protocol.ProtocolLayerClient;
1111
import com.openelements.hiero.base.protocol.data.TokenAssociateRequest;
12+
import com.openelements.hiero.base.protocol.data.TokenDissociateRequest;
1213
import com.openelements.hiero.base.protocol.data.TokenBurnRequest;
1314
import com.openelements.hiero.base.protocol.data.TokenBurnResult;
1415
import com.openelements.hiero.base.protocol.data.TokenCreateRequest;
@@ -18,6 +19,7 @@
1819
import com.openelements.hiero.base.protocol.data.TokenTransferRequest;
1920
import org.jspecify.annotations.NonNull;
2021

22+
import java.util.List;
2123
import java.util.Objects;
2224

2325
public class FungibleTokenClientImpl implements FungibleTokenClient {
@@ -65,6 +67,27 @@ public void associateToken(@NonNull TokenId tokenId, @NonNull AccountId accountI
6567
client.executeTokenAssociateTransaction(request);
6668
}
6769

70+
@Override
71+
public void dissociateToken(@NonNull TokenId tokenId, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) throws HieroException {
72+
Objects.requireNonNull(tokenId, "tokenId must not be null");
73+
Objects.requireNonNull(accountId, "accountId must not be null");
74+
Objects.requireNonNull(accountKey, "accountKey must not be null");
75+
final TokenDissociateRequest request = TokenDissociateRequest.of(tokenId, accountId, accountKey);
76+
client.executeTokenDissociateTransaction(request);
77+
}
78+
79+
@Override
80+
public void dissociateToken(@NonNull List<TokenId> tokenIds, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) throws HieroException {
81+
Objects.requireNonNull(tokenIds, "tokenIds must not be null");
82+
Objects.requireNonNull(accountId, "accountId must not be null");
83+
Objects.requireNonNull(accountKey, "accountKey must not be null");
84+
if (tokenIds.isEmpty()) {
85+
throw new IllegalArgumentException("tokenIds must not be empty");
86+
}
87+
final TokenDissociateRequest request = TokenDissociateRequest.of(tokenIds, accountId, accountKey);
88+
client.executeTokenDissociateTransaction(request);
89+
}
90+
6891
@Override
6992
public long mintToken(@NonNull TokenId tokenId, long amount) throws HieroException {
7093
return mintToken(tokenId, operationalAccount.privateKey(), amount);

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import com.openelements.hiero.base.NftClient;
1010
import com.openelements.hiero.base.protocol.ProtocolLayerClient;
1111
import com.openelements.hiero.base.protocol.data.TokenAssociateRequest;
12+
import com.openelements.hiero.base.protocol.data.TokenDissociateRequest;
1213
import com.openelements.hiero.base.protocol.data.TokenBurnRequest;
1314
import com.openelements.hiero.base.protocol.data.TokenCreateRequest;
1415
import com.openelements.hiero.base.protocol.data.TokenCreateResult;
@@ -67,6 +68,27 @@ public void associateNft(@NonNull final TokenId tokenId, @NonNull final AccountI
6768
client.executeTokenAssociateTransaction(request);
6869
}
6970

71+
@Override
72+
public void dissociateNft(@NonNull TokenId tokenId, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) throws HieroException {
73+
Objects.requireNonNull(tokenId, "tokenId must not be null");
74+
Objects.requireNonNull(accountId, "accountId must not be null");
75+
Objects.requireNonNull(accountKey, "accountKey must not be null");
76+
final TokenDissociateRequest request = TokenDissociateRequest.of(tokenId, accountId, accountKey);
77+
client.executeTokenDissociateTransaction(request);
78+
}
79+
80+
@Override
81+
public void dissociateNft(@NonNull List<TokenId> tokenIds, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) throws HieroException {
82+
Objects.requireNonNull(tokenIds, "tokenIds must not be null");
83+
Objects.requireNonNull(accountId, "accountId must not be null");
84+
Objects.requireNonNull(accountKey, "accountKey must not be null");
85+
if (tokenIds.isEmpty()) {
86+
throw new IllegalArgumentException("tokenIds must not be empty");
87+
}
88+
final TokenDissociateRequest request = TokenDissociateRequest.of(tokenIds, accountId, accountKey);
89+
client.executeTokenDissociateTransaction(request);
90+
}
91+
7092
@Override
7193
public long mintNft(@NonNull TokenId tokenId, @NonNull byte[] metadata) throws HieroException {
7294
return mintNft(tokenId, operationalAccount.privateKey(), metadata);

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.hedera.hashgraph.sdk.Query;
2424
import com.hedera.hashgraph.sdk.SubscriptionHandle;
2525
import com.hedera.hashgraph.sdk.TokenAssociateTransaction;
26+
import com.hedera.hashgraph.sdk.TokenDissociateTransaction;
2627
import com.hedera.hashgraph.sdk.TokenBurnTransaction;
2728
import com.hedera.hashgraph.sdk.TokenCreateTransaction;
2829
import com.hedera.hashgraph.sdk.TokenMintTransaction;
@@ -67,6 +68,8 @@
6768
import com.openelements.hiero.base.protocol.ProtocolLayerClient;
6869
import com.openelements.hiero.base.protocol.data.TokenAssociateRequest;
6970
import com.openelements.hiero.base.protocol.data.TokenAssociateResult;
71+
import com.openelements.hiero.base.protocol.data.TokenDissociateRequest;
72+
import com.openelements.hiero.base.protocol.data.TokenDissociateResult;
7073
import com.openelements.hiero.base.protocol.data.TokenBurnRequest;
7174
import com.openelements.hiero.base.protocol.data.TokenBurnResult;
7275
import com.openelements.hiero.base.protocol.data.TokenCreateRequest;
@@ -462,6 +465,24 @@ public TokenAssociateResult executeTokenAssociateTransaction(@NonNull final Toke
462465
}
463466
}
464467

468+
@Override
469+
public @NonNull TokenDissociateResult executeTokenDissociateTransaction(@NonNull TokenDissociateRequest request)
470+
throws HieroException {
471+
Objects.requireNonNull(request, "request must not be null");
472+
try {
473+
final TokenDissociateTransaction transaction = new TokenDissociateTransaction()
474+
.setMaxTransactionFee(request.maxTransactionFee())
475+
.setTransactionValidDuration(request.transactionValidDuration())
476+
.setAccountId(request.accountId())
477+
.setTokenIds(request.tokenIds());
478+
sign(transaction, request.accountKey());
479+
final TransactionReceipt receipt = executeTransactionAndWaitOnReceipt(transaction);
480+
return new TokenDissociateResult(receipt.transactionId, receipt.status);
481+
} catch (final Exception e) {
482+
throw new HieroException("Failed to execute dissociate token transaction", e);
483+
}
484+
}
485+
465486
public TokenBurnResult executeBurnTokenTransaction(@NonNull final TokenBurnRequest request) throws HieroException {
466487
Objects.requireNonNull(request, "request must not be null");
467488
try {

hiero-enterprise-base/src/main/java/com/openelements/hiero/base/protocol/ProtocolLayerClient.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import com.openelements.hiero.base.protocol.data.FileUpdateResult;
2929
import com.openelements.hiero.base.protocol.data.TokenAssociateRequest;
3030
import com.openelements.hiero.base.protocol.data.TokenAssociateResult;
31+
import com.openelements.hiero.base.protocol.data.TokenDissociateRequest;
32+
import com.openelements.hiero.base.protocol.data.TokenDissociateResult;
3133
import com.openelements.hiero.base.protocol.data.TokenBurnRequest;
3234
import com.openelements.hiero.base.protocol.data.TokenBurnResult;
3335
import com.openelements.hiero.base.protocol.data.TokenCreateRequest;
@@ -197,6 +199,17 @@ AccountCreateResult executeAccountCreateTransaction(@NonNull final AccountCreate
197199
TokenAssociateResult executeTokenAssociateTransaction(@NonNull final TokenAssociateRequest request)
198200
throws HieroException;
199201

202+
/**
203+
* Executes a token dissociate transaction.
204+
*
205+
* @param request the request containing the details of the token dissociate transaction
206+
* @return the result of the token dissociate transaction
207+
* @throws HieroException if the transaction could not be executed
208+
*/
209+
@NonNull
210+
TokenDissociateResult executeTokenDissociateTransaction(@NonNull final TokenDissociateRequest request)
211+
throws HieroException;
212+
200213
/**
201214
* Executes a token mint transaction.
202215
*
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package com.openelements.hiero.base.protocol.data;
2+
3+
import com.hedera.hashgraph.sdk.AccountId;
4+
import com.hedera.hashgraph.sdk.Hbar;
5+
import com.hedera.hashgraph.sdk.PrivateKey;
6+
import com.hedera.hashgraph.sdk.TokenId;
7+
import org.jspecify.annotations.NonNull;
8+
9+
import java.time.Duration;
10+
import java.util.List;
11+
import java.util.Objects;
12+
13+
public record TokenDissociateRequest(@NonNull Hbar maxTransactionFee,
14+
@NonNull Duration transactionValidDuration,
15+
@NonNull List<TokenId> tokenIds,
16+
@NonNull AccountId accountId,
17+
@NonNull PrivateKey accountKey) implements TransactionRequest {
18+
public TokenDissociateRequest {
19+
Objects.requireNonNull(tokenIds, "tokenIds must not be null");
20+
Objects.requireNonNull(accountId, "accountId must not be null");
21+
Objects.requireNonNull(accountKey, "accountKey must not be null");
22+
}
23+
24+
public static TokenDissociateRequest of(@NonNull TokenId tokenId, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) {
25+
return of(List.of(tokenId), accountId, accountKey);
26+
}
27+
28+
public static TokenDissociateRequest of(@NonNull List<TokenId> tokenIds, @NonNull AccountId accountId, @NonNull PrivateKey accountKey) {
29+
return new TokenDissociateRequest(TransactionRequest.DEFAULT_MAX_TRANSACTION_FEE,
30+
TransactionRequest.DEFAULT_TRANSACTION_VALID_DURATION, tokenIds, accountId, accountKey);
31+
}
32+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.openelements.hiero.base.protocol.data;
2+
3+
import com.hedera.hashgraph.sdk.Status;
4+
import com.hedera.hashgraph.sdk.TransactionId;
5+
import org.jspecify.annotations.NonNull;
6+
7+
import java.util.Objects;
8+
9+
public record TokenDissociateResult(@NonNull TransactionId transactionId, @NonNull Status status) implements
10+
TransactionResult {
11+
public TokenDissociateResult {
12+
Objects.requireNonNull(transactionId, "transactionId must not be null");
13+
Objects.requireNonNull(status, "status must not be null");
14+
}
15+
}

hiero-enterprise-base/src/test/java/com/openelements/hiero/base/test/ProtocolLayerClientTests.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ void testNullParams() {
4949
Assertions.assertThrows(NullPointerException.class, () -> client.executeAccountCreateTransaction(null));
5050
Assertions.assertThrows(NullPointerException.class, () -> client.executeTokenCreateTransaction(null));
5151
Assertions.assertThrows(NullPointerException.class, () -> client.executeTokenAssociateTransaction(null));
52+
Assertions.assertThrows(NullPointerException.class, () -> client.executeTokenDissociateTransaction(null));
5253
Assertions.assertThrows(NullPointerException.class, () -> client.executeTopicCreateTransaction(null));
5354
Assertions.assertThrows(NullPointerException.class, () -> client.executeTopicDeleteTransaction(null));
5455
Assertions.assertThrows(NullPointerException.class, () -> client.executeTopicMessageSubmitTransaction(null));

0 commit comments

Comments
 (0)