Skip to main content

hopper_runtime/
system.rs

1//! TEMPORARY: backend facade for System Program CPI builders.
2//!
3//! This module keeps Hopper-owned instruction semantics while execution still
4//! flows through the active backend substrate. It will be replaced by
5//! Hopper-native builders once the system-instruction surface is fully owned.
6//!
7//! Semantic CPI facades: the API is Hopper-owned (builder pattern over
8//! `AccountView` / `Address` / `Signer`), while execution is delegated to the
9//! active backend through Hopper's checked CPI semantics.
10//!
11//! Provides CreateAccount, Transfer, Assign, and Allocate builders.
12
13use crate::account::AccountView;
14use crate::address::Address;
15use crate::instruction::{InstructionAccount, InstructionView, Signer};
16use crate::ProgramResult;
17
18/// System program address: 11111111111111111111111111111111
19pub const SYSTEM_PROGRAM_ID: Address = Address::new_from_array([
20    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21]);
22
23// ── CreateAccount ────────────────────────────────────────────────────
24
25/// Builder for the system program's CreateAccount instruction.
26pub struct CreateAccount<'a, 'b> {
27    pub from: &'a AccountView,
28    pub to: &'a AccountView,
29    pub lamports: u64,
30    pub space: u64,
31    pub owner: &'b Address,
32}
33
34impl CreateAccount<'_, '_> {
35    #[inline]
36    pub fn invoke(&self) -> ProgramResult {
37        self.invoke_signed(&[])
38    }
39
40    #[inline]
41    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
42        let mut data = [0u8; 52];
43        // index 0 = CreateAccount (already zero)
44        data[4..12].copy_from_slice(&self.lamports.to_le_bytes());
45        data[12..20].copy_from_slice(&self.space.to_le_bytes());
46        data[20..52].copy_from_slice(self.owner.as_array());
47
48        let accounts = [
49            InstructionAccount::writable_signer(self.from.address()),
50            InstructionAccount::writable_signer(self.to.address()),
51        ];
52        let views = [self.from, self.to];
53        let instruction = InstructionView {
54            program_id: &SYSTEM_PROGRAM_ID,
55            data: &data,
56            accounts: &accounts,
57        };
58
59        crate::cpi::invoke_signed(&instruction, &views, signers)
60    }
61}
62
63// ── Transfer ─────────────────────────────────────────────────────────
64
65/// Builder for the system program's Transfer instruction.
66pub struct Transfer<'a> {
67    pub from: &'a AccountView,
68    pub to: &'a AccountView,
69    pub lamports: u64,
70}
71
72impl Transfer<'_> {
73    #[inline]
74    pub fn invoke(&self) -> ProgramResult {
75        self.invoke_signed(&[])
76    }
77
78    #[inline]
79    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
80        let mut data = [0u8; 12];
81        data[0] = 2;
82        data[4..12].copy_from_slice(&self.lamports.to_le_bytes());
83
84        let accounts = [
85            InstructionAccount::writable_signer(self.from.address()),
86            InstructionAccount::writable(self.to.address()),
87        ];
88        let views = [self.from, self.to];
89        let instruction = InstructionView {
90            program_id: &SYSTEM_PROGRAM_ID,
91            data: &data,
92            accounts: &accounts,
93        };
94
95        crate::cpi::invoke_signed(&instruction, &views, signers)
96    }
97}
98
99// ── Assign ───────────────────────────────────────────────────────────
100
101/// Builder for the system program's Assign instruction.
102pub struct Assign<'a, 'b> {
103    pub account: &'a AccountView,
104    pub owner: &'b Address,
105}
106
107impl Assign<'_, '_> {
108    #[inline]
109    pub fn invoke(&self) -> ProgramResult {
110        self.invoke_signed(&[])
111    }
112
113    #[inline]
114    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
115        let mut data = [0u8; 36];
116        data[0] = 1;
117        data[4..36].copy_from_slice(self.owner.as_array());
118
119        let accounts = [InstructionAccount::writable_signer(self.account.address())];
120        let views = [self.account];
121        let instruction = InstructionView {
122            program_id: &SYSTEM_PROGRAM_ID,
123            data: &data,
124            accounts: &accounts,
125        };
126
127        crate::cpi::invoke_signed(&instruction, &views, signers)
128    }
129}
130
131// ── Allocate ─────────────────────────────────────────────────────────
132
133/// Builder for the system program's Allocate instruction.
134pub struct Allocate<'a> {
135    pub account: &'a AccountView,
136    pub space: u64,
137}
138
139impl Allocate<'_> {
140    #[inline]
141    pub fn invoke(&self) -> ProgramResult {
142        self.invoke_signed(&[])
143    }
144
145    #[inline]
146    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
147        let mut data = [0u8; 12];
148        data[0] = 8;
149        data[4..12].copy_from_slice(&self.space.to_le_bytes());
150
151        let accounts = [InstructionAccount::writable_signer(self.account.address())];
152        let views = [self.account];
153        let instruction = InstructionView {
154            program_id: &SYSTEM_PROGRAM_ID,
155            data: &data,
156            accounts: &accounts,
157        };
158
159        crate::cpi::invoke_signed(&instruction, &views, signers)
160    }
161}
162
163/// Compatibility re-exports.
164pub mod instructions {
165    pub use super::{Allocate, Assign, CreateAccount, Transfer};
166}