Staking and Delegation
The Go SDK covers both sides of staking: operating a pool (creation, block production, decommissioning) and delegating to one. The JavaScript SDK covers the delegator side only; see the JavaScript version. The wallet-cli version, with the underlying concepts (pledge, cost per block, margin ratio, decommission key), is Managing a staking pool.
The reward split: the staker receives cost_per_block + margin × (block_reward − cost_per_block); delegators split the remainder proportionally.
Creating a pool
import "github.com/mintlayer/go-sdk/wallet"
wc := wallet.New("http://127.0.0.1:3034")
result, err := wc.CreateStakePool(ctx, wallet.CreatePoolParams{
Account: 0,
Amount: wallet.Amount{Atoms: "40000000000000"}, // 40,000 ML pledge
CostPerBlock: wallet.Amount{Atoms: "100000000"},
MarginRatioPerThousand: "100", // 10% staker cut
DecommissionAddress: decommissionAddr,
// StakerAddress / VRFPublicKey default to wallet-managed keys when nil
})
MarginRatioPerThousand is expressed in thousandths ("100" = 10%, "50" = 5%, "1000" = 100%). CostPerBlock is a flat atom amount deducted from rewards before the margin split.
Operating the pool
err = wc.StartStaking(ctx, 0) // begin producing blocks
status, _ := wc.GetStakingStatus(ctx, 0) // "Staking" | "NotStaking"
err = wc.StopStaking(ctx, 0) // stop producing; pool stays alive
pools, _ := wc.ListOwnedPools(ctx, 0)
for _, p := range pools {
fmt.Printf("pool %s pledge=%s balance=%s\n", p.PoolID, p.Pledge.Atoms, p.Balance.Atoms)
}
_, err = wc.DecommissionStakePool(ctx, wallet.DecommissionParams{
Account: 0, PoolID: "mpool1...", OutputAddress: returnAddr,
})
StopStaking pauses block production; DecommissionStakePool shuts the pool down and returns the pledge to OutputAddress after maturity. Delegators must withdraw separately.
Delegating
Create the delegation, then fund it (waiting for the creation transaction to confirm in between):
createResult, err := wc.CreateDelegation(ctx, wallet.CreateDelegationParams{
Account: 0,
Address: ownerAddr, // address that can withdraw
PoolID: "mpool1...",
})
fmt.Printf("delegation id: %s\n", createResult.DelegationID)
_, err = wc.DelegateStaking(ctx, wallet.DelegateParams{
Account: 0,
Amount: wallet.Amount{Atoms: "10000000000000"}, // 100 ML
DelegationID: createResult.DelegationID,
})
Multiple stakes to the same delegation accumulate. Withdrawing sends the coins to Address after the consensus lock period:
_, err = wc.WithdrawFromDelegation(ctx, wallet.WithdrawParams{
Account: 0, Address: recipientAddr,
Amount: wallet.Amount{Atoms: "5000000000000"}, // 50 ML
DelegationID: "mdelg1...",
})
delegations, _ := wc.ListDelegations(ctx, 0)
Reading state from the indexer
import "github.com/mintlayer/go-sdk/indexer"
idx := indexer.New("http://127.0.0.1:3000")
pool, _ := idx.GetPool(ctx, "mpool1...")
fmt.Printf("staker: %s delegations: %s\n", pool.StakerBalance.Decimal, pool.DelegationsBalance.Decimal)
count, _ := idx.GetPoolBlockStats(ctx, "mpool1...", time.Now().Add(-24*time.Hour), time.Now())
delegation, _ := idx.GetDelegation(ctx, "mdelg1...")
fmt.Printf("pool: %s balance: %s nonce: %d\n", delegation.PoolID, delegation.Balance.Decimal, delegation.NextNonce)
To walk all pools (deep listing, not just the first page), use the cursor-paginated pools pager. It follows the default by_height order; the by-pledge sort only exists on the offset-based ListPools:
pools := indexer.PoolsPager(idx, indexer.WithItems(100))
for {
page, err := pools.NextPage(ctx)
if err != nil {
return err
}
if page == nil { // nil = last page
break
}
for _, p := range page {
fmt.Printf("pool %s pledge=%s\n", p.PoolID, p.StakerBalance.Decimal)
}
}
Cursor pages are stable only once the indexer's scanner is fully caught up; during catch-up or a reorg a walk may skip or repeat a pool.
To estimate rewards: pool block stats for a time range, the pool's cost_per_block and margin from GetPool, and your delegation's share of the total pool balance.
Manual transaction building
The wasm package encodes delegation transactions without the wallet daemon: EncodeOutputCreateDelegation, EncodeOutputDelegateStaking, EncodeInputForWithdrawFromDelegation (nonce from the indexer's NextNonce). See Go SDK: Staking for the full low-level flow, and Composing UTXOs for the spend-and-recreate composition pattern.