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
31 changes: 31 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
"name": "State Transition Java SDK",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/java:21-bullseye",

"features": {
"ghcr.io/devcontainers/features/java:1": {
"version": "none",
"installMaven": "false",
"installGradle": "true"
}
},

// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],

// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "java -version",

// Configure tool-specific properties.
"customizations" : {
"jetbrains" : {
"backend" : "IntelliJ"
}
},

// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
243 changes: 1 addition & 242 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,247 +56,6 @@ dependencies {

## Quick Start

### Util methods

```java
private static final SecureRandom RANDOM = new SecureRandom();

/**
* Generate random bytes of specified length.
*/
public static byte[] randomBytes(int length) {
byte[] bytes = new byte[length];
RANDOM.nextBytes(bytes);
return bytes;
}
```

### Initialize the Client

```java
// Connect to the Unicity test network
String aggregatorUrl = "https://gateway-test.unicity.network";
DefaultAggregatorClient aggregatorClient = new DefaultAggregatorClient(aggregatorUrl);
StateTransitionClient client = new StateTransitionClient(aggregatorClient);

// Create root trust base from classpath
RootTrustBase trustbase = RootTrustBase.fromJson(
new String(getClass().getResourceAsStream("/trust-base.json").readAllBytes())
);
```

### Mint a Token

```java
byte[] secret = "minter_secret".getBytes(StandardCharsets.UTF_8);
// Generate data for token
TokenId tokenId = new TokenId(randomBytes(32));
TokenType tokenType = new TokenType(randomBytes(32));
byte[] tokenData = "token immutable data".getBytes(StandardCharsets.UTF_8);
TokenCoinData coinData = new TokenCoinData(
Map.of(
new CoinId("coin".getBytes()), BigInteger.valueOf(100),
new CoinId("second coin".getBytes()), BigInteger.valueOf(5)
)
);

// Create predicate for initial state and use its reference as address
byte[] nonce = randomBytes(32);
// Create key pair from nonce and secret
SigningService signingService = SigningService.createFromMaskedSecret(secret, nonce);
MaskedPredicate predicate = MaskedPredicate.create(
tokenId,
tokenType,
signingService,
HashAlgorithm.SHA256,
nonce
);

byte[] salt = randomBytes(32);
MintCommitment<?> commitment = MintCommitment.create(
new MintTransaction.Data<>(
tokenId,
tokenType,
tokenData,
coinData,
predicate.getReference().toAddress(),
salt,
null,
null
)
);

// Submit mint transaction using StateTransitionClient
SubmitCommitmentResponse response = client
.submitCommitment(commitment)
.get();

if (response.getStatus() != SubmitCommitmentStatus.SUCCESS) {
throw new Exception(
String.format(
"Failed to submit mint commitment: %s",
response.getStatus()
)
);
}

// Wait for inclusion proof
InclusionProof inclusionProof = InclusionProofUtils.waitInclusionProof(
client,
trustBase,
commitment
).get();

// Create mint transaction
Token<?> token = Token.create(
trustBase,
// Create initial state with transaction data
new TokenState(predicate, null),
commitment.toTransaction(inclusionProof)
);
```

### Get Block Height

```java
Long blockHeight = client.getAggregatorClient().getBlockHeight().get();
System.out.println("Current block height: "+blockHeight);
```

### Transfer a Token

```java
byte[] senderSecret = secret;
byte[] senderNonce = nonce;

String recipientNametag = "RECIPIENT";
byte[] recipientData = "Custom data".getBytes(StandardCharsets.UTF_8);
DataHash recipientDataHash = new DataHasher(HashAlgorithm.SHA256)
.update(recipientData)
.digest();

byte[] salt = randomBytes(32);

// Submit transfer transaction
TransferCommitment transferCommitment = TransferCommitment.create(
token,
ProxyAddress.create(recipientNametag),
salt,
recipientDataHash,
null,
SigningService.createFromMaskedSecret(senderSecret, senderNonce)
);

SubmitCommitmentResponse transferResponse = this.client.submitCommitment(transferCommitment).get();
if (transferResponse.getStatus() != SubmitCommitmentStatus.SUCCESS) {
throw new Exception(
String.format(
"Failed to submit transfer commitment: %s",
transferResponse.getStatus()
)
);
}

// Create transfer transaction
TransferTransaction transferTransaction = transferCommitment.toTransaction(
InclusionProofUtils.waitInclusionProof(
client,
trustBase,
transferCommitment
).get()
);

// Prepare info for sending to recipient
String transferTransactionJson = transferTransaction.toJson();
String tokenJson = token.toJson();
```

### Receive the token

```java
String recipientNametag = "RECIPIENT";
byte[] receiverSecret = "RECEIVER_SECRET".getBytes();

Token<?> token = Token.fromJson("TOKEN JSON");
TransferTransaction transaction = TransferTransaction.fromJson("TRANSFER TRANSACTION JSON");

// Create nametag token
TokenType nametagType = new TokenType(randomBytes(32));
byte[] nametagNonce = randomBytes(32);
byte[] nametagSalt = randomBytes(32);

MintCommitment<?> nametagMintCommitment = MintCommitment.create(
new MintTransaction.NametagData(
recipientNametag,
nametagType,
MaskedPredicateReference.create(
nametagType,
SigningService.createFromMaskedSecret(receiverSecret, nametagNonce),
HashAlgorithm.SHA256,
nametagNonce
).toAddress(),
nametagSalt,
UnmaskedPredicateReference.create(
token.getType(),
SigningService.createFromSecret(receiverSecret),
HashAlgorithm.SHA256
).toAddress()
)
);

// Submit nametag mint transaction using StateTransitionClient
SubmitCommitmentResponse nametagMintResponse = client.submitCommitment(nametagMintCommitment).get();
if (nametagMintResponse.getStatus() != SubmitCommitmentStatus.SUCCESS) {
throw new Exception(
String.format(
"Failed to submit nametag mint commitment: %s",
nametagMintResponse.getStatus()
)
);
}

// Wait for inclusion proof
InclusionProof inclusionProof = InclusionProofUtils.waitInclusionProof(
client,
trustBase,
nametagMintCommitment
).get();

Token<?> nametagToken = Token.create(
trustBase,
new TokenState(
MaskedPredicate.create(
nametagMintCommitment.getTransactionData().getTokenId(),
nametagMintCommitment.getTransactionData().getTokenType(),
SigningService.createFromMaskedSecret(receiverSecret, nametagNonce),
HashAlgorithm.SHA256,
nametagNonce
),
null
),
nametagMintCommitment.toTransaction(inclusionProof)
);

// Receiver finalizes the token
Token<?> finalizedToken = client.finalizeTransaction(
trustBase,
token,
new TokenState(
UnmaskedPredicate.create(
token.getId(),
token.getType(),
SigningService.createFromSecret(receiverSecret),
HashAlgorithm.SHA256,
transaction.getData().getSalt()
),
null
),
transaction,
List.of(nametagToken)
);

```

## Building from Source

### Clone the Repository
Expand Down Expand Up @@ -410,7 +169,7 @@ Located in `src/test/java/org/unicitylabs/sdk/`:
./gradlew integrationTest

# Specific test class
./gradlew test --tests "org.unicitylabs.sdk.api.RequestIdTest"
./gradlew test --tests "org.unicitylabs.sdk.api.StateIdTest"
```

## License
Expand Down
Loading
Loading