Skip to content

Commit 06ac236

Browse files
committed
macro single account set + propagate marker traits
1 parent 664e755 commit 06ac236

File tree

18 files changed

+414
-302
lines changed

18 files changed

+414
-302
lines changed

framework/example_programs/counter/src/lib.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use star_frame::anyhow::bail;
22
use star_frame::borsh::{BorshDeserialize, BorshSerialize};
3+
use star_frame::derive_more::{Deref, DerefMut};
34
use star_frame::prelude::*;
45
use star_frame::solana_program::pubkey::Pubkey;
56

@@ -14,10 +15,23 @@ pub struct CounterAccount {
1415
}
1516

1617
impl ProgramAccount for CounterAccount {
17-
type OwnerProgram = CounterProgram;
1818
const DISCRIMINANT: <Self::OwnerProgram as StarFrameProgram>::AccountDiscriminant = [0; 8];
1919
}
2020

21+
#[derive(AccountSet, Deref, DerefMut, Debug)]
22+
#[cleanup(generics = [<A> where DataAccount<'info, CounterAccount>: AccountSetCleanup<'info, A>], arg = A)]
23+
#[validate(generics = [<A> where DataAccount<'info, CounterAccount>: AccountSetValidate<'info, A>], arg = A)]
24+
pub struct WrappedCounter<'info>(
25+
#[cleanup(arg = arg)]
26+
#[validate(arg = arg)]
27+
#[single_account_set]
28+
DataAccount<'info, CounterAccount>,
29+
);
30+
31+
impl HasOwnerProgram for CounterAccount {
32+
type OwnerProgram = CounterProgram;
33+
}
34+
2135
impl HasSeeds for CounterAccount {
2236
type Seeds = CounterAccountSeeds;
2337
}
@@ -41,7 +55,7 @@ pub struct CreateCounterAccounts<'info> {
4155
CreateIfNeeded(CreateAccount::new(&self.system_program, &self.funder)),
4256
Seeds(CounterAccountSeeds { owner: *self.owner.key(), }),
4357
))]
44-
pub counter: Init<Seeded<DataAccount<'info, CounterAccount>>>,
58+
pub counter: Init<Seeded<WrappedCounter<'info>>>,
4559
pub system_program: Program<'info, SystemProgram>,
4660
}
4761

@@ -186,7 +200,7 @@ pub struct CloseCounterAccounts<'info> {
186200
#[account_set(recipient)]
187201
pub funds_to: Writable<SystemAccount<'info>>,
188202
#[cleanup(arg = NormalizeRentAuto)]
189-
pub counter: Writable<DataAccount<'info, CounterAccount>>,
203+
pub counter: Writable<WrappedCounter<'info>>,
190204
}
191205

192206
impl StarFrameInstruction for CloseCounterIx {

framework/example_programs/faction_enlistment/src/lib.rs

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub struct ProcessEnlistPlayerIx {
3737

3838
impl StarFrameInstruction for ProcessEnlistPlayerIx {
3939
type DecodeArg<'a> = ();
40-
type ValidateArg<'a> = u8;
40+
type ValidateArg<'a> = ();
4141
type CleanupArg<'a> = ();
4242
type ReturnType = ();
4343
// type RunArg<'a> = (FactionId, &'a Vec<u8>);
@@ -46,20 +46,15 @@ impl StarFrameInstruction for ProcessEnlistPlayerIx {
4646
// type ReturnType = usize;
4747

4848
fn split_to_args<'a>(r: &Self) -> IxArgs<Self> {
49-
IxArgs {
50-
validate: r.bump,
51-
run: r.faction_id,
52-
// run: (r.faction_id, &r.buncha_data),
53-
cleanup: (),
54-
decode: (),
55-
}
49+
IxArgs::run(r.faction_id)
5650
}
5751

5852
fn run_instruction<'info>(
5953
account_set: &mut Self::Accounts<'_, '_, 'info>,
6054
faction_id: Self::RunArg<'_>,
6155
syscalls: &mut impl SyscallInvoke<'info>,
6256
) -> Result<Self::ReturnType> {
57+
// let cloned_account = account_set.player_account.clone();
6358
let clock = syscalls.get_clock()?;
6459
let bump = account_set.player_faction_account.access_seeds().bump;
6560
*account_set.player_faction_account.data_mut()? = PlayerFactionData {
@@ -74,15 +69,18 @@ impl StarFrameInstruction for ProcessEnlistPlayerIx {
7469
}
7570

7671
#[derive(AccountSet)]
77-
#[validate(arg = u8)]
78-
#[account_set(skip_default_idl)]
7972
pub struct ProcessEnlistPlayer<'info> {
8073
/// The player faction account
81-
#[validate(arg = (Create(()),
74+
#[validate(arg = (Create(CreateAccount::new(&self.system_program, &self.player_account)),
8275
Seeds(PlayerFactionAccountSeeds {
8376
player_account: *self.player_account.key()
8477
})))]
8578
pub player_faction_account: Init<Seeded<DataAccount<'info, PlayerFactionData>>>,
79+
#[validate(arg =Seeds(PlayerFactionAccountSeeds {
80+
player_account: *self.player_account.key()
81+
}))]
82+
pub player_faction_account2:
83+
Seeded<DataAccount<'info, PlayerFactionData>, PlayerFactionAccountSeeds, CurrentProgram>,
8684
/// The player account
8785
#[account_set(funder)]
8886
pub player_account: Writable<Signer<SystemAccount<'info>>>,
@@ -136,11 +134,14 @@ unsafe impl Zeroable for FactionId {}
136134

137135
// TODO - Macro should derive this and with the idl feature enabled would also derive `AccountToIdl` and `TypeToIdl`
138136
impl ProgramAccount for PlayerFactionData {
139-
type OwnerProgram = StarFrameDeclaredProgram;
140137
const DISCRIMINANT: <Self::OwnerProgram as StarFrameProgram>::AccountDiscriminant =
141138
[47, 44, 255, 15, 103, 77, 139, 247];
142139
}
143140

141+
impl HasOwnerProgram for PlayerFactionData {
142+
type OwnerProgram = FactionEnlistment;
143+
}
144+
144145
impl HasSeeds for PlayerFactionData {
145146
type Seeds = PlayerFactionAccountSeeds;
146147
}
@@ -156,15 +157,17 @@ mod tests {
156157
use super::*;
157158
use bytemuck::checked::try_from_bytes;
158159
use solana_program_test::{processor, ProgramTest};
160+
use solana_sdk::account::Account;
159161
use solana_sdk::clock::Clock;
160-
use solana_sdk::signature::Signer;
162+
use solana_sdk::signature::{Keypair, Signer};
161163
use star_frame::borsh::to_vec;
162164
use star_frame::itertools::Itertools;
163165
use star_frame::solana_program::instruction::AccountMeta;
166+
use star_frame::solana_program::native_token::LAMPORTS_PER_SOL;
164167

165168
#[tokio::test]
166169
async fn banks_test() -> Result<()> {
167-
const SBF_FILE: bool = false;
170+
const SBF_FILE: bool = true;
168171
let program_test = if SBF_FILE {
169172
let target_dir = std::env::current_dir()?
170173
.join("../../../target/deploy")
@@ -186,24 +189,27 @@ mod tests {
186189
)
187190
};
188191

189-
let test_context = program_test.start_with_context().await;
192+
let mut test_context = program_test.start_with_context().await;
193+
let (player_account, (faction_account, bump)) = loop {
194+
let key = Keypair::new();
195+
let seeds = PlayerFactionAccountSeeds {
196+
player_account: key.pubkey(),
197+
};
198+
let player_faction =
199+
Pubkey::find_program_address(&seeds.seeds(), &StarFrameDeclaredProgram::PROGRAM_ID);
200+
if player_faction.1 == 255 {
201+
let data = Account {
202+
lamports: LAMPORTS_PER_SOL * 100,
203+
..Default::default()
204+
};
205+
test_context.set_account(&key.pubkey(), &data.into());
206+
break (key, player_faction);
207+
}
208+
};
190209
let mut banks_client = test_context.banks_client;
191210

192-
let player_account = test_context.payer;
193-
194-
let seeds = PlayerFactionAccountSeeds {
195-
player_account: player_account.pubkey(),
196-
};
197-
let (faction_account, bump) =
198-
Pubkey::find_program_address(&seeds.seeds(), &StarFrameDeclaredProgram::PROGRAM_ID);
199-
println!("Bump: {}", bump);
200211
let faction_id = FactionId::MUD;
201212

202-
// let mut random_bytes = [0u8; 1];
203-
// let mut rng = rand::thread_rng();
204-
// rand::rngs::ThreadRng::try_fill(&mut rng, &mut random_bytes[..]).unwrap();
205-
// let bunch_bytes = random_bytes.to_vec();
206-
207213
let enlist_ix = ProcessEnlistPlayerIx {
208214
bump,
209215
faction_id,

framework/star_frame/src/__private/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
pub mod macro_prelude {
2+
pub use crate::account_set::{
3+
AccountSet, CanInitAccount, CanSetSeeds, HasOwnerProgram, HasProgramAccount, HasSeeds,
4+
SignedAccount, SingleAccountSet, SingleAccountSetMetadata, WritableAccount,
5+
};
26
pub use crate::instruction::{Instruction, InstructionDiscriminant};
3-
pub use crate::syscalls::SyscallAccountCache;
7+
pub use crate::syscalls::{SyscallAccountCache, SyscallInvoke};
48
pub use crate::unsize::{
59
AsBytes, AsMutBytes, FromBytesReturn, RefBytes, RefBytesMut, RefDeref, RefDerefMut,
610
RefResize, RefWrapper, RefWrapperMutExt, RefWrapperTypes, Resize, UnsizedInit, UnsizedType,

framework/star_frame/src/account_set/data_account.rs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ use std::marker::PhantomData;
1212
use std::mem::size_of;
1313
use std::slice::from_raw_parts_mut;
1414

15-
pub trait ProgramAccount {
16-
type OwnerProgram: StarFrameProgram;
15+
pub trait ProgramAccount: HasOwnerProgram {
1716
const DISCRIMINANT: <Self::OwnerProgram as StarFrameProgram>::AccountDiscriminant;
1817
}
1918

@@ -93,6 +92,12 @@ pub struct CloseAccountAuto;
9392
}
9493
)]
9594
pub struct DataAccount<'info, T: ProgramAccount + UnsizedType + ?Sized> {
95+
#[single_account_set(
96+
skip_has_program_account,
97+
skip_can_init_account,
98+
skip_has_seeds,
99+
skip_has_owner_program
100+
)]
96101
#[validate(arg = arg)]
97102
info: AccountInfo<'info>,
98103
phantom_t: PhantomData<T>,
@@ -224,20 +229,14 @@ where
224229
}
225230
}
226231

227-
impl<'info, T> SingleAccountSet<'info> for DataAccount<'info, T>
228-
where
229-
T: ProgramAccount + UnsizedType + ?Sized,
230-
{
231-
const METADATA: SingleAccountSetMetadata = SingleAccountSetMetadata::DEFAULT;
232-
fn account_info(&self) -> &AccountInfo<'info> {
233-
&self.info
234-
}
235-
}
236-
237232
impl<'info, T: ProgramAccount + UnsizedType + ?Sized> HasProgramAccount for DataAccount<'info, T> {
238233
type ProgramAccount = T;
239234
}
240235

236+
impl<'info, T: ProgramAccount + UnsizedType + ?Sized> HasOwnerProgram for DataAccount<'info, T> {
237+
type OwnerProgram = T::OwnerProgram;
238+
}
239+
241240
impl<'info, T: ProgramAccount + UnsizedType + ?Sized> HasSeeds for DataAccount<'info, T>
242241
where
243242
T: HasSeeds,

framework/star_frame/src/account_set/funder.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ use star_frame::prelude::*;
1111
skip_default_idl
1212
)]
1313
pub struct Funder<'info> {
14+
#[single_account_set(metadata = SingleAccountSetMetadata {
15+
should_sign: true,
16+
should_mut: true,
17+
..SingleAccountSetMetadata::DEFAULT
18+
}, skip_signed_account)]
1419
inner: Writable<SignerInfo<'info>>,
1520
#[account_set(skip = None)]
1621
seeds: Option<Vec<Vec<u8>>>,
@@ -26,24 +31,10 @@ impl<'info> Funder<'info> {
2631
}
2732
}
2833

29-
impl<'info> SingleAccountSet<'info> for Funder<'info> {
30-
const METADATA: SingleAccountSetMetadata = SingleAccountSetMetadata {
31-
should_sign: true,
32-
should_mut: true,
33-
..SingleAccountSetMetadata::DEFAULT
34-
};
35-
36-
fn account_info(&self) -> &AccountInfo<'info> {
37-
self.inner.account_info()
38-
}
39-
}
40-
4134
impl<'info> SignedAccount<'info> for Funder<'info> {
4235
fn signer_seeds(&self) -> Option<Vec<&[u8]>> {
4336
self.seeds
4437
.as_ref()
4538
.map(|seeds| seeds.iter().map(Vec::as_slice).collect())
4639
}
4740
}
48-
49-
impl<'info> WritableAccount<'info> for Funder<'info> {}

framework/star_frame/src/account_set/modifiers/init.rs

Lines changed: 9 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -67,48 +67,18 @@ pub struct Init<T>(
6767
#[validate(id = "create_generic", arg = arg.1)]
6868
#[validate(id = "create_if_needed_generic", arg = arg.1)]
6969
#[cleanup(arg = arg)]
70+
#[single_account_set(
71+
metadata = SingleAccountSetMetadata {
72+
is_init: true,
73+
should_mut: true,
74+
..T::METADATA
75+
},
76+
skip_can_set_seeds,
77+
skip_can_init_account
78+
)]
7079
T,
7180
);
7281

73-
impl<'info, T> SingleAccountSet<'info> for Init<T>
74-
where
75-
T: SingleAccountSet<'info>,
76-
{
77-
const METADATA: SingleAccountSetMetadata = SingleAccountSetMetadata {
78-
is_init: true,
79-
should_mut: true,
80-
..T::METADATA
81-
};
82-
fn account_info(&self) -> &AccountInfo<'info> {
83-
self.0.account_info()
84-
}
85-
}
86-
87-
impl<'info, T> SignedAccount<'info> for Init<T>
88-
where
89-
T: SignedAccount<'info>,
90-
{
91-
fn signer_seeds(&self) -> Option<Vec<&[u8]>> {
92-
self.0.signer_seeds()
93-
}
94-
}
95-
96-
impl<'info, T> WritableAccount<'info> for Init<T> where T: SingleAccountSet<'info> {}
97-
98-
impl<T> HasProgramAccount for Init<T>
99-
where
100-
T: HasProgramAccount,
101-
{
102-
type ProgramAccount = T::ProgramAccount;
103-
}
104-
105-
impl<T> HasSeeds for Init<T>
106-
where
107-
T: HasSeeds,
108-
{
109-
type Seeds = T::Seeds;
110-
}
111-
11282
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
11383
#[repr(transparent)]
11484
pub struct Create<T>(pub T);

framework/star_frame/src/account_set/modifiers/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ pub trait HasProgramAccount {
2727
type ProgramAccount: ProgramAccount + ?Sized;
2828
}
2929

30+
/// A marker trait that indicates the underlying type is owned by a [`StarFrameProgram`].
31+
pub trait HasOwnerProgram {
32+
type OwnerProgram: StarFrameProgram;
33+
}
34+
3035
/// A marker trait that indicates the underlying type has seeds in it.
3136
pub trait HasSeeds {
3237
type Seeds: GetSeeds;

0 commit comments

Comments
 (0)