MidnightSdk

Top-level entry point for the Midnight Android SDK.

Provides a fully standalone environment for dApps: contract execution, local proving, embedded wallet (dust fee payment), and node submission. No external wallet process (mn serve) required.

val sdk = MidnightSdk.Builder(context)
.network(MidnightNetwork.PREPROD)
.seed(mnemonicSeed)
.build()

val contract = MidnightContract.create(sdk.config) {
contractJs = assets.open("runtime/my-contract-iife.js")
address = contractAddress
coinPublicKey = sdk.coinPublicKey
// ... witnesses, private state
}

val receipt = contract.call("myCircuit", arg1) // Fully standalone
sdk.close()

Types

Link copied to clipboard
class Builder(context: Context)

Builder for MidnightSdk.

Link copied to clipboard
object Companion
Link copied to clipboard

Coarse progress stages for sendNight, for driving a UI spinner/status.

Link copied to clipboard
sealed class SendResult

Outcome of sendNight — a typed result so callers can render distinct UX.

Properties

Link copied to clipboard

HD derivation path of the access key (e.g., "m/44'/2400'/0'/5/0").

Link copied to clipboard

Access key for sigil identity — 33-byte compressed secp256k1 public key. Use this with KeyAuthorization to build delegation payloads.

Link copied to clipboard

Coin public key for circuit execution (32 bytes).

Link copied to clipboard

MidnightConfig pre-wired with the embedded wallet.

Link copied to clipboard

Registry of in-flight value-bearing operations (#261-264). Observe OperationRegistry.active / OperationRegistry.outcomes to project any UI (the wallet pill is just one consumer); enroll your own long-running work via runForegroundOperation / launchForegroundOperation to get the same process-survival + notification treatment the SDK's own send/dust/contract actions receive.

Link copied to clipboard

Proving key manager (for checking/downloading keys).

Link copied to clipboard

Shielded receive address (Bech32m-encoded, HRP mn_shield-addr_<network>).

Link copied to clipboard

Embedded wallet for direct balance/submit operations.

Link copied to clipboard

Unshielded wallet address (Bech32m-encoded).

Functions

Link copied to clipboard
suspend fun buildUnshieldedFundingJson(amount: BigInteger, tokenType: String = UtxoSpend.NATIVE_TOKEN_TYPE): String

Build the unshielded-funding JSON that lets a contract call fund the value a contract receives via receiveUnshielded (e.g. a treasury deposit). Pass the result to MidnightContract.call's unshieldedFundingJson; the native assembler adds + signs a guaranteed offer whose inputs cover amount (+ change back to this wallet).

Link copied to clipboard
fun buildUnshieldedWithdrawalJson(recipientAddressHash: ByteArray, amount: BigInteger, tokenType: String = UtxoSpend.NATIVE_TOKEN_TYPE): String

Build the unshielded-withdrawal JSON for a contract call whose circuit SENDS value out via sendUnshielded (e.g. a treasury withdrawal). Pass the result to MidnightContract.call's unshieldedWithdrawalJson; the native assembler adds a fallible offer with the recipient output (no inputs, no signature — the contract provides the value). The recipientAddressHash MUST match the recipient the contract claims (verify.rs claimed_unshielded_spends).

Link copied to clipboard

One-time pre-flight: confirm the node's ledger is coherent with the client's bundled version, so a skew surfaces as a named warning rather than an opaque Custom error: N mid-submit (#16).

Link copied to clipboard
suspend fun close()

Release all resources. Suspends because wallet.close() serializes the dust-state close against an in-flight balance (see MidnightWallet.close) — a teardown that raced a running balance is exactly what threw "DustLocalState has been closed" on PreProd.

Link copied to clipboard

Ids of protocol sagas that started but haven't completed — candidates to resume on app start. The dApp re-launches each via runProtocol with the same id; the ledger- anchored doneWhens skip the already-done steps. (Saga definitions are code the dApp re-provides — only ids are persisted.)

Link copied to clipboard
fun launchForegroundOperation(label: String, completionLabel: String? = null, contentIntent: PendingIntent? = null, block: suspend () -> Unit): Job

Fire-and-forget runForegroundOperation on the SDK's lifecycle scope: returns a Job immediately, and the tracked work keeps running (under the foreground service) even after the caller leaves the screen. Failures are logged, not thrown.

Link copied to clipboard
fun launchProtocol(id: String, label: String, block: suspend ProtocolScope.() -> Unit): Job

Fire-and-forget runProtocol on the SDK's lifecycle scope (survives the caller); #253.

Link copied to clipboard
fun launchSendNight(toAddress: String, amount: BigInteger, onProgress: (MidnightSdk.SendProgress) -> Unit? = null, onResult: (MidnightSdk.SendResult) -> Unit? = null): Job

Fire-and-forget sendNight on the SDK's lifecycle scope so the transfer survives the caller leaving the app (#263). Returns immediately; the durable lifecycle (foreground service + finalization notification) is owned by the operation registry. onProgress is best-effort for an in-app live view while the caller is still around; onResult delivers the typed SendResult when done (also on the SDK scope, so it survives the caller — a dead caller's callback is simply a no-op).

Link copied to clipboard

Observe the chain's new-block stream (#255). Each emission is a freshly-produced BlockInfo (height, hash, timestamp, ledger params). This is the same stream that drives com.midnight.kuira.core.compact.MidnightContract.observeLedger; exposed here so a dApp can react to chain progress directly (e.g. a tip indicator, time-gating). Cold — collecting opens an indexer subscription; cancel the collection to close it.

Link copied to clipboard

Register this wallet's NIGHT key to generate dust against its public dust key.

Link copied to clipboard
suspend fun requestAttention(title: String, body: String? = null)

Pull the user BACK to the current foreground operation with a heads-up alert (#264 inbound) — e.g. a protocol step that needs their input, or a counterparty's move. Fires an alerting notification that taps back to the operation's screen. title/body are YOUR strings (the SDK emits none). No-op outside a tracked operation; the host suppresses it when the app is already foreground, so you can call it unconditionally.

Link copied to clipboard
suspend fun <T> runForegroundOperation(label: String, completionLabel: String? = null, contentIntent: PendingIntent? = null, block: suspend () -> T): T

Run block as a tracked foreground operation (#261-264) and return its result.

Link copied to clipboard
suspend fun runProtocol(id: String, label: String, block: suspend ProtocolScope.() -> Unit): ProtocolResult

Run a durable, idempotent multi-step protocol saga as ONE foreground operation (#253). Each ProtocolScope.step is skipped when its doneWhen is already true on-ledger, so re-running id (after process death, or on app resume) resumes from the first not-done step with no double-submit — the chain is the journal. The inner contract.calls coalesce under this op, so it reads as ONE operation + one finalization push. label drives the notification.

Link copied to clipboard
suspend fun sendNight(toAddress: String, amount: BigInteger, onProgress: (MidnightSdk.SendProgress) -> Unit? = null): MidnightSdk.SendResult

Send unshielded NIGHT from this wallet to toAddress (#240 — Send from the wallet pill).

Link copied to clipboard
suspend fun updateOperationStage(stage: String?)

Update the live progress stage of the foreground operation the CURRENT coroutine is running inside (see runForegroundOperation) — this drives the ongoing notification text and the status-bar chip ("Submitting commit…" → "Finalizing…"). stage is YOUR string (the SDK emits none). No-op when called outside a tracked operation.