use crate::{App, result::Result, utils::Hex};
use anyhow::{Context, anyhow};
use clap::Parser;
use gsdk::{
Event,
gear::{gear::Event as GearEvent, runtime_types::gear_common::event::MessageEntry},
signer::Signer,
};
use std::{fs, path::PathBuf};
use tokio::{io, io::AsyncReadExt};
#[derive(Clone, Debug, Parser)]
pub struct Upload {
code: PathBuf,
#[arg(short, long)]
code_only: bool,
#[arg(short, long, default_value = "0x")]
salt: String,
#[arg(short, long, default_value = "0x")]
payload: String,
#[arg(short, long)]
gas_limit: Option<u64>,
#[arg(short, long, default_value = "0")]
value: u128,
}
impl Upload {
pub async fn exec(&self, app: &impl App) -> Result<()> {
let signer: Signer = app.signer().await?.into();
#[allow(clippy::cmp_owned)]
let code = if self.code == PathBuf::from("-") {
let mut stdin = io::stdin();
let mut code = Vec::new();
stdin
.read_to_end(&mut code)
.await
.context("failed to read from stdin")?;
code
} else {
fs::read(&self.code).map_err(|e| anyhow!("program {:?} not found, {e}", &self.code))?
};
if self.code_only {
signer.calls().upload_code(code).await?;
return Ok(());
}
let payload = self.payload.to_vec()?;
let gas_limit = if let Some(gas_limit) = self.gas_limit {
gas_limit
} else {
signer
.rpc()
.calculate_upload_gas(None, code.clone(), payload.clone(), self.value, false, None)
.await?
.min_limit
};
let tx = signer
.calls()
.upload_program(code, self.salt.to_vec()?, payload, gas_limit, self.value)
.await?;
for event in signer.api().events_of(&tx).await? {
match event {
Event::Gear(GearEvent::MessageQueued {
id,
destination,
entry: MessageEntry::Init,
..
}) => {
log::info!("Program ID: 0x{}", hex::encode(destination));
log::info!("Init Message ID: 0x{}", hex::encode(id));
}
Event::Gear(GearEvent::CodeChanged { id, .. }) => {
log::info!("Code ID: 0x{}", hex::encode(id));
}
_ => {}
}
}
Ok(())
}
}