Skip to content

Commit 52b3a69

Browse files
authored
add basics/checking-accounts/steel (solana-developers#199)
1 parent ff2ab18 commit 52b3a69

File tree

14 files changed

+275
-0
lines changed

14 files changed

+275
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
test-ledger
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
[workspace]
2+
resolver = "2"
3+
members = ["api", "program"]
4+
5+
[workspace.package]
6+
version = "0.1.0"
7+
edition = "2021"
8+
license = "Apache-2.0"
9+
homepage = ""
10+
documentation = ""
11+
respository = ""
12+
readme = "./README.md"
13+
keywords = ["solana"]
14+
15+
[workspace.dependencies]
16+
steel-api = { path = "./api", version = "0.1.0" }
17+
bytemuck = "1.14"
18+
num_enum = "0.7"
19+
solana-program = "1.18"
20+
steel = "1.3"
21+
thiserror = "1.0"
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Steel
2+
3+
**Steel** is a ...
4+
5+
## API
6+
- [`Consts`](api/src/consts.rs) – Program constants.
7+
- [`Error`](api/src/error.rs) – Custom program errors.
8+
- [`Event`](api/src/event.rs) – Custom program events.
9+
- [`Instruction`](api/src/instruction.rs) – Declared instructions.
10+
11+
## Instructions
12+
- [`Hello`](program/src/hello.rs) – Hello ...
13+
14+
## State
15+
- [`User`](api/src/state/user.rs) – User ...
16+
17+
## Tests
18+
19+
To run the test suit, use the Solana toolchain:
20+
```
21+
cargo test-sbf
22+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "steel-api"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
bytemuck.workspace = true
8+
num_enum.workspace = true
9+
solana-program.workspace = true
10+
steel.workspace = true
11+
thiserror.workspace = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/// Seed of the account_to_change account PDA.
2+
pub const ACCOUNT_TO_CHANGE: &[u8] = b"account_to_change";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use steel::*;
2+
3+
#[repr(u8)]
4+
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
5+
pub enum SteelInstruction {
6+
CheckAccounts = 0,
7+
}
8+
9+
#[repr(C)]
10+
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
11+
pub struct CheckAccounts {}
12+
13+
instruction!(SteelInstruction, CheckAccounts);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
pub mod consts;
2+
pub mod instruction;
3+
pub mod sdk;
4+
pub mod state;
5+
6+
pub mod prelude {
7+
pub use crate::consts::*;
8+
pub use crate::instruction::*;
9+
pub use crate::sdk::*;
10+
pub use crate::state::*;
11+
}
12+
13+
use steel::*;
14+
15+
// TODO Set program id
16+
declare_id!("z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use steel::*;
2+
3+
use crate::prelude::*;
4+
5+
pub fn check_accounts(
6+
signer: Pubkey,
7+
account_to_create: Pubkey,
8+
account_to_change: Pubkey,
9+
) -> Instruction {
10+
Instruction {
11+
program_id: crate::ID,
12+
accounts: vec![
13+
AccountMeta::new(signer, true),
14+
AccountMeta::new(account_to_create, false),
15+
AccountMeta::new(account_to_change, false),
16+
AccountMeta::new_readonly(system_program::ID, false),
17+
],
18+
data: CheckAccounts {}.to_bytes(),
19+
}
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
use steel::*;
2+
3+
use super::SteelAccount;
4+
5+
#[repr(C)]
6+
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
7+
pub struct AccountToChange {}
8+
9+
account!(SteelAccount, AccountToChange);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
mod account_to_change;
2+
3+
pub use account_to_change::*;
4+
5+
use steel::*;
6+
7+
use crate::consts::*;
8+
9+
#[repr(u8)]
10+
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
11+
pub enum SteelAccount {
12+
AccountToChange = 0,
13+
}
14+
15+
/// Fetch PDA of the account_to_change account.
16+
pub fn account_to_change_pda() -> (Pubkey, u8) {
17+
Pubkey::find_program_address(&[ACCOUNT_TO_CHANGE], &crate::id())
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[package]
2+
name = "steel-program"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib", "lib"]
8+
9+
[dependencies]
10+
steel-api.workspace = true
11+
solana-program.workspace = true
12+
steel.workspace = true
13+
14+
[dev-dependencies]
15+
base64 = "0.21"
16+
rand = "0.8.5"
17+
solana-program-test = "1.18"
18+
solana-sdk = "1.18"
19+
tokio = { version = "1.35", features = ["full"] }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
use solana_program::msg;
2+
use steel::*;
3+
4+
pub fn process_check_accounts(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
5+
// Load accounts.
6+
// You can verify the list has the correct number of accounts.
7+
let [signer_info, account_to_create_info, account_to_change_info, system_program] = accounts
8+
else {
9+
return Err(ProgramError::NotEnoughAccountKeys);
10+
};
11+
12+
// You can verify if an account is a signer
13+
signer_info.is_signer()?;
14+
15+
// You can verify the program ID from the instruction is in fact
16+
// the program ID of your program.
17+
if system_program.is_program(&system_program::ID).is_err() {
18+
return Err(ProgramError::IncorrectProgramId);
19+
};
20+
21+
// You can make sure an account has NOT been initialized.
22+
23+
msg!("New account: {}", account_to_create_info.key);
24+
if account_to_create_info.lamports() != 0 {
25+
msg!("The program expected the account to create to not yet be initialized.");
26+
return Err(ProgramError::AccountAlreadyInitialized);
27+
};
28+
// (Create account...)
29+
30+
// You can also make sure an account has been initialized.
31+
msg!("Account to change: {}", account_to_change_info.key);
32+
if account_to_change_info.lamports() == 0 {
33+
msg!("The program expected the account to change to be initialized.");
34+
return Err(ProgramError::UninitializedAccount);
35+
};
36+
37+
// If we want to modify an account's data, it must be owned by our program.
38+
if account_to_change_info.owner != &steel_api::ID {
39+
msg!("Account to change does not have the correct program id.");
40+
return Err(ProgramError::IncorrectProgramId);
41+
};
42+
43+
// You can also check pubkeys against constants.
44+
if system_program.key != &system_program::ID {
45+
return Err(ProgramError::IncorrectProgramId);
46+
};
47+
48+
Ok(())
49+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
mod check_accounts;
2+
3+
use check_accounts::*;
4+
5+
use steel::*;
6+
use steel_api::prelude::*;
7+
8+
pub fn process_instruction(
9+
program_id: &Pubkey,
10+
accounts: &[AccountInfo],
11+
data: &[u8],
12+
) -> ProgramResult {
13+
let (ix, data) = parse_instruction(&steel_api::ID, program_id, data)?;
14+
15+
match ix {
16+
SteelInstruction::CheckAccounts => process_check_accounts(accounts, data)?,
17+
}
18+
19+
Ok(())
20+
}
21+
22+
entrypoint!(process_instruction);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
use solana_program::hash::Hash;
2+
use solana_program_test::{processor, BanksClient, ProgramTest};
3+
use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction};
4+
use steel_api::prelude::*;
5+
6+
async fn setup() -> (BanksClient, Keypair, Hash) {
7+
let mut program_test = ProgramTest::new(
8+
"steel_program",
9+
steel_api::ID,
10+
processor!(steel_program::process_instruction),
11+
);
12+
program_test.prefer_bpf(true);
13+
program_test.start().await
14+
}
15+
16+
#[tokio::test]
17+
async fn run_test() {
18+
// Setup test
19+
let (mut banks, payer, blockhash) = setup().await;
20+
21+
let account_to_create = Keypair::new();
22+
let account_to_change = Keypair::new();
23+
24+
let account_to_change_ix = solana_sdk::system_instruction::create_account(
25+
&payer.pubkey(),
26+
&account_to_change.pubkey(),
27+
solana_sdk::native_token::LAMPORTS_PER_SOL,
28+
0,
29+
&steel_api::ID,
30+
);
31+
32+
let tx = Transaction::new_signed_with_payer(
33+
&[account_to_change_ix],
34+
Some(&payer.pubkey()),
35+
&[&payer, &account_to_change],
36+
blockhash,
37+
);
38+
39+
let res = banks.process_transaction(tx).await;
40+
assert!(res.is_ok());
41+
42+
// Submit check_accounts transaction.
43+
let ix = check_accounts(
44+
payer.pubkey(),
45+
account_to_create.pubkey(),
46+
account_to_change.pubkey(),
47+
);
48+
let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash);
49+
let res = banks.process_transaction(tx).await;
50+
assert!(res.is_ok());
51+
}

0 commit comments

Comments
 (0)