Skip to content
Merged
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
90 changes: 49 additions & 41 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,39 +19,44 @@ A Java SDK for interacting with the Unicity network, enabling state transitions

## Installation

### Gradle (JVM)
### Using JitPack

Add JitPack repository:
```groovy
dependencies {
implementation 'com.unicity.sdk:unicity-sdk:1.0-SNAPSHOT'
repositories {
maven { url 'https://jitpack.io' }
}
```

### Gradle (Android)
#### For Android Projects:
```groovy
dependencies {
implementation 'com.github.unicitynetwork:java-state-transition-sdk:1.1:android'
}
```

#### For JVM Projects:
```groovy
dependencies {
implementation 'com.unicity.sdk:unicity-sdk-android:1.0-SNAPSHOT'
implementation 'com.github.unicitynetwork:java-state-transition-sdk:1.1:jvm'
}
```

### Maven (JVM)
### Using Local Maven

```xml
<dependency>
<groupId>com.unicity.sdk</groupId>
<artifactId>unicity-sdk</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
```groovy
dependencies {
implementation 'org.unicitylabs:java-state-transition-sdk:1.1-SNAPSHOT'
}
```

## Quick Start

### Initialize the Client

```java
import com.unicity.sdk.StateTransitionClient;
import com.unicity.sdk.api.AggregatorClient;
import org.unicitylabs.sdk.StateTransitionClient;
import org.unicitylabs.sdk.api.AggregatorClient;

// Connect to the Unicity test network
String aggregatorUrl = "https://gateway-test.unicity.network";
Expand All @@ -62,12 +67,12 @@ StateTransitionClient client = new StateTransitionClient(aggregatorClient);
### Mint a Token

```java
import com.unicity.sdk.token.*;
import com.unicity.sdk.token.fungible.*;
import com.unicity.sdk.transaction.*;
import com.unicity.sdk.predicate.*;
import com.unicity.sdk.shared.signing.SigningService;
import com.unicity.sdk.shared.hash.HashAlgorithm;
import org.unicitylabs.sdk.token.*;
import org.unicitylabs.sdk.token.fungible.*;
import org.unicitylabs.sdk.transaction.*;
import org.unicitylabs.sdk.predicate.*;
import org.unicitylabs.sdk.signing.SigningService;
import org.unicitylabs.sdk.hash.HashAlgorithm;

// Create signing service from secret
byte[] secret = "your-secret-key".getBytes();
Expand Down Expand Up @@ -227,7 +232,7 @@ Token<?> updatedToken = client.finishTransaction(
### Clone the Repository

```bash
git clone https://github.com/unicity/java-state-transition-sdk.git
git clone https://github.com/unicitynetwork/java-state-transition-sdk.git
cd java-state-transition-sdk
```

Expand All @@ -247,7 +252,7 @@ cd java-state-transition-sdk
./gradlew integrationTest

# Run E2E tests against deployed aggregator
AGGREGATOR_URL=https://gateway-test.unicity.network ./gradlew integrationTest --tests "*E2ETest"
AGGREGATOR_URL=https://gateway-test.unicity.network ./gradlew integrationTest
```

## Platform-Specific Considerations
Expand All @@ -268,23 +273,25 @@ The standard JVM version uses:

## Architecture

The SDK follows a modular architecture:
The SDK follows a modular architecture under `org.unicitylabs.sdk`:

- **`api`**: Core API interfaces and aggregator client
- **`api`**: Core API interfaces and aggregator client
- **`address`**: Address schemes and implementations
- **`predicate`**: Ownership predicates (Masked, Unmasked, Burn) and authorization
- **`serializer`**: CBOR and JSON serializers for tokens and transactions
- **`token`**: Token-related classes (TokenId, TokenType, TokenState) and fungible token support
- **`transaction`**: Transaction types (Mint, Transfer, Commitment) and builders
- **`shared`**: Common utilities
- `cbor`: CBOR encoding/decoding
- `hash`: Cryptographic hashing (SHA256, SHA224, SHA384, SHA512, RIPEMD160)
- `jsonrpc`: JSON-RPC transport layer
- `signing`: Digital signature support (ECDSA secp256k1)
- `smt`/`smst`: Sparse Merkle Tree implementations
- `util`: BitString and other utilities
- **`utils`**: Helper utilities
- **`address`**: Address schemes and implementations (DirectAddress, ProxyAddress)
- **`hash`**: Cryptographic hashing (SHA256, SHA224, SHA384, SHA512, RIPEMD160)
- **`jsonrpc`**: JSON-RPC transport layer with OkHttp
- **`mtree`**: Merkle tree implementations
- `plain`: Sparse Merkle Tree (SMT)
- `sum`: Sparse Merkle Sum Tree (SMST)
- **`predicate`**: Ownership predicates (Masked, Unmasked, Burn, Default)
- **`serializer`**: CBOR and JSON serializers hierarchy
- `cbor/`: CBOR serializers for all domain objects
- `json/`: JSON serializers for all domain objects
- **`signing`**: Digital signature support (ECDSA secp256k1)
- **`token`**: Token types including fungible tokens and nametags
- `fungible`: Fungible token support with CoinId and TokenCoinData
- **`transaction`**: Transaction types and builders
- `split`: Token splitting functionality with TokenSplitBuilder
- **`util`**: Utilities including BitString and HexConverter

## Error Handling

Expand Down Expand Up @@ -326,9 +333,10 @@ The SDK includes comprehensive test suites:
Located in `src/test/java`, these test individual components in isolation.

### Integration Tests
Located in `src/test/java/com/unicity/sdk/integration`:
- `TokenIntegrationTest`: Tests against Docker-based local aggregator
- `TokenE2ETest`: Tests against deployed aggregator (requires `AGGREGATOR_URL` env var)
Located in `src/test/java/org/unicitylabs/sdk/`:
- `integration/TokenIntegrationTest`: Tests against Docker-based local aggregator
- `e2e/TokenE2ETest`: E2E tests using CommonTestFlow (requires `AGGREGATOR_URL` env var)
- `e2e/BasicE2ETest`: Basic connectivity and performance tests

### Running Tests

Expand All @@ -340,7 +348,7 @@ Located in `src/test/java/com/unicity/sdk/integration`:
./gradlew integrationTest

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

## License
Expand Down
96 changes: 87 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,17 @@ dependencies {
testImplementation("org.testcontainers:testcontainers:1.19.8")
testImplementation("org.testcontainers:junit-jupiter:1.19.8")
testImplementation("org.testcontainers:mongodb:1.19.8")
testImplementation("org.awaitility:awaitility:4.2.0")
testImplementation("org.slf4j:slf4j-simple:2.0.13")
testImplementation("com.google.guava:guava:33.0.0-jre")

// ✅ Cucumber for BDD
testImplementation("io.cucumber:cucumber-java:7.27.2")
testImplementation("io.cucumber:cucumber-junit-platform-engine:7.27.2")

// JUnit 5 Suite annotations
testImplementation("org.junit.platform:junit-platform-suite:1.13.4")

checkstyle("com.puppycrawl.tools:checkstyle:10.26.1")
}

Expand All @@ -70,9 +78,16 @@ tasks.test {
excludeTags("integration")
}
maxHeapSize = "1024m"
systemProperty("cucumber.junit-platform.naming-strategy", "long")
systemProperties(System.getProperties().toMap() as Map<String, Any>)

filter {
excludeTestsMatching("*CucumberTestRunner*")
excludeTestsMatching("*Cucumber*")
}
}

tasks.withType<Checkstyle>{
tasks.withType<Checkstyle> {
reports {
xml.required.set(false)
html.required.set(true)
Expand All @@ -85,6 +100,69 @@ tasks.register<Test>("integrationTest") {
}
maxHeapSize = "2048m"
shouldRunAfter(tasks.test)
systemProperty("cucumber.junit-platform.naming-strategy", "long")

filter {
excludeTestsMatching("*CucumberTestRunner*")
excludeTestsMatching("*Cucumber*")
}
}

tasks.register<Test>("tokenTests") {
useJUnitPlatform()
maxHeapSize = "1024m"
systemProperty("cucumber.junit-platform.naming-strategy", "long")
// Set the system properties first
systemProperties = System.getProperties().toMap() as Map<String, Any>
// Then override the specific cucumber filter (this will take precedence)
systemProperty("cucumber.filter.tags", "@token-transfer")

filter {
includeTestsMatching("*CucumberTestRunner*")
}
shouldRunAfter(tasks.test)
}

tasks.register<Test>("aggregatorTests") {
useJUnitPlatform()
maxHeapSize = "1024m"
systemProperty("cucumber.junit-platform.naming-strategy", "long")
// Set the system properties first
systemProperties = System.getProperties().toMap() as Map<String, Any>
systemProperty("cucumber.filter.tags", "@aggregator-connectivity")

filter {
includeTestsMatching("*CucumberTestRunner*")
}
shouldRunAfter(tasks.test)
}

tasks.register<Test>("advancedTokenTests") {
useJUnitPlatform()
maxHeapSize = "1024m"
systemProperty("cucumber.junit-platform.naming-strategy", "long")
// Set the system properties first
systemProperties = System.getProperties().toMap() as Map<String, Any>
systemProperty("cucumber.filter.tags", "@advanced-token")

filter {
includeTestsMatching("*CucumberTestRunner*")
}
shouldRunAfter(tasks.test)
}

// ✅ Run all cucumber tests (including integration)
tasks.register<Test>("allCucumberTests") {
useJUnitPlatform()
maxHeapSize = "1024m"
systemProperty("cucumber.junit-platform.naming-strategy", "long")
systemProperties = System.getProperties().toMap() as Map<String, Any>
systemProperty("cucumber.filter.tags", "not @ignore")

filter {
includeTestsMatching("*CucumberTestRunner*")
}
shouldRunAfter(tasks.test)
}

// Create separate JARs for each platform
Expand Down Expand Up @@ -112,40 +190,40 @@ publishing {
groupId = project.group.toString()
artifactId = "java-state-transition-sdk"
version = project.version.toString()

// Use the Java component as base - this includes the standard JAR
from(components["java"])

// Add Android JAR as additional artifact with classifier
artifact(tasks["androidJar"]) {
classifier = "android"
}
// Add JVM JAR as additional artifact with classifier

// Add JVM JAR as additional artifact with classifier
artifact(tasks["jvmJar"]) {
classifier = "jvm"
}

// Simple POM configuration without XML manipulation
pom {
name.set("Unicity State Transition SDK")
description.set("Unicity State Transition SDK for Android and JVM")
url.set("https://github.com/unicitynetwork/java-state-transition-sdk")

licenses {
license {
name.set("MIT License")
url.set("https://opensource.org/licenses/MIT")
}
}

developers {
developer {
id.set("unicitynetwork")
name.set("Unicity Network")
}
}

scm {
connection.set("scm:git:git://github.com/unicitynetwork/java-state-transition-sdk.git")
developerConnection.set("scm:git:ssh://github.com/unicitynetwork/java-state-transition-sdk.git")
Expand Down
25 changes: 25 additions & 0 deletions src/test/java/org/unicitylabs/sdk/e2e/CucumberTestRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.unicitylabs.sdk.e2e;

import io.cucumber.junit.platform.engine.Constants;
import org.junit.platform.suite.api.*;

/**
* Updated Cucumber test runner configuration for E2E tests.
* This class configures the test execution environment and feature discovery
* with the new shared step definitions approach.
*/
@Suite
@IncludeEngines("cucumber")
@SelectPackages("org.unicitylabs.sdk.features")
@ConfigurationParameter(key = Constants.GLUE_PROPERTY_NAME, value = "org.unicitylabs.sdk.e2e.steps,org.unicitylabs.sdk.e2e.steps.shared,org.unicitylabs.sdk.e2e.config")
@ConfigurationParameter(key = Constants.PLUGIN_PROPERTY_NAME, value = "pretty,html:build/cucumber-reports/cucumber.html,json:build/cucumber-reports/cucumber.json")
@ConfigurationParameter(key = Constants.EXECUTION_DRY_RUN_PROPERTY_NAME, value = "false")
@ConfigurationParameter(key = Constants.PLUGIN_PUBLISH_QUIET_PROPERTY_NAME, value = "true")
public class CucumberTestRunner {
static {
// Only set default tags if no tags are specified
if (System.getProperty("cucumber.filter.tags") == null) {
System.setProperty("cucumber.filter.tags", "not @ignore");
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package org.unicitylabs.sdk.e2e.config;

import org.unicitylabs.sdk.e2e.context.TestContext;
import io.cucumber.java.Before;
import io.cucumber.java.After;

/**
* Cucumber configuration for dependency injection and test lifecycle management.
* This ensures that TestContext is properly shared across all step definition classes.
*/
public class CucumberConfiguration {

private static TestContext testContext = new TestContext();

/**
* Provides a shared TestContext instance for all step definition classes.
* This method will be called by step definition classes to get
* the shared TestContext instance.
*/
public static TestContext getTestContext() {
return testContext;
}

/**
* Hook that runs before each scenario to reset the test context.
* This ensures each scenario starts with a clean state.
*/
@Before
public void setUp() {
testContext.clearTestState(); // Clear test state but keep clients if they exist
System.out.println("Test context cleared for new scenario");
}

/**
* Hook that runs after each scenario for cleanup.
* This can be used for any additional cleanup if needed.
*/
@After
public void tearDown() {
// Optional: Add any cleanup logic here
// For now, we keep the context alive for potential debugging
System.out.println("Scenario completed");
}

/**
* Hook that runs after scenarios tagged with @reset to completely reset the context.
*/
@After("@reset")
public void fullReset() {
testContext.reset();
System.out.println("Full context reset performed");
}
}
Loading
Loading