Skip to content
This repository was archived by the owner on Mar 11, 2025. It is now read-only.

Commit a98977f

Browse files
token-2022: add more tests (#2783)
* Add extended-mint case to test_get_account_data_size() * Add missing account-type init * Add basic init-acct ProgramTest tests
1 parent c03c1fc commit a98977f

File tree

2 files changed

+299
-6
lines changed

2 files changed

+299
-6
lines changed

token/program-2022/src/processor.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ impl Processor {
149149
};
150150

151151
account.pack_base();
152+
account.init_account_type()?;
152153

153154
Ok(())
154155
}
@@ -1113,10 +1114,15 @@ impl PrintProgramError for TokenError {
11131114
#[cfg(test)]
11141115
mod tests {
11151116
use super::*;
1116-
use crate::instruction::*;
1117+
use crate::{
1118+
extension::transfer_fee::instruction::initialize_transfer_fee_config, instruction::*,
1119+
};
11171120
use solana_program::{
1118-
account_info::IntoAccountInfo, clock::Epoch, instruction::Instruction, program_error,
1119-
sysvar::rent,
1121+
account_info::IntoAccountInfo,
1122+
clock::Epoch,
1123+
instruction::Instruction,
1124+
program_error,
1125+
sysvar::{clock::Clock, rent},
11201126
};
11211127
use solana_sdk::account::{
11221128
create_account_for_test, create_is_signer_account_infos, Account as SolanaAccount,
@@ -1144,8 +1150,11 @@ mod tests {
11441150
Err(ProgramError::Custom(42)) // Not supported
11451151
}
11461152

1147-
fn sol_get_clock_sysvar(&self, _var_addr: *mut u8) -> u64 {
1148-
program_error::UNSUPPORTED_SYSVAR
1153+
fn sol_get_clock_sysvar(&self, var_addr: *mut u8) -> u64 {
1154+
unsafe {
1155+
*(var_addr as *mut _ as *mut Clock) = Clock::default();
1156+
}
1157+
solana_program::entrypoint::SUCCESS
11491158
}
11501159

11511160
fn sol_get_epoch_schedule_sysvar(&self, _var_addr: *mut u8) -> u64 {
@@ -6597,7 +6606,35 @@ mod tests {
65976606
)
65986607
.unwrap();
65996608

6600-
// TODO: Extended mint
6609+
// Extended mint
6610+
let mint_len = ExtensionType::get_account_len::<Mint>(&[ExtensionType::TransferFeeConfig]);
6611+
let mut extended_mint_account = SolanaAccount::new(
6612+
Rent::default().minimum_balance(mint_len),
6613+
mint_len,
6614+
&program_id,
6615+
);
6616+
let extended_mint_key = Pubkey::new_unique();
6617+
do_process_instruction(
6618+
initialize_transfer_fee_config(&extended_mint_key, None, None, 10, 4242),
6619+
vec![&mut extended_mint_account],
6620+
)
6621+
.unwrap();
6622+
do_process_instruction(
6623+
initialize_mint(&program_id, &extended_mint_key, &owner_key, None, 2).unwrap(),
6624+
vec![&mut extended_mint_account, &mut rent_sysvar],
6625+
)
6626+
.unwrap();
6627+
6628+
set_expected_data(
6629+
ExtensionType::get_account_len::<Account>(&[ExtensionType::TransferFeeAmount])
6630+
.to_le_bytes()
6631+
.to_vec(),
6632+
);
6633+
do_process_instruction(
6634+
get_account_data_size(&program_id, &mint_key).unwrap(),
6635+
vec![&mut extended_mint_account],
6636+
)
6637+
.unwrap();
66016638

66026639
// Invalid mint
66036640
let mut invalid_mint_account = SolanaAccount::new(
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
#![cfg(feature = "test-bpf")]
2+
3+
use {
4+
solana_program_test::{processor, tokio, ProgramTest},
5+
solana_sdk::{
6+
instruction::InstructionError,
7+
program_pack::Pack,
8+
pubkey::Pubkey,
9+
signature::Signer,
10+
signer::keypair::Keypair,
11+
system_instruction,
12+
transaction::{Transaction, TransactionError},
13+
},
14+
spl_token_2022::{
15+
error::TokenError,
16+
extension::{
17+
transfer_fee::{self, TransferFeeAmount},
18+
ExtensionType, StateWithExtensions,
19+
},
20+
id, instruction,
21+
processor::Processor,
22+
state::{Account, Mint},
23+
},
24+
};
25+
26+
#[tokio::test]
27+
async fn no_extensions() {
28+
let program_test = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process));
29+
let mut ctx = program_test.start_with_context().await;
30+
let rent = ctx.banks_client.get_rent().await.unwrap();
31+
let mint_account = Keypair::new();
32+
let mint_authority_pubkey = Pubkey::new_unique();
33+
34+
let space = ExtensionType::get_account_len::<Mint>(&[]);
35+
let instructions = vec![
36+
system_instruction::create_account(
37+
&ctx.payer.pubkey(),
38+
&mint_account.pubkey(),
39+
rent.minimum_balance(space),
40+
space as u64,
41+
&spl_token_2022::id(),
42+
),
43+
instruction::initialize_mint(
44+
&spl_token_2022::id(),
45+
&mint_account.pubkey(),
46+
&mint_authority_pubkey,
47+
None,
48+
9,
49+
)
50+
.unwrap(),
51+
];
52+
let tx = Transaction::new_signed_with_payer(
53+
&instructions,
54+
Some(&ctx.payer.pubkey()),
55+
&[&ctx.payer, &mint_account],
56+
ctx.last_blockhash,
57+
);
58+
ctx.banks_client.process_transaction(tx).await.unwrap();
59+
60+
let account = Keypair::new();
61+
let account_owner_pubkey = Pubkey::new_unique();
62+
let space = ExtensionType::get_account_len::<Account>(&[]);
63+
let instructions = vec![
64+
system_instruction::create_account(
65+
&ctx.payer.pubkey(),
66+
&account.pubkey(),
67+
rent.minimum_balance(space),
68+
space as u64,
69+
&spl_token_2022::id(),
70+
),
71+
instruction::initialize_account3(
72+
&spl_token_2022::id(),
73+
&account.pubkey(),
74+
&mint_account.pubkey(),
75+
&account_owner_pubkey,
76+
)
77+
.unwrap(),
78+
];
79+
let tx = Transaction::new_signed_with_payer(
80+
&instructions,
81+
Some(&ctx.payer.pubkey()),
82+
&[&ctx.payer, &account],
83+
ctx.last_blockhash,
84+
);
85+
ctx.banks_client.process_transaction(tx).await.unwrap();
86+
let account_info = ctx
87+
.banks_client
88+
.get_account(account.pubkey())
89+
.await
90+
.expect("get_account")
91+
.expect("account not none");
92+
assert_eq!(account_info.data.len(), spl_token_2022::state::Account::LEN);
93+
assert_eq!(account_info.owner, spl_token_2022::id());
94+
assert_eq!(account_info.lamports, rent.minimum_balance(space));
95+
}
96+
97+
#[tokio::test]
98+
async fn fail_on_invalid_mint() {
99+
let program_test = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process));
100+
let mut ctx = program_test.start_with_context().await;
101+
let rent = ctx.banks_client.get_rent().await.unwrap();
102+
let mint_account = Keypair::new();
103+
104+
let space = ExtensionType::get_account_len::<Mint>(&[]);
105+
let instructions = vec![system_instruction::create_account(
106+
&ctx.payer.pubkey(),
107+
&mint_account.pubkey(),
108+
rent.minimum_balance(space),
109+
space as u64,
110+
&spl_token_2022::id(),
111+
)];
112+
let tx = Transaction::new_signed_with_payer(
113+
&instructions,
114+
Some(&ctx.payer.pubkey()),
115+
&[&ctx.payer, &mint_account],
116+
ctx.last_blockhash,
117+
);
118+
ctx.banks_client.process_transaction(tx).await.unwrap();
119+
120+
let account = Keypair::new();
121+
let account_owner_pubkey = Pubkey::new_unique();
122+
let space = ExtensionType::get_account_len::<Account>(&[]);
123+
let instructions = vec![
124+
system_instruction::create_account(
125+
&ctx.payer.pubkey(),
126+
&account.pubkey(),
127+
rent.minimum_balance(space),
128+
space as u64,
129+
&spl_token_2022::id(),
130+
),
131+
instruction::initialize_account3(
132+
&spl_token_2022::id(),
133+
&account.pubkey(),
134+
&mint_account.pubkey(),
135+
&account_owner_pubkey,
136+
)
137+
.unwrap(),
138+
];
139+
let tx = Transaction::new_signed_with_payer(
140+
&instructions,
141+
Some(&ctx.payer.pubkey()),
142+
&[&ctx.payer, &account],
143+
ctx.last_blockhash,
144+
);
145+
#[allow(clippy::useless_conversion)]
146+
let err: TransactionError = ctx
147+
.banks_client
148+
.process_transaction(tx)
149+
.await
150+
.unwrap_err()
151+
.unwrap()
152+
.into();
153+
assert_eq!(
154+
err,
155+
TransactionError::InstructionError(
156+
1,
157+
InstructionError::Custom(TokenError::InvalidMint as u32)
158+
)
159+
);
160+
}
161+
162+
#[tokio::test]
163+
async fn single_extension() {
164+
let program_test = ProgramTest::new("spl_token_2022", id(), processor!(Processor::process));
165+
let mut ctx = program_test.start_with_context().await;
166+
let rent = ctx.banks_client.get_rent().await.unwrap();
167+
let mint_account = Keypair::new();
168+
let mint_authority_pubkey = Pubkey::new_unique();
169+
170+
let space = ExtensionType::get_account_len::<Mint>(&[ExtensionType::TransferFeeConfig]);
171+
let instructions = vec![
172+
system_instruction::create_account(
173+
&ctx.payer.pubkey(),
174+
&mint_account.pubkey(),
175+
rent.minimum_balance(space),
176+
space as u64,
177+
&spl_token_2022::id(),
178+
),
179+
transfer_fee::instruction::initialize_transfer_fee_config(
180+
&mint_account.pubkey(),
181+
None,
182+
None,
183+
10,
184+
4242,
185+
),
186+
instruction::initialize_mint(
187+
&spl_token_2022::id(),
188+
&mint_account.pubkey(),
189+
&mint_authority_pubkey,
190+
None,
191+
9,
192+
)
193+
.unwrap(),
194+
];
195+
let tx = Transaction::new_signed_with_payer(
196+
&instructions,
197+
Some(&ctx.payer.pubkey()),
198+
&[&ctx.payer, &mint_account],
199+
ctx.last_blockhash,
200+
);
201+
ctx.banks_client.process_transaction(tx).await.unwrap();
202+
203+
let account = Keypair::new();
204+
let account_owner_pubkey = Pubkey::new_unique();
205+
let space = ExtensionType::get_account_len::<Account>(&[ExtensionType::TransferFeeAmount]);
206+
let instructions = vec![
207+
system_instruction::create_account(
208+
&ctx.payer.pubkey(),
209+
&account.pubkey(),
210+
rent.minimum_balance(space),
211+
space as u64,
212+
&spl_token_2022::id(),
213+
),
214+
instruction::initialize_account3(
215+
&spl_token_2022::id(),
216+
&account.pubkey(),
217+
&mint_account.pubkey(),
218+
&account_owner_pubkey,
219+
)
220+
.unwrap(),
221+
];
222+
let tx = Transaction::new_signed_with_payer(
223+
&instructions,
224+
Some(&ctx.payer.pubkey()),
225+
&[&ctx.payer, &account],
226+
ctx.last_blockhash,
227+
);
228+
ctx.banks_client.process_transaction(tx).await.unwrap();
229+
let account_info = ctx
230+
.banks_client
231+
.get_account(account.pubkey())
232+
.await
233+
.expect("get_account")
234+
.expect("account not none");
235+
assert_eq!(
236+
account_info.data.len(),
237+
ExtensionType::get_account_len::<Account>(&[ExtensionType::TransferFeeAmount]),
238+
);
239+
assert_eq!(account_info.owner, spl_token_2022::id());
240+
assert_eq!(account_info.lamports, rent.minimum_balance(space));
241+
let state = StateWithExtensions::<Account>::unpack(&account_info.data).unwrap();
242+
assert_eq!(state.base.mint, mint_account.pubkey());
243+
assert_eq!(
244+
&state.get_extension_types().unwrap(),
245+
&[ExtensionType::TransferFeeAmount]
246+
);
247+
let unpacked_extension = state.get_extension::<TransferFeeAmount>().unwrap();
248+
assert_eq!(
249+
*unpacked_extension,
250+
TransferFeeAmount {
251+
withheld_amount: 0.into()
252+
}
253+
);
254+
}
255+
256+
// TODO: add test for multiple Account extensions when memo extension is present

0 commit comments

Comments
 (0)