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,
21    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
22]);
23
24// ── CreateAccount ────────────────────────────────────────────────────
25
26/// Builder for the system program's CreateAccount instruction.
27pub struct CreateAccount<'a, 'b> {
28    pub from: &'a AccountView,
29    pub to: &'a AccountView,
30    pub lamports: u64,
31    pub space: u64,
32    pub owner: &'b Address,
33}
34
35impl CreateAccount<'_, '_> {
36    #[inline]
37    pub fn invoke(&self) -> ProgramResult {
38        self.invoke_signed(&[])
39    }
40
41    #[inline]
42    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
43        let mut data = [0u8; 52];
44        // index 0 = CreateAccount (already zero)
45        data[4..12].copy_from_slice(&self.lamports.to_le_bytes());
46        data[12..20].copy_from_slice(&self.space.to_le_bytes());
47        data[20..52].copy_from_slice(self.owner.as_array());
48
49        let accounts = [
50            InstructionAccount::writable_signer(self.from.address()),
51            InstructionAccount::writable_signer(self.to.address()),
52        ];
53        let views = [self.from, self.to];
54        let instruction = InstructionView {
55            program_id: &SYSTEM_PROGRAM_ID,
56            data: &data,
57            accounts: &accounts,
58        };
59
60        crate::cpi::invoke_signed(&instruction, &views, signers)
61    }
62}
63
64// ── Transfer ─────────────────────────────────────────────────────────
65
66/// Builder for the system program's Transfer instruction.
67pub struct Transfer<'a> {
68    pub from: &'a AccountView,
69    pub to: &'a AccountView,
70    pub lamports: u64,
71}
72
73impl Transfer<'_> {
74    #[inline]
75    pub fn invoke(&self) -> ProgramResult {
76        self.invoke_signed(&[])
77    }
78
79    #[inline]
80    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
81        let mut data = [0u8; 12];
82        data[0] = 2;
83        data[4..12].copy_from_slice(&self.lamports.to_le_bytes());
84
85        let accounts = [
86            InstructionAccount::writable_signer(self.from.address()),
87            InstructionAccount::writable(self.to.address()),
88        ];
89        let views = [self.from, self.to];
90        let instruction = InstructionView {
91            program_id: &SYSTEM_PROGRAM_ID,
92            data: &data,
93            accounts: &accounts,
94        };
95
96        crate::cpi::invoke_signed(&instruction, &views, signers)
97    }
98}
99
100// ── Assign ───────────────────────────────────────────────────────────
101
102/// Builder for the system program's Assign instruction.
103pub struct Assign<'a, 'b> {
104    pub account: &'a AccountView,
105    pub owner: &'b Address,
106}
107
108impl Assign<'_, '_> {
109    #[inline]
110    pub fn invoke(&self) -> ProgramResult {
111        self.invoke_signed(&[])
112    }
113
114    #[inline]
115    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
116        let mut data = [0u8; 36];
117        data[0] = 1;
118        data[4..36].copy_from_slice(self.owner.as_array());
119
120        let accounts = [InstructionAccount::writable_signer(self.account.address())];
121        let views = [self.account];
122        let instruction = InstructionView {
123            program_id: &SYSTEM_PROGRAM_ID,
124            data: &data,
125            accounts: &accounts,
126        };
127
128        crate::cpi::invoke_signed(&instruction, &views, signers)
129    }
130}
131
132// ── Allocate ─────────────────────────────────────────────────────────
133
134/// Builder for the system program's Allocate instruction.
135pub struct Allocate<'a> {
136    pub account: &'a AccountView,
137    pub space: u64,
138}
139
140impl Allocate<'_> {
141    #[inline]
142    pub fn invoke(&self) -> ProgramResult {
143        self.invoke_signed(&[])
144    }
145
146    #[inline]
147    pub fn invoke_signed(&self, signers: &[Signer]) -> ProgramResult {
148        let mut data = [0u8; 12];
149        data[0] = 8;
150        data[4..12].copy_from_slice(&self.space.to_le_bytes());
151
152        let accounts = [InstructionAccount::writable_signer(self.account.address())];
153        let views = [self.account];
154        let instruction = InstructionView {
155            program_id: &SYSTEM_PROGRAM_ID,
156            data: &data,
157            accounts: &accounts,
158        };
159
160        crate::cpi::invoke_signed(&instruction, &views, signers)
161    }
162}
163
164/// Compatibility re-exports.
165pub mod instructions {
166    pub use super::{CreateAccount, Transfer, Assign, Allocate};
167}