avalanche-sdk 0.71.2

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

use avalanche_types::jsonrpc::{self, platformvm};

/// e.g., "platform.issueTx" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetcurrentvalidators
pub async fn issue_tx(http_rpc: &str, tx: &str) -> io::Result<jsonrpc::IssueTxResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("issuing a transaction via {:?}", joined.as_str());

    let mut data = jsonrpc::DataForIssueTx::default();
    data.method = String::from("platform.issueTx");

    let params = jsonrpc::IssueTxRequest {
        tx: prefix_manager::prepend_0x(tx),
        encoding: String::from("hex"), // don't use "cb58"
    };
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: jsonrpc::RawIssueTxResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!("failed to decode jsonrpc::RawIssueTxResponse {}", e),
            ));
        }
    };
    Ok(resp.convert())
}

/// e.g., "platform.getTx" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/apis/avalanchego/apis/p-chain/#platformgettx
pub async fn get_tx(http_rpc: &str, tx_id: &str) -> io::Result<platformvm::GetTxResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting tx via {}", joined.as_str());

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getTx");

    let mut params = HashMap::new();
    params.insert(String::from("txID"), String::from(tx_id));
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    serde_json::from_slice(&rb)
        .map_err(|e| Error::new(ErrorKind::InvalidData, format!("failed to decode '{}'", e)))
}

/// e.g., "platform.getTxStatus" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/apis/avalanchego/apis/p-chain/#platformgettxstatus
pub async fn get_tx_status(
    http_rpc: &str,
    tx_id: &str,
) -> io::Result<platformvm::GetTxStatusResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting tx status via {}", joined.as_str());

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getTxStatus");

    let mut params = HashMap::new();
    params.insert(String::from("txID"), String::from(tx_id));
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: platformvm::RawGetTxStatusResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::InvalidData,
                format!("failed to decode jsonrpc::RawGetTxStatusResponse {}", e),
            ));
        }
    };
    Ok(resp.convert()?)
}

/// e.g., "platform.getHeight" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetheight
pub async fn get_height(http_rpc: &str) -> io::Result<platformvm::GetHeightResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting height for {:?}", joined);

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getHeight");

    let params = HashMap::new();
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: platformvm::RawGetHeightResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!("failed to decode platformvm::RawGetHeightResponse {}", e),
            ));
        }
    };
    Ok(resp.convert())
}

/// e.g., "platform.getBalance" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetbalance
pub async fn get_balance(
    http_rpc: &str,
    paddr: &str,
) -> io::Result<platformvm::GetBalanceResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting balances for {} via {:?}", paddr, joined);

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getBalance");

    let mut params = HashMap::new();
    params.insert(String::from("address"), paddr.to_string());
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: platformvm::RawGetBalanceResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!("failed to decode platformvm::RawGetBalanceResponse {}", e),
            ));
        }
    };
    Ok(resp.convert()?)
}

/// e.g., "platform.getUTXOs" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetutxos
pub async fn get_utxos(http_rpc: &str, paddr: &str) -> io::Result<jsonrpc::GetUtxosResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting UTXOs for {} via {:?}", paddr, joined);

    let mut data = jsonrpc::DataForGetUtxos::default();
    data.method = String::from("platform.getUTXOs");

    let params = jsonrpc::GetUtxosRequest {
        addresses: vec![paddr.to_string()],
        limit: 100,
        encoding: String::from("hex"), // don't use "cb58"
    };
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: jsonrpc::RawGetUtxosResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!("failed to decode jsonrpc::RawGetUtxosResponse {}", e),
            ));
        }
    };
    Ok(resp.convert()?)
}

/// e.g., "platform.getCurrentValidators" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetcurrentvalidators
/// ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/vms/platformvm#APIPrimaryValidator
pub async fn get_primary_network_validators(
    http_rpc: &str,
) -> io::Result<platformvm::GetCurrentValidatorsResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!("getting primary network validators via {}", joined.as_str());

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getCurrentValidators");

    let params = HashMap::new();
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: platformvm::RawGetCurrentValidatorsResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!(
                    "failed to decode platformvm::RawGetCurrentValidatorsResponse {}",
                    e
                ),
            ));
        }
    };
    Ok(resp.convert()?)
}

/// e.g., "platform.getCurrentValidators" on "http://[ADDR]:9650" and "/ext/P" path.
/// ref. https://docs.avax.network/build/avalanchego-apis/p-chain/#platformgetcurrentvalidators
/// ref. https://pkg.go.dev/github.com/ava-labs/avalanchego/vms/platformvm#APIPrimaryValidator
pub async fn get_subnet_validators(
    http_rpc: &str,
    subnet_id: &str,
) -> io::Result<platformvm::GetCurrentValidatorsResponse> {
    let joined = http_manager::join_uri(http_rpc, "/ext/P")?;
    log::debug!(
        "getting subnet {} validators via {}",
        subnet_id,
        joined.as_str()
    );

    let mut data = jsonrpc::Data::default();
    data.method = String::from("platform.getCurrentValidators");

    let mut params = HashMap::new();
    params.insert(String::from("subnetID"), subnet_id.to_string());
    data.params = Some(params);

    let d = data.encode_json()?;
    let rb = http_manager::post_non_tls(http_rpc, "/ext/P", &d).await?;

    let resp: platformvm::RawGetCurrentValidatorsResponse = match serde_json::from_slice(&rb) {
        Ok(p) => p,
        Err(e) => {
            return Err(Error::new(
                ErrorKind::Other,
                format!(
                    "failed to decode platformvm::RawGetCurrentValidatorsResponse {}",
                    e
                ),
            ));
        }
    };
    Ok(resp.convert()?)
}