aelf-sdk 0.1.0-alpha.1

AElf Rust SDK facade crate.
Documentation
use aelf_sdk::dto::{
    CalculateTransactionFeeInput, CreateRawTransactionInput, ExecuteRawTransactionDto,
    SendRawTransactionInput,
};
use aelf_sdk::proto::token::TransferInput;
use aelf_sdk::{decode_address, parse_aelf_address, AElfClient, ClientConfig, Wallet};
use prost::Message;
use tokio::time::{sleep, Duration};

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let endpoint =
        std::env::var("AELF_ENDPOINT").unwrap_or_else(|_| "http://127.0.0.1:8000".to_owned());
    let private_key = std::env::var("AELF_PRIVATE_KEY")?;
    let to_env = std::env::var("AELF_TO_ADDRESS")?;
    let to = parse_aelf_address(&to_env).to_owned();
    let amount = std::env::var("AELF_AMOUNT")
        .ok()
        .map(|value| value.parse::<i64>())
        .transpose()?
        .unwrap_or(1);
    let should_send = matches!(
        std::env::var("AELF_SEND").ok().as_deref(),
        Some("1" | "true" | "TRUE" | "yes" | "YES")
    );
    let client = AElfClient::new(ClientConfig::new(endpoint))?;
    let wallet = Wallet::from_private_key(&private_key)?;
    let token_address = client
        .utils()
        .get_contract_address_by_name("AElf.ContractNames.Token")
        .await?;
    let chain_status = client.chain().get_chain_status().await?;
    let transfer = TransferInput {
        to: Some(aelf_sdk::proto::aelf::Address {
            value: decode_address(&to)?,
        }),
        symbol: "ELF".to_owned(),
        amount,
        memo: "raw transaction flow validation".to_owned(),
    };
    let params_json = serde_json::to_string(&transfer)?;

    let unsigned = client
        .utils()
        .generate_transaction(wallet.address(), &token_address, "Transfer", &transfer)
        .await?;
    let signed = client.utils().sign_transaction(&wallet, unsigned)?;
    let mut unsigned_only = signed.clone();
    unsigned_only.signature.clear();
    let unsigned_raw = hex::encode(unsigned_only.encode_to_vec());
    let created = client
        .tx()
        .create_raw_transaction(&CreateRawTransactionInput {
            from: wallet.address().to_owned(),
            to: token_address.clone(),
            ref_block_number: chain_status.best_chain_height,
            ref_block_hash: chain_status.best_chain_hash.clone(),
            method_name: "Transfer".to_owned(),
            params: params_json,
        })
        .await;
    let (raw_transaction, created_by_node) = match created {
        Ok(created) => (created.raw_transaction, true),
        Err(error) => {
            println!("create_raw_transaction_error={error}");
            (unsigned_raw.clone(), false)
        }
    };
    let signature = hex::encode(wallet.sign(&hex::decode(&raw_transaction)?)?);

    println!("from={}", wallet.address());
    println!("to={to}");
    println!(
        "formatted_to={}",
        client.utils().get_formatted_address(&to).await?
    );
    println!("token_contract={token_address}");
    println!("amount_raw={amount}");
    println!("created_by_node={created_by_node}");
    println!(
        "raw_transaction_matches_sdk={}",
        raw_transaction.eq_ignore_ascii_case(&unsigned_raw)
    );

    let execute_raw = client
        .tx()
        .execute_raw_transaction(&ExecuteRawTransactionDto {
            raw_transaction: raw_transaction.clone(),
            signature: signature.clone(),
        })
        .await?;
    println!("execute_raw_result={execute_raw}");

    let fee = client
        .tx()
        .calculate_transaction_fee(&CalculateTransactionFeeInput {
            raw_transaction: raw_transaction.clone(),
        })
        .await?;
    println!("estimated_fee={:?}", fee.transaction_fee);

    if !should_send {
        println!("dry_run=true");
        return Ok(());
    }

    let sent = client
        .tx()
        .send_raw_transaction(&SendRawTransactionInput {
            transaction: raw_transaction,
            signature,
            return_transaction: true,
        })
        .await?;
    println!("transaction_id={}", sent.transaction_id);

    for _ in 0..15 {
        let result = client
            .tx()
            .get_transaction_result(&sent.transaction_id)
            .await?;
        println!("status={}", result.status);
        if result.status != "PENDING" {
            println!("tx_fee={:?}", result.get_transaction_fees());
            println!("block_number={}", result.block_number);
            if !result.error.is_empty() {
                println!("error={}", result.error);
            }
            break;
        }
        sleep(Duration::from_secs(1)).await;
    }

    Ok(())
}