impl 2 task

master
plazmoid 1 week ago
parent 544be727e3
commit f389b6f856
  1. 6289
      mass-transfer-2/Cargo.lock
  2. 14
      mass-transfer-2/Cargo.toml
  3. 10
      mass-transfer-2/config.yaml
  4. 162
      mass-transfer-2/src/main.rs

File diff suppressed because it is too large Load Diff

@ -0,0 +1,14 @@
[package]
name = "mass-transfer-2"
version = "0.1.0"
edition = "2024"
[dependencies]
bs58 = "0.5.1"
config = "0.15.11"
futures = "0.3.31"
serde = { version = "1.0.219", features = ["derive"] }
serde_json = "1.0.140"
solana-client = "2.2.7"
solana-sdk = "2.2.2"
tokio = { version = "1.45.0", features = ["macros", "rt-multi-thread"] }

@ -0,0 +1,10 @@
transfers:
- sender:
pubkey: BqrHGjskCWo9Sx6gWeoVHVZbpi6KoE9q6BspdaaGDkmc
privkey: BEYTkFt8uZp2uKtXrWTvt8CzVHjF9BvjvMQnWKvAwGrB
receiver: Sysvar1nstructions1111111111111111111111111
- sender:
pubkey: EvsGrL9cXhCJn3KxfHnxKjRJwZgHt2tmHuvn7WMq1Vxu
privkey: 6dWCFhZXSHsdQapb9wks6qR8EvkjgEQhZtcJnR5GS1dc
receiver: HEvSKofvBgfaexv23kMabbYqxasxU3mQ4ibBMEmJWHny
solana_url: https://api.devnet.solana.com

@ -0,0 +1,162 @@
use std::{error::Error, str::FromStr, sync::Arc};
use config::Config;
use futures::future::join_all;
use serde::{Deserialize, de};
use solana_client::{client_error::ClientError, nonblocking::rpc_client::RpcClient};
use solana_sdk::{
commitment_config::CommitmentConfig,
native_token::LAMPORTS_PER_SOL,
pubkey::Pubkey,
signature::{Keypair, Signature},
signer::Signer,
system_instruction,
transaction::Transaction,
};
#[derive(Deserialize)]
struct Cfg {
transfers: Vec<CfgTransfer>,
solana_url: String,
}
#[derive(Deserialize)]
struct CfgTransfer {
#[serde(deserialize_with = "deser_keypair")]
sender: Keypair,
#[serde(deserialize_with = "deser_pubkey")]
receiver: Pubkey,
}
pub fn deser_keypair<'de, D>(deserializer: D) -> Result<Keypair, D::Error>
where
D: de::Deserializer<'de>,
{
#[derive(Deserialize)]
struct CfgKeyPair {
pubkey: String,
privkey: String,
}
let pair: CfgKeyPair = de::Deserialize::deserialize(deserializer)?;
let privkey = bs58::decode(pair.privkey)
.into_vec()
.map_err(de::Error::custom)?;
let pubkey = bs58::decode(pair.pubkey)
.into_vec()
.map_err(de::Error::custom)?;
let mut bytes = [0u8; 64];
bytes[..32].copy_from_slice(&privkey);
bytes[32..].copy_from_slice(&pubkey);
Keypair::from_bytes(&bytes).map_err(de::Error::custom)
}
pub fn deser_pubkey<'de, D>(deserializer: D) -> Result<Pubkey, D::Error>
where
D: de::Deserializer<'de>,
{
let s: String = de::Deserialize::deserialize(deserializer)?;
Pubkey::from_str(&s).map_err(de::Error::custom)
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let config = {
let config_parser = Config::builder()
.add_source(config::File::with_name("config.yaml"))
.build()?;
config_parser.try_deserialize::<Cfg>()?
};
let client = Arc::new(RpcClient::new_with_commitment(
config.solana_url.clone(),
CommitmentConfig::confirmed(),
));
let accounts_from = config
.transfers
.iter()
.map(|t| t.sender.pubkey())
.collect::<Vec<_>>();
let accounts_to = config
.transfers
.iter()
.map(|s| s.receiver)
.collect::<Vec<_>>();
// for acc in &accounts_from {
// println!("requesting airdrop for {acc}");
// let signature = client.request_airdrop(&acc, LAMPORTS_PER_SOL).await?;
// wait_for_confirmation(client.clone(), &[signature]).await?;
// }
let all_accounts = accounts_from.iter().chain(&accounts_to);
print_balances(client.clone(), all_accounts.clone()).await?;
let transfer_amount = LAMPORTS_PER_SOL / 100;
println!("sending {transfer_amount} SOL");
let transactions = run_batch(config.transfers.iter().map(|tr| {
let instruction =
system_instruction::transfer(&tr.sender.pubkey(), &tr.receiver, transfer_amount);
let mut transaction =
Transaction::new_with_payer(&[instruction], Some(&tr.sender.pubkey()));
let client = client.clone();
async move {
let blockhash = client.get_latest_blockhash().await?;
transaction.sign(&[&tr.sender], blockhash);
client.send_transaction(&transaction).await
}
}))
.await?;
println!("Pending transactions: \n{transactions:#?}");
println!("Waiting for confirmation...");
wait_for_confirmation(client.clone(), &transactions).await?;
println!("Mass-transfer is done");
print_balances(client.clone(), all_accounts).await?;
Ok(())
}
async fn wait_for_confirmation(
client: Arc<RpcClient>,
signatures: &[Signature],
) -> Result<(), ClientError> {
for sgn in signatures {
'conf: loop {
let confirmed = client.confirm_transaction(sgn).await?;
if confirmed {
break 'conf;
}
}
}
Ok(())
}
async fn run_batch<T>(
tasks: impl IntoIterator<Item = impl Future<Output = Result<T, ClientError>>>,
) -> Result<Vec<T>, ClientError> {
join_all(tasks).await.into_iter().collect()
}
async fn print_balances(
client: Arc<RpcClient>,
accounts: impl IntoIterator<Item = &Pubkey> + Clone,
) -> Result<(), ClientError> {
let balances = run_batch(accounts.clone().into_iter().map(|acc| {
let client = client.clone();
async move {
let balance = client.get_balance(acc).await?;
Ok(balance as f64 / LAMPORTS_PER_SOL as f64)
}
}))
.await?;
for (acc, bal) in accounts.into_iter().zip(balances) {
println!("{acc}: {bal} SOL");
}
Ok(())
}
Loading…
Cancel
Save