-
Notifications
You must be signed in to change notification settings - Fork 0
Stake SOL with a Validator
pzupan edited this page Jul 5, 2026
·
1 revision
A complete example that creates a new stake account, funds it, and delegates it to a validator — all in two transactions. The first transaction allocates and initialises the account; the second delegates it once the first has confirmed.
require 'base64'
require 'solana/ruby/kit'
Kit = Solana::Ruby::Kit
Stake = Kit::Programs::StakeProgram
TxMsg = Kit::TransactionMessages
Txns = Kit::Transactions
rpc = Kit::Rpc::Client.new(Kit::RpcTypes.devnet)
# ── 1. Signers ────────────────────────────────────────────────────────────────
# Your funding wallet — pays rent and signs as the fee payer.
owner = Kit::Signers.create_key_pair_signer_from_bytes(File.binread('wallet.bin'))
# A fresh keypair for the stake account itself (must sign the createAccount ix).
stake_keypair = Kit::Signers.generate_key_pair_signer
# The validator you want to delegate to (look this up via get_vote_accounts).
vote_address = Kit::Addresses.address('VALIDATOR_VOTE_ADDRESS_HERE')
# ── 2. How many lamports to stake? ────────────────────────────────────────────
# The account must be rent-exempt (200 bytes) plus however much you want to stake.
rent_exempt = rpc.get_minimum_balance_for_rent_exemption(Stake::STAKE_ACCOUNT_SPACE)
stake_amount = 500_000_000 # 0.5 SOL on top of rent exemption
lamports = rent_exempt + stake_amount
# ── 3. Build the first transaction: create + initialise the stake account ──────
create_ixs = Stake.create_account_instructions(
from: owner.address,
stake_account: stake_keypair.address,
authorized: owner.address, # owner is both staker and withdrawer
lamports: lamports
)
bh = rpc.get_latest_blockhash
constraint = TxMsg::BlockhashLifetimeConstraint.new(
blockhash: bh.value.blockhash,
last_valid_block_height: bh.value.last_valid_block_height
)
create_msg = Kit::Functional.pipe(
TxMsg.create_transaction_message(version: :legacy),
->(tx) { TxMsg.set_fee_payer(owner.address, tx) },
->(tx) { TxMsg.set_blockhash_lifetime(constraint, tx) },
->(tx) { TxMsg.append_instructions(tx, create_ixs) }
)
create_tx = Txns.compile_transaction_message(create_msg)
# Both owner and stake_keypair must sign: owner funds the account,
# stake_keypair authorises the createAccount on its own address.
create_signed = Txns.sign_transaction(
[owner.key_pair.signing_key, stake_keypair.key_pair.signing_key],
create_tx
)
create_sig = rpc.send_transaction(
Base64.strict_encode64(Txns.wire_encode_transaction(create_signed))
)
puts "Create stake account: #{create_sig}"
Kit::TransactionConfirmation.wait_for_confirmation(
rpc, create_sig,
commitment: :confirmed,
timeout_secs: 60
)
puts "Stake account confirmed."
# ── 4. Build the second transaction: delegate to a validator ──────────────────
delegate_ix = Stake.delegate_instruction(
stake_account: stake_keypair.address,
vote_account: vote_address,
authorized: owner.address # must sign as the authorised staker
)
bh = rpc.get_latest_blockhash
delegate_constraint = TxMsg::BlockhashLifetimeConstraint.new(
blockhash: bh.value.blockhash,
last_valid_block_height: bh.value.last_valid_block_height
)
delegate_msg = Kit::Functional.pipe(
TxMsg.create_transaction_message(version: :legacy),
->(tx) { TxMsg.set_fee_payer(owner.address, tx) },
->(tx) { TxMsg.set_blockhash_lifetime(delegate_constraint, tx) },
->(tx) { TxMsg.append_instructions(tx, [delegate_ix]) }
)
delegate_tx = Txns.compile_transaction_message(delegate_msg)
delegate_signed = Txns.sign_transaction([owner.key_pair.signing_key], delegate_tx)
delegate_sig = rpc.send_transaction(
Base64.strict_encode64(Txns.wire_encode_transaction(delegate_signed))
)
puts "Delegate stake: #{delegate_sig}"
Kit::TransactionConfirmation.wait_for_confirmation(
rpc, delegate_sig,
commitment: :confirmed,
timeout_secs: 60
)
puts "Delegation confirmed. Stake account: #{stake_keypair.address}"Note Stake activation takes one full epoch (roughly 2–3 days on mainnet). The account will show status
activatinguntil then.