Algorand Integration

This guide covers the Algorand blockchain integration for TrustWeave. The Algorand plugin provides blockchain anchoring support for Algorand mainnet, testnet, and betanet chains.

Overview

The chains/plugins/algorand module provides a complete implementation of TrustWeave’s BlockchainAnchorClient interface using Algorand blockchain. This integration enables you to:

  • Anchor data to Algorand mainnet, testnet, or betanet
  • Use Algorand transaction note fields to store payload data
  • Leverage Algorand’s fast transaction confirmation times
  • Support type-safe configuration with AlgorandOptions
  • Auto-discover Algorand adapter via SPI

Installation

Add the Algorand module to your dependencies:

1
2
3
4
5
6
7
8
9
dependencies {
    implementation("com.trustweave.chains:algorand:1.0.0-SNAPSHOT")
    implementation("com.trustweave:trustweave-anchor:1.0.0-SNAPSHOT")
    implementation("com.trustweave:trustweave-common:1.0.0-SNAPSHOT")
    implementation("com.trustweave:trustweave-json:1.0.0-SNAPSHOT")

    // Algorand SDK
    implementation("com.algorand:algosdk:2.7.0")
}

Configuration

Basic Configuration

The Algorand adapter supports type-safe configuration using AlgorandOptions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import com.trustweave.algorand.*
import com.trustweave.anchor.*
import com.trustweave.anchor.options.AlgorandOptions

// Create type-safe options
val options = AlgorandOptions(
    algodUrl = "https://testnet-api.algonode.cloud",
    indexerUrl = "https://testnet-idx.algonode.cloud",  // Optional
    privateKey = "base64-encoded-private-key"
)

// Create anchor client
val chainId = "algorand:testnet"
val client = AlgorandBlockchainAnchorClient(chainId, options)

Pre-configured Networks

1
2
3
4
5
6
7
8
9
10
11
12
13
// Algorand testnet (recommended for development)
val testnetOptions = AlgorandOptions(
    algodUrl = "https://testnet-api.algonode.cloud",
    privateKey = "..."
)
val testnetClient = AlgorandBlockchainAnchorClient("algorand:testnet", testnetOptions)

// Algorand mainnet
val mainnetOptions = AlgorandOptions(
    algodUrl = "https://mainnet-api.algonode.cloud",
    privateKey = "..."
)
val mainnetClient = AlgorandBlockchainAnchorClient("algorand:mainnet", mainnetOptions)

SPI Auto-Discovery

When the chains/plugins/algorand module is on the classpath, Algorand adapter is automatically discoverable:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import com.trustweave.anchor.*
import com.trustweave.anchor.options.AlgorandOptions
import java.util.ServiceLoader

// Discover Algorand provider
val providers = ServiceLoader.load(BlockchainAnchorClientProvider::class.java)
val algorandProvider = providers.find { it.supportsChain("algorand:testnet") }

// Create client with type-safe options
val options = AlgorandOptions(
    algodUrl = "https://testnet-api.algonode.cloud",
    privateKey = "..."
)

val client = algorandProvider?.create("algorand:testnet", options)

Usage Examples

Anchoring Data

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
import com.trustweave.algorand.*
import com.trustweave.anchor.*
import com.trustweave.anchor.options.AlgorandOptions
import kotlinx.coroutines.runBlocking

runBlocking {
    // Create client
    val options = AlgorandOptions(
        algodUrl = "https://testnet-api.algonode.cloud",
        privateKey = "..."
    )
    val client = AlgorandBlockchainAnchorClient("algorand:testnet", options)

    // Anchor data
    val payload = "Hello, Algorand!".toByteArray()
    val result = client.writePayload(payload)

    result.fold(
        onSuccess = { anchorResult ->
            println("Anchored to: ${anchorResult.anchorRef.chainId}")
            println("Transaction hash: ${anchorResult.anchorRef.transactionHash}")
            println("Block height: ${anchorResult.anchorRef.metadata?.get("blockHeight")}")
        },
        onFailure = { error ->
            println("Anchoring failed: ${error.message}")
        }
    )
}

Reading Anchored Data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import com.trustweave.anchor.*

val anchorRef = AnchorRef(
    chainId = "algorand:testnet",
    transactionHash = "abc123...",
    metadata = mapOf("blockHeight" to 12345L)
)

val result = client.readPayload(anchorRef)

result.fold(
    onSuccess = { data ->
        println("Read payload: ${data.toString(Charsets.UTF_8)}")
    },
    onFailure = { error ->
        println("Read failed: ${error.message}")
    }
)

Using with TrustWeave Facade

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
import com.trustweave.TrustWeave
import com.trustweave.algorand.*
import com.trustweave.anchor.options.AlgorandOptions
import kotlinx.coroutines.runBlocking

runBlocking {
    // Setup Algorand client
    val options = AlgorandOptions(
        algodUrl = "https://testnet-api.algonode.cloud",
        privateKey = "..."
    )
    val client = AlgorandBlockchainAnchorClient("algorand:testnet", options)

    // Register with TrustWeave
    val TrustWeave = TrustWeave.create()
    // Register during TrustWeave.create { }
    val TrustWeave = TrustWeave.create {
        blockchains {
            "algorand:testnet" to client
        }
    }

    // Anchor credential
    val credential = /* your credential */
    val anchorResult = trustWeave.blockchains.anchor(
        data = credential,
        serializer = VerifiableCredential.serializer(),
        chainId = "algorand:testnet"
    )

    anchorResult.fold(
        onSuccess = { result ->
            println("Anchored: ${result.anchorRef.transactionHash}")
        },
        onFailure = { error ->
            println("Error: ${error.message}")
        }
    )
}

Type-Safe Configuration

The AlgorandOptions class provides compile-time validation:

1
2
3
4
5
val options = AlgorandOptions(
    algodUrl = "https://testnet-api.algonode.cloud",
    indexerUrl = "https://testnet-idx.algonode.cloud",  // Optional
    privateKey = "base64-encoded-private-key"  // Required
)

Benefits:

  • ✅ Compile-time validation of required fields
  • ✅ Type-safe configuration
  • ✅ IDE autocomplete support
  • ✅ Clear error messages for missing fields

Error Handling

The Algorand adapter provides structured error handling:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import com.trustweave.anchor.exceptions.*

try {
    val result = client.writePayload(payload)
    // Handle success
} catch (e: BlockchainTransactionException) {
    // Rich context: chainId, txHash, payloadSize
    println("Transaction failed: ${e.txHash}")
    println("Chain: ${e.chainId}")
    println("Payload size: ${e.payloadSize}")
} catch (e: BlockchainConnectionException) {
    // Connection error: endpoint
    println("Connection failed: ${e.endpoint}")
} catch (e: BlockchainConfigurationException) {
    // Configuration error: config key
    println("Config error: ${e.configKey}")
}

Supported Chains

The Algorand adapter supports:

  • algorand:mainnet – Algorand mainnet
  • algorand:testnet – Algorand testnet (recommended for development)
  • algorand:betanet – Algorand betanet

Network Endpoints

Default endpoints for each network:

  • Mainnet: https://mainnet-api.algonode.cloud
  • Testnet: https://testnet-api.algonode.cloud
  • Betanet: https://betanet-api.algonode.cloud

You can override these by providing custom URLs in AlgorandOptions.

Transaction Fees

Algorand has very low transaction fees (typically 0.001 ALGO). The adapter automatically handles fee estimation and transaction submission.

Testing

1
2
3
4
5
# Run all Algorand tests
./gradlew :chains/plugins/algorand:test

# Run EO integration test
./gradlew :chains/plugins/algorand:test --tests "AlgorandEoIntegrationTest"

Next Steps

References