wavecli exitGetExitPlan
GetExitPlan previews unilateral-exit readiness for one VTXO. The response includes CPFP fee input requirements and, when funding is needed, a backing-wallet address callers can fund before forced unroll.
Endpoints
rpc GetExitPlan(GetExitPlanRequest) returns (GetExitPlanResponse)POST/v1/wallet/exit-planExamples
wavecli exit plan --outpoint 4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0wavecli exit plan --outpoint 4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0conn, err := grpc.NewClient("localhost:10029",
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatal(err)
}
defer conn.Close()
client := wavewalletrpc.NewWalletServiceClient(conn)
ctx := context.Background()
req := &wavewalletrpc.GetExitPlanRequest{
Outpoints: []string{"4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0"},
ConfTarget: 6,
}
resp, err := client.GetExitPlan(ctx, req)
if err != nil {
log.Fatal(err)
}
fmt.Println(resp)import grpc
import wallet_pb2
import wallet_pb2_grpc
channel = grpc.insecure_channel('localhost:10029')
stub = wallet_pb2_grpc.WalletServiceStub(channel)
request = wallet_pb2.GetExitPlanRequest(
outpoints=["4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0"],
conf_target=6,
)
response = stub.GetExitPlan(request)
print(response)const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');
const packageDefinition = protoLoader.loadSync('wallet.proto');
const { wavewalletrpc } = grpc.loadPackageDefinition(packageDefinition);
const client = new wavewalletrpc.WalletService(
'localhost:10029',
grpc.credentials.createInsecure(),
);
const request = {
"outpoints": [
"4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0"
],
"conf_target": 6
};
// Calls wavewalletrpc.WalletService.GetExitPlan.
client.getExitPlan(request, (err, response) => {
if (err) throw err;
console.log(response);
});curl -X POST http://localhost:10031/v1/wallet/exit-plan \
-H 'Content-Type: application/json' \
-d '{"outpoints":["4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0"],"conf_target":6}'const res = await fetch('http://localhost:10031/v1/wallet/exit-plan', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
"outpoints": [
"4b2e9f1a7c3d5e6f8091a2b3c4d5e6f70819a2b3c4d5e6f708192a3b4c5d6e7f:0"
],
"conf_target": 6
}),
});
const getExitPlanResponse = await res.json();RequestGetExitPlanRequest
GetExitPlanRequest lists the VTXO outpoints to preview for unilateral exit via WalletService.GetExitPlan.
| Field | Type | Description |
|---|---|---|
outpoints | repeated string | outpoints are the VTXO outpoints to preview, each "txid:index". |
conf_target | uint32 | conf_target selects the fee-estimation target in blocks. Zero uses the daemon's default unroll confirmation target. |
ResponseGetExitPlanResponse
GetExitPlanResponse returns one ExitPlanEntry per requested outpoint, plus the batch-level fee estimate and aggregate funding verdict.
| Field | Type | Description |
|---|---|---|
plans | repeated ExitPlanEntry | plans holds one entry per requested outpoint, in request order. Entries are evaluated against a running wallet allocation: each feasible exit reserves its fee inputs before the next entry is planned, so a per-entry verdict reflects the wallet left after the earlier entries in the batch notionally start. |
fee_rate_sat_per_vbyte | int64 | fee_rate_sat_per_vbyte is the shared chain fee estimate used for all entries. |
can_start | bool | can_start is the AND over every entry that has no per-outpoint error. Because entries draw from a shared wallet via the running allocation above, it is true only when every requested exit can be funded simultaneously, not merely one at a time. |
total_funding_shortfall_sat | int64 | total_funding_shortfall_sat is the summed shortfall across entries under simultaneous funding, so it already accounts for fee inputs two outpoints would otherwise both claim. |
total_recommended_funding_sat | int64 | total_recommended_funding_sat is the summed recommended funding across entries. |
ExitPlanEntrymessage
ExitPlanEntry is the per-outpoint unilateral-exit readiness preview: the backing-wallet fee requirements and, when an unroll job already exists, its current state.
| Field | Type | Description |
|---|---|---|
outpoint | string | outpoint is the previewed VTXO outpoint, formatted as "txid:index". |
funding_address | string | funding_address is empty when can_start is true (no shortfall, so no address is allocated). |
required_confirmations | uint32 | required_confirmations is the number of confirmations a backing-wallet UTXO must have before it can fund the unroll CPFP. |
required_fee_utxo_count | uint32 | required_fee_utxo_count is the number of distinct confirmed wallet UTXOs the exit needs to fund CPFP fees, one per unroll ancestry path. |
usable_fee_utxo_count | uint32 | usable_fee_utxo_count is the number of confirmed wallet UTXOs large enough to each fund a CPFP child on their own. |
recommended_utxo_amount_sat | int64 | recommended_utxo_amount_sat is the suggested value in satoshis for each fee-funding UTXO the caller provisions. |
recommended_total_funding_sat | int64 | recommended_total_funding_sat is the suggested total backing-wallet funding in satoshis: recommended_utxo_amount_sat times the required fee UTXO count. |
funding_shortfall_sat | int64 | funding_shortfall_sat is the additional backing-wallet funding in satoshis needed before this exit can start. Zero when can_start is true. |
can_start | bool | can_start is true when the backing wallet already has the fee inputs and balance to fund this exit's forced unroll. |
exit_job_found | bool | exit_job_found is true when an unroll job already exists for this outpoint, in which case exit_status, sweep_txid, and last_error describe it. |
exit_status | ExitJobStatus | exit_status is the current phase of the existing unroll job, when exit_job_found is true. |
sweep_txid | string | sweep_txid is the hex-encoded txid of the existing job's sweep transaction, set once it has been broadcast. |
last_error | string | last_error is the failure reason of the existing unroll job, when it is in a failed state. |
error | string | error is a per-outpoint failure (e.g. VTXO not found) so one bad outpoint does not fail the whole batch. Empty on success. |
infeasibility_reason | ExitInfeasibilityReason | infeasibility_reason explains why can_start is false. It may be a structural block - a dust or uneconomical VTXO the wallet can never make exitable (funding_shortfall_sat is zero) - or a funding shortfall the wallet could cover (wallet underfunded or too few fee inputs, also reflected in funding_shortfall_sat). It is EXIT_INFEASIBILITY_REASON_UNSPECIFIED when can_start is true. |
ExitJobStatusenum
ExitJobStatus collapses the underlying unroll job phases to a short wallet-facing string set.
| Name | Number | Description |
|---|---|---|
EXIT_JOB_STATUS_UNSPECIFIED | 0 | EXIT_JOB_STATUS_UNSPECIFIED - the proto zero value; no job phase has been reported. |
EXIT_JOB_STATUS_PENDING | 1 | EXIT_JOB_STATUS_PENDING - job created but recovery transactions not yet materialized. |
EXIT_JOB_STATUS_MATERIALIZING | 2 | EXIT_JOB_STATUS_MATERIALIZING - recovery transactions are being broadcast and confirmed on-chain. |
EXIT_JOB_STATUS_CSV_PENDING | 3 | EXIT_JOB_STATUS_CSV_PENDING - recovery transactions confirmed, waiting for the CSV delay to expire. |
EXIT_JOB_STATUS_SWEEPING | 4 | EXIT_JOB_STATUS_SWEEPING - CSV delay expired, sweep transaction is being broadcast/confirmed. |
EXIT_JOB_STATUS_COMPLETED | 5 | EXIT_JOB_STATUS_COMPLETED - terminal: the sweep confirmed and the funds are in the on-chain wallet. |
EXIT_JOB_STATUS_FAILED | 6 | EXIT_JOB_STATUS_FAILED - terminal: an unrecoverable error occurred. |
ExitInfeasibilityReasonenum
ExitInfeasibilityReason enumerates why a unilateral exit was judged infeasible. It mirrors the daemon's unroll feasibility verdict so a caller can distinguish a dust/uneconomical block (no amount of wallet funding fixes it) from a plain funding shortfall.
| Name | Number | Description |
|---|---|---|
EXIT_INFEASIBILITY_REASON_UNSPECIFIED | 0 | EXIT_INFEASIBILITY_REASON_UNSPECIFIED - the proto zero value; the exit is feasible, or the block is a plain funding shortfall reported via funding_shortfall_sat instead. |
EXIT_INFEASIBILITY_REASON_SWEEP_BELOW_DUST | 1 | EXIT_INFEASIBILITY_REASON_SWEEP_BELOW_DUST - the swept output, after deducting the sweep fee from the VTXO value, would fall at or below the dust limit, so the sweep could never relay. The exit is impossible regardless of wallet funding. |
EXIT_INFEASIBILITY_REASON_UNECONOMICAL | 2 | EXIT_INFEASIBILITY_REASON_UNECONOMICAL - the total on-chain cost to recover the VTXO exceeds the configured fraction of its value. The exit could technically complete but burns more than it returns. |
EXIT_INFEASIBILITY_REASON_WALLET_UNDERFUNDED | 3 | EXIT_INFEASIBILITY_REASON_WALLET_UNDERFUNDED - the confirmed on-chain wallet balance is too small to cover the CPFP fees. Funding the wallet and retrying resolves it (also reported via funding_shortfall_sat). |
EXIT_INFEASIBILITY_REASON_WALLET_TOO_FEW_INPUTS | 4 | EXIT_INFEASIBILITY_REASON_WALLET_TOO_FEW_INPUTS - the wallet has fewer usable confirmed UTXOs than the VTXO has independent ancestry paths, so it lacks distinct CPFP fee inputs. |