Skip to content

Commit

Permalink
added "download-abi" command
Browse files Browse the repository at this point in the history
  • Loading branch information
FroVolod committed Feb 14, 2024
1 parent 4e2c68f commit 775830c
Show file tree
Hide file tree
Showing 3 changed files with 150 additions and 28 deletions.
126 changes: 126 additions & 0 deletions src/commands/contract/download_contract_abi/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use std::io::Write;

use color_eyre::eyre::{Context, ContextCompat};
use inquire::Text;

use crate::common::RpcQueryResponseExt;

#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(input_context = crate::GlobalContext)]
#[interactive_clap(output_context = ContractContext)]
pub struct Contract {
#[interactive_clap(skip_default_input_arg)]
/// What is the contract account ID?
account_id: crate::types::account_id::AccountId,
#[interactive_clap(named_arg)]
/// Enter the name of the file to save the contract ABI:
save_to_file: DownloadContractAbi,
}

#[derive(Debug, Clone)]
pub struct ContractContext {
global_context: crate::GlobalContext,
account_id: near_primitives::types::AccountId,
}

impl ContractContext {
pub fn from_previous_context(
previous_context: crate::GlobalContext,
scope: &<Contract as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
) -> color_eyre::eyre::Result<Self> {
Ok(Self {
global_context: previous_context,
account_id: scope.account_id.clone().into(),
})
}
}

impl Contract {
pub fn input_account_id(
context: &crate::GlobalContext,
) -> color_eyre::eyre::Result<Option<crate::types::account_id::AccountId>> {
crate::common::input_non_signer_account_id_from_used_account_list(
&context.config.credentials_home_dir,
"What is the contract account ID?",
)
}
}

#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(input_context = ContractContext)]
#[interactive_clap(output_context = DownloadContractContext)]
pub struct DownloadContractAbi {
#[interactive_clap(skip_default_input_arg)]
/// Enter the name of the file to save the contract ABI:
file_path: crate::types::path_buf::PathBuf,
#[interactive_clap(named_arg)]
/// Select network
network_config: crate::network_view_at_block::NetworkViewAtBlockArgs,
}

#[derive(Clone)]
pub struct DownloadContractContext(crate::network_view_at_block::ArgsForViewContext);

impl DownloadContractContext {
pub fn from_previous_context(
previous_context: ContractContext,
scope: &<DownloadContractAbi as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
) -> color_eyre::eyre::Result<Self> {
let on_after_getting_block_reference_callback: crate::network_view_at_block::OnAfterGettingBlockReferenceCallback = std::sync::Arc::new({
let account_id = previous_context.account_id.clone();
let file_path: std::path::PathBuf = scope.file_path.clone().into();

move |network_config, block_reference| {
if let Ok(contract_abi_response) = tokio::runtime::Runtime::new()
.unwrap()
.block_on(super::inspect_contract::get_contract_abi(&network_config.network_name, &network_config.json_rpc_client(), block_reference, &account_id))
{
let abi_root = serde_json::from_slice::<near_abi::AbiRoot>(&zstd::decode_all(
&contract_abi_response.call_result()?.result[..],
)?)?;
std::fs::File::create(&file_path)
.wrap_err_with(|| format!("Failed to create file: {:?}", &file_path))?
.write(&serde_json::to_vec_pretty(&abi_root)?)
.wrap_err_with(|| {
format!("Failed to write to file: {:?}", &file_path)
})?;
eprintln!("\nThe file {:?} was downloaded successfully", &file_path);
} else {
return Err(color_eyre::Report::msg(format!(
"Contact <{account_id}> does not support ABI (https://github.com/near/abi), so there is no way to get detailed information."
)));
}
Ok(())
}
});
Ok(Self(crate::network_view_at_block::ArgsForViewContext {
config: previous_context.global_context.config,
on_after_getting_block_reference_callback,
interacting_with_account_ids: vec![previous_context.account_id],
}))
}
}

impl From<DownloadContractContext> for crate::network_view_at_block::ArgsForViewContext {
fn from(item: DownloadContractContext) -> Self {
item.0
}
}

impl DownloadContractAbi {
fn input_file_path(
context: &ContractContext,
) -> color_eyre::eyre::Result<Option<crate::types::path_buf::PathBuf>> {
let home_dir = dirs::home_dir().wrap_err("Impossible to get your home dir!")?;
let mut folder_path = std::path::PathBuf::from(&home_dir);
folder_path.push("Downloads");
let file_name = format!("abi_{}.json", context.account_id.as_str().replace('.', "_"));
let file_path = folder_path.join(file_name);
eprintln!();
let input_file_path = Text::new("Enter the name of the file to save the contract ABI:")
.with_initial_value(&format!("{}", file_path.to_string_lossy()))
.prompt()?;

Ok(Some(shellexpand::tilde(&input_file_path).as_ref().parse()?))
}
}
42 changes: 17 additions & 25 deletions src/commands/contract/inspect_contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,15 @@ async fn display_inspect_contract(
};

let account_view = get_account_view(
network_config,
&network_config.network_name,
&json_rpc_client,
&block_reference,
account_id,
)
.await?;

let access_keys = get_access_keys(
network_config,
&network_config.network_name,
&json_rpc_client,
&block_reference,
account_id,
Expand Down Expand Up @@ -159,7 +159,7 @@ async fn display_inspect_contract(
]);

if let Ok(contract_source_metadata_response) = get_contract_source_metadata(
network_config,
&network_config.network_name,
&json_rpc_client,
&block_reference,
account_id,
Expand Down Expand Up @@ -190,7 +190,7 @@ async fn display_inspect_contract(
}

if let Ok(contract_abi_response) = get_contract_abi(
network_config,
&network_config.network_name,
&json_rpc_client,
&block_reference,
account_id,
Expand Down Expand Up @@ -311,7 +311,7 @@ async fn display_inspect_contract(
}

async fn get_account_view(
network_config: &crate::config::NetworkConfig,
network_name: &str,
json_rpc_client: &near_jsonrpc_client::JsonRpcClient,
block_reference: &BlockReference,
account_id: &near_primitives::types::AccountId,
Expand All @@ -335,21 +335,19 @@ async fn get_account_view(
return account_view_response
.wrap_err_with(|| {
format!(
"Failed to fetch query ViewAccount for contract <{}> on network <{}>",
account_id, network_config.network_name
"Failed to fetch query ViewAccount for contract <{account_id}> on network <{network_name}>"
)
})?
.account_view();
}
}
color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(format!(
"Transport error. Failed to fetch query ViewAccount for contract <{}> on network <{}>",
account_id, network_config.network_name
"Transport error. Failed to fetch query ViewAccount for contract <{account_id}> on network <{network_name}>"
)))
}

async fn get_access_keys(
network_config: &crate::config::NetworkConfig,
network_name: &str,
json_rpc_client: &near_jsonrpc_client::JsonRpcClient,
block_reference: &BlockReference,
account_id: &near_primitives::types::AccountId,
Expand All @@ -373,22 +371,20 @@ async fn get_access_keys(
return Ok(access_keys_response
.wrap_err_with(|| {
format!(
"Failed to fetch ViewAccessKeyList for contract <{}> on network <{}>",
account_id, network_config.network_name
"Failed to fetch ViewAccessKeyList for contract <{account_id}> on network <{network_name}>"
)
})?
.access_key_list_view()?
.keys);
}
}
color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(format!(
"Transport error. Failed to fetch query ViewAccessKeyList for contract <{}> on network <{}>",
account_id, network_config.network_name
"Transport error. Failed to fetch query ViewAccessKeyList for contract <{account_id}> on network <{network_name}>"
)))
}

async fn get_contract_source_metadata(
network_config: &crate::config::NetworkConfig,
network_name: &str,
json_rpc_client: &near_jsonrpc_client::JsonRpcClient,
block_reference: &BlockReference,
account_id: &near_primitives::types::AccountId,
Expand All @@ -413,20 +409,18 @@ async fn get_contract_source_metadata(
} else {
return contract_source_metadata_response.wrap_err_with(|| {
format!(
"Failed to fetch 'contract_source_metadata' for account <{}> on network <{}>",
account_id, network_config.network_name
"Failed to fetch 'contract_source_metadata' for account <{account_id}> on network <{network_name}>"
)
});
}
}
color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(format!(
"Transport error. Failed to fetch 'contract_source_metadata' for account <{}> on network <{}>",
account_id, network_config.network_name
"Transport error. Failed to fetch 'contract_source_metadata' for account <{account_id}> on network <{network_name}>"
)))
}

async fn get_contract_abi(
network_config: &crate::config::NetworkConfig,
pub async fn get_contract_abi(
network_name: &str,
json_rpc_client: &near_jsonrpc_client::JsonRpcClient,
block_reference: &BlockReference,
account_id: &near_primitives::types::AccountId,
Expand All @@ -451,14 +445,12 @@ async fn get_contract_abi(
} else {
return contract_abi_response.wrap_err_with(|| {
format!(
"Failed to fetch 'contract_abi' for account <{}> on network <{}>",
account_id, network_config.network_name
"Failed to fetch 'contract_abi' for account <{account_id}> on network <{network_name}>"
)
});
}
}
color_eyre::eyre::Result::Err(color_eyre::eyre::eyre!(format!(
"Transport error. Failed to fetch 'contract_abi' for account <{}> on network <{}>",
account_id, network_config.network_name
"Transport error. Failed to fetch 'contract_abi' for account <{account_id}> on network <{network_name}>"
)))
}
10 changes: 7 additions & 3 deletions src/commands/contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage};

pub mod call_function;
pub mod deploy;
mod download_contract_abi;
mod download_wasm;
mod inspect_contract;
mod view_storage;
Expand All @@ -24,14 +25,17 @@ pub enum ContractActions {
))]
/// Execute function (contract method)
CallFunction(self::call_function::CallFunctionCommands),
#[strum_discriminants(strum(message = "deploy - Add a new contract code"))]
/// Add a contract code
Deploy(self::deploy::Contract),
#[strum_discriminants(strum(
message = "inspect - Get a list of available function names"
))]
/// Get a list of available function names
Inspect(self::inspect_contract::Contract),
#[strum_discriminants(strum(message = "deploy - Add a new contract code"))]
/// Add a contract code
Deploy(self::deploy::Contract),
#[strum_discriminants(strum(message = "download-abi - Download contract ABI"))]
/// Download contract ABI
DownloadAbi(self::download_contract_abi::Contract),
#[strum_discriminants(strum(message = "download-wasm - Download wasm"))]
/// Download wasm
DownloadWasm(self::download_wasm::ContractAccount),
Expand Down

0 comments on commit 775830c

Please sign in to comment.