Module: Solana::SystemProgram

Defined in:
lib/solana/system_program.rb

Overview

System Program instruction encoders — the subset needed for DURABLE NONCE accounts (plus CreateAccount, which nonce creation needs). Mirrors the SplToken encoder pattern: each method returns a { program_id, accounts, data } hash for Transaction#add_instruction.

A durable nonce lets a transaction stay valid INDEFINITELY (until consumed) instead of expiring with a recent blockhash (~90s) — the canonical pattern for long / async / multi-party signing. A nonce-anchored tx sets recentBlockhash = the account’s stored nonce and MUST carry advance_nonce_account as its FIRST instruction, signed by the nonce authority.

Instruction data is ‘u32 LE index` + fields (the System Program’s bincode layout). Indices: CreateAccount 0, AdvanceNonceAccount 4, WithdrawNonceAccount 5, InitializeNonceAccount 6, AuthorizeNonceAccount 7. Each encoder is byte-match tested against a known-good @solana/web3.js reference before being trusted.

Constant Summary collapse

PROGRAM_ID =

32 zero bytes

Transaction::SYSTEM_PROGRAM_ID
RECENT_BLOCKHASHES_SYSVAR =
Keypair.decode_base58("SysvarRecentB1ockHashes11111111111111111111")
RENT_SYSVAR =
Transaction::SYSVAR_RENT_PUBKEY
NONCE_ACCOUNT_LENGTH =
80

Class Method Summary collapse

Class Method Details

.advance_nonce_account(nonce:, authority:) ⇒ Object

AdvanceNonceAccount (ix 4): MUST be the first instruction of any tx anchored on this nonce. The ‘authority` signs it.



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/solana/system_program.rb', line 41

def (nonce:, authority:)
  {
    program_id: PROGRAM_ID,
    accounts: [
      { pubkey: normalize(nonce),                     is_signer: false, is_writable: true },
      { pubkey: RECENT_BLOCKHASHES_SYSVAR,            is_signer: false, is_writable: false },
      { pubkey: normalize(authority),                 is_signer: true,  is_writable: false }
    ],
    data: u32(4)
  }
end

.authorize_nonce_account(nonce:, authority:, new_authority:) ⇒ Object

AuthorizeNonceAccount (ix 7): rotate the nonce authority. Current authority signs.



83
84
85
86
87
88
89
90
91
92
# File 'lib/solana/system_program.rb', line 83

def (nonce:, authority:, new_authority:)
  {
    program_id: PROGRAM_ID,
    accounts: [
      { pubkey: normalize(nonce),     is_signer: false, is_writable: true },
      { pubkey: normalize(authority), is_signer: true,  is_writable: false }
    ],
    data: u32(7) + normalize(new_authority)
  }
end

.create_account(from:, new_account:, lamports:, space:, owner:) ⇒ Object

CreateAccount (ix 0): fund + allocate ‘space` bytes owned by `owner`. Both `from` (payer) and `new_account` must sign.



27
28
29
30
31
32
33
34
35
36
37
# File 'lib/solana/system_program.rb', line 27

def (from:, new_account:, lamports:, space:, owner:)
  data = u32(0) + u64(lamports) + u64(space) + normalize(owner)
  {
    program_id: PROGRAM_ID,
    accounts: [
      { pubkey: normalize(from),        is_signer: true, is_writable: true },
      { pubkey: normalize(), is_signer: true, is_writable: true }
    ],
    data: data
  }
end

.initialize_nonce_account(nonce:, authority:) ⇒ Object

InitializeNonceAccount (ix 6): turn a freshly-created account into a nonce account owned by ‘authority`. Paired with create_account in one tx.



70
71
72
73
74
75
76
77
78
79
80
# File 'lib/solana/system_program.rb', line 70

def (nonce:, authority:)
  {
    program_id: PROGRAM_ID,
    accounts: [
      { pubkey: normalize(nonce),          is_signer: false, is_writable: true },
      { pubkey: RECENT_BLOCKHASHES_SYSVAR, is_signer: false, is_writable: false },
      { pubkey: RENT_SYSVAR,               is_signer: false, is_writable: false }
    ],
    data: u32(6) + normalize(authority)
  }
end

.normalize(value) ⇒ Object

base58 string / Keypair / 32-byte binary → 32-byte binary.



100
101
102
103
104
105
106
107
108
109
110
# File 'lib/solana/system_program.rb', line 100

def normalize(value)
  if value.is_a?(Keypair)
    value.public_key_bytes
  elsif value.is_a?(String) && value.bytesize == 32
    value.b
  elsif value.is_a?(String)
    Keypair.decode_base58(value)
  else
    value
  end
end

.u32(n) ⇒ Object

— helpers ————————————————————–



96
# File 'lib/solana/system_program.rb', line 96

def u32(n) = [n].pack("V")

.u64(n) ⇒ Object



97
# File 'lib/solana/system_program.rb', line 97

def u64(n) = [n].pack("Q<")

.withdraw_nonce_account(nonce:, to:, authority:, lamports:) ⇒ Object

WithdrawNonceAccount (ix 5): reclaim lamports from the nonce account.



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/solana/system_program.rb', line 54

def (nonce:, to:, authority:, lamports:)
  {
    program_id: PROGRAM_ID,
    accounts: [
      { pubkey: normalize(nonce),          is_signer: false, is_writable: true },
      { pubkey: normalize(to),             is_signer: false, is_writable: true },
      { pubkey: RECENT_BLOCKHASHES_SYSVAR, is_signer: false, is_writable: false },
      { pubkey: RENT_SYSVAR,               is_signer: false, is_writable: false },
      { pubkey: normalize(authority),      is_signer: true,  is_writable: false }
    ],
    data: u32(5) + u64(lamports)
  }
end