Skip to content
Draft
2 changes: 2 additions & 0 deletions tokens/token-2022/cpi-guard/steel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
test-ledger
22 changes: 22 additions & 0 deletions tokens/token-2022/cpi-guard/steel/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[workspace]
resolver = "2"
members = ["api", "program"]

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

[workspace.dependencies]
steel-api = { path = "./api", version = "0.1.0" }
bytemuck = "1.14"
num_enum = "0.7"
solana-program = "2.1"
steel = "3.0"
thiserror = "1.0"
spl-token-2022 = {version = "7.0.0", features = ["no-entrypoint"]}
28 changes: 28 additions & 0 deletions tokens/token-2022/cpi-guard/steel/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# 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
- [`Add`](program/src/add.rs) – Add ...
- [`Initialize`](program/src/initialize.rs) – Initialize ...

## State
- [`Counter`](api/src/state/counter.rs) – Counter ...

## Get started

Compile your program:
```sh
steel build
```

Run unit and integration tests:
```sh
steel test
```
19 changes: 19 additions & 0 deletions tokens/token-2022/cpi-guard/steel/api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[package]
name = "steel-api"
description = "API for interacting with the Steel program"
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
documentation.workspace = true
repository.workspace = true
readme.workspace = true
keywords.workspace = true

[dependencies]
bytemuck.workspace = true
num_enum.workspace = true
solana-program.workspace = true
steel.workspace = true
thiserror.workspace = true
spl-token-2022.workspace = true
10 changes: 10 additions & 0 deletions tokens/token-2022/cpi-guard/steel/api/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
use steel::*;

#[derive(Debug, Error, Clone, Copy, PartialEq, Eq, IntoPrimitive)]
#[repr(u32)]
pub enum SteelError {
#[error("This is a dummy error")]
Dummy = 0,
}

error!(SteelError);
13 changes: 13 additions & 0 deletions tokens/token-2022/cpi-guard/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 {
CpiBurn = 0,
}

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

instruction!(SteelInstruction, CpiBurn);
14 changes: 14 additions & 0 deletions tokens/token-2022/cpi-guard/steel/api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pub mod error;
pub mod instruction;
pub mod sdk;

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

use steel::*;

// TODO Set program id
declare_id!("z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35");
17 changes: 17 additions & 0 deletions tokens/token-2022/cpi-guard/steel/api/src/sdk.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use steel::*;

use crate::prelude::*;

pub fn cpi_burn(signer: Pubkey, mint: Pubkey, recipient_token_account: Pubkey) -> Instruction {
Instruction {
program_id: crate::ID,
accounts: vec![
AccountMeta::new(signer, true),
AccountMeta::new(mint, false),
AccountMeta::new(recipient_token_account, false),
AccountMeta::new_readonly(system_program::ID, false),
AccountMeta::new_readonly(spl_token_2022::ID, false),
],
data: CpiBurn {}.to_bytes(),
}
}
27 changes: 27 additions & 0 deletions tokens/token-2022/cpi-guard/steel/program/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
[package]
name = "steel-program"
description = ""
version.workspace = true
edition.workspace = true
license.workspace = true
homepage.workspace = true
documentation.workspace = true
repository.workspace = true
readme.workspace = true
keywords.workspace = true

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

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

[dev-dependencies]
base64 = "0.21"
rand = "0.8.5"
solana-program-test = "2.1"
solana-sdk = "2.1"
tokio = { version = "1.35", features = ["full"] }
54 changes: 54 additions & 0 deletions tokens/token-2022/cpi-guard/steel/program/src/cpi_burn.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
use solana_program::{msg, program::invoke};
use spl_token_2022::instruction::{burn, mint_to};
use steel::*;

pub fn process_cpi_burn(accounts: &[AccountInfo<'_>], _data: &[u8]) -> ProgramResult {
// Load accounts.
let [signer_info, mint_info, recipient_token_account_info, system_program, token_program] =
accounts
else {
return Err(ProgramError::NotEnoughAccountKeys);
};

//Validation
signer_info.is_signer()?;
recipient_token_account_info.is_writable()?;
token_program.is_program(&spl_token_2022::ID)?;
system_program.is_program(&system_program::ID)?;

invoke(
&mint_to(
token_program.key,
mint_info.key,
recipient_token_account_info.key,
signer_info.key,
&[],
1000,
)?,
&[
mint_info.clone(),
recipient_token_account_info.clone(),
signer_info.clone(),
],
)?;

invoke(
&burn(
token_program.key,
recipient_token_account_info.key,
mint_info.key,
signer_info.key,
&[],
100,
)?,
&[
recipient_token_account_info.clone(),
mint_info.clone(),
signer_info.clone(),
],
)?;

msg!("Cpi Guard Extension Test: Burn.");

Ok(())
}
22 changes: 22 additions & 0 deletions tokens/token-2022/cpi-guard/steel/program/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
mod cpi_burn;

use cpi_burn::*;

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::CpiBurn => process_cpi_burn(accounts, data)?,
}

Ok(())
}

entrypoint!(process_instruction);
133 changes: 133 additions & 0 deletions tokens/token-2022/cpi-guard/steel/program/tests/test.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
use solana_program::{hash::Hash, program_pack::Pack};
use solana_program_test::{processor, BanksClient, ProgramTest};
use solana_sdk::{
signature::Keypair, signer::Signer, system_instruction::create_account,
transaction::Transaction,
};
use spl_token_2022::{
extension::{
cpi_guard::instruction::{disable_cpi_guard, enable_cpi_guard},
ExtensionType,
},
instruction::{initialize_account3, initialize_mint2},
state::{Account, Mint},
};
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 mint = Keypair::new();
let token_acc = Keypair::new();

//Setup Mint.
let create_mint_ix = create_account(
&payer.pubkey(),
&mint.pubkey(),
banks.get_rent().await.unwrap().minimum_balance(Mint::LEN),
Mint::LEN as u64,
&spl_token_2022::ID,
);
let init_mint_ix = initialize_mint2(
&spl_token_2022::ID,
&mint.pubkey(),
&payer.pubkey(),
None,
6,
)
.unwrap();

//Setup Token Account
let space =
ExtensionType::try_calculate_account_len::<Account>(&[ExtensionType::CpiGuard]).unwrap();

let create_acc_ix = create_account(
&payer.pubkey(),
&token_acc.pubkey(),
banks.get_rent().await.unwrap().minimum_balance(space),
space as u64,
&spl_token_2022::ID,
);

let init_acc_ix = initialize_account3(
&spl_token_2022::ID,
&token_acc.pubkey(),
&mint.pubkey(),
&payer.pubkey(),
)
.unwrap();

//Initialize Cpi Guard Extension
let enable_cpi_guard_ix = enable_cpi_guard(
&spl_token_2022::ID,
&token_acc.pubkey(),
&payer.pubkey(),
&[],
)
.unwrap();

let tx = Transaction::new_signed_with_payer(
&[
create_mint_ix,
init_mint_ix,
create_acc_ix,
init_acc_ix,
enable_cpi_guard_ix,
],
Some(&payer.pubkey()),
&[&payer, &mint, &token_acc],
blockhash,
);
let res = banks.process_transaction(tx).await;
assert!(res.is_ok());

//Try to burn tokens via cpi, should fail
let cpi_burn_ix = cpi_burn(payer.pubkey(), mint.pubkey(), token_acc.pubkey());

let tx = Transaction::new_signed_with_payer(
&[cpi_burn_ix],
Some(&payer.pubkey()),
&[&payer],
blockhash,
);
let res = banks.process_transaction(tx).await;

let err_string = format!("{:?}", res);

assert!(
err_string.contains("Custom(43)"),
"Expected TokenError::CpiGuardBurnBlocked(43) , got: {}",
err_string
);

//Disable CPI Guard and try burn again, should pass
let disable_cpi_ix = disable_cpi_guard(
&spl_token_2022::ID,
&token_acc.pubkey(),
&payer.pubkey(),
&[],
)
.unwrap();
let cpi_burn_ix = cpi_burn(payer.pubkey(), mint.pubkey(), token_acc.pubkey());

let tx = Transaction::new_signed_with_payer(
&[disable_cpi_ix, cpi_burn_ix],
Some(&payer.pubkey()),
&[&payer],
blockhash,
);
let res = banks.process_transaction(tx).await;
assert!(res.is_ok());
}
2 changes: 2 additions & 0 deletions tokens/token-2022/default-account-state/steel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target
test-ledger
23 changes: 23 additions & 0 deletions tokens/token-2022/default-account-state/steel/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[workspace]
resolver = "2"
members = ["api", "program"]

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

[workspace.dependencies]
steel-api = { path = "./api", version = "0.1.0" }
bytemuck = "1.14"
num_enum = "0.7"
solana-program = "2.1"
steel = "4.0"
thiserror = "1.0"
spl-token-2022 = {version = "7.0.0", features = ["no-entrypoint"]}

Loading
Loading