Skip to content

Commit

Permalink
add basics/checking-accounts/steel (#199)
Browse files Browse the repository at this point in the history
  • Loading branch information
Perelyn-sama authored Jan 4, 2025
1 parent ff2ab18 commit 52b3a69
Show file tree
Hide file tree
Showing 14 changed files with 275 additions and 0 deletions.
2 changes: 2 additions & 0 deletions basics/checking-accounts/steel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
test-ledger
21 changes: 21 additions & 0 deletions basics/checking-accounts/steel/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[workspace]
resolver = "2"
members = ["api", "program"]

[workspace.package]
version = "0.1.0"
edition = "2021"
license = "Apache-2.0"
homepage = ""
documentation = ""
respository = ""
readme = "./README.md"
keywords = ["solana"]

[workspace.dependencies]
steel-api = { path = "./api", version = "0.1.0" }
bytemuck = "1.14"
num_enum = "0.7"
solana-program = "1.18"
steel = "1.3"
thiserror = "1.0"
22 changes: 22 additions & 0 deletions basics/checking-accounts/steel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Steel

**Steel** is a ...

## API
- [`Consts`](api/src/consts.rs) – Program constants.
- [`Error`](api/src/error.rs) – Custom program errors.
- [`Event`](api/src/event.rs) – Custom program events.
- [`Instruction`](api/src/instruction.rs) – Declared instructions.

## Instructions
- [`Hello`](program/src/hello.rs) – Hello ...

## State
- [`User`](api/src/state/user.rs) – User ...

## Tests

To run the test suit, use the Solana toolchain:
```
cargo test-sbf
```
11 changes: 11 additions & 0 deletions basics/checking-accounts/steel/api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "steel-api"
version = "0.1.0"
edition = "2021"

[dependencies]
bytemuck.workspace = true
num_enum.workspace = true
solana-program.workspace = true
steel.workspace = true
thiserror.workspace = true
2 changes: 2 additions & 0 deletions basics/checking-accounts/steel/api/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/// Seed of the account_to_change account PDA.
pub const ACCOUNT_TO_CHANGE: &[u8] = b"account_to_change";
13 changes: 13 additions & 0 deletions basics/checking-accounts/steel/api/src/instruction.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use steel::*;

#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)]
pub enum SteelInstruction {
CheckAccounts = 0,
}

#[repr(C)]
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
pub struct CheckAccounts {}

instruction!(SteelInstruction, CheckAccounts);
16 changes: 16 additions & 0 deletions basics/checking-accounts/steel/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
pub mod consts;
pub mod instruction;
pub mod sdk;
pub mod state;

pub mod prelude {
pub use crate::consts::*;
pub use crate::instruction::*;
pub use crate::sdk::*;
pub use crate::state::*;
}

use steel::*;

// TODO Set program id
declare_id!("z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35");
20 changes: 20 additions & 0 deletions basics/checking-accounts/steel/api/src/sdk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use steel::*;

use crate::prelude::*;

pub fn check_accounts(
signer: Pubkey,
account_to_create: Pubkey,
account_to_change: Pubkey,
) -> Instruction {
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(account_to_create, false),
AccountMeta::new(account_to_change, false),
AccountMeta::new_readonly(system_program::ID, false),
],
data: CheckAccounts {}.to_bytes(),
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use steel::*;

use super::SteelAccount;

#[repr(C)]
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)]
pub struct AccountToChange {}

account!(SteelAccount, AccountToChange);
18 changes: 18 additions & 0 deletions basics/checking-accounts/steel/api/src/state/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
mod account_to_change;

pub use account_to_change::*;

use steel::*;

use crate::consts::*;

#[repr(u8)]
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)]
pub enum SteelAccount {
AccountToChange = 0,
}

/// Fetch PDA of the account_to_change account.
pub fn account_to_change_pda() -> (Pubkey, u8) {
Pubkey::find_program_address(&[ACCOUNT_TO_CHANGE], &crate::id())
}
19 changes: 19 additions & 0 deletions basics/checking-accounts/steel/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "steel-program"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib", "lib"]

[dependencies]
steel-api.workspace = true
solana-program.workspace = true
steel.workspace = true

[dev-dependencies]
base64 = "0.21"
rand = "0.8.5"
solana-program-test = "1.18"
solana-sdk = "1.18"
tokio = { version = "1.35", features = ["full"] }
49 changes: 49 additions & 0 deletions basics/checking-accounts/steel/program/src/check_accounts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use solana_program::msg;
use steel::*;

pub fn process_check_accounts(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
// You can verify the list has the correct number of accounts.
let [signer_info, account_to_create_info, account_to_change_info, system_program] = accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};

// You can verify if an account is a signer
signer_info.is_signer()?;

// You can verify the program ID from the instruction is in fact
// the program ID of your program.
if system_program.is_program(&system_program::ID).is_err() {
return Err(ProgramError::IncorrectProgramId);
};

// You can make sure an account has NOT been initialized.

msg!("New account: {}", account_to_create_info.key);
if account_to_create_info.lamports() != 0 {
msg!("The program expected the account to create to not yet be initialized.");
return Err(ProgramError::AccountAlreadyInitialized);
};
// (Create account...)

// You can also make sure an account has been initialized.
msg!("Account to change: {}", account_to_change_info.key);
if account_to_change_info.lamports() == 0 {
msg!("The program expected the account to change to be initialized.");
return Err(ProgramError::UninitializedAccount);
};

// If we want to modify an account's data, it must be owned by our program.
if account_to_change_info.owner != &steel_api::ID {
msg!("Account to change does not have the correct program id.");
return Err(ProgramError::IncorrectProgramId);
};

// You can also check pubkeys against constants.
if system_program.key != &system_program::ID {
return Err(ProgramError::IncorrectProgramId);
};

Ok(())
}
22 changes: 22 additions & 0 deletions basics/checking-accounts/steel/program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
mod check_accounts;

use check_accounts::*;

use steel::*;
use steel_api::prelude::*;

pub fn process_instruction(
program_id: &Pubkey,
accounts: &[AccountInfo],
data: &[u8],
) -> ProgramResult {
let (ix, data) = parse_instruction(&steel_api::ID, program_id, data)?;

match ix {
SteelInstruction::CheckAccounts => process_check_accounts(accounts, data)?,
}

Ok(())
}

entrypoint!(process_instruction);
51 changes: 51 additions & 0 deletions basics/checking-accounts/steel/program/tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use solana_program::hash::Hash;
use solana_program_test::{processor, BanksClient, ProgramTest};
use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction};
use steel_api::prelude::*;

async fn setup() -> (BanksClient, Keypair, Hash) {
let mut program_test = ProgramTest::new(
"steel_program",
steel_api::ID,
processor!(steel_program::process_instruction),
);
program_test.prefer_bpf(true);
program_test.start().await
}

#[tokio::test]
async fn run_test() {
// Setup test
let (mut banks, payer, blockhash) = setup().await;

let account_to_create = Keypair::new();
let account_to_change = Keypair::new();

let account_to_change_ix = solana_sdk::system_instruction::create_account(
&payer.pubkey(),
&account_to_change.pubkey(),
solana_sdk::native_token::LAMPORTS_PER_SOL,
0,
&steel_api::ID,
);

let tx = Transaction::new_signed_with_payer(
&[account_to_change_ix],
Some(&payer.pubkey()),
&[&payer, &account_to_change],
blockhash,
);

let res = banks.process_transaction(tx).await;
assert!(res.is_ok());

// Submit check_accounts transaction.
let ix = check_accounts(
payer.pubkey(),
account_to_create.pubkey(),
account_to_change.pubkey(),
);
let tx = Transaction::new_signed_with_payer(&[ix], Some(&payer.pubkey()), &[&payer], blockhash);
let res = banks.process_transaction(tx).await;
assert!(res.is_ok());
}

0 comments on commit 52b3a69

Please sign in to comment.