Skip to content

StealthTransfer

Defined in: ootle/src/stealth/transfer.ts:99

Fluent builder for a confidential (stealth) transfer.

Supports the full input/output matrix: spend revealed input (withdraw from a vault) and/or one or more confidential UTXOs (spendStealthInput), emit one or more stealth outputs (+ optional revealed change), and a fee. The balance equation (revealed-in + stealth-in == stealth-out + revealed-out) must hold; the stealth-input value is carried by each input’s mask, recovered by the authorizer.

const spec = await new StealthTransfer(provider, resourceAddress)
.spendRevealedInput(account, 5n * TARI)
.toStealthOutput(createOutput({ destination, amount: 3n * TARI, resourceAddress }))
.toRevealedOutput(1n * TARI) // revealed change back to `account`
.payFeeFromRevealed(1n * TARI)
.prepare();

new StealthTransfer(provider, resourceAddress, crypto?): StealthTransfer

Defined in: ootle/src/stealth/transfer.ts:113

Provider

Read-only chain access (used by prepare to resolve inputs).

string

The resource being transferred.

StealthCryptoProvider = ...

Injectable crypto seam; defaults to WasmStealthCrypto. Tests pass a FakeStealthCrypto for WASM-free runs.

StealthTransfer

payFeeFromRevealed(amount): this

Defined in: ootle/src/stealth/transfer.ts:178

Pay the transaction fee from the revealed source account (max amount).

bigint

this

if no source account is set, or amount is not > 0.


prepare(): Promise<StealthTransferSpec>

Defined in: ootle/src/stealth/transfer.ts:258

Assemble the unsigned transaction and the (incomplete) transfer statement.

  1. validate (≥1 input, ≥1 stealth output);
  2. generate the outputs statement (+ aggregated output mask) via the crypto seam;
  3. build the inputs statement (concatenated commitments + revealed input amount) and assemble an incomplete StealthTransferStatement (balanceProof: undefined);
  4. emit instructions: revealed withdrawsaveVar → the native StealthTransfer instruction (+ deposit the revealed-change bucket);
  5. register the revealed source account + every vault it references as tx inputs (otherwise the engine rejects withdraw / pay_fee with SubstateNotFound);
  6. register each stealth input’s UTXO substate id as a tx input so it is resolved / locked alongside the revealed inputs;
  7. resolve substate versions via the provider;
  8. return the StealthTransferSpec.

Stealth-input values are carried by their masks (recovered later by the authorizer), not as amounts — there is no balance-equation check here when stealth inputs are present, because the builder does not know their values; the balance proof (which the authorizer signs over the recovered masks) is the authoritative check.

Promise<StealthTransferSpec>

if the builder is invalid (no inputs, no outputs, no stealth output, unbalanced revealed-only transfer, or revealed change without a revealed source) or prepare has already been called once.


spendRevealedInput(account, amount): this

Defined in: ootle/src/stealth/transfer.ts:139

Withdraw amount of the transfer’s resource from account’s revealed vault.

All revealed input must come from a single account (the fee/change source). Calling this more than once accumulates the amount but the account must be the same.

string

bigint

this

if amount is not > 0, or a different source account is supplied on a second call.


spendStealthInput(ownerAddr, commitment): this

Defined in: ootle/src/stealth/transfer.ts:215

Spend a confidential UTXO owned by ownerAddr, identified by its 32-byte commitment.

Repeatable: each call adds another stealth input. Inputs are keyed by their commitment hex alone and de-duplicated — a second call with the same commitment throws, regardless of the owner label. A commitment uniquely identifies a UTXO within the builder’s single resource and a UTXO has exactly one owner, so the same commitment under two different owner labels is still the same UTXO; accepting it twice would register the substate id twice and emit the commitment twice in the inputs statement — a self-double-spend the engine rejects. The owner address is recorded alongside the input so the authorizer can pick the one-time spend signer for each.

The input’s value contributes to the balance equation via its mask (recovered by the authorizer when it unblinds the UTXO), so the builder does not need the amount here — only the commitment.

string

Uint8Array

this

if commitment is not 32 bytes, or the same commitment is added twice (under any owner).


toRevealedOutput(amount): this

Defined in: ootle/src/stealth/transfer.ts:165

Add revealed (un-confidential) change, returned to the revealed source account.

bigint

this

if amount is not > 0.


toStealthOutput(spec): this

Defined in: ootle/src/stealth/transfer.ts:155

Add a stealth output to create (repeatable).

Output

this


withBuilder(fn): this

Defined in: ootle/src/stealth/transfer.ts:190

Escape hatch over the inner TransactionBuilder (e.g. extra instructions).

(b) => TransactionBuilder

this