use anchor_client::solana_sdk::pubkey::Pubkey; use anchor_client::solana_sdk::signature::{Keypair, Signer}; use anchor_client::solana_sdk::system_instruction; use anchor_client::{Client, Cluster}; use anyhow::Result; use clap::Parser; use solana_sdk::commitment_config::CommitmentConfig; use solana_sdk::signature::read_keypair_file; use solana_sdk::system_program; // The `accounts` and `instructions` modules are generated by the framework. use basic_2::accounts as basic_2_accounts; use basic_2::instruction as basic_2_instruction; use basic_2::Counter; use events::instruction as events_instruction; use events::MyEvent; use optional::accounts::Initialize as OptionalInitialize; use optional::instruction as optional_instruction; // The `accounts` and `instructions` modules are generated by the framework. use basic_4::accounts as basic_4_accounts; use basic_4::instruction as basic_4_instruction; use basic_4::Counter as CounterAccount; // The `accounts` and `instructions` modules are generated by the framework. use crate::Opts; use composite::accounts::{Bar, CompositeUpdate, Foo, Initialize}; use composite::instruction as composite_instruction; use composite::{DummyA, DummyB}; use optional::account::{DataAccount, DataPda}; use std::ops::Deref; use std::sync::Arc; use std::time::Duration; use tokio::sync::mpsc; use tokio::time::sleep; pub async fn main() -> Result<()> { let opts = Opts::parse(); // Wallet and cluster params. let payer = read_keypair_file(&*shellexpand::tilde("~/.config/solana/id.json")) .expect("Example requires a keypair file"); let url = Cluster::Custom( "http://localhost:8899".to_string(), "ws://127.0.0.1:8900".to_string(), ); // Client. let payer = Arc::new(payer); let client = Client::new_with_options(url.clone(), payer.clone(), CommitmentConfig::processed()); println!("\nStarting async test..."); composite(&client, opts.composite_pid).await?; basic_2(&client, opts.basic_2_pid).await?; basic_4(&client, opts.basic_4_pid).await?; test_tokio(client, opts.basic_2_pid).await?; // Can also use references, since they deref to a signer let payer: &Keypair = &payer; let client = Client::new_with_options(url, payer, CommitmentConfig::processed()); events(&client, opts.events_pid).await?; optional(&client, opts.optional_pid).await?; // Success. Ok(()) } pub async fn test_tokio(client: Client>, pid: Pubkey) -> Result<()> { tokio::spawn(async move { let program = client.program(pid).unwrap(); // `Create` parameters. let counter = Arc::new(Keypair::new()); let counter_pubkey = counter.pubkey(); let authority = program.payer(); // Build and send a transaction. program .request() .signer(counter) .accounts(basic_2_accounts::Create { counter: counter_pubkey, user: authority, system_program: system_program::ID, }) .args(basic_2_instruction::Create { authority }) .send() .await .unwrap(); let counter_account: Counter = program.account(counter_pubkey).await.unwrap(); assert_eq!(counter_account.authority, authority); assert_eq!(counter_account.count, 0); }) .await .unwrap(); println!("Tokio success!"); Ok(()) } pub async fn composite + Clone>( client: &Client, pid: Pubkey, ) -> Result<()> { // Program client. let program = client.program(pid)?; // `Initialize` parameters. let dummy_a = Arc::new(Keypair::new()); let dummy_b = Arc::new(Keypair::new()); // Build and send a transaction. program .request() .instruction(system_instruction::create_account( &program.payer(), &dummy_a.pubkey(), program .rpc() .get_minimum_balance_for_rent_exemption(500) .await?, 500, &program.id(), )) .instruction(system_instruction::create_account( &program.payer(), &dummy_b.pubkey(), program .rpc() .get_minimum_balance_for_rent_exemption(500) .await?, 500, &program.id(), )) .signer(dummy_a.clone()) .signer(dummy_b.clone()) .accounts(Initialize { dummy_a: dummy_a.pubkey(), dummy_b: dummy_b.pubkey(), }) .args(composite_instruction::Initialize) .send() .await?; // Assert the transaction worked. let dummy_a_account: DummyA = program.account(dummy_a.pubkey()).await?; let dummy_b_account: DummyB = program.account(dummy_b.pubkey()).await?; assert_eq!(dummy_a_account.data, 0); assert_eq!(dummy_b_account.data, 0); // Build and send another transaction, using composite account parameters. program .request() .accounts(CompositeUpdate { foo: Foo { dummy_a: dummy_a.pubkey(), }, bar: Bar { dummy_b: dummy_b.pubkey(), }, }) .args(composite_instruction::CompositeUpdate { dummy_a: 1234, dummy_b: 4321, }) .send() .await?; // Assert the transaction worked. let dummy_a_account: DummyA = program.account(dummy_a.pubkey()).await?; let dummy_b_account: DummyB = program.account(dummy_b.pubkey()).await?; assert_eq!(dummy_a_account.data, 1234); assert_eq!(dummy_b_account.data, 4321); println!("Composite success!"); Ok(()) } pub async fn basic_2 + Clone>( client: &Client, pid: Pubkey, ) -> Result<()> { let program = client.program(pid)?; // `Create` parameters. let counter = Arc::new(Keypair::new()); let authority = program.payer(); // Build and send a transaction. program .request() .signer(counter.clone()) .accounts(basic_2_accounts::Create { counter: counter.pubkey(), user: authority, system_program: system_program::ID, }) .args(basic_2_instruction::Create { authority }) .send() .await?; let counter_account: Counter = program.account(counter.pubkey()).await?; assert_eq!(counter_account.authority, authority); assert_eq!(counter_account.count, 0); println!("Basic 2 success!"); Ok(()) } pub async fn events + Clone>( client: &Client, pid: Pubkey, ) -> Result<()> { let program = client.program(pid)?; let (sender, mut receiver) = mpsc::unbounded_channel(); let event_unsubscriber = program .on(move |_, event: MyEvent| { if sender.send(event).is_err() { println!("Error while transferring the event.") } }) .await?; sleep(Duration::from_millis(1000)).await; program .request() .args(events_instruction::Initialize {}) .send() .await?; let event = receiver.recv().await.unwrap(); assert_eq!(event.data, 5); assert_eq!(event.label, "hello".to_string()); event_unsubscriber.unsubscribe().await; println!("Events success!"); Ok(()) } pub async fn basic_4 + Clone>( client: &Client, pid: Pubkey, ) -> Result<()> { let program = client.program(pid)?; let authority = program.payer(); let (counter, _) = Pubkey::find_program_address(&[b"counter"], &pid); program .request() .accounts(basic_4_accounts::Initialize { counter, authority, system_program: system_program::ID, }) .args(basic_4_instruction::Initialize {}) .send() .await?; let counter_account: CounterAccount = program.account(counter).await?; assert_eq!(counter_account.authority, authority); assert_eq!(counter_account.count, 0); program .request() .accounts(basic_4_accounts::Increment { counter, authority }) .args(basic_4_instruction::Increment {}) .send() .await?; let counter_account: CounterAccount = program.account(counter).await?; assert_eq!(counter_account.authority, authority); assert_eq!(counter_account.count, 1); println!("Basic 4 success!"); Ok(()) } pub async fn optional + Clone>( client: &Client, pid: Pubkey, ) -> Result<()> { // Program client. let program = client.program(pid)?; // `Initialize` parameters. let data_account_keypair = Arc::new(Keypair::new()); let data_account_key = data_account_keypair.pubkey(); let data_pda_seeds = &[DataPda::PREFIX.as_ref(), data_account_key.as_ref()]; let data_pda_key = Pubkey::find_program_address(data_pda_seeds, &pid).0; let required_keypair = Arc::new(Keypair::new()); let value: u64 = 10; // Build and send a transaction. program .request() .instruction(system_instruction::create_account( &program.payer(), &required_keypair.pubkey(), program .rpc() .get_minimum_balance_for_rent_exemption(DataAccount::LEN) .await?, DataAccount::LEN as u64, &program.id(), )) .signer(data_account_keypair.clone()) .signer(required_keypair.clone()) .accounts(OptionalInitialize { payer: Some(program.payer()), required: required_keypair.pubkey(), system_program: Some(system_program::id()), optional_account: Some(data_account_keypair.pubkey()), optional_pda: None, }) .args(optional_instruction::Initialize { value, key: pid }) .send() .await .unwrap(); // Assert the transaction worked. let required: DataAccount = program.account(required_keypair.pubkey()).await?; assert_eq!(required.data, 0); let optional_pda = program.account::(data_pda_key).await; assert!(optional_pda.is_err()); let optional_account: DataAccount = program.account(data_account_keypair.pubkey()).await?; assert_eq!(optional_account.data, value * 2); println!("Optional success!"); Ok(()) }