-
Notifications
You must be signed in to change notification settings - Fork 325
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
ecf7486
commit 81d5424
Showing
17 changed files
with
529 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
target | ||
test-ledger |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
/// Seed of the favorites account PDA. | ||
pub const FAVORITES: &[u8] = b"favorites"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
use steel::*; | ||
|
||
#[repr(u8)] | ||
#[derive(Clone, Copy, Debug, Eq, PartialEq, TryFromPrimitive)] | ||
pub enum SteelInstruction { | ||
SetFavorites = 0, | ||
} | ||
|
||
#[repr(C)] | ||
#[derive(Clone, Copy, Debug, Pod, Zeroable)] | ||
pub struct SetFavorites { | ||
pub number: [u8; 8], | ||
|
||
pub color: [u8; 32], | ||
|
||
pub hobbies: [[u8; 32]; 3], | ||
} | ||
|
||
instruction!(SteelInstruction, SetFavorites); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
pub mod consts; | ||
pub mod error; | ||
pub mod instruction; | ||
pub mod sdk; | ||
pub mod state; | ||
pub mod utils; | ||
|
||
pub mod prelude { | ||
pub use crate::consts::*; | ||
pub use crate::error::*; | ||
pub use crate::instruction::*; | ||
pub use crate::sdk::*; | ||
pub use crate::state::*; | ||
pub use crate::utils::*; | ||
} | ||
|
||
use steel::*; | ||
|
||
// TODO Set program id | ||
declare_id!("z7msBPQHDJjTvdQRoEcKyENgXDhSRYeHieN1ZMTqo35"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
use steel::*; | ||
|
||
use crate::prelude::*; | ||
|
||
pub fn set_favorites(signer: Pubkey, number: u64, color: &str, hobbies: Vec<&str>) -> Instruction { | ||
let color_bytes: [u8; 32] = string_to_bytes32_padded(color).unwrap(); | ||
|
||
let hobbies_bytes = strings_to_bytes32_array_padded(hobbies).unwrap(); | ||
|
||
Instruction { | ||
program_id: crate::ID, | ||
accounts: vec![ | ||
AccountMeta::new(signer, true), | ||
AccountMeta::new(favorites_pda().0, false), | ||
AccountMeta::new_readonly(system_program::ID, false), | ||
], | ||
data: SetFavorites { | ||
number: number.to_le_bytes(), | ||
color: color_bytes, | ||
hobbies: hobbies_bytes, | ||
} | ||
.to_bytes(), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
use steel::*; | ||
|
||
use super::SteelAccount; | ||
|
||
#[repr(C)] | ||
#[derive(Clone, Copy, Debug, PartialEq, Pod, Zeroable)] | ||
pub struct Favorites { | ||
pub number: u64, | ||
|
||
pub color: [u8; 32], | ||
|
||
pub hobbies: [[u8; 32]; 3], | ||
} | ||
|
||
account!(SteelAccount, Favorites); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
mod favorites; | ||
|
||
pub use favorites::*; | ||
|
||
use steel::*; | ||
|
||
use crate::consts::*; | ||
|
||
#[repr(u8)] | ||
#[derive(Clone, Copy, Debug, Eq, PartialEq, IntoPrimitive, TryFromPrimitive)] | ||
pub enum SteelAccount { | ||
Favorites = 0, | ||
} | ||
|
||
/// Fetch PDA of the favorites account. | ||
pub fn favorites_pda() -> (Pubkey, u8) { | ||
Pubkey::find_program_address(&[FAVORITES], &crate::id()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
use std::error::Error; | ||
use std::fmt; | ||
|
||
#[derive(Debug)] | ||
pub enum ConversionError { | ||
StringTooLong(usize), | ||
StringTooShort(usize), | ||
VecLengthMismatch { expected: usize, actual: usize }, | ||
InvalidUtf8, | ||
} | ||
|
||
impl fmt::Display for ConversionError { | ||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||
match self { | ||
ConversionError::StringTooLong(len) => { | ||
write!(f, "String length {} exceeds 32 bytes", len) | ||
} | ||
ConversionError::StringTooShort(len) => { | ||
write!(f, "String length {} is less than 32 bytes", len) | ||
} | ||
ConversionError::VecLengthMismatch { expected, actual } => { | ||
write!( | ||
f, | ||
"Vector length mismatch: expected {}, got {}", | ||
expected, actual | ||
) | ||
} | ||
ConversionError::InvalidUtf8 => write!(f, "Invalid UTF-8 sequence in bytes"), | ||
} | ||
} | ||
} | ||
|
||
impl Error for ConversionError {} | ||
|
||
// Convert string to bytes with padding | ||
pub fn string_to_bytes32_padded(input: &str) -> Result<[u8; 32], ConversionError> { | ||
let bytes = input.as_bytes(); | ||
let len = bytes.len(); | ||
|
||
if len > 32 { | ||
return Err(ConversionError::StringTooLong(len)); | ||
} | ||
|
||
let mut result = [0u8; 32]; | ||
result[..len].copy_from_slice(bytes); | ||
Ok(result) | ||
} | ||
|
||
// Convert bytes back to string, trimming trailing zeros | ||
pub fn bytes32_to_string(bytes: &[u8; 32]) -> Result<String, ConversionError> { | ||
// Find the actual length by looking for the first zero or taking full length | ||
let actual_len = bytes.iter().position(|&b| b == 0).unwrap_or(32); | ||
|
||
// Convert the slice up to actual_len to a string | ||
String::from_utf8(bytes[..actual_len].to_vec()).map_err(|_| ConversionError::InvalidUtf8) | ||
} | ||
|
||
// Convert vec of strings to byte arrays with padding | ||
pub fn strings_to_bytes32_array_padded<const N: usize>( | ||
inputs: Vec<&str>, | ||
) -> Result<[[u8; 32]; N], ConversionError> { | ||
if inputs.len() != N { | ||
return Err(ConversionError::VecLengthMismatch { | ||
expected: N, | ||
actual: inputs.len(), | ||
}); | ||
} | ||
|
||
let mut result = [[0u8; 32]; N]; | ||
for (i, input) in inputs.iter().enumerate() { | ||
result[i] = string_to_bytes32_padded(input)?; | ||
} | ||
Ok(result) | ||
} | ||
|
||
// Convert array of byte arrays back to vec of strings | ||
pub fn bytes32_array_to_strings<const N: usize>( | ||
bytes_array: &[[u8; 32]; N], | ||
) -> Result<Vec<String>, ConversionError> { | ||
let mut result = Vec::with_capacity(N); | ||
for bytes in bytes_array.iter() { | ||
result.push(bytes32_to_string(bytes)?); | ||
} | ||
Ok(result) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"] } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
mod set_favorites; | ||
|
||
pub use set_favorites::*; | ||
|
||
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::SetFavorites => process_set_favorites(accounts, data)?, | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
entrypoint!(process_instruction); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
use solana_program::msg; | ||
use steel::*; | ||
use steel_api::prelude::*; | ||
|
||
pub fn process_set_favorites(accounts: &[AccountInfo<'_>], data: &[u8]) -> ProgramResult { | ||
// Parse args. | ||
let args = SetFavorites::try_from_bytes(data)?; | ||
let number = u64::from_le_bytes(args.number); | ||
let color = bytes32_to_string(&args.color).unwrap(); | ||
let hobbies = bytes32_array_to_strings(&args.hobbies).unwrap(); | ||
|
||
// Get expected pda bump. | ||
let favorites_bump = favorites_pda().1; | ||
|
||
// Load accounts. | ||
let [user_info, favorites_info, system_program] = accounts else { | ||
return Err(ProgramError::NotEnoughAccountKeys); | ||
}; | ||
user_info.is_signer()?; | ||
favorites_info.is_empty()?.is_writable()?.has_seeds( | ||
&[FAVORITES], | ||
favorites_bump, | ||
&steel_api::ID, | ||
)?; | ||
system_program.is_program(&system_program::ID)?; | ||
|
||
// Initialize favorites. | ||
create_account::<Favorites>( | ||
favorites_info, | ||
&steel_api::ID, | ||
&[FAVORITES, &[favorites_bump]], | ||
system_program, | ||
user_info, | ||
)?; | ||
|
||
msg!("Greetings from {}", &steel_api::ID); | ||
let user_public_key = user_info.key; | ||
|
||
msg!( | ||
"User {user_public_key}'s favorite number is {number}, favorite color is: {color}, and their hobbies are {hobbies:?}", | ||
); | ||
|
||
let favorites = favorites_info.to_account_mut::<Favorites>(&steel_api::ID)?; | ||
favorites.number = number; | ||
favorites.color = args.color; | ||
favorites.hobbies = args.hobbies; | ||
|
||
Ok(()) | ||
} |
Oops, something went wrong.