Table of Contents

Class UnilateralExitService

Namespace
NArk.Core.Services
Assembly
NArk.Core.dll

Orchestrates unilateral exit for VTXOs. Broadcasts the chain of virtual txs from commitment to leaf, waits for CSV timelock, then claims funds on-chain.

public class UnilateralExitService
Inheritance
UnilateralExitService
Inherited Members

Constructors

UnilateralExitService(IClientTransport, IVirtualTxStorage, IExitSessionStorage, IVtxoStorage, IContractStorage, IBitcoinBlockchain, IWalletProvider, VirtualTxService, IVtxoChainProofProvider, IFeeWallet?, ILogger<UnilateralExitService>?)

Orchestrates unilateral exit for VTXOs. Broadcasts the chain of virtual txs from commitment to leaf, waits for CSV timelock, then claims funds on-chain.

public UnilateralExitService(IClientTransport transport, IVirtualTxStorage virtualTxStorage, IExitSessionStorage exitSessionStorage, IVtxoStorage vtxoStorage, IContractStorage contractStorage, IBitcoinBlockchain blockchain, IWalletProvider walletProvider, VirtualTxService virtualTxService, IVtxoChainProofProvider proofProvider, IFeeWallet? feeWallet = null, ILogger<UnilateralExitService>? logger = null)

Parameters

transport IClientTransport
virtualTxStorage IVirtualTxStorage
exitSessionStorage IExitSessionStorage
vtxoStorage IVtxoStorage
contractStorage IContractStorage
blockchain IBitcoinBlockchain
walletProvider IWalletProvider
virtualTxService VirtualTxService
proofProvider IVtxoChainProofProvider
feeWallet IFeeWallet
logger ILogger<UnilateralExitService>

Methods

BroadcastExitChainAsync(string, OutPoint, BitcoinAddress, CancellationToken)

Stateless equivalent of StartExitAsync(string, IReadOnlyCollection<OutPoint>, BitcoinAddress, CancellationToken) + the Broadcasting phase of ProgressExitsAsync(CancellationToken): fetches the virtual-tx chain from arkd, broadcasts the next off-chain row that isn't already on-chain, and returns an ExitPlan the caller persists in whatever form they prefer.

public Task<ExitPlan> BroadcastExitChainAsync(string walletId, OutPoint vtxoOutpoint, BitcoinAddress claimAddress, CancellationToken cancellationToken = default)

Parameters

walletId string
vtxoOutpoint OutPoint
claimAddress BitcoinAddress
cancellationToken CancellationToken

Returns

Task<ExitPlan>

Remarks

The SDK doesn't write anything exit-specific in this call — IExitSessionStorage and IVirtualTxStorage are not touched.

Broadcasts at most one off-chain row per call, not the whole chain. Bitcoin Core's TRUC/v3 policy (BIP 431) caps a transaction at 1 unconfirmed descendant; since every off-chain row gets its own CPFP child, broadcasting two chained rows before the first confirms would give it a second unconfirmed descendant and get rejected — the same constraint go-sdk and ts-sdk's unroll sessions are built around. Callers must call this repeatedly (polling GetTxStatusAsync or simply retrying on an interval) until the whole chain has confirmed.

Once the leaf-tx confirms on-chain and the CSV timelock has matured, feed the returned ExitPlan to ClaimMaturedExitAsync(ExitPlan, CancellationToken) to finalise the exit.

ClaimMaturedExitAsync(ExitPlan, CancellationToken)

Stateless counterpart to the Claimable phase of ProgressExitsAsync(CancellationToken). Verifies the leaf tx referenced by plan is confirmed and that the CSV timelock has matured, then builds, signs, and broadcasts the claim transaction.

public Task<string?> ClaimMaturedExitAsync(ExitPlan plan, CancellationToken cancellationToken = default)

Parameters

plan ExitPlan
cancellationToken CancellationToken

Returns

Task<string>

Txid of the broadcast claim transaction, or null when CSV hasn't matured yet (caller should poll again later).

Remarks

The server's unilateral-exit delay is a BIP-68 relative timelock and may be height- or time-based. Maturity is evaluated accordingly (heights for the former, median time past for the latter) — see CsvMaturity.

Exceptions

InvalidOperationException

VTXO / contract / signer state required to build the claim is unavailable, the leaf tx is not yet confirmed at all (callers should distinguish "not yet" from a hard failure via the message), or the exit delay is time-based and the backend could not resolve the leaf block's median time past.

NotSupportedException

The exit delay is time-based and the configured IBitcoinBlockchain does not implement GetMedianTimePastAsync(uint, CancellationToken).

GetActiveSessionsAsync(string?, CancellationToken)

Get current exit sessions, optionally filtered by wallet.

public Task<IReadOnlyList<ExitSession>> GetActiveSessionsAsync(string? walletId = null, CancellationToken cancellationToken = default)

Parameters

walletId string
cancellationToken CancellationToken

Returns

Task<IReadOnlyList<ExitSession>>

ProgressExitsAsync(CancellationToken)

Progress all active exit sessions. Call this periodically. Advances sessions through: Broadcasting → AwaitingCsvDelay → Claimable → Claiming → Completed.

public Task ProgressExitsAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken

Returns

Task

StartExitAsync(string, IReadOnlyCollection<OutPoint>, BitcoinAddress, CancellationToken)

Start unilateral exit for specific VTXOs.

public Task<IReadOnlyList<ExitSession>> StartExitAsync(string walletId, IReadOnlyCollection<OutPoint> vtxoOutpoints, BitcoinAddress claimAddress, CancellationToken cancellationToken = default)

Parameters

walletId string
vtxoOutpoints IReadOnlyCollection<OutPoint>
claimAddress BitcoinAddress
cancellationToken CancellationToken

Returns

Task<IReadOnlyList<ExitSession>>

StartExitForWalletAsync(string, BitcoinAddress, CancellationToken)

Start unilateral exit for all unspent VTXOs in a wallet.

public Task<IReadOnlyList<ExitSession>> StartExitForWalletAsync(string walletId, BitcoinAddress claimAddress, CancellationToken cancellationToken = default)

Parameters

walletId string
claimAddress BitcoinAddress
cancellationToken CancellationToken

Returns

Task<IReadOnlyList<ExitSession>>