nitrate_program/
system.rs

1// Copyright (c) 2024 nifty-oss maintainers
2// Copyright (c) 2024 Magnetar Fields
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16//! System Program CPI functions.
17
18use solana_program::{pubkey::Pubkey, system_program};
19
20use crate::{
21    cpi::{CAccountInfo, CAccountMeta, CInstruction},
22    AccountInfo,
23};
24
25/// Create a new account.
26///
27/// # Arguments
28///
29/// * `funder`: Funding account.
30/// * `account`: New account.
31/// * `lamports`: Number of lamports to transfer to the new account.
32/// * `space`: Number of bytes of memory to allocate.
33/// * `owner`: Address of program that will own the new account.
34pub fn create_account(
35    funder: &AccountInfo,
36    account: &AccountInfo,
37    lamports: u64,
38    space: u64,
39    owner: &Pubkey,
40) {
41    let instruction_accounts: [CAccountMeta; 2] = [funder.into(), account.into()];
42
43    // -   0..4: instruction discriminator
44    // -  4..12: lamports
45    // - 12..20: account space
46    // - 20..52: owner pubkey
47    let mut instruction_data = [0; 52];
48    // create account instruction has a '0' discriminator
49    instruction_data[4..12].copy_from_slice(&lamports.to_le_bytes());
50    instruction_data[12..20].copy_from_slice(&space.to_le_bytes());
51    instruction_data[20..52].copy_from_slice(owner.as_ref());
52
53    let instruction = CInstruction {
54        program_id: &system_program::ID,
55        accounts: instruction_accounts.as_ptr(),
56        accounts_len: instruction_accounts.len() as u64,
57        data: instruction_data.as_ptr(),
58        data_len: instruction_data.len() as u64,
59    };
60
61    // account infos and seeds
62    let account_infos: [CAccountInfo; 2] = [funder.into(), account.into()];
63    let seeds: &[&[&[u8]]] = &[];
64
65    #[cfg(target_os = "solana")]
66    unsafe {
67        solana_program::syscalls::sol_invoke_signed_c(
68            &instruction as *const CInstruction as *const u8,
69            account_infos.as_ptr() as *const u8,
70            account_infos.len() as u64,
71            seeds.as_ptr() as *const u8,
72            seeds.len() as u64,
73        );
74    }
75
76    // keep clippy happy
77    #[cfg(not(target_os = "solana"))]
78    core::hint::black_box(&(&instruction, &account_infos, &seeds));
79}
80
81/// Transfer lamports between accounts.
82///
83/// # Arguments
84///
85/// * `from`: Funding account.
86/// * `recipient`: Recipient account.
87/// * `amount`: Number of lamports to transfer.
88pub fn transfer(from: &AccountInfo, recipient: &AccountInfo, amount: u64) {
89    let instruction_accounts: [CAccountMeta; 2] = [from.into(), recipient.into()];
90
91    // -   0..4: instruction discriminator
92    // -  4..12: lamports amount
93    let mut instruction_data = [0; 12];
94    // transfer instruction has a '2' discriminator
95    instruction_data[0] = 2;
96    instruction_data[4..12].copy_from_slice(&amount.to_le_bytes());
97
98    let instruction = CInstruction {
99        program_id: &system_program::ID,
100        accounts: instruction_accounts.as_ptr(),
101        accounts_len: instruction_accounts.len() as u64,
102        data: instruction_data.as_ptr(),
103        data_len: instruction_data.len() as u64,
104    };
105
106    // account infos and seeds
107    let account_infos: [CAccountInfo; 2] = [from.into(), recipient.into()];
108    let seeds: &[&[&[u8]]] = &[];
109
110    #[cfg(target_os = "solana")]
111    unsafe {
112        solana_program::syscalls::sol_invoke_signed_c(
113            &instruction as *const CInstruction as *const u8,
114            account_infos.as_ptr() as *const u8,
115            account_infos.len() as u64,
116            seeds.as_ptr() as *const u8,
117            seeds.len() as u64,
118        );
119    }
120
121    // keep clippy happy
122    #[cfg(not(target_os = "solana"))]
123    core::hint::black_box(&(&instruction, &account_infos, &seeds));
124}