#![allow(dead_code)] use solana_client::rpc_client::RpcClient; use solana_program::program_pack::Pack; use solana_sdk::{ pubkey::Pubkey, signature::keypair::Keypair, signer::Signer, system_instruction, transaction::Transaction, }; use spl_associated_token_account::{ get_associated_token_address, instruction::create_associated_token_account, }; use spl_token::{ instruction::{initialize_mint, mint_to}, state::Mint, }; use std::error::Error; use tokio::time::{sleep, Duration}; const RPC_URL: &str = "https://api.devnet.solana.com"; pub struct Client { client: RpcClient, keypair: Keypair, token: Pubkey, } impl Client { pub async fn new() -> Self { let client = RpcClient::new(RPC_URL); let keypair = Keypair::new(); let token = create_token(&client, &keypair).await; Self { client, keypair, token } } pub fn from(keypair: Keypair, token: Pubkey) -> Self { Self { client: RpcClient::new(RPC_URL), keypair, token } } pub fn mint(&self, recipient: &Pubkey) -> Result> { let associated_token_address = self.create_token_account(recipient)?; let mint_to_instruction = mint_to( &spl_token::id(), &self.token, &associated_token_address, &self.keypair.pubkey(), &[], 1_000_000_000, )?; let transaction = Transaction::new_signed_with_payer( &[mint_to_instruction], Some(&self.keypair.pubkey()), &[&self.keypair], self.client.get_latest_blockhash()?, ); let signature = self.client.send_and_confirm_transaction(&transaction)?; Ok(signature.to_string()) } fn create_token_account(&self, recipient: &Pubkey) -> Result> { let address = get_associated_token_address(&recipient, &self.token); if self.client.get_account(&address).is_err() { let create_token_account_instruction = create_associated_token_account( &self.keypair.pubkey(), recipient, &self.token, &spl_token::id(), ); let recent_blockhash = self.client.get_latest_blockhash()?; let tx = Transaction::new_signed_with_payer( &[create_token_account_instruction], Some(&self.keypair.pubkey()), &[&self.keypair], recent_blockhash, ); self.client.send_and_confirm_transaction(&tx)?; } Ok(address) } pub fn wallet_address(&self) -> String { self.keypair.pubkey().to_string() } pub fn token_address(&self) -> String { self.token.to_string() } pub fn get_keypair_base58(&self) -> String { self.keypair.to_base58_string() } } async fn wait_for_sol(client: &RpcClient, pubkey: &Pubkey) { println!("Waiting to receive 0.01 SOL in address {pubkey}"); loop { sleep(Duration::from_secs(30)).await; match client.get_balance(pubkey) { Ok(balance) => { println!("Got {balance} lamports."); if balance > 10_000_000 { return; } } Err(e) => println!("Could not get balance: {e:?}"), } } } async fn create_token(client: &RpcClient, keypair: &Keypair) -> Pubkey { wait_for_sol(client, &keypair.pubkey()).await; let mint_keypair = Keypair::new(); let payer = Keypair::from_base58_string(&keypair.to_base58_string()); let mint_rent = client.get_minimum_balance_for_rent_exemption(Mint::LEN).unwrap(); let create_mint_account_ix = system_instruction::create_account( &payer.pubkey(), &mint_keypair.pubkey(), mint_rent, Mint::LEN as u64, &spl_token::id(), ); let init_mint_ix = initialize_mint(&spl_token::id(), &mint_keypair.pubkey(), &payer.pubkey(), None, 9) .unwrap(); let recent_blockhash = client.get_latest_blockhash().unwrap(); let tx = Transaction::new_signed_with_payer( &[create_mint_account_ix, init_mint_ix], Some(&payer.pubkey()), &[&payer, &mint_keypair], recent_blockhash, ); let signature = client.send_and_confirm_transaction(&tx).unwrap(); println!("Mint created: {}", mint_keypair.pubkey()); println!("Transaction signature: {}", signature); mint_keypair.pubkey() }