CircuitExecutor

class CircuitExecutor(context: Context, ioDispatcher: CoroutineDispatcher = Dispatchers.IO)

Executes Compact smart contract circuits on Android via QuickJS + Rust FFI.

Wraps the full lifecycle: QuickJS environment setup, native FFI registration, runtime loading, witness bridging, circuit execution, transcript transformation, and transaction assembly.

Usage:

val executor = CircuitExecutor(context)
val result = executor.executeCircuit(
contractJs = loadContractIife(),
contractAddress = "abcd...",
circuitName = "post",
circuitArgs = listOf("'Hello from Android!'"),
witnesses = mapOf("localSecretKey" to WitnessProvider {
WitnessResult(null, secretKeyBytes)
}),
initialPrivateState = "{ secretKey: new Uint8Array(32) }",
coinPublicKey = ByteArray(32),
)
// result.unprovenTxHex is ready for proving

Constructors

Link copied to clipboard
constructor(context: Context, ioDispatcher: CoroutineDispatcher = Dispatchers.IO)

Types

Link copied to clipboard
data class CircuitReadRequest(val key: String, val circuitName: String, val circuitArgs: List<String> = emptyList())

One view-circuit invocation inside a readManyCircuits batch, identified by key.

Link copied to clipboard
data class CircuitReadResult(val json: String?, val error: String?)

Per-key outcome of a batch read: the circuit's JSON result, or its error message.

Link copied to clipboard
object Companion

Functions

Link copied to clipboard
suspend fun executeCircuit(contractJs: String, contractAddress: String, circuitName: String, circuitArgs: List<String> = emptyList(), witnesses: Map<String, WitnessProvider>, initialPrivateState: String, coinPublicKey: ByteArray, networkId: String = "undeployed", onChainStateHex: String? = null, ledgerParametersHex: String? = null, ttlSecs: Long? = null, blockTimeSecs: Long? = null, constructorArgs: List<String> = emptyList(), unshieldedFundingJson: String? = null, unshieldedWithdrawalJson: String? = null): ExecutionResult

Execute a contract circuit and assemble an UnprovenTransaction.

Link copied to clipboard
suspend fun executeConstructor(contractJs: String, witnesses: Map<String, WitnessProvider>, initialPrivateState: String, coinPublicKey: ByteArray, networkId: String = "undeployed", verifierKeys: Map<String, String> = emptyMap(), ttlSecs: Long? = null, constructorArgs: List<String> = emptyList()): DeployExecutionResult
Link copied to clipboard
suspend fun readCircuit(contractJs: String, contractAddress: String, circuitName: String, circuitArgs: List<String> = emptyList(), initialPrivateState: String, coinPublicKey: ByteArray, onChainStateHex: String, constructorArgs: List<String> = emptyList(), networkId: String = "undeployed", witnesses: Map<String, WitnessProvider> = emptyMap()): String

Run a view/getter circuit against the on-chain state and return its RETURN value as JSON — no proving, no transaction, no submit. BigInt → decimal string, Uint8Array → hex, nested structs preserved (see jsonSafe). Lets a dApp read a contract's computed views (balances, proposals, thresholds) that aren't exposed as raw ledger fields.

Link copied to clipboard
suspend fun readCircuitLocal(contractJs: String, circuitName: String, circuitArgs: List<String> = emptyList(), initialPrivateState: String, coinPublicKey: ByteArray, constructorArgs: List<String> = emptyList(), networkId: String = "undeployed", witnesses: Map<String, WitnessProvider> = emptyMap()): String

Run a circuit LOCALLY against the contract's initialState() — no on-chain state, no fetch. The engine-level counterpart of readCircuit for state-independent (pure) circuits: it omits the onChainStateHex entirely (null → executeInQuickJs builds from initialState()), so there is no deployed instance to validate and no hex to supply.

Link copied to clipboard
suspend fun readManyCircuits(contractJs: String, contractAddress: String, requests: List<CircuitExecutor.CircuitReadRequest>, initialPrivateState: String, coinPublicKey: ByteArray, onChainStateHex: String, constructorArgs: List<String> = emptyList(), networkId: String = "undeployed", witnesses: Map<String, WitnessProvider> = emptyMap()): Map<String, CircuitExecutor.CircuitReadResult>

Run MANY view circuits in ONE engine session against ONE on-chain state — one runtime + contract load, one initialState, one state snapshot — instead of a full engine boot and state fetch per read. Every circuit runs against its own NATIVE CLONE of the fetched state, so reads are isolated (a circuit's context mutations can't leak into the next) and all see the SAME snapshot (no mixed-block reads within a batch).