Skip to content

Messages ​

Every execute message, who can call it, and what it does. All messages use snake_case — the CosmWasm wire convention.

User ​

stake ​

json
{ "stake": {} }

Attach ATOM as funds. Mints vATOM at the current rate and delegates across the validator set.

Refused when: paused, the rewards vault is unset, the amount is below the minimum, the deposit cap would be exceeded, or the amount is too small to mint any vATOM. Also refused while a previous cohort is still winding down; the departing cohort's batches must all finalize first. See errors.

When it is the first stake after a total exit, it additionally disposes of the rewards vault's balance to the community pool in the same transaction, reported as orphaned_rewards_disposed.

redeem ​

json
{ "redeem": { "receiver": null } }

Attach vATOM as funds. Burns it, records the ATOM owed at the current rate, and adds the request to the open batch. receiver may nominate another address that can claim; null means the sender. Either can claim.

The chain undelegation is deferred to process_unbond_batch.

claim ​

json
{ "claim": { "request_id": 7 } }

Pays out a finalized withdrawal. Callable by the owner or the receiver.

Refused when: the batch is not finalized, the withdrawal is not mature, or it is already claimed.

Permissionless ​

Anyone may call these. See keeping it running.

compound ​

json
{ "compound": { "start_after": null, "limit": 30 } }

Withdraws staking rewards to the vault for a page of validators. Paginated by index; default page 30, maximum 64. Iterates live delegations, not the configured set.

Each withdrawal is isolated, so one un-withdrawable validator cannot abort the call.

restake_rewards ​

json
{ "restake_rewards": {} }

Sweeps the vault and re-delegates it across the set, raising the pool without minting vATOM. The lump is recognised into the rate linearly over 24 hours.

Refused while a vesting window is still running.

sweep_orphaned_rewards ​

json
{ "sweep_orphaned_rewards": {} }

Sends the rewards vault's entire balance to the community pool. Only callable while no vATOM is outstanding, when that balance was earned by holders who have all since exited and belongs to nobody.

Not required to reopen deposits — the first stake after a total exit disposes of the vault balance itself, in the same transaction, so there is no window in which a donation could block it. This is for disposing of that balance when nobody is depositing.

reconcile ​

json
{ "reconcile": {} }

Re-prices the pool against the live delegation, lowering it to reflect slashing. Splits any shortfall proportionally between continuing holders and the open batch. Only ever lowers.

process_unbond_batch ​

json
{ "process_unbond_batch": {} }

Closes the open batch, dispatches one undelegation per validator proportional to current delegation, and opens a fresh batch. This is when the unbonding clock starts.

Refused when the batch is not old enough, is empty, or a validator is already at the 7-entry unbonding limit.

finalize_unbond_batch ​

json
{ "finalize_unbond_batch": { "batch_id": 3 } }

Settles a matured batch by measuring the contract's actual balance. Mandatory before any claim from that batch.

Two calls. The first records an arrival observation (action = observe_arrival, settled = false); a call at any later height settles (settled = true). Necessary because transactions run before the staking module delivers matured ATOM — see stage 3.

Refused when more than one batch has arrived, or the batch's maturity is a forecast — both need the governed path.

Admin ​

set_rewards_vault ​

json
{ "set_rewards_vault": { "vault": "cosmos1…", "expected_code_id": 42 } }

Binds the vault and points the reward withdraw-address at it. Required before staking. expected_code_id is mandatory and verified on chain, along with the vault being immutable.

set_paused ​

json
{ "set_paused": { "paused": true } }

set_deposit_cap ​

json
{ "set_deposit_cap": { "cap": "1000000000000" } }

null uncaps. In uatom.

update_config ​

json
{ "update_config": {
    "admin": null,
    "guardian": null,
    "clear_guardian": false,
    "min_stake_amount": null,
    "min_redeem_amount": null,
    "unbond_batch_seconds": null
} }

null leaves a field unchanged. The unbonding period is deliberately not updatable.

guardian appoints the guardian; clear_guardian removes it entirely. Two fields rather than one because null has to keep meaning "unchanged" for callers that omit it — and because pointing the guardian at the admin's own address is not retirement: it stops being equivalent the moment the admin role moves, leaving a former admin holding pause and validator-removal authority. Rotate both together, or clear it explicitly.

Sending both is refused, not resolved: a request that names a guardian and also asks to clear one states two intentions, and picking either silently would let a malformed rotation report success while leaving the emergency role empty.

update_validators ​

Also clears a halt left by a guardian's removal: declaring a set with weights is the review the halt waits for. There is no separate resume message, and no guardian message that lifts it.

json
{ "update_validators": { "validators": [ { "address": "cosmosvaloper1…", "weight_bps": 10000 } ] } }

Weights must sum to 10000. Every validator must be bonded on chain.

admin_finalize_unbond_batches ​

json
{ "admin_finalize_unbond_batches": { "finalizations": [
  { "batch_id": 3, "slashing_effect": "1.0", "accept_shortfall": false }
] } }

Must cover every batch whose ATOM has arrived. See stage 3. Subject to the same two-call arrival rule as the permissionless path: being admin does not make the balance evidence arrive any sooner.

admin_finalize_unbond_batch ​

json
{ "admin_finalize_unbond_batch": { "batch_id": 3, "slashing_effect": "1.0", "accept_shortfall": false } }

Convenience form for one batch, with the same requirement — it refuses unless that batch is the only one whose ATOM has arrived.

admin_redelegate ​

json
{ "admin_redelegate": {
    "src_validator": "cosmosvaloper1…",
    "dst_validator": "cosmosvaloper1…",
    "amount": null
} }

Move an existing delegation from one validator to another. null moves everything the chain says is there, slash-adjusted.

src may be a validator that has already been removed from the set — that is the point. dst must be in the set, so stake is never scattered across validators the configured allocation would not have chosen.

This is the protocol's only fast exit from a bad validator: removing one from the set stops future delegation but leaves existing stake in place, whereas a redelegation takes effect immediately on the Hub and does not restart anyone's unbonding clock.

Guardian ​

A second key, whose entire power is to make the contract do less. Every message below is also callable by the admin — a guardian is a restriction of the admin, not a separate authority.

There is no guardian message to unpause, raise a cap, add a validator, move funds or transfer a role. That absence is the security property: a stolen guardian key has nothing to steal with.

guardian → pause ​

json
{ "guardian": { "pause": {} } }

Freezes staking, redeeming and claiming. One-way — unpausing is set_paused, which is admin-only, so whoever raised the alarm does not also decide it is over.

guardian → lower_deposit_cap ​

json
{ "guardian": { "lower_deposit_cap": { "cap": "1000000000" } } }

Reduces the cap, or introduces one where the pool was uncapped. Refused unless it is strictly a reduction. Existing positions are untouched; a cap only refuses new deposits.

guardian → remove_validators ​

json
{ "guardian": { "remove_validators": { "validators": ["cosmosvaloper1…"] } } }

Drops validators from the set so no further stake is delegated to them, and halts new delegation until an admin calls update_validators.

Surviving weights are re-normalised in proportion to what they held; the caller does not supply new weights. That alone is not enough, though — the survivors absorb the removed share, so reducing the set concentrates it, and reducing it to one validator would point everything at that one. Hence the halt: stake and restake_rewards are refused with new delegation is halted… until an admin declares a set with weights.

redeem and claim are unaffected, deliberately. At least one validator must remain, and naming one that is not in the set is an error rather than a no-op.

Governs future delegations only; use admin_redelegate to move what is already staked.

See also ​

Running on a testnet. See the risks page for what holding vATOM involves.