Staking & cold staking¶
navio-sdk 0.4.0+
Staked-output tracking, delegation and unstaking ship in navio-sdk 0.4.0, which requires @nav-io/navio-blsct 1.3.0.
A light wallet can lock NAV as a staked commitment and delegate it to a third-party staker (cold staking): the staker can stake the output but never spend it, and the wallet keeps its spending keys and can unstake at any time. This mirrors navio-core's delegatestake, listdelegations and stakeunlock RPCs; see Cold staking for the operator side.
Staked balance¶
Staked commitments are recognised during sync and kept out of the spendable balance and coin selection:
await client.getStakedOutputs(); // WalletOutput[] with isStakedCommitment: true
await client.getStakedBalance(); // bigint, satoshis
client.getMinStakeAmount(); // bigint — chain minimum stake
getMinStakeAmount() returns the minStakeAmount config option if set, else the network default (10,000 NAV). Set minStakeAmount only for a chain with a different minimum, such as navio-core's blsctregtest.
Delegate stake¶
const res = await client.delegateStake({
amount: 20_000n * 100_000_000n, // satoshis, at least getMinStakeAmount()
delegateKey: '<96-hex G1 point>', // published by the staking operator
rewardAddress: 'nav1...', // optional
});
console.log(res.txId);
DelegateStakeOptions:
| Field | Type | Notes |
|---|---|---|
amount |
bigint |
Satoshis to stake; must reach the minimum stake. |
delegateKey |
string |
The staker's delegation public key, a non-identity G1 point (96 hex). |
rewardAddress |
string? |
Where the staker is asked to pay rewards. Defaults (when omitted or empty) to the wallet's primary address. Advisory: the staker controls its own coinbase. |
selectedUtxos |
string[]? |
Fund the stake and fee from these outputs. |
randomBlindingKeys |
boolean? |
See Output authorship. |
The staked commitment goes to the wallet's staking sub-address (account -2) and carries an encrypted delegation payload for the staker. Each call adds a new staked commitment; unlike delegatestake, existing commitments are not folded in. A reward address with null keys is refused.
List delegations¶
const delegations = await client.getStakeDelegations();
for (const d of delegations) {
console.log(d.outputHash, d.amount, d.delegateKey, d.rewardAddress, d.blockHeight);
}
Like listdelegations, it reads the payload of each unspent staked commitment with the wallet's view key, from outputs sync already stored. It needs no extra state and works after a restore from seed. A delegation appears once its output confirms. A payload the wallet cannot open is skipped, with one warning per session.
Unstake¶
// Unstake everything
await client.unstake();
// Partial: unlock 5,000 NAV from specific commitments, restake the rest
await client.unstake({
stakedOutputs: ['<outputHash>', '<outputHash>'],
amount: 5_000n * 100_000_000n,
});
| Field | Default | Notes |
|---|---|---|
stakedOutputs |
every confirmed staked commitment | Commitments to spend, by outputHash. |
amount |
the whole of the spent commitments | NAV to unlock, fee included. |
randomBlindingKeys |
false |
See Output authorship. |
Unstaking spends the commitments, which also revokes their delegation. The unlocked NAV, less the fee, returns to the staking address as a normal output. A partial unstake stakes the remainder again; it must still reach the minimum stake. Unlike stakeunlock, the remainder keeps the delegation the spent commitments share; unstake refuses commitments that are delegated differently, or whose delegation the wallet cannot read. Only confirmed commitments can be unstaked.
Upgrading to 0.4.0¶
getBalance()andgetUnspentOutputs()no longer include staked commitments; before 0.4.0 they were counted as spendable NAV.- Existing databases are upgraded on open: SQLite gains an
is_staked_commitmentcolumn (added and backfilled in one transaction) and the IndexedDB database moves to version 5. - Custom
IWalletDBimplementations must addgetOutputData(outputHash), setisStakedCommitmenton everyWalletOutput, and leave staked commitments out ofgetBalance()andgetUnspentOutputs().
Regtest¶
npm run test:cold-staking:regtest in the navio-sdk repo runs delegation, listing and unstaking against a local naviod -chain=blsctregtest. It finds naviod on PATH by default.