From c4388d09339fcdb43f879ebe9d7c5c2db14a8284 Mon Sep 17 00:00:00 2001 From: Martti Marran Date: Fri, 14 Nov 2025 12:53:29 +0200 Subject: [PATCH 1/2] #35 Add isMinted and isStateSpent methods in transition client --- .../sdk/StateTransitionClient.java | 86 ++++++++++--------- .../sdk/common/CommonTestFlow.java | 28 +----- 2 files changed, 46 insertions(+), 68 deletions(-) diff --git a/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java b/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java index 1b0e293..b3f58a3 100644 --- a/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java +++ b/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java @@ -13,10 +13,12 @@ import org.unicitylabs.sdk.predicate.PredicateEngineService; import org.unicitylabs.sdk.signing.MintSigningService; import org.unicitylabs.sdk.token.Token; +import org.unicitylabs.sdk.token.TokenId; import org.unicitylabs.sdk.token.TokenState; +import org.unicitylabs.sdk.transaction.InclusionProofVerificationStatus; import org.unicitylabs.sdk.transaction.MintCommitment; -import org.unicitylabs.sdk.transaction.MintTransaction; import org.unicitylabs.sdk.transaction.MintTransactionReason; +import org.unicitylabs.sdk.transaction.MintTransactionState; import org.unicitylabs.sdk.transaction.TransferCommitment; import org.unicitylabs.sdk.transaction.TransferTransaction; import org.unicitylabs.sdk.verification.VerificationException; @@ -48,7 +50,7 @@ public StateTransitionClient(AggregatorClient client) { * @return A CompletableFuture that resolves to the response from the aggregator. */ public - CompletableFuture submitCommitment(MintCommitment commitment) { + CompletableFuture submitCommitment(MintCommitment commitment) { return this.client.submitCommitment( commitment.getRequestId(), commitment.getTransactionData().calculateHash(), @@ -134,65 +136,65 @@ public CompletableFuture getInclusionProof(RequestId req } /** - * Get inclusion proof for mint transaction. + * Check if state is already spent for given request id. * - * @param transaction mint transaction. - * @return A CompletableFuture that resolves to the inclusion proof response from the aggregator. + * @param requestId request id + * @param trustBase root trust base + * @return A CompletableFuture that resolves to true if state is spent, false otherwise. */ - public CompletableFuture getInclusionProof(MintTransaction transaction) { - return this.client.getInclusionProof( - RequestId.create( - MintSigningService.create(transaction.getData().getTokenId()).getPublicKey(), - transaction.getData().getSourceState() - ) - ); + public CompletableFuture isStateSpent(RequestId requestId, RootTrustBase trustBase) { + return this.getInclusionProof(requestId) + .thenApply(inclusionProof -> { + InclusionProofVerificationStatus result = inclusionProof.getInclusionProof().verify(requestId, trustBase); + switch (result) { + case OK: + return true; + case PATH_NOT_INCLUDED: + return false; + default: + throw new RuntimeException( + String.format("Inclusion proof verification failed with status %s", result) + ); + } + }); } + /** - * Get inclusion proof for transfer transaction. This method does not check if transaction is owned by public key. + * Get inclusion proof for current token state. * - * @param transaction transfer transaction. - * @param publicKey public key of transaction sender + * @param token token + * @param publicKey public key + * @param trustBase trustBase * @return A CompletableFuture that resolves to the inclusion proof response from the aggregator. */ - public CompletableFuture getInclusionProof( - TransferTransaction transaction, - byte[] publicKey + public CompletableFuture isStateSpent( + Token token, + byte[] publicKey, + RootTrustBase trustBase ) { - Predicate predicate = PredicateEngineService.createPredicate(transaction.getData().getSourceState().getPredicate()); + Predicate predicate = PredicateEngineService.createPredicate(token.getState().getPredicate()); if (!predicate.isOwner(publicKey)) { throw new IllegalArgumentException("Given key is not owner of the token."); } - return this.client.getInclusionProof( - RequestId.create( - publicKey, - transaction.getData().getSourceState() - ) - ); + return this.isStateSpent(RequestId.create(publicKey, token.getState()), trustBase); } /** - * Get inclusion proof for current token state. + * Check if token id is already minted. * - * @param token token. - * @param publicKey public key of transaction sender - * @return A CompletableFuture that resolves to the inclusion proof response from the aggregator. + * @param tokenId token id + * @param trustBase root trust base + * @return A CompletableFuture that resolves to true if token id is spent, false otherwise. */ - public CompletableFuture getInclusionProof( - Token token, - byte[] publicKey - ) { - Predicate predicate = PredicateEngineService.createPredicate(token.getState().getPredicate()); - if (!predicate.isOwner(publicKey)) { - throw new IllegalArgumentException("Given key is not owner of the token."); - } - - return this.client.getInclusionProof( + public CompletableFuture isMinted(TokenId tokenId, RootTrustBase trustBase) { + return this.isStateSpent( RequestId.create( - publicKey, - token.getState() - ) + MintSigningService.create(tokenId).getPublicKey(), + MintTransactionState.create(tokenId) + ), + trustBase ); } diff --git a/src/test/java/org/unicitylabs/sdk/common/CommonTestFlow.java b/src/test/java/org/unicitylabs/sdk/common/CommonTestFlow.java index 72fe9d7..56c2b2b 100644 --- a/src/test/java/org/unicitylabs/sdk/common/CommonTestFlow.java +++ b/src/test/java/org/unicitylabs/sdk/common/CommonTestFlow.java @@ -70,20 +70,8 @@ public void testTransferFlow() throws Exception { ALICE_SECRET ); + assertTrue(this.client.isMinted(aliceToken.getId(), this.trustBase).get()); assertTrue(aliceToken.verify(this.trustBase).isSuccessful()); - assertEquals( - InclusionProofVerificationStatus.OK, - this.client.getInclusionProof(aliceToken.getGenesis()) - .get() - .getInclusionProof() - .verify( - RequestId.create( - MintSigningService.create(aliceToken.getId()).getPublicKey(), - aliceToken.getGenesis().getData().getSourceState() - ), - this.trustBase - ) - ); String bobNameTag = UUID.randomUUID().toString(); @@ -127,19 +115,7 @@ public void testTransferFlow() throws Exception { ); // Check if alice token is spent - assertEquals( - InclusionProofVerificationStatus.OK, - this.client.getInclusionProof(aliceToken, aliceSigningService.getPublicKey()) - .get() - .getInclusionProof() - .verify( - RequestId.create( - aliceSigningService.getPublicKey(), - aliceToken.getState() - ), - this.trustBase - ) - ); + assertTrue(this.client.isStateSpent(aliceToken, aliceSigningService.getPublicKey(), this.trustBase).get()); // Bob prepares to receive the token DirectAddress bobAddress = UnmaskedPredicateReference.create( From 7980e6823ff53777506afd4d2913222db89a1674 Mon Sep 17 00:00:00 2001 From: Martti Marran Date: Fri, 14 Nov 2025 12:56:57 +0200 Subject: [PATCH 2/2] Update code identation for submitCommitment function --- src/main/java/org/unicitylabs/sdk/StateTransitionClient.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java b/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java index b3f58a3..5bba9b8 100644 --- a/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java +++ b/src/main/java/org/unicitylabs/sdk/StateTransitionClient.java @@ -50,7 +50,7 @@ public StateTransitionClient(AggregatorClient client) { * @return A CompletableFuture that resolves to the response from the aggregator. */ public - CompletableFuture submitCommitment(MintCommitment commitment) { + CompletableFuture submitCommitment(MintCommitment commitment) { return this.client.submitCommitment( commitment.getRequestId(), commitment.getTransactionData().calculateHash(),