291 lines
7.4 KiB
Rust
291 lines
7.4 KiB
Rust
use solana_program_test::{
|
|
tokio::{self, sync::Mutex},
|
|
ProgramTest,
|
|
};
|
|
use solana_sdk::{
|
|
program_option::COption,
|
|
signer::{keypair::Keypair, Signer},
|
|
};
|
|
use spl_token_2022::{instruction, state};
|
|
use spl_token_client::{
|
|
client::{ProgramBanksClient, ProgramBanksClientProcessTransaction, ProgramClient},
|
|
token::Token,
|
|
};
|
|
use std::sync::Arc;
|
|
|
|
struct TestContext {
|
|
pub decimals: u8,
|
|
pub mint_authority: Keypair,
|
|
pub token: Token<ProgramBanksClientProcessTransaction, Keypair>,
|
|
|
|
pub alice: Keypair,
|
|
pub bob: Keypair,
|
|
}
|
|
|
|
impl TestContext {
|
|
async fn new() -> Self {
|
|
let program_test = ProgramTest::default();
|
|
let ctx = program_test.start_with_context().await;
|
|
let ctx = Arc::new(Mutex::new(ctx));
|
|
|
|
let payer = keypair_clone(&ctx.lock().await.payer);
|
|
|
|
let client: Arc<dyn ProgramClient<ProgramBanksClientProcessTransaction>> =
|
|
Arc::new(ProgramBanksClient::new_from_context(
|
|
Arc::clone(&ctx),
|
|
ProgramBanksClientProcessTransaction,
|
|
));
|
|
|
|
let decimals: u8 = 6;
|
|
|
|
let mint_account = Keypair::new();
|
|
let mint_authority = Keypair::new();
|
|
let mint_authority_pubkey = mint_authority.pubkey();
|
|
|
|
let token = Token::create_mint(
|
|
Arc::clone(&client),
|
|
&spl_token_2022::id(),
|
|
keypair_clone(&payer),
|
|
&mint_account,
|
|
&mint_authority_pubkey,
|
|
None,
|
|
decimals,
|
|
vec![],
|
|
)
|
|
.await
|
|
.expect("failed to create mint");
|
|
|
|
Self {
|
|
decimals,
|
|
mint_authority,
|
|
token,
|
|
|
|
alice: Keypair::new(),
|
|
bob: Keypair::new(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn keypair_clone(kp: &Keypair) -> Keypair {
|
|
Keypair::from_bytes(&kp.to_bytes()).expect("failed to copy keypair")
|
|
}
|
|
|
|
// TODO unignore once spl-token-2022 becomes spl-token, and is included in
|
|
// ProgramTest by default
|
|
#[ignore]
|
|
#[tokio::test]
|
|
async fn associated_token_account() {
|
|
let TestContext { token, alice, .. } = TestContext::new().await;
|
|
|
|
let alice_vault = token
|
|
.create_associated_token_account(&alice.pubkey())
|
|
.await
|
|
.expect("failed to create associated token account");
|
|
|
|
assert_eq!(
|
|
token.get_associated_token_address(&alice.pubkey()),
|
|
alice_vault
|
|
);
|
|
|
|
assert_eq!(
|
|
token
|
|
.get_account_info(&alice_vault)
|
|
.await
|
|
.expect("failed to get account info")
|
|
.base,
|
|
state::Account {
|
|
mint: *token.get_address(),
|
|
owner: alice.pubkey(),
|
|
amount: 0,
|
|
delegate: COption::None,
|
|
state: state::AccountState::Initialized,
|
|
is_native: COption::None,
|
|
delegated_amount: 0,
|
|
close_authority: COption::None,
|
|
}
|
|
);
|
|
}
|
|
|
|
// TODO unignore once spl-token-2022 becomes spl-token, and is included in
|
|
// ProgramTest by default
|
|
#[ignore]
|
|
#[tokio::test]
|
|
async fn get_or_create_associated_token_account() {
|
|
let TestContext { token, alice, .. } = TestContext::new().await;
|
|
|
|
assert_eq!(
|
|
token
|
|
.get_or_create_associated_account_info(&alice.pubkey())
|
|
.await
|
|
.expect("failed to get account info")
|
|
.base,
|
|
state::Account {
|
|
mint: *token.get_address(),
|
|
owner: alice.pubkey(),
|
|
amount: 0,
|
|
delegate: COption::None,
|
|
state: state::AccountState::Initialized,
|
|
is_native: COption::None,
|
|
delegated_amount: 0,
|
|
close_authority: COption::None,
|
|
}
|
|
);
|
|
}
|
|
|
|
// TODO unignore once spl-token-2022 becomes spl-token, and is included in
|
|
// ProgramTest by default
|
|
#[ignore]
|
|
#[tokio::test]
|
|
async fn set_authority() {
|
|
let TestContext {
|
|
mint_authority,
|
|
token,
|
|
alice,
|
|
bob,
|
|
..
|
|
} = TestContext::new().await;
|
|
|
|
let alice_vault = token
|
|
.create_associated_token_account(&alice.pubkey())
|
|
.await
|
|
.expect("failed to create associated token account");
|
|
|
|
token
|
|
.mint_to(&alice_vault, &mint_authority, 1)
|
|
.await
|
|
.expect("failed to mint token");
|
|
|
|
token
|
|
.set_authority(
|
|
token.get_address(),
|
|
None,
|
|
instruction::AuthorityType::MintTokens,
|
|
&mint_authority,
|
|
)
|
|
.await
|
|
.expect("failed to set authority");
|
|
|
|
let mint = token
|
|
.get_mint_info()
|
|
.await
|
|
.expect("failed to get mint info");
|
|
assert!(mint.base.mint_authority.is_none());
|
|
|
|
// TODO: compare
|
|
// Err(Client(TransactionError(InstructionError(0, Custom(5)))))
|
|
assert!(token
|
|
.mint_to(&alice_vault, &mint_authority, 2)
|
|
.await
|
|
.is_err());
|
|
|
|
token
|
|
.set_authority(
|
|
&alice_vault,
|
|
Some(&bob.pubkey()),
|
|
instruction::AuthorityType::AccountOwner,
|
|
&alice,
|
|
)
|
|
.await
|
|
.expect("failed to set_authority");
|
|
|
|
assert_eq!(
|
|
token
|
|
.get_account_info(&alice_vault)
|
|
.await
|
|
.expect("failed to get account info")
|
|
.base
|
|
.owner,
|
|
bob.pubkey(),
|
|
);
|
|
}
|
|
|
|
// TODO unignore once spl-token-2022 becomes spl-token, and is included in
|
|
// ProgramTest by default
|
|
#[ignore]
|
|
#[tokio::test]
|
|
async fn mint_to() {
|
|
let TestContext {
|
|
decimals,
|
|
mint_authority,
|
|
token,
|
|
alice,
|
|
..
|
|
} = TestContext::new().await;
|
|
|
|
let alice_vault = token
|
|
.create_associated_token_account(&alice.pubkey())
|
|
.await
|
|
.expect("failed to create associated token account");
|
|
|
|
let mint_amount = 10 * u64::pow(10, decimals as u32);
|
|
token
|
|
.mint_to(&alice_vault, &mint_authority, mint_amount)
|
|
.await
|
|
.expect("failed to mint token");
|
|
|
|
assert_eq!(
|
|
token
|
|
.get_account_info(&alice_vault)
|
|
.await
|
|
.expect("failed to get account")
|
|
.base
|
|
.amount,
|
|
mint_amount
|
|
);
|
|
}
|
|
|
|
// TODO unignore once spl-token-2022 becomes spl-token, and is included in
|
|
// ProgramTest by default
|
|
#[ignore]
|
|
#[tokio::test]
|
|
async fn transfer() {
|
|
let TestContext {
|
|
decimals,
|
|
mint_authority,
|
|
token,
|
|
alice,
|
|
bob,
|
|
..
|
|
} = TestContext::new().await;
|
|
|
|
let alice_vault = token
|
|
.create_associated_token_account(&alice.pubkey())
|
|
.await
|
|
.expect("failed to create associated token account");
|
|
let bob_vault = token
|
|
.create_associated_token_account(&bob.pubkey())
|
|
.await
|
|
.expect("failed to create associated token account");
|
|
|
|
let mint_amount = 10 * u64::pow(10, decimals as u32);
|
|
token
|
|
.mint_to(&alice_vault, &mint_authority, mint_amount)
|
|
.await
|
|
.expect("failed to mint token");
|
|
|
|
let transfer_amount = mint_amount.overflowing_div(3).0;
|
|
token
|
|
.transfer_checked(&alice_vault, &bob_vault, &alice, transfer_amount, decimals)
|
|
.await
|
|
.expect("failed to transfer");
|
|
|
|
assert_eq!(
|
|
token
|
|
.get_account_info(&alice_vault)
|
|
.await
|
|
.expect("failed to get account")
|
|
.base
|
|
.amount,
|
|
mint_amount - transfer_amount
|
|
);
|
|
assert_eq!(
|
|
token
|
|
.get_account_info(&bob_vault)
|
|
.await
|
|
.expect("failed to get account")
|
|
.base
|
|
.amount,
|
|
transfer_amount
|
|
);
|
|
}
|