avalanche-sdk 0.93.0

Avalanche API/SDK
Documentation
use std::io::{self, Error, ErrorKind};

use avalanche_types::key;
use primitive_types::{H160, H256, U256};
use tokio::time::{sleep, Duration, Instant};

pub const DEFAULT_GAS: u64 = 21000;

#[derive(Clone, Debug)]
pub struct Tx<T>
where
    T: key::secp256k1::ReadOnly + key::secp256k1::SignOnly + Clone,
{
    pub inner: crate::wallet::eth::Eth<T>,

    /// Transfer fund receiver address.
    pub receiver: H160,

    /// Transfer amount.
    pub amount: U256,

    /// Gas.
    /// "Max priority fee (GWEI)" in Metamask maps to "GasTipCap".
    /// "Max fee(GWEI)" in Metamask maps to "GasPrice".
    pub gas: U256,
    /// Gas price.
    /// "Max priority fee (GWEI)" in Metamask maps to "GasTipCap".
    /// "Max fee(GWEI)" in Metamask maps to "GasPrice".
    pub gas_price: U256,

    /// Integer of a nonce. This overwrites its own pending transactions
    /// that use the same nonce.
    pub nonce: Option<primitive_types::U256>,

    /// The compiled code of a contract OR the hash of the invoked
    /// method signature and encoded parameters.
    pub data: Option<Vec<u8>>,

    /// Set "true" to poll transfer status after issuance for its acceptance.
    pub check_acceptance: bool,

    /// Initial wait duration before polling for acceptance.
    pub poll_initial_wait: Duration,
    /// Wait between each poll intervals for acceptance.
    pub poll_interval: Duration,
    /// Maximum duration for polling.
    pub poll_timeout: Duration,

    /// Set to true to return transaction Id for "issue" in dry mode.
    pub dry_mode: bool,
}

impl<T> Tx<T>
where
    T: key::secp256k1::ReadOnly + key::secp256k1::SignOnly + Clone,
{
    pub fn new(ev: &crate::wallet::eth::Eth<T>) -> Self {
        Self {
            inner: ev.clone(),
            receiver: H160::zero(),

            amount: U256::from(0),

            gas: U256::from(DEFAULT_GAS),
            gas_price: U256::from(0),

            nonce: None,

            data: None,

            check_acceptance: false,

            poll_initial_wait: Duration::from_millis(500),
            poll_interval: Duration::from_millis(700),
            poll_timeout: Duration::from_secs(300),

            dry_mode: false,
        }
    }

    /// Sets the transfer fund receiver address.
    #[must_use]
    pub fn receiver(mut self, receiver: H160) -> Self {
        self.receiver = receiver;
        self
    }

    /// Sets the transfer amount.
    #[must_use]
    pub fn amount(mut self, amount: U256) -> Self {
        self.amount = amount;
        self
    }

    #[must_use]
    pub fn gas(mut self, gas: U256) -> Self {
        self.gas = gas;
        self
    }

    #[must_use]
    pub fn gas_price(mut self, gas_price: U256) -> Self {
        self.gas_price = gas_price;
        self
    }

    #[must_use]
    pub fn nonce(mut self, nonce: U256) -> Self {
        self.nonce = Some(nonce);
        self
    }

    #[must_use]
    pub fn data(mut self, data: Vec<u8>) -> Self {
        self.data = Some(data);
        self
    }

    /// Sets the check acceptance boolean flag.
    #[must_use]
    pub fn check_acceptance(mut self, check_acceptance: bool) -> Self {
        self.check_acceptance = check_acceptance;
        self
    }

    /// Sets the initial poll wait time.
    #[must_use]
    pub fn poll_initial_wait(mut self, poll_initial_wait: Duration) -> Self {
        self.poll_initial_wait = poll_initial_wait;
        self
    }

    /// Sets the poll wait time between intervals.
    #[must_use]
    pub fn poll_interval(mut self, poll_interval: Duration) -> Self {
        self.poll_interval = poll_interval;
        self
    }

    /// Sets the poll timeout.
    #[must_use]
    pub fn poll_timeout(mut self, poll_timeout: Duration) -> Self {
        self.poll_timeout = poll_timeout;
        self
    }

    /// Sets the dry mode boolean flag.
    #[must_use]
    pub fn dry_mode(mut self, dry_mode: bool) -> Self {
        self.dry_mode = dry_mode;
        self
    }

    /// Issues the transfer transaction and returns the transaction Id.
    pub async fn issue(&self) -> io::Result<H256> {
        let picked_http_rpc = self.inner.inner.pick_http_rpc();
        log::info!(
            "transferring EVM {} AVAX from {} to {} via {} (chain RPC {})",
            self.amount,
            self.inner.inner.h160_address,
            self.receiver,
            picked_http_rpc.1,
            self.inner.chain_rpc_url_path
        );

        // enough time for txs processing
        log::info!("initial waiting {:?}", self.poll_initial_wait);
        sleep(self.poll_initial_wait).await;

        log::info!("polling to confirm transaction");
        let (start, mut success) = (Instant::now(), false);
        loop {
            let elapsed = start.elapsed();
            if elapsed.gt(&self.poll_timeout) {
                break;
            }

            if 1 == 1 {
                success = true;
                break;
            }

            sleep(self.poll_interval).await;
        }
        if !success {
            return Err(Error::new(
                ErrorKind::Other,
                "failed to check acceptance in time",
            ));
        }

        return Err(Error::new(ErrorKind::Other, "not implemented"));
    }
}