Эх сурвалжийг харах

add basics/checking-accounts/steel (#199)

Perelyn 9 сар өмнө
parent
commit
52b3a69ff0

+ 2 - 0
basics/checking-accounts/steel/.gitignore

@@ -0,0 +1,2 @@
+target
+test-ledger

+ 21 - 0
basics/checking-accounts/steel/Cargo.toml

@@ -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 - 0
basics/checking-accounts/steel/README.md

@@ -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 - 0
basics/checking-accounts/steel/api/Cargo.toml

@@ -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 - 0
basics/checking-accounts/steel/api/src/consts.rs

@@ -0,0 +1,2 @@
+/// Seed of the account_to_change account PDA.
+pub const ACCOUNT_TO_CHANGE: &[u8] = b"account_to_change";

+ 13 - 0
basics/checking-accounts/steel/api/src/instruction.rs

@@ -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 - 0
basics/checking-accounts/steel/api/src/lib.rs

@@ -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 - 0
basics/checking-accounts/steel/api/src/sdk.rs

@@ -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(),
+    }
+}

+ 9 - 0
basics/checking-accounts/steel/api/src/state/account_to_change.rs

@@ -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 - 0
basics/checking-accounts/steel/api/src/state/mod.rs

@@ -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 - 0
basics/checking-accounts/steel/program/Cargo.toml

@@ -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 - 0
basics/checking-accounts/steel/program/src/check_accounts.rs

@@ -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 - 0
basics/checking-accounts/steel/program/src/lib.rs

@@ -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 - 0
basics/checking-accounts/steel/program/tests/test.rs

@@ -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());
+}