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 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.