264 lines
7.2 KiB
Rust
264 lines
7.2 KiB
Rust
use anyhow::{anyhow, Result};
|
|
use rand::rngs::OsRng;
|
|
use solana_client::rpc_client::RpcClient;
|
|
use solana_client::rpc_config::RpcSendTransactionConfig;
|
|
use solana_client::rpc_request::RpcRequest;
|
|
use solana_client::rpc_response::{RpcResult, RpcSimulateTransactionResult};
|
|
use solana_sdk::commitment_config::CommitmentConfig;
|
|
use solana_sdk::instruction::Instruction;
|
|
use solana_sdk::program_pack::Pack as TokenPack;
|
|
use solana_sdk::pubkey::Pubkey;
|
|
use solana_sdk::signature::{Keypair, Signature, Signer};
|
|
use solana_sdk::transaction::Transaction;
|
|
use spl_token::instruction::{self as token_instruction};
|
|
use std::convert::Into;
|
|
|
|
pub fn create_account_rent_exempt(
|
|
client: &RpcClient,
|
|
payer: &Keypair,
|
|
data_size: usize,
|
|
owner: &Pubkey,
|
|
) -> Result<Keypair> {
|
|
let account = Keypair::generate(&mut OsRng);
|
|
|
|
let signers = [payer, &account];
|
|
|
|
let lamports = client.get_minimum_balance_for_rent_exemption(data_size)?;
|
|
|
|
let create_account_instr = solana_sdk::system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&account.pubkey(),
|
|
lamports,
|
|
data_size as u64,
|
|
owner,
|
|
);
|
|
|
|
let instructions = vec![create_account_instr];
|
|
|
|
let recent_hash = client.get_latest_blockhash()?;
|
|
|
|
let txn = Transaction::new_signed_with_payer(
|
|
&instructions,
|
|
Some(&payer.pubkey()),
|
|
&signers,
|
|
recent_hash,
|
|
);
|
|
|
|
send_txn(client, &txn, false)?;
|
|
Ok(account)
|
|
}
|
|
|
|
pub fn create_token_account(
|
|
client: &RpcClient,
|
|
mint_pubkey: &Pubkey,
|
|
owner_pubkey: &Pubkey,
|
|
payer: &Keypair,
|
|
) -> Result<Keypair> {
|
|
let spl_account = Keypair::generate(&mut OsRng);
|
|
let instructions = create_token_account_instructions(
|
|
client,
|
|
spl_account.pubkey(),
|
|
mint_pubkey,
|
|
owner_pubkey,
|
|
payer,
|
|
)?;
|
|
|
|
let recent_hash = client.get_latest_blockhash()?;
|
|
let signers = vec![payer, &spl_account];
|
|
|
|
let txn = Transaction::new_signed_with_payer(
|
|
&instructions,
|
|
Some(&payer.pubkey()),
|
|
&signers,
|
|
recent_hash,
|
|
);
|
|
send_txn(client, &txn, false)?;
|
|
Ok(spl_account)
|
|
}
|
|
|
|
pub fn create_token_account_instructions(
|
|
client: &RpcClient,
|
|
spl_account: Pubkey,
|
|
mint_pubkey: &Pubkey,
|
|
owner_pubkey: &Pubkey,
|
|
payer: &Keypair,
|
|
) -> Result<Vec<Instruction>> {
|
|
let lamports = client.get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN)?;
|
|
|
|
let create_account_instr = solana_sdk::system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&spl_account,
|
|
lamports,
|
|
spl_token::state::Account::LEN as u64,
|
|
&spl_token::ID,
|
|
);
|
|
|
|
let init_account_instr = token_instruction::initialize_account(
|
|
&spl_token::ID,
|
|
&spl_account,
|
|
&mint_pubkey,
|
|
&owner_pubkey,
|
|
)?;
|
|
|
|
let instructions = vec![create_account_instr, init_account_instr];
|
|
|
|
Ok(instructions)
|
|
}
|
|
|
|
pub fn new_mint(
|
|
client: &RpcClient,
|
|
payer_keypair: &Keypair,
|
|
owner_pubkey: &Pubkey,
|
|
decimals: u8,
|
|
) -> Result<(Keypair, Signature)> {
|
|
let mint = Keypair::generate(&mut OsRng);
|
|
let s = create_and_init_mint(client, payer_keypair, &mint, owner_pubkey, decimals)?;
|
|
Ok((mint, s))
|
|
}
|
|
|
|
pub fn create_and_init_mint(
|
|
client: &RpcClient,
|
|
payer_keypair: &Keypair,
|
|
mint_keypair: &Keypair,
|
|
owner_pubkey: &Pubkey,
|
|
decimals: u8,
|
|
) -> Result<Signature> {
|
|
let signers = vec![payer_keypair, mint_keypair];
|
|
|
|
let lamports = client.get_minimum_balance_for_rent_exemption(spl_token::state::Mint::LEN)?;
|
|
|
|
let create_mint_account_instruction = solana_sdk::system_instruction::create_account(
|
|
&payer_keypair.pubkey(),
|
|
&mint_keypair.pubkey(),
|
|
lamports,
|
|
spl_token::state::Mint::LEN as u64,
|
|
&spl_token::ID,
|
|
);
|
|
let initialize_mint_instruction = token_instruction::initialize_mint(
|
|
&spl_token::ID,
|
|
&mint_keypair.pubkey(),
|
|
owner_pubkey,
|
|
None,
|
|
decimals,
|
|
)?;
|
|
let instructions = vec![create_mint_account_instruction, initialize_mint_instruction];
|
|
|
|
let recent_hash = client.get_latest_blockhash()?;
|
|
let txn = Transaction::new_signed_with_payer(
|
|
&instructions,
|
|
Some(&payer_keypair.pubkey()),
|
|
&signers,
|
|
recent_hash,
|
|
);
|
|
|
|
send_txn(client, &txn, false)
|
|
}
|
|
|
|
pub fn mint_to_new_account(
|
|
client: &RpcClient,
|
|
payer: &Keypair,
|
|
minting_key: &Keypair,
|
|
mint: &Pubkey,
|
|
quantity: u64,
|
|
) -> Result<Keypair> {
|
|
let recip_keypair = Keypair::generate(&mut OsRng);
|
|
|
|
let lamports = client.get_minimum_balance_for_rent_exemption(spl_token::state::Account::LEN)?;
|
|
|
|
let signers = vec![payer, minting_key, &recip_keypair];
|
|
|
|
let create_recip_instr = solana_sdk::system_instruction::create_account(
|
|
&payer.pubkey(),
|
|
&recip_keypair.pubkey(),
|
|
lamports,
|
|
spl_token::state::Account::LEN as u64,
|
|
&spl_token::ID,
|
|
);
|
|
|
|
let init_recip_instr = token_instruction::initialize_account(
|
|
&spl_token::ID,
|
|
&recip_keypair.pubkey(),
|
|
mint,
|
|
&payer.pubkey(),
|
|
)?;
|
|
|
|
let mint_tokens_instr = token_instruction::mint_to(
|
|
&spl_token::ID,
|
|
mint,
|
|
&recip_keypair.pubkey(),
|
|
&minting_key.pubkey(),
|
|
&[],
|
|
quantity,
|
|
)?;
|
|
|
|
let instructions = vec![create_recip_instr, init_recip_instr, mint_tokens_instr];
|
|
|
|
let recent_hash = client.get_latest_blockhash()?;
|
|
let txn = Transaction::new_signed_with_payer(
|
|
&instructions,
|
|
Some(&payer.pubkey()),
|
|
&signers,
|
|
recent_hash,
|
|
);
|
|
|
|
send_txn(client, &txn, false)?;
|
|
Ok(recip_keypair)
|
|
}
|
|
|
|
pub fn transfer(
|
|
client: &RpcClient,
|
|
from: &Pubkey,
|
|
to: &Pubkey,
|
|
amount: u64,
|
|
from_authority: &Keypair,
|
|
payer: &Keypair,
|
|
) -> Result<Signature> {
|
|
let instr = token_instruction::transfer(
|
|
&spl_token::ID,
|
|
from,
|
|
to,
|
|
&from_authority.pubkey(),
|
|
&[],
|
|
amount,
|
|
)?;
|
|
let recent_hash = client.get_latest_blockhash()?;
|
|
let signers = [payer, from_authority];
|
|
let txn =
|
|
Transaction::new_signed_with_payer(&[instr], Some(&payer.pubkey()), &signers, recent_hash);
|
|
send_txn(client, &txn, false)
|
|
}
|
|
|
|
pub fn send_txn(client: &RpcClient, txn: &Transaction, _simulate: bool) -> Result<Signature> {
|
|
Ok(client.send_and_confirm_transaction_with_spinner_and_config(
|
|
txn,
|
|
CommitmentConfig::confirmed(),
|
|
RpcSendTransactionConfig {
|
|
skip_preflight: true,
|
|
..RpcSendTransactionConfig::default()
|
|
},
|
|
)?)
|
|
}
|
|
|
|
pub fn simulate_transaction(
|
|
client: &RpcClient,
|
|
transaction: &Transaction,
|
|
sig_verify: bool,
|
|
cfg: CommitmentConfig,
|
|
) -> RpcResult<RpcSimulateTransactionResult> {
|
|
let serialized_encoded = bs58::encode(bincode::serialize(transaction).unwrap()).into_string();
|
|
client.send(
|
|
RpcRequest::SimulateTransaction,
|
|
serde_json::json!([serialized_encoded, {
|
|
"sigVerify": sig_verify, "commitment": cfg.commitment
|
|
}]),
|
|
)
|
|
}
|
|
|
|
pub fn get_token_account<T: TokenPack>(client: &RpcClient, addr: &Pubkey) -> Result<T> {
|
|
let account = client
|
|
.get_account_with_commitment(addr, CommitmentConfig::processed())?
|
|
.value
|
|
.map_or(Err(anyhow!("Account not found")), Ok)?;
|
|
T::unpack_from_slice(&account.data).map_err(Into::into)
|
|
}
|