Your First Application
Build a complete TrustWeave application that demonstrates the full workflow: creating DIDs, computing digests, and anchoring to blockchains.
Complete Example: Verifiable Credential Workflow
This example shows how to:
- Set up services (KMS, DID method, blockchain client)
- Create a DID for an issuer
- Create a Verifiable Credential payload
- Compute a digest
- Anchor the digest to a blockchain
- Read it back and verify
The block below wires together in-memory services so you can run the whole workflow locally without external infrastructure.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import com.trustweave.anchor.*
import com.trustweave.did.*
import com.trustweave.json.DigestUtils
import com.trustweave.testkit.anchor.InMemoryBlockchainAnchorClient
import com.trustweave.testkit.did.DidKeyMockMethod
import com.trustweave.testkit.kms.InMemoryKeyManagementService
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.*
import kotlinx.serialization.Serializable
@Serializable
data class VerifiableCredentialDigest(
val vcId: String,
val vcDigest: String,
val issuer: String
)
fun main() = runBlocking {
// Step 1: Setup services
val kms = InMemoryKeyManagementService()
val didMethod = DidKeyMockMethod(kms)
val anchorClient = InMemoryBlockchainAnchorClient("algorand:mainnet")
val didRegistry = DidMethodRegistry().apply { register(didMethod) }
val blockchainRegistry = BlockchainAnchorRegistry().apply {
register("algorand:mainnet", anchorClient)
}
// Step 2: Create a DID for the issuer
val issuerDoc = didMethod.createDid()
val issuerDid = issuerDoc.id
println("Created issuer DID: $issuerDid")
// Step 3: Create a verifiable credential payload
val vcPayload = buildJsonObject {
put("vcId", "vc-12345")
put("issuer", issuerDid)
put("credentialSubject", buildJsonObject {
put("id", "subject-123")
put("type", "Person")
put("name", "Alice")
put("email", "alice@example.com")
})
put("issued", "2024-01-01T00:00:00Z")
}
// Step 4: Compute digest
val digest = DigestUtils.sha256DigestMultibase(vcPayload)
println("Computed VC digest: $digest")
// Step 5: Create digest object and anchor it
val digestObj = VerifiableCredentialDigest(
vcId = "vc-12345",
vcDigest = digest,
issuer = issuerDid
)
val anchorResult = blockchainRegistry.anchorTyped(
value = digestObj,
serializer = VerifiableCredentialDigest.serializer(),
targetChainId = "algorand:mainnet"
)
println("Anchored at: ${anchorResult.ref.txHash}")
println("Chain: ${anchorResult.ref.chainId}")
println("Timestamp: ${anchorResult.timestamp}")
// Step 6: Verify by reading back
val retrieved = blockchainRegistry.readTyped<VerifiableCredentialDigest>(
ref = anchorResult.ref,
serializer = VerifiableCredentialDigest.serializer()
)
assert(retrieved.vcDigest == digest)
assert(retrieved.issuer == issuerDid)
println("Verification successful!")
}
Result: Running the program prints the issuer DID, the anchored transaction metadata, and a final “Verification successful!” message, proving that the digest retrieved from the registry matches the original payload.
Running the Example
- Create a new Kotlin file:
TrustWeaveExample.kt - Copy the code above
- Ensure you have TrustWeave dependencies in your
build.gradle.kts - Run the application
Understanding the Code
Service Setup
Initialise the in-memory services that stand in for production infrastructure.
1
2
3
val kms = InMemoryKeyManagementService()
val didMethod = DidKeyMockMethod(kms)
val anchorClient = InMemoryBlockchainAnchorClient("algorand:mainnet")
InMemoryKeyManagementService: supplies Ed25519 keys on demand without external dependencies.DidKeyMockMethod: producesdid:keydocuments backed by the in-memory KMS.InMemoryBlockchainAnchorClient: simulates anchoring on Algorand so you can verify results instantly.- Outcome: Together they let you issue credentials and anchor digests without touching real infrastructure.
DID Creation
Mint a DID document that represents the issuer.
1
val issuerDoc = didMethod.createDid()
- What happens: the mock method generates a new key pair, constructs a DID document, and returns it.
- Result:
issuerDoc.idis the DID string you will embed in credentials and anchors.
Digest Computation
Canonicalise and hash the credential payload.
1
val digest = DigestUtils.sha256DigestMultibase(vcPayload)
- What happens: TrustWeave applies JSON Canonicalization Scheme (JCS) and then hashes the bytes with SHA-256.
- Result:
digestis a multibase string you can store or anchor; identical payloads always produce the same value.
Blockchain Anchoring
Persist the digest to the in-memory blockchain client.
1
val anchorResult = blockchainRegistry.anchorTyped(...)
- What happens: the registry serializes
VerifiableCredentialDigest, stores it through the registered client, and returns anAnchorResult. - Result:
anchorResult.refcontains the chain identifier and transaction hash you can log or share with verifiers.
Verification
Read the anchored record and compare it with the original payload.
1
val retrieved = blockchainRegistry.readTyped<VerifiableCredentialDigest>(...)
- What happens: the client fetches the payload, deserializes it, and hands it back as
VerifiableCredentialDigest. - Result: After the equality checks succeed you know the tamper-evident record matches your original digest.
Next Steps
- Explore Core Concepts for deeper understanding
- Learn about Integration Modules for production use