diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ebcb09a..c28929c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## 0.40.0 +- Supported [ABI 2.7](https://github.com/everx-labs/ever-abi/blob/master/CHANGELOG.md#version-270) +- Supported calling [TVM-Solidity getters](https://github.com/everx-labs/TVM-Solidity-Compiler/blob/master/API.md#getter). + ## 0.39.0 - Using sdk 1.48.0 diff --git a/Cargo.lock b/Cargo.lock index 90b6eb04..54413fe2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -227,6 +227,12 @@ dependencies = [ "syn 2.0.74", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -292,6 +298,12 @@ version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + [[package]] name = "base64ct" version = "1.6.0" @@ -402,12 +414,13 @@ checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" [[package]] name = "cc" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +checksum = "5fb8dd288a69fc53a1996d7ecfbf4a20d59065bff137ce7e56bbd620de191189" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -533,6 +546,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", + "unicode-width", "windows-sys 0.52.0", ] @@ -839,7 +853,7 @@ dependencies = [ [[package]] name = "ever-cli" -version = "0.39.0" +version = "0.40.0" dependencies = [ "anyhow", "assert_cmd", @@ -865,7 +879,7 @@ dependencies = [ "predicates 2.1.5", "qr2term", "regex", - "reqwest", + "reqwest 0.12.4", "serde", "serde_derive", "serde_json", @@ -1015,7 +1029,7 @@ dependencies = [ "pbkdf2 0.8.0", "rand 0.7.3", "regex", - "reqwest", + "reqwest 0.11.27", "scrypt", "serde", "serde_derive", @@ -1311,7 +1325,26 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.12", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa82e28a107a8cc405f0839610bdc9b15f1e25ec7d696aa5cf173edbcb1486ab" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", "indexmap", "slab", "tokio", @@ -1418,6 +1451,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http-body" version = "0.4.6" @@ -1425,7 +1469,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", - "http", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -1451,9 +1518,9 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", "httparse", "httpdate", "itoa", @@ -1465,6 +1532,26 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "itoa", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -1472,12 +1559,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper", + "hyper 0.14.30", "native-tls", "tokio", "tokio-native-tls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.60" @@ -1529,9 +1652,9 @@ checksum = "4161ceaf2f41b6cd3f6502f5da085d4ad4393a51e0c70ed2fce1d5698d798fae" [[package]] name = "indexmap" -version = "2.3.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3fc2e30ba82dd1b3911c8de1ffc143c74a914a14e99514d7637e3099df5ea0" +checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -1539,14 +1662,24 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.16.2" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", - "lazy_static", + "instant", "number_prefix", - "regex", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", ] [[package]] @@ -2318,11 +2451,53 @@ dependencies = [ "encoding_rs", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "hyper-tls 0.5.0", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.4.5", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-tls 0.6.0", + "hyper-util", "ipnet", "js-sys", "log", @@ -2331,7 +2506,7 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls-pemfile", + "rustls-pemfile 2.1.3", "serde", "serde_json", "serde_urlencoded", @@ -2344,7 +2519,7 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "winreg", + "winreg 0.52.0", ] [[package]] @@ -2390,6 +2565,22 @@ dependencies = [ "base64 0.21.7", ] +[[package]] +name = "rustls-pemfile" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +dependencies = [ + "base64 0.22.1", + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" + [[package]] name = "ryu" version = "1.0.18" @@ -2561,6 +2752,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -2990,11 +3187,32 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -3030,7 +3248,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes", - "http", + "http 0.2.12", "httparse", "log", "native-tls", @@ -3420,6 +3638,16 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "x25519-dalek" version = "2.0.1" diff --git a/Cargo.toml b/Cargo.toml index 9a3d9aa0..72bdff18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,55 +1,49 @@ [package] authors = [ 'EverX Labs Ltd ' ] build = 'build.rs' +default-run = 'ever-cli' description = 'command line tool for TVM blockchain' documentation = 'https://docs.everos.dev/' edition = '2021' homepage = 'https://docs.everos.dev/' -keywords = [ - 'TVM', - 'SDK', - 'smart-contract', - 'everx-labs', - 'solidity' -] +keywords = [ 'TVM', 'SDK', 'smart-contract', 'everx-labs', 'solidity' ] license = 'Apache-2.0' name = 'ever-cli' readme = 'README.md' repository = 'https://github.com/everx-labs/ever-cli' -version = '0.39.0' -default-run = 'ever-cli' +version = '0.40.0' [dependencies] +anyhow = '1.0' async-trait = '0.1.42' base64 = '0.13' chrono = '0.4' clap = '2.32' -anyhow = '1.0' -thiserror = '1.0' futures = '0.3' hex = '0.4' -indicatif = '0.16' +indicatif = '0.17' +log = { features = [ 'std' ], version = '0.4' } num-bigint = '0.4' num-traits = '0.2' qr2term = '0.2' regex = '1.5' -reqwest = '0.11' +reqwest = '0.12' +serde = { features = [ 'derive' ], version = '1.0' } serde_derive = '1.0' serde_json = '1.0' simplelog = '0.8' -tokio-retry = '0.3' -log = { features = [ 'std' ], version = '0.4' } -serde = { features = [ 'derive' ], version = '1.0' } +thiserror = '1.0' tokio = { default-features = false, features = [ 'full' ], version = '1.21' } +tokio-retry = '0.3' url = '2.3.1' -ever_abi = { git = 'https://github.com/everx-labs/ever-abi.git', tag = '2.7.2' } +ever_abi = { git = 'https://github.com/everx-labs/ever-abi.git', tag = '2.7.2' } +ever_assembler = { git = 'https://github.com/everx-labs/ever-assembler.git', tag = '1.6.14' } ever_block = { git = 'https://github.com/everx-labs/ever-block.git', tag = '1.11.11' } ever_block_json = { git = 'https://github.com/everx-labs/ever-block-json.git', tag = '0.9.18' } +ever_client = { git = 'https://github.com/everx-labs/ever-sdk.git', tag = '1.48.0' } ever_executor = { git = 'https://github.com/everx-labs/ever-executor.git', tag = '1.18.12' } -ever_assembler = { git = 'https://github.com/everx-labs/ever-assembler.git', tag = '1.6.14' } ever_sdk = { git = 'https://github.com/everx-labs/ever-sdk.git', tag = '1.48.0' } -ever_client = { git = 'https://github.com/everx-labs/ever-sdk.git', tag = '1.48.0' } ever_vm = { git = 'https://github.com/everx-labs/ever-vm.git', tag = '2.2.12' } [dev-dependencies] @@ -58,10 +52,3 @@ lazy_static = '1.4' predicates = '2.1' string-error = '0.1.0' -[[bin]] -name = "ever-cli" -path = "src/main.rs" - -[[bin]] -name = "__ever-cli_completion" -path = "src/completion.rs" diff --git a/README.md b/README.md index 9fdcb318..1de20db9 100644 --- a/README.md +++ b/README.md @@ -1800,8 +1800,8 @@ Connecting to net.evercloud.dev DeBot Info: Name : Multisig Version: 1.2.0 -Author : TON Labs -Publisher: TON Labs +Author : EverX +Publisher: EverX Support: 0:66e01d6df5a8d7677d9ab2daf7f258f1e2a7fe73da5320300395f99e01dc3b5f Description: DeBot for multisig wallets Hi, I will help you work with multisig wallets that can have multiple custodians. diff --git a/src/account.rs b/src/account.rs index e1f7f028..c445e5ca 100644 --- a/src/account.rs +++ b/src/account.rs @@ -10,15 +10,19 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use std::sync::Arc; -use crate::helpers::{check_dir, create_client_verbose, json_account, print_account, query_account_field}; use crate::config::Config; -use serde_json::{json, Value}; +use crate::decode::print_account_data; +use crate::helpers::{ + check_dir, create_client_verbose, json_account, print_account, query_account_field, +}; +use ever_block::{Account, Deserializable, Serializable}; use ever_client::error::ClientError; -use ever_client::net::{ParamsOfQueryCollection, query_collection, ResultOfSubscription, ParamsOfSubscribeCollection}; +use ever_client::net::{ + query_collection, ParamsOfQueryCollection, ParamsOfSubscribeCollection, ResultOfSubscription, +}; use ever_client::utils::{calc_storage_fee, ParamsOfCalcStorageFee}; -use ever_block::{Account, Deserializable, Serializable}; -use crate::decode::print_account_data; +use serde_json::{json, Value}; +use std::sync::Arc; const ACCOUNT_FIELDS: &str = r#" id @@ -33,7 +37,11 @@ const ACCOUNT_FIELDS: &str = r#" const DEFAULT_PATH: &str = "."; -async fn query_accounts(config: &Config, addresses: Vec, fields: &str) -> Result, String> { +async fn query_accounts( + config: &Config, + addresses: Vec, + fields: &str, +) -> Result, String> { let ton = create_client_verbose(config)?; if !config.is_json { @@ -64,18 +72,27 @@ async fn query_accounts(config: &Config, addresses: Vec, fields: &str) - limit: Some(cnt as u32), ..Default::default() }, - ).await.map_err(|e| format!("failed to query account info: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query account info: {}", e))?; res.append(query_result.result.as_mut()); } Ok(res) } -pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Option<&str>, dumpboc: Option<&str>, is_boc: bool) -> Result<(), String> { +pub async fn get_account( + config: &Config, + addresses: Vec, + dumptvc: Option<&str>, + dumpboc: Option<&str>, + is_boc: bool, +) -> Result<(), String> { if is_boc { let mut accounts = vec![]; for path in addresses { - let account = Account::construct_from_file(&path) - .map_err(|e| format!(" failed to load account from the boc file {}: {}", path, e))?; + let account = Account::construct_from_file(&path).map_err(|e| { + format!(" failed to load account from the boc file {}: {}", path, e) + })?; accounts.push(account); } if !config.is_json { @@ -92,53 +109,59 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } let mut found_addresses = vec![]; if !accounts.is_empty() { - let mut json_res = json!({ }); + let mut json_res = json!({}); for acc in accounts.iter() { let address = acc["id"].as_str().unwrap_or("Undefined").to_owned(); found_addresses.push(address.clone()); - let acc_type = acc["acc_type_name"].as_str().unwrap_or("Undefined").to_owned(); + let acc_type = acc["acc_type_name"] + .as_str() + .unwrap_or("Undefined") + .to_owned(); if acc_type != "NonExist" { let bal = acc["balance"].as_str(); - let balance = - if bal.is_some() { - let bal = bal.unwrap(); - if config.balance_in_tons { - let bal = u64::from_str_radix(bal, 10) - .map_err(|e| format!("failed to decode balance: {}", e))?; - let int_bal = bal as f64 / 1e9; - let frac_balance = (bal as f64 / 1e6 + 0.5) as u64 % 1000; - let balance_str = format!("{}", int_bal as u64); - format!("{}.{}{}", balance_str.chars() + let balance = if bal.is_some() { + let bal = bal.unwrap(); + if config.balance_in_tons { + let bal = u64::from_str_radix(bal, 10) + .map_err(|e| format!("failed to decode balance: {}", e))?; + let int_bal = bal as f64 / 1e9; + let frac_balance = (bal as f64 / 1e6 + 0.5) as u64 % 1000; + let balance_str = format!("{}", int_bal as u64); + format!( + "{}.{}{}", + balance_str + .chars() .collect::>() .rchunks(3) .map(|c| c.iter().collect::()) .rev() .collect::>() .join(" "), - frac_balance, - if config.is_json { - "" - } else { - " ton" - } - ) - } else { - format!("{}{}", bal, - if config.is_json { - "" - } else { - " nanoton" - } - ) - } + frac_balance, + if config.is_json { "" } else { " ton" } + ) } else { - "Undefined".to_owned() - }; - let last_paid = format!("{}", acc["last_paid"].as_u64().ok_or("failed to decode last_paid".to_owned())?); - let last_trans_id = acc["last_trans_lt"].as_str().unwrap_or("Undefined").to_owned(); + format!("{}{}", bal, if config.is_json { "" } else { " nanoton" }) + } + } else { + "Undefined".to_owned() + }; + let last_paid = format!( + "{}", + acc["last_paid"] + .as_u64() + .ok_or("failed to decode last_paid".to_owned())? + ); + let last_trans_id = acc["last_trans_lt"] + .as_str() + .unwrap_or("Undefined") + .to_owned(); let data = acc["data"].as_str(); let data_boc = if data.is_some() { - hex::encode(base64::decode(data.unwrap()).map_err(|e| format!("failed to decode account data: {}", e))?) + hex::encode( + base64::decode(data.unwrap()) + .map_err(|e| format!("failed to decode account data: {}", e))?, + ) } else { "null".to_owned() }; @@ -168,9 +191,28 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio ); } } else if config.is_json { - json_res = json_account(Some(acc_type), Some(address.clone()), None, None, None, None, None, None); + json_res = json_account( + Some(acc_type), + Some(address.clone()), + None, + None, + None, + None, + None, + None, + ); } else { - print_account(config, Some(acc_type), Some(address.clone()), None, None, None, None, None, None); + print_account( + config, + Some(acc_type), + Some(address.clone()), + None, + None, + None, + None, + None, + None, + ); } if !config.is_json { println!(); @@ -200,15 +242,24 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio if dumptvc.is_some() || dumpboc.is_some() && addresses.len() == 1 && accounts.len() == 1 { let acc = &accounts[0]; - let boc = acc["boc"].as_str() + let boc = acc["boc"] + .as_str() .ok_or("failed to get boc of the account".to_owned())?; let account = Account::construct_from_base64(boc) .map_err(|e| format!("failed to load account from the boc: {}", e))?; if dumptvc.is_some() { if account.state_init().is_some() { - account.state_init().unwrap() + account + .state_init() + .unwrap() .write_to_file(dumptvc.unwrap()) - .map_err(|e| format!("failed to write data to the file {}: {}", dumptvc.unwrap(), e))?; + .map_err(|e| { + format!( + "failed to write data to the file {}: {}", + dumptvc.unwrap(), + e + ) + })?; } else { return Err("account doesn't contain state init.".to_owned()); } @@ -217,8 +268,13 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } } if dumpboc.is_some() { - account.write_to_file(dumpboc.unwrap()) - .map_err(|e| format!("failed to write data to the file {}: {}", dumpboc.unwrap(), e))?; + account.write_to_file(dumpboc.unwrap()).map_err(|e| { + format!( + "failed to write data to the file {}: {}", + dumpboc.unwrap(), + e + ) + })?; if !config.is_json { println!("Saved account to file {}", &dumpboc.unwrap()); } @@ -234,19 +290,17 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() println!("Processing..."); } - let boc = query_account_field( - ton.clone(), - addr, - "boc", - ).await?; + let boc = query_account_field(ton.clone(), addr, "boc").await?; let res = calc_storage_fee( ton.clone(), ParamsOfCalcStorageFee { account: boc, period, - } - ).await.map_err(|e| format!("failed to calculate storage fee: {}", e))?; + }, + ) + .await + .map_err(|e| format!("failed to calculate storage fee: {}", e))?; if !config.is_json { println!("Storage fee per {} seconds: {} nanotons", period, res.fee); @@ -259,22 +313,30 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() Ok(()) } -pub async fn dump_accounts(config: &Config, addresses: Vec, path: Option<&str>) -> Result<(), String> { +pub async fn dump_accounts( + config: &Config, + addresses: Vec, + path: Option<&str>, +) -> Result<(), String> { let accounts = query_accounts(config, addresses.clone(), "id boc").await?; let mut addresses = addresses.clone(); check_dir(path.unwrap_or(""))?; for account in accounts.iter() { - let mut address = account["id"].as_str() + let mut address = account["id"] + .as_str() .ok_or("Failed to parse address in the query result".to_owned())? .to_owned(); match addresses.iter().position(|el| el == &address) { - Some(index) => { addresses.remove(index) }, - None => { return Err("Query contains an unexpected address.".to_string()); } + Some(index) => addresses.remove(index), + None => { + return Err("Query contains an unexpected address.".to_string()); + } }; address.replace_range(..address.find(':').unwrap_or(0) + 1, ""); let path = format!("{}/{}.boc", path.unwrap_or(DEFAULT_PATH), address); - let boc = account["boc"].as_str() + let boc = account["boc"] + .as_str() .ok_or("Failed to parse boc in the query result".to_owned())?; Account::construct_from_base64(boc) .map_err(|e| format!("Failed to load account from the boc: {}", e))? @@ -302,7 +364,11 @@ fn extract_last_trans_lt(v: &serde_json::Value) -> Option<&str> { v.as_object()?["last_trans_lt"].as_str() } -pub async fn wait_for_change(config: &Config, account_address: &str, wait_secs: u64) -> Result<(), String> { +pub async fn wait_for_change( + config: &Config, + account_address: &str, + wait_secs: u64, +) -> Result<(), String> { let context = create_client_verbose(config)?; let query = ever_client::net::query_collection( @@ -317,8 +383,10 @@ pub async fn wait_for_change(config: &Config, account_address: &str, wait_secs: limit: None, order: None, result: "last_trans_lt".to_owned(), - } - ).await.map_err(|e| format!("Failed to query the account: {}", e))?; + }, + ) + .await + .map_err(|e| format!("Failed to query the account: {}", e))?; let last_trans_lt = extract_last_trans_lt(&query.result[0]) .ok_or_else(|| format!("Failed to parse query result: {}", query.result[0]))?; @@ -338,9 +406,7 @@ pub async fn wait_for_change(config: &Config, account_address: &str, wait_secs: Err(format!("Can't parse the result: {}", res.result)) } } - Err(e) => { - Err(format!("Client error: {}", e)) - } + Err(e) => Err(format!("Client error: {}", e)), }; s.send(res).await.unwrap() } @@ -360,16 +426,22 @@ pub async fn wait_for_change(config: &Config, account_address: &str, wait_secs: })), result: "last_trans_lt".to_owned(), }, - callback - ).await.map_err(|e| format!("Failed to subscribe: {}", e))?; + callback, + ) + .await + .map_err(|e| format!("Failed to subscribe: {}", e))?; tokio::spawn(async move { tokio::time::sleep(std::time::Duration::from_secs(wait_secs)).await; s.send(Err("Timeout".to_owned())).await.unwrap() }); - let res = r.recv().await.ok_or_else(|| "Sender has dropped".to_owned())?; - ever_client::net::unsubscribe(context.clone(), subscription).await + let res = r + .recv() + .await + .ok_or_else(|| "Sender has dropped".to_owned())?; + ever_client::net::unsubscribe(context.clone(), subscription) + .await .map_err(|e| format!("Failed to unsubscribe: {}", e))?; if !config.is_json { diff --git a/src/call.rs b/src/call.rs index 970585e5..19f3cb07 100644 --- a/src/call.rs +++ b/src/call.rs @@ -12,33 +12,34 @@ */ use crate::config::Config; use crate::convert; -use crate::helpers::{TonClient, now_ms, create_client_verbose, load_abi, query_account_field, - create_client, load_ton_abi, get_blockchain_config}; - -use ever_client::abi::{encode_message, decode_message, ParamsOfDecodeMessage, ParamsOfEncodeMessage, - Abi}; -use ever_client::processing::{ - ParamsOfSendMessage, - ParamsOfWaitForTransaction, - ParamsOfProcessMessage, - ProcessingEvent, - wait_for_transaction, - send_message, +use crate::helpers::{ + create_client, create_client_verbose, get_blockchain_config, load_abi, load_ton_abi, now_ms, + query_account_field, TonClient, }; -use ever_client::tvm::{ - run_executor, - ParamsOfRunExecutor, - AccountForExecutor + +use crate::debug::{debug_error, init_debug_logger, DebugParams}; +use crate::message::{ + prepare_message_params, print_encoded_message, unpack_message, EncodedMessage, }; -use ever_block::{Account, Serializable}; -use std::str::FromStr; -use serde_json::{json, Value}; use ever_abi::ParamType; +use ever_block::{Account, Serializable}; +use ever_client::abi::{ + decode_message, encode_message, Abi, ParamsOfDecodeMessage, ParamsOfEncodeMessage, +}; use ever_client::error::ClientError; -use crate::debug::{init_debug_logger, debug_error, DebugParams}; -use crate::message::{EncodedMessage, prepare_message_params, print_encoded_message, unpack_message}; +use ever_client::processing::{ + send_message, wait_for_transaction, ParamsOfProcessMessage, ParamsOfSendMessage, + ParamsOfWaitForTransaction, ProcessingEvent, +}; +use ever_client::tvm::{run_executor, AccountForExecutor, ParamsOfRunExecutor}; +use serde_json::{json, Value}; +use std::str::FromStr; -async fn decode_call_parameters(ton: TonClient, msg: &EncodedMessage, abi: Abi) -> Result<(String, String), String> { +async fn decode_call_parameters( + ton: TonClient, + msg: &EncodedMessage, + abi: Abi, +) -> Result<(String, String), String> { let result = decode_message( ton, ParamsOfDecodeMessage { @@ -51,7 +52,7 @@ async fn decode_call_parameters(ton: TonClient, msg: &EncodedMessage, abi: Abi) Ok(( result.name, - format!("{:#}", result.value.unwrap_or(json!({}))) + format!("{:#}", result.value.unwrap_or(json!({}))), )) } @@ -65,27 +66,42 @@ fn parse_integer_param(value: &str) -> Result { } } -async fn build_json_from_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { +async fn build_json_from_params( + params_vec: Vec<&str>, + abi_path: &str, + method: &str, + config: &Config, +) -> Result { let abi_obj = load_ton_abi(abi_path, config).await?; let functions = abi_obj.functions(); - let func_obj = functions.get(method).ok_or("failed to load function from abi")?; + let func_obj = functions + .get(method) + .ok_or("failed to load function from abi")?; let inputs = func_obj.input_params(); - let mut params_json = json!({ }); + let mut params_json = json!({}); for input in inputs { let mut iter = params_vec.iter(); - let _param = iter.find(|x| x.starts_with('-') && (x.trim_start_matches('-') == input.name)) - .ok_or(format!(r#"argument "{}" of type "{}" not found"#, input.name, input.kind))?; - - let value = iter.next() - .ok_or(format!(r#"argument "{}" of type "{}" has no value"#, input.name, input.kind))? + let _param = iter + .find(|x| x.starts_with('-') && (x.trim_start_matches('-') == input.name)) + .ok_or(format!( + r#"argument "{}" of type "{}" not found"#, + input.name, input.kind + ))?; + + let value = iter + .next() + .ok_or(format!( + r#"argument "{}" of type "{}" has no value"#, + input.name, input.kind + ))? .to_string(); let value = match input.kind { ParamType::Uint(_) | ParamType::Int(_) => { json!(parse_integer_param(&value)?) - }, + } ParamType::Array(ref _x) => { let mut result_vec: Vec = vec![]; for i in value.split(|c| c == ',' || c == '[' || c == ']') { @@ -94,7 +110,7 @@ async fn build_json_from_params(params_vec: Vec<&str>, abi_path: &str, method: & } } json!(result_vec) - }, + } _ => { json!(value) } @@ -118,11 +134,10 @@ pub async fn emulate_locally( let addr = ever_block::MsgAddressInt::from_str(addr) .map_err(|e| format!("couldn't decode address: {}", e))?; state = base64::encode( - ever_block::write_boc( - &Account::with_address(addr) - .serialize() - .map_err(|e| format!("couldn't create dummy account for deploy emulation: {}", e))? - ).map_err(|e| format!("failed to serialize account cell: {}", e))? + ever_block::write_boc(&Account::with_address(addr).serialize().map_err(|e| { + format!("couldn't create dummy account for deploy emulation: {}", e) + })?) + .map_err(|e| format!("failed to serialize account cell: {}", e))?, ); } else { return Err(state_boc.err().unwrap()); @@ -136,11 +151,7 @@ pub async fn emulate_locally( message: msg.clone(), account: AccountForExecutor::Account { boc: state, - unlimited_balance: if is_fee { - Some(true) - } else { - None - }, + unlimited_balance: if is_fee { Some(true) } else { None }, }, ..Default::default() }, @@ -172,13 +183,10 @@ pub async fn send_message_and_wait( msg: String, config: &Config, ) -> Result { - if !config.is_json { println!("Processing... "); } - let callback = |_| { - async move {} - }; + let callback = |_| async move {}; let result = send_message( ton.clone(), ParamsOfSendMessage { @@ -187,8 +195,9 @@ pub async fn send_message_and_wait( send_events: false, }, callback, - ).await - .map_err(|e| format!("{:#}", e))?; + ) + .await + .map_err(|e| format!("{:#}", e))?; if !config.async_call { let result = wait_for_transaction( @@ -201,8 +210,9 @@ pub async fn send_message_and_wait( ..Default::default() }, callback, - ).await - .map_err(|e| format!("{:#}", e))?; + ) + .await + .map_err(|e| format!("{:#}", e))?; Ok(result.decoded.and_then(|d| d.output).unwrap_or(json!({}))) } else { Ok(json!({})) @@ -214,16 +224,17 @@ pub async fn process_message( msg: ParamsOfEncodeMessage, config: &Config, ) -> Result { - let callback = |event| { async move { + let callback = |event| async move { if let ProcessingEvent::DidSend { shard_block_id: _, message_id, message_dst: _, message: _, - } = event { + } = event + { println!("MessageId: {}", message_id) } - }}; + }; let res = if !config.is_json { ever_client::processing::process_message( ton.clone(), @@ -232,7 +243,8 @@ pub async fn process_message( send_events: true, }, callback, - ).await + ) + .await } else { ever_client::processing::process_message( ton.clone(), @@ -240,8 +252,9 @@ pub async fn process_message( message_encode_params: msg.clone(), send_events: true, }, - |_| { async move {} }, - ).await + |_| async move {}, + ) + .await }?; Ok(res.decoded.and_then(|d| d.output).unwrap_or(json!({}))) @@ -277,23 +290,15 @@ pub async fn call_contract_with_client( ) -> Result { let abi = load_abi(abi_path, config).await?; - let msg_params = prepare_message_params( - addr, - abi.clone(), - method, - params, - None, - keys.clone(), - None, - )?; - - let needs_encoded_msg = is_fee || - config.async_call || - config.local_run || - config.debug_fail != "None"; + let msg_params = + prepare_message_params(addr, abi.clone(), method, params, None, keys.clone(), None)?; + + let needs_encoded_msg = + is_fee || config.async_call || config.local_run || config.debug_fail != "None"; let message = if needs_encoded_msg { - let msg = encode_message(ton.clone(), msg_params.clone()).await + let msg = encode_message(ton.clone(), msg_params.clone()) + .await .map_err(|e| format!("failed to create inbound message: {}", e))?; if config.local_run || is_fee { @@ -303,10 +308,7 @@ pub async fn call_contract_with_client( } } if config.async_call { - return send_message_and_wait(ton, - Some(abi), - msg.message.clone(), - config).await; + return send_message_and_wait(ton, Some(abi), msg.message.clone(), config).await; } Some(msg.message) } else { @@ -316,11 +318,7 @@ pub async fn call_contract_with_client( match process_message(ton.clone(), msg_params, config).await { Ok(result) => Ok(result), Err(e) => { - let acc_boc = query_account_field( - ton.clone(), - addr, - "boc", - ).await?; + let acc_boc = query_account_field(ton.clone(), addr, "boc").await?; let now = now_ms(); let bc_config = get_blockchain_config(config, None).await?; let debug_params = DebugParams { @@ -357,7 +355,8 @@ pub async fn call_contract( keys: Option, is_fee: bool, ) -> Result<(), String> { - let result = call_contract_with_result(config, addr, abi_path, method, params, keys, is_fee).await?; + let result = + call_contract_with_result(config, addr, abi_path, method, params, keys, is_fee).await?; if !config.is_json { println!("Succeeded."); } @@ -365,8 +364,11 @@ pub async fn call_contract( Ok(()) } - -pub async fn call_contract_with_msg(config: &Config, str_msg: String, abi_path: &str) -> Result<(), String> { +pub async fn call_contract_with_msg( + config: &Config, + str_msg: String, + abi_path: &str, +) -> Result<(), String> { let ton = create_client_verbose(config)?; let abi = load_abi(abi_path, config).await?; @@ -387,7 +389,7 @@ pub async fn call_contract_with_msg(config: &Config, str_msg: String, abi_path: println!(" \"Parameters\": {},", params.1); println!("}}"); } - let result = send_message_and_wait(ton, Some(abi), msg.message, config).await?; + let result = send_message_and_wait(ton, Some(abi), msg.message, config).await?; if !config.is_json { println!("Succeeded."); @@ -398,7 +400,12 @@ pub async fn call_contract_with_msg(config: &Config, str_msg: String, abi_path: Ok(()) } -pub async fn parse_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { +pub async fn parse_params( + params_vec: Vec<&str>, + abi_path: &str, + method: &str, + config: &Config, +) -> Result { if params_vec.len() == 1 { // if there is only 1 parameter it must be a json string with arguments Ok(params_vec[0].to_owned()) diff --git a/src/config.rs b/src/config.rs index 62a351b1..be9a1ad7 100644 --- a/src/config.rs +++ b/src/config.rs @@ -10,12 +10,12 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use serde::{Deserialize, Serialize}; -use std::collections::BTreeMap; -use clap::ArgMatches; -use regex::Regex; use crate::global_config_path; use crate::helpers::default_config_name; +use clap::ArgMatches; +use regex::Regex; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; const TESTNET: &str = "net.evercloud.dev"; const MAINNET: &str = "main.evercloud.dev"; @@ -41,13 +41,17 @@ fn default_timeout() -> u32 { 40000 } -fn default_out_of_sync() -> u32 { 15 } +fn default_out_of_sync() -> u32 { + 15 +} fn default_false() -> bool { false } -fn default_true() -> bool { true } +fn default_true() -> bool { + true +} fn default_lifetime() -> u32 { 60 @@ -65,7 +69,9 @@ fn default_endpoints_map() -> BTreeMap> { FullConfig::default_map() } -fn default_trace() -> String { "None".to_string() } +fn default_trace() -> String { + "None".to_string() +} fn default_config() -> Config { Config::new() @@ -113,7 +119,6 @@ pub struct Config { pub project_id: Option, pub access_key: Option, //////////////////////////////// - #[serde(default = "default_endpoints")] pub endpoints: Vec, } @@ -212,18 +217,9 @@ impl Config { } } - -const MAIN_ENDPOINTS: &[&str] = &[ - "https://mainnet.evercloud.dev", -]; -const NET_ENDPOINTS: &[&str] = &[ - "https://devnet.evercloud.dev", -]; -const SE_ENDPOINTS: &[&str] = &[ - "http://0.0.0.0", - "http://127.0.0.1", - "http://localhost", -]; +const MAIN_ENDPOINTS: &[&str] = &["https://mainnet.evercloud.dev"]; +const NET_ENDPOINTS: &[&str] = &["https://devnet.evercloud.dev"]; +const SE_ENDPOINTS: &[&str] = &["http://0.0.0.0", "http://127.0.0.1", "http://localhost"]; pub fn resolve_net_name(url: &str) -> Option { let url_regex = Regex::new(r"^\s*(?:https?://)?(?P\w+\.evercloud\.dev)\s*") @@ -235,11 +231,14 @@ pub fn resolve_net_name(url: &str) -> Option { let mut net = None; for regex in [url_regex, ton_url_regex, everos_url_regex] { if let Some(captures) = regex.captures(url) { - net = Some(captures.name("net") - .expect("Unexpected: capture was not found") - .as_str() - .replace("ton", "evercloud") - .replace("everos", "evercloud")); + net = Some( + captures + .name("net") + .expect("Unexpected: capture was not found") + .as_str() + .replace("ton", "evercloud") + .replace("everos", "evercloud"), + ); } } if let Some(net) = net { @@ -253,16 +252,14 @@ pub fn resolve_net_name(url: &str) -> Option { if url == "dev" || url == "devnet" { return Some(TESTNET.to_string()); } - if url.contains("127.0.0.1") || - url.contains("0.0.0.0") || - url.contains("localhost") { + if url.contains("127.0.0.1") || url.contains("0.0.0.0") || url.contains("localhost") { return Some(LOCALNET.to_string()); } None } impl FullConfig { - fn new(config: Config,path: String) -> Self { + fn new(config: Config, path: String) -> Self { FullConfig { config, endpoints_map: Self::default_map(), @@ -278,16 +275,13 @@ impl FullConfig { (LOCALNET, SE_ENDPOINTS), ] .iter() - .map(|(k, v)| ( - k.to_string(), - v.iter().map(|s| s.to_string()).collect()) - ) + .map(|(k, v)| (k.to_string(), v.iter().map(|s| s.to_string()).collect())) .collect() } pub fn from_file(path: &str) -> FullConfig { let conf_str = std::fs::read_to_string(path).ok().unwrap_or_default(); - let config: serde_json::error::Result = serde_json::from_str(&conf_str); + let config: serde_json::error::Result = serde_json::from_str(&conf_str); if let Ok(config) = config { if config != Config::default() { return FullConfig::new(config, path.to_string()); @@ -297,10 +291,11 @@ impl FullConfig { let mut full_config = if let Ok(full_config) = full_config { full_config } else { - let conf_str = std::fs::read_to_string(global_config_path()).ok() - .unwrap_or_default(); - let mut global_config = serde_json::from_str::(&conf_str) + let conf_str = std::fs::read_to_string(global_config_path()) + .ok() .unwrap_or_default(); + let mut global_config = + serde_json::from_str::(&conf_str).unwrap_or_default(); global_config.path = path.to_string(); global_config }; @@ -308,10 +303,11 @@ impl FullConfig { full_config } - pub fn to_file(&self, path: &str) -> Result<(), String>{ + pub fn to_file(&self, path: &str) -> Result<(), String> { let conf_str = serde_json::to_string_pretty(self) .map_err(|_| "failed to serialize config object".to_string())?; - std::fs::write(path, conf_str).map_err(|e| format!("failed to write config file {}: {}", path, e))?; + std::fs::write(path, conf_str) + .map_err(|e| format!("failed to write config file {}: {}", path, e))?; Ok(()) } @@ -319,23 +315,34 @@ impl FullConfig { let fconf = FullConfig::from_file(path); println!( "{}", - serde_json::to_string_pretty(&fconf.endpoints_map).unwrap_or( - "Failed to print endpoints map.".to_owned() - ) + serde_json::to_string_pretty(&fconf.endpoints_map) + .unwrap_or("Failed to print endpoints map.".to_owned()) ); } pub fn print_aliases(&self) { println!( "{}", - serde_json::to_string_pretty(&self.aliases).unwrap_or( - "Failed to print aliases map.".to_owned() - ) + serde_json::to_string_pretty(&self.aliases) + .unwrap_or("Failed to print aliases map.".to_owned()) ); } - pub fn add_alias(&mut self, alias: &str, address: Option, abi: Option, key_path: Option) -> Result<(), String> { - self.aliases.insert(alias.to_owned(), ContractData {abi_path: abi, address, key_path} ); + pub fn add_alias( + &mut self, + alias: &str, + address: Option, + abi: Option, + key_path: Option, + ) -> Result<(), String> { + self.aliases.insert( + alias.to_owned(), + ContractData { + abi_path: abi, + address, + key_path, + }, + ); self.to_file(&self.path) } @@ -346,7 +353,7 @@ impl FullConfig { pub fn add_endpoint(path: &str, url: &str, endpoints: &str) -> Result<(), String> { let mut fconf = FullConfig::from_file(path); - let mut new_endpoints : Vec = endpoints + let mut new_endpoints: Vec = endpoints .replace(['[', ']'], "") .split(',') .map(|s| s.to_string()) @@ -473,11 +480,15 @@ pub fn set_config( matches: &ArgMatches, is_json: bool, ) -> Result<(), String> { - let config= &mut full_config.config; + let config = &mut full_config.config; if let Some(s) = matches.value_of("URL") { let resolved_url = resolve_net_name(s).unwrap_or(s.to_owned()); - let empty : Vec = Vec::new(); - config.endpoints = full_config.endpoints_map.get(&resolved_url).unwrap_or(&empty).clone(); + let empty: Vec = Vec::new(); + config.endpoints = full_config + .endpoints_map + .get(&resolved_url) + .unwrap_or(&empty) + .clone(); config.url = resolved_url; } if let Some(s) = matches.value_of("ADDR") { @@ -525,33 +536,38 @@ pub fn set_config( .map_err(|e| format!(r#"failed to parse "workchain id": {}"#, e))?; } if let Some(depool_fee) = matches.value_of("DEPOOL_FEE") { - config.depool_fee = depool_fee.parse::() + config.depool_fee = depool_fee + .parse::() .map_err(|e| format!(r#"failed to parse "depool_fee": {}"#, e))?; if config.depool_fee < 0.5 { return Err("Minimal value for depool fee is 0.5".to_string()); } } if let Some(no_answer) = matches.value_of("NO_ANSWER") { - config.no_answer = no_answer.parse::() + config.no_answer = no_answer + .parse::() .map_err(|e| format!(r#"failed to parse "no_answer": {}"#, e))?; } if let Some(balance_in_tons) = matches.value_of("BALANCE_IN_TONS") { - config.balance_in_tons = balance_in_tons.parse::() + config.balance_in_tons = balance_in_tons + .parse::() .map_err(|e| format!(r#"failed to parse "balance_in_tons": {}"#, e))?; } if let Some(local_run) = matches.value_of("LOCAL_RUN") { - config.local_run = local_run.parse::() + config.local_run = local_run + .parse::() .map_err(|e| format!(r#"failed to parse "local_run": {}"#, e))?; } if let Some(async_call) = matches.value_of("ASYNC_CALL") { - config.async_call = async_call.parse::() + config.async_call = async_call + .parse::() .map_err(|e| format!(r#"failed to parse "async_call": {}"#, e))?; } if let Some(out_of_sync_threshold) = matches.value_of("OUT_OF_SYNC") { let time = u32::from_str_radix(out_of_sync_threshold, 10) .map_err(|e| format!(r#"failed to parse "out_of_sync_threshold": {}"#, e))?; if time * 2 > config.lifetime { - return Err("\"out_of_sync\" should not exceed 0.5 * \"lifetime\".".to_string()); + return Err("\"out_of_sync\" should not exceed 0.5 * \"lifetime\".".to_string()); } config.out_of_sync_threshold = time; } @@ -564,11 +580,12 @@ pub fn set_config( } else if debug_fail == "none" { "None".to_string() } else { - return Err(r#"Wrong value for "debug_fail" config."#.to_string()) + return Err(r#"Wrong value for "debug_fail" config."#.to_string()); }; } if let Some(is_json) = matches.value_of("IS_JSON") { - config.is_json = is_json.parse::() + config.is_json = is_json + .parse::() .map_err(|e| format!(r#"failed to parse "is_json": {}"#, e))?; } if let Some(s) = matches.value_of("PROJECT_ID") { @@ -588,10 +605,9 @@ pub fn set_config( Ok(()) } - #[cfg(test)] mod tests { - use super::{resolve_net_name, LOCALNET, TESTNET, MAINNET}; + use super::{resolve_net_name, LOCALNET, MAINNET, TESTNET}; #[test] fn test_endpoints_resolver() { @@ -600,34 +616,88 @@ mod tests { assert_eq!(resolve_net_name("https://rustnet.ton.dev"), None); assert_eq!(resolve_net_name("rustnet.ton.com"), None); assert_eq!(resolve_net_name("https://example.com"), None); - assert_eq!(resolve_net_name("http://localhost"), Some(LOCALNET.to_owned())); - assert_eq!(resolve_net_name("https://localhost"), Some(LOCALNET.to_owned())); + assert_eq!( + resolve_net_name("http://localhost"), + Some(LOCALNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://localhost"), + Some(LOCALNET.to_owned()) + ); assert_eq!(resolve_net_name("localhost"), Some(LOCALNET.to_owned())); - assert_eq!(resolve_net_name("http://127.0.0.1"), Some(LOCALNET.to_owned())); - assert_eq!(resolve_net_name("https://127.0.0.1"), Some(LOCALNET.to_owned())); + assert_eq!( + resolve_net_name("http://127.0.0.1"), + Some(LOCALNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://127.0.0.1"), + Some(LOCALNET.to_owned()) + ); assert_eq!(resolve_net_name("https://127.0.0.2"), None); assert_eq!(resolve_net_name("https://127.1.0.1"), None); assert_eq!(resolve_net_name("https://0.0.0.1"), None); assert_eq!(resolve_net_name("https://1.0.0.0"), None); - assert_eq!(resolve_net_name("https://main.ton.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name("https://main.everos.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name("https://main.evercloud.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name("http://main.ton.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name(" http://main.ton.dev "), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name(" https://main.ton.dev "), Some(MAINNET.to_owned())); + assert_eq!( + resolve_net_name("https://main.ton.dev"), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://main.everos.dev"), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://main.evercloud.dev"), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name("http://main.ton.dev"), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name(" http://main.ton.dev "), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name(" https://main.ton.dev "), + Some(MAINNET.to_owned()) + ); assert_eq!(resolve_net_name("main.ton.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name("main.everos.dev"), Some(MAINNET.to_owned())); - assert_eq!(resolve_net_name("main.evercloud.dev"), Some(MAINNET.to_owned())); + assert_eq!( + resolve_net_name("main.everos.dev"), + Some(MAINNET.to_owned()) + ); + assert_eq!( + resolve_net_name("main.evercloud.dev"), + Some(MAINNET.to_owned()) + ); assert_eq!(resolve_net_name("main"), Some(MAINNET.to_owned())); assert_eq!(resolve_net_name("main.ton.com"), None); - assert_eq!(resolve_net_name("https://net.ton.dev"), Some(TESTNET.to_owned())); - assert_eq!(resolve_net_name("https://net.everos.dev"), Some(TESTNET.to_owned())); - assert_eq!(resolve_net_name("https://net.evercloud.dev"), Some(TESTNET.to_owned())); - assert_eq!(resolve_net_name("http://net.ton.dev"), Some(TESTNET.to_owned())); - assert_eq!(resolve_net_name(" http://net.ton.dev "), Some(TESTNET.to_owned())); - assert_eq!(resolve_net_name(" https://net.ton.dev "), Some(TESTNET.to_owned())); + assert_eq!( + resolve_net_name("https://net.ton.dev"), + Some(TESTNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://net.everos.dev"), + Some(TESTNET.to_owned()) + ); + assert_eq!( + resolve_net_name("https://net.evercloud.dev"), + Some(TESTNET.to_owned()) + ); + assert_eq!( + resolve_net_name("http://net.ton.dev"), + Some(TESTNET.to_owned()) + ); + assert_eq!( + resolve_net_name(" http://net.ton.dev "), + Some(TESTNET.to_owned()) + ); + assert_eq!( + resolve_net_name(" https://net.ton.dev "), + Some(TESTNET.to_owned()) + ); assert_eq!(resolve_net_name("net.ton.dev"), Some(TESTNET.to_owned())); assert_eq!(resolve_net_name("dev"), Some(TESTNET.to_owned())); assert_eq!(resolve_net_name("devnet"), Some(TESTNET.to_owned())); diff --git a/src/convert.rs b/src/convert.rs index ba288d49..0bb7ee4a 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -32,8 +32,7 @@ pub fn convert_amount(amount: &str, decimals: usize) -> Result { result += &"0".repeat(decimals); } let result = result.trim_start_matches('0').to_string(); - u64::from_str_radix(&result, 10) - .map_err(|e| format!("failed to parse amount: {}", e))?; + u64::from_str_radix(&result, 10).map_err(|e| format!("failed to parse amount: {}", e))?; return Ok(result); } diff --git a/src/crypto.rs b/src/crypto.rs index 2055a8d7..7c04ec86 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -10,22 +10,14 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use crate::helpers::{create_client_local, read_keys, WORD_COUNT, HD_PATH, check_dir}; +use crate::helpers::{check_dir, create_client_local, read_keys, HD_PATH, WORD_COUNT}; +use crate::Config; use ever_client::crypto::{ - KeyPair, - mnemonic_from_random, - hdkey_xprv_from_mnemonic, - hdkey_secret_from_xprv, - nacl_sign_keypair_from_secret_key, - hdkey_derive_from_xprv_path, - MnemonicDictionary, - ParamsOfHDKeySecretFromXPrv, - ParamsOfHDKeyDeriveFromXPrvPath, - ParamsOfHDKeyXPrvFromMnemonic, - ParamsOfNaclSignKeyPairFromSecret, - ParamsOfMnemonicFromRandom + hdkey_derive_from_xprv_path, hdkey_secret_from_xprv, hdkey_xprv_from_mnemonic, + mnemonic_from_random, nacl_sign_keypair_from_secret_key, KeyPair, MnemonicDictionary, + ParamsOfHDKeyDeriveFromXPrvPath, ParamsOfHDKeySecretFromXPrv, ParamsOfHDKeyXPrvFromMnemonic, + ParamsOfMnemonicFromRandom, ParamsOfNaclSignKeyPairFromSecret, }; -use crate::Config; pub fn load_keypair(keys: &str) -> Result { if keys.find(' ').is_none() { @@ -58,7 +50,8 @@ pub fn generate_keypair_from_mnemonic(mnemonic: &str) -> Result word_count: Some(WORD_COUNT), phrase: mnemonic.to_string(), }, - ).map_err(|e| format!("{}", e))?; + ) + .map_err(|e| format!("{}", e))?; let hdk_root = hdkey_derive_from_xprv_path( client.clone(), @@ -66,25 +59,28 @@ pub fn generate_keypair_from_mnemonic(mnemonic: &str) -> Result xprv: hdk_master.xprv.clone(), path: HD_PATH.to_string(), }, - ).map_err(|e| format!("{}", e))?; + ) + .map_err(|e| format!("{}", e))?; let secret = hdkey_secret_from_xprv( client.clone(), ParamsOfHDKeySecretFromXPrv { xprv: hdk_root.xprv.clone(), }, - ).map_err(|e| format!("{}", e))?; + ) + .map_err(|e| format!("{}", e))?; let mut keypair: KeyPair = nacl_sign_keypair_from_secret_key( client, ParamsOfNaclSignKeyPairFromSecret { secret: secret.secret.clone(), }, - ).map_err(|e| format!("failed to get KeyPair from secret key: {}", e))?; + ) + .map_err(|e| format!("failed to get KeyPair from secret key: {}", e))?; // special case if secret contains public key too. - let secret = hex::decode(&keypair.secret) - .map_err(|e| format!("failed to decode the keypair: {}", e))?; + let secret = + hex::decode(&keypair.secret).map_err(|e| format!("failed to decode the keypair: {}", e))?; if secret.len() > 32 { keypair.secret = hex::encode(&secret[..32]); } @@ -93,15 +89,12 @@ pub fn generate_keypair_from_mnemonic(mnemonic: &str) -> Result pub fn generate_keypair_from_secret(secret: String) -> Result { let client = create_client_local()?; - let mut keypair: KeyPair = nacl_sign_keypair_from_secret_key( - client, - ParamsOfNaclSignKeyPairFromSecret { - secret, - }, - ).map_err(|e| format!("failed to get KeyPair from secret key: {}", e))?; + let mut keypair: KeyPair = + nacl_sign_keypair_from_secret_key(client, ParamsOfNaclSignKeyPairFromSecret { secret }) + .map_err(|e| format!("failed to get KeyPair from secret key: {}", e))?; // special case if secret contains public key too. - let secret = hex::decode(&keypair.secret) - .map_err(|e| format!("failed to decode the keypair: {}", e))?; + let secret = + hex::decode(&keypair.secret).map_err(|e| format!("failed to decode the keypair: {}", e))?; if secret.len() > 32 { keypair.secret = hex::encode(&secret[..32]); } @@ -144,7 +137,11 @@ pub fn extract_pubkey(mnemonic: &str, is_json: bool) -> Result<(), String> { Ok(()) } -pub fn generate_keypair(keys_path: Option<&str>, mnemonic: Option<&str>, config: &Config) -> Result<(), String> { +pub fn generate_keypair( + keys_path: Option<&str>, + mnemonic: Option<&str>, + config: &Config, +) -> Result<(), String> { let mnemonic = match mnemonic { Some(mnemonic) => mnemonic.to_owned(), None => { @@ -194,15 +191,29 @@ mod tests { #[test] fn test_generate_keypair() { - let mnemonic = "multiply extra monitor fog rocket defy attack right night jaguar hollow enlist"; + let mnemonic = + "multiply extra monitor fog rocket defy attack right night jaguar hollow enlist"; let keypair = generate_keypair_from_mnemonic(mnemonic).unwrap(); - assert_eq!(&keypair.public, "757221fe3d4992e44632e75e700aaf205d799cb7373ee929273daf26adf29e56"); - assert_eq!(&keypair.secret, "30e3bc5e67af2b0a72971bcc11256e83d052c6cb861a69a19a8af88922fadf3a"); - - let mnemonic = "penalty nut enrich input palace flame safe session torch depth various hunt"; + assert_eq!( + &keypair.public, + "757221fe3d4992e44632e75e700aaf205d799cb7373ee929273daf26adf29e56" + ); + assert_eq!( + &keypair.secret, + "30e3bc5e67af2b0a72971bcc11256e83d052c6cb861a69a19a8af88922fadf3a" + ); + + let mnemonic = + "penalty nut enrich input palace flame safe session torch depth various hunt"; let keypair = generate_keypair_from_mnemonic(mnemonic).unwrap(); - assert_eq!(&keypair.public, "8cf557aab2666867a1174e3147d89ddf28c2041a7322522276cd1cf1df47ae73"); - assert_eq!(&keypair.secret, "f63d3d11e0dc91f730f22d5397f269e01f1a5f984879c8581ac87f099bfd3b3a"); + assert_eq!( + &keypair.public, + "8cf557aab2666867a1174e3147d89ddf28c2041a7322522276cd1cf1df47ae73" + ); + assert_eq!( + &keypair.secret, + "f63d3d11e0dc91f730f22d5397f269e01f1a5f984879c8581ac87f099bfd3b3a" + ); } #[test] @@ -229,5 +240,4 @@ mod tests { assert!(generate_keypair_from_mnemonic(phrase).is_err()); } } - } diff --git a/src/debot/callbacks.rs b/src/debot/callbacks.rs index e5cdf4a7..6c8a2811 100644 --- a/src/debot/callbacks.rs +++ b/src/debot/callbacks.rs @@ -15,12 +15,12 @@ use super::{action_input, input, terminal_input, ChainProcessor, ProcessorError} use crate::config::Config; use crate::convert::convert_u64_to_tokens; use crate::helpers::TonClient; -use std::collections::VecDeque; -use std::io; -use std::sync::{Arc, RwLock}; use ever_client::crypto::SigningBoxHandle; use ever_client::debot::{BrowserCallbacks, DAction, DebotActivity, STATE_EXIT}; use ever_client::error::ClientResult; +use std::collections::VecDeque; +use std::io; +use std::sync::{Arc, RwLock}; #[derive(Default)] struct ActiveState { @@ -182,8 +182,7 @@ impl BrowserCallbacks for Callbacks { } info += &format!(" Message signer public key: {}\n", signkey); if setcode { - info += - " Warning: the transaction will change the account's code\n"; + info += " Warning: the transaction will change the account's code\n"; } "Confirm the transaction (y/n)?" } diff --git a/src/debot/interfaces/address_input.rs b/src/debot/interfaces/address_input.rs index 9454e8f6..83d459a0 100644 --- a/src/debot/interfaces/address_input.rs +++ b/src/debot/interfaces/address_input.rs @@ -1,10 +1,10 @@ +use super::dinterface::{decode_answer_id, decode_prompt}; +use crate::config::Config; use crate::debot::term_browser::terminal_input; use crate::helpers::load_ton_address; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; -use super::dinterface::{decode_answer_id, decode_prompt}; -use crate::config::Config; +use serde_json::{json, Value}; const ID: &str = "d7ed1bd8e6230871116f4522e58df0a93c5520c56f4ade23ef3d8919a984653b"; @@ -47,17 +47,18 @@ pub const ABI: &str = r#" "#; pub struct AddressInput { - config: Config + config: Config, } impl AddressInput { pub fn new(config: Config) -> Self { - Self {config} + Self { config } } fn get(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; let prompt = decode_prompt(args)?; let value = terminal_input(&prompt, |val| { - let _ = load_ton_address(val, &self.config).map_err(|e| format!("Invalid address: {}", e))?; + let _ = load_ton_address(val, &self.config) + .map_err(|e| format!("Invalid address: {}", e))?; Ok(()) }); Ok((answer_id, json!({ "value": value }))) @@ -65,7 +66,8 @@ impl AddressInput { fn select(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; let value = terminal_input("", |val| { - let _ = load_ton_address(val, &self.config).map_err(|e| format!("Invalid address: {}", e))?; + let _ = load_ton_address(val, &self.config) + .map_err(|e| format!("Invalid address: {}", e))?; Ok(()) }); Ok((answer_id, json!({ "value": value }))) diff --git a/src/debot/interfaces/amount_input.rs b/src/debot/interfaces/amount_input.rs index cf01223a..1d9abf89 100644 --- a/src/debot/interfaces/amount_input.rs +++ b/src/debot/interfaces/amount_input.rs @@ -1,10 +1,10 @@ +use super::dinterface::{decode_answer_id, decode_num_arg, decode_prompt}; +use crate::convert; use crate::debot::term_browser::terminal_input; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; -use super::dinterface::{decode_answer_id, decode_num_arg, decode_prompt}; use ever_client::encoding::decode_abi_number; -use crate::convert; +use serde_json::{json, Value}; const ID: &str = "a1d347099e29c1624c8890619daf207bde18e92df5220a54bcc6d858309ece84"; @@ -103,7 +103,7 @@ impl DebotInterface for AmountInput { } } -fn format_amount(amount: u128, decimals: usize) -> String { +fn format_amount(amount: u128, decimals: usize) -> String { if decimals == 0 { format!("{}", amount) } else { diff --git a/src/debot/interfaces/confirm_input.rs b/src/debot/interfaces/confirm_input.rs index 9819eaf6..e1ab6231 100644 --- a/src/debot/interfaces/confirm_input.rs +++ b/src/debot/interfaces/confirm_input.rs @@ -1,8 +1,8 @@ +use super::dinterface::{decode_answer_id, decode_prompt}; use crate::debot::term_browser::terminal_input; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; -use super::dinterface::{decode_answer_id, decode_prompt}; +use serde_json::{json, Value}; const ID: &str = "16653eaf34c921467120f2685d425ff963db5cbb5aa676a62a2e33bfc3f6828a"; diff --git a/src/debot/interfaces/dinterface.rs b/src/debot/interfaces/dinterface.rs index d9462b71..4d40e1c2 100644 --- a/src/debot/interfaces/dinterface.rs +++ b/src/debot/interfaces/dinterface.rs @@ -1,8 +1,8 @@ use super::echo::Echo; use super::stdout::Stdout; use super::{ - AddressInput, AmountInput, ConfirmInput, Menu, NumberInput, SigningBoxInput, - EncryptionBoxInput, Terminal, UserInfo, InputInterface + AddressInput, AmountInput, ConfirmInput, EncryptionBoxInput, InputInterface, Menu, NumberInput, + SigningBoxInput, Terminal, UserInfo, }; use crate::config::Config; use crate::debot::ChainProcessor; @@ -49,9 +49,12 @@ impl SupportedInterfaces { pub fn new(client: TonClient, config: &Config, processor: Arc>) -> Self { let mut interfaces = HashMap::new(); - let iw = InterfaceWrapper { processor: processor.clone() }; + let iw = InterfaceWrapper { + processor: processor.clone(), + }; - let iface: Arc = iw.wrap(Arc::new(AddressInput::new(config.clone()))); + let iface: Arc = + iw.wrap(Arc::new(AddressInput::new(config.clone()))); interfaces.insert(iface.get_id(), iface); let iface: Arc = iw.wrap(Arc::new(AmountInput::new())); @@ -69,22 +72,19 @@ impl SupportedInterfaces { let iface: Arc = Arc::new(Echo::new()); interfaces.insert(iface.get_id(), iface); - let iface: Arc = iw.wrap( - Arc::new(Terminal::new(Printer {processor})) - ); + let iface: Arc = + iw.wrap(Arc::new(Terminal::new(Printer { processor }))); interfaces.insert(iface.get_id(), iface); let iface: Arc = iw.wrap(Arc::new(Menu::new())); interfaces.insert(iface.get_id(), iface); - let iface: Arc = Arc::new( - SigningBoxInput::new(client.clone(), iw.processor.clone()) - ); + let iface: Arc = + Arc::new(SigningBoxInput::new(client.clone(), iw.processor.clone())); interfaces.insert(iface.get_id(), iface); - let iface: Arc = iw.wrap( - Arc::new(UserInfo::new(client.clone(), config.clone())) - ); + let iface: Arc = + iw.wrap(Arc::new(UserInfo::new(client.clone(), config.clone()))); interfaces.insert(iface.get_id(), iface); let iface: Arc = diff --git a/src/debot/interfaces/echo.rs b/src/debot/interfaces/echo.rs index 92284f9b..c4f94a9a 100644 --- a/src/debot/interfaces/echo.rs +++ b/src/debot/interfaces/echo.rs @@ -1,6 +1,6 @@ -use serde_json::{Value, json}; -use ever_client::debot::{DebotInterface, InterfaceResult}; use ever_client::abi::Abi; +use ever_client::debot::{DebotInterface, InterfaceResult}; +use serde_json::{json, Value}; const ECHO_ID: &str = "f6927c0d4bdb69e1b52d27f018d156ff04152f00558042ff674f0fec32e4369d"; @@ -36,16 +36,18 @@ pub const ECHO_ABI: &str = r#" pub struct Echo {} impl Echo { - - pub fn new() -> Self { - Self{} - } - + pub fn new() -> Self { + Self {} + } + fn echo(&self, args: &Value) -> InterfaceResult { - let answer_id = u32::from_str_radix(args["answerId"].as_str().unwrap(), 10).unwrap(); - let request_vec = hex::decode(args["request"].as_str().unwrap()).unwrap(); - let request = std::str::from_utf8(&request_vec).unwrap(); - Ok(( answer_id, json!({ "response": hex::encode(request.as_bytes()) }) )) + let answer_id = u32::from_str_radix(args["answerId"].as_str().unwrap(), 10).unwrap(); + let request_vec = hex::decode(args["request"].as_str().unwrap()).unwrap(); + let request = std::str::from_utf8(&request_vec).unwrap(); + Ok(( + answer_id, + json!({ "response": hex::encode(request.as_bytes()) }), + )) } } diff --git a/src/debot/interfaces/encryption_box_input.rs b/src/debot/interfaces/encryption_box_input.rs index cb915a21..eabd81cc 100644 --- a/src/debot/interfaces/encryption_box_input.rs +++ b/src/debot/interfaces/encryption_box_input.rs @@ -1,12 +1,14 @@ -use super::dinterface::{decode_answer_id, decode_nonce, decode_prompt, decode_arg, decode_num_arg}; +use super::dinterface::{ + decode_answer_id, decode_arg, decode_nonce, decode_num_arg, decode_prompt, +}; use crate::debot::term_encryption_box::{ EncryptionBoxType, ParamsOfTerminalEncryptionBox, TerminalEncryptionBox, }; use crate::helpers::TonClient; -use serde_json::{Value, json}; -use tokio::sync::RwLock; -use ever_client::{abi::Abi, crypto::EncryptionBoxHandle}; use ever_client::debot::{DebotInterface, InterfaceResult}; +use ever_client::{abi::Abi, crypto::EncryptionBoxHandle}; +use serde_json::{json, Value}; +use tokio::sync::RwLock; const ID: &str = "5b5f76b54d976d72f1ada3063d1af2e5352edaf1ba86b3b311170d4d81056d61"; @@ -119,8 +121,12 @@ impl EncryptionBoxInput { box_type: EncryptionBoxType::NaCl, their_pubkey, nonce, - }).await; - Ok((answer_id, json!({ "handle": self.insert_box(result).await.0 }))) + }) + .await; + Ok(( + answer_id, + json!({ "handle": self.insert_box(result).await.0 }), + )) } async fn get_nacl_secret_box(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; @@ -134,7 +140,10 @@ impl EncryptionBoxInput { nonce, }) .await; - Ok((answer_id, json!({ "handle": self.insert_box(result).await.0}))) + Ok(( + answer_id, + json!({ "handle": self.insert_box(result).await.0}), + )) } async fn get_chacha20_box(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; @@ -148,7 +157,10 @@ impl EncryptionBoxInput { nonce, }) .await; - Ok((answer_id, json!({ "handle": self.insert_box(result).await.0}))) + Ok(( + answer_id, + json!({ "handle": self.insert_box(result).await.0}), + )) } async fn remove_handle(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; @@ -173,13 +185,16 @@ impl EncryptionBoxInput { }), )) } - async fn insert_box(&self, result_box: Result) -> EncryptionBoxHandle { + async fn insert_box( + &self, + result_box: Result, + ) -> EncryptionBoxHandle { match result_box { Ok(enc_box) => { let handle = enc_box.handle(); self.handles.write().await.push(enc_box); handle - }, + } Err(_) => 0.into(), } } @@ -206,4 +221,3 @@ impl DebotInterface for EncryptionBoxInput { } } } - diff --git a/src/debot/interfaces/input_interface.rs b/src/debot/interfaces/input_interface.rs index 41841f66..ec9dbf19 100644 --- a/src/debot/interfaces/input_interface.rs +++ b/src/debot/interfaces/input_interface.rs @@ -1,12 +1,12 @@ -use ever_client::abi::Abi; -use crate::debot::{ChainProcessor, ProcessorError}; -use ever_client::debot::{DebotInterface, InterfaceResult}; -use std::sync::{Arc}; -use tokio::sync::RwLock; -use serde_json::{Value, json}; use super::dinterface::{decode_answer_id, decode_prompt, decode_string_arg}; use super::menu::{MenuItem, ID as MENU_ID}; use super::terminal::ID as TERMINAL_ID; +use crate::debot::{ChainProcessor, ProcessorError}; +use ever_client::abi::Abi; +use ever_client::debot::{DebotInterface, InterfaceResult}; +use serde_json::{json, Value}; +use std::sync::Arc; +use tokio::sync::RwLock; pub struct InputInterface { processor: Arc>, @@ -39,12 +39,16 @@ impl DebotInterface for InputInterface { if self.get_id() == TERMINAL_ID && (func == "print" || func == "printf") { return self.inner_interface.call(func, args).await; } - let result = self.processor.write().await.next_input(&self.get_id(), func, args); + let result = self + .processor + .write() + .await + .next_input(&self.get_id(), func, args); match result { Err(ProcessorError::InterfaceCallNeeded) => { let res = self.inner_interface.call(func, args).await?; Ok(res) - }, + } Err(e) => return Err(format!("{:?}", e)), Ok(params) => { let prompt = decode_prompt(args); @@ -63,12 +67,14 @@ impl DebotInterface for InputInterface { } } let answer_id = if self.get_id() == MENU_ID { - let n = params["index"].as_u64() + let n = params["index"] + .as_u64() .ok_or("invalid arguments for menu callback".to_string())?; - let menu_items: Vec = serde_json::from_value(args["items"].clone()) - .map_err(|e| e.to_string())?; + let menu_items: Vec = + serde_json::from_value(args["items"].clone()).map_err(|e| e.to_string())?; let menu = menu_items.get(n as usize); - menu.ok_or("menu index is out of range".to_string())?.handler_id + menu.ok_or("menu index is out of range".to_string())? + .handler_id } else { decode_answer_id(args)? }; @@ -77,4 +83,4 @@ impl DebotInterface for InputInterface { } } } -} \ No newline at end of file +} diff --git a/src/debot/interfaces/menu.rs b/src/debot/interfaces/menu.rs index 97aa229a..2e3e38b7 100644 --- a/src/debot/interfaces/menu.rs +++ b/src/debot/interfaces/menu.rs @@ -1,10 +1,10 @@ -use super::dinterface::{decode_string_arg}; -use crate::debot::term_browser::{action_input}; -use serde_json::{Value, json}; -use serde::{de, Deserialize, Deserializer}; +use super::dinterface::decode_string_arg; +use crate::debot::term_browser::action_input; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; use ever_client::encoding::decode_abi_number; +use serde::{de, Deserialize, Deserializer}; +use serde_json::{json, Value}; pub(super) const ID: &str = "ac1a4d3ecea232e49783df4a23a81823cdca3205dc58cd20c4db259c25605b48"; @@ -58,7 +58,7 @@ pub struct MenuItem { fn from_abi_num<'de, D>(des: D) -> Result where - D: Deserializer<'de> + D: Deserializer<'de>, { let s: String = Deserialize::deserialize(des)?; decode_abi_number(&s).map_err(de::Error::custom) @@ -66,13 +66,12 @@ where pub struct Menu {} impl Menu { - - pub fn new() -> Self { - Self{} - } + pub fn new() -> Self { + Self {} + } fn select(&self, args: &Value) -> InterfaceResult { - let menu_items: Vec = serde_json::from_value(args["items"].clone()).unwrap(); + let menu_items: Vec = serde_json::from_value(args["items"].clone()).unwrap(); let title = decode_string_arg(args, "title")?; let description = decode_string_arg(args, "description")?; if !title.is_empty() { @@ -100,9 +99,8 @@ impl Menu { continue; } - return Ok(( menu.unwrap().handler_id, json!({ "index": n - 1 }) )); + return Ok((menu.unwrap().handler_id, json!({ "index": n - 1 }))); } - } } diff --git a/src/debot/interfaces/mod.rs b/src/debot/interfaces/mod.rs index 4d83a74e..8bf2475c 100644 --- a/src/debot/interfaces/mod.rs +++ b/src/debot/interfaces/mod.rs @@ -16,21 +16,21 @@ pub mod amount_input; pub mod confirm_input; pub mod dinterface; pub mod echo; +pub mod encryption_box_input; +pub mod input_interface; pub mod menu; pub mod number_input; pub mod signing_box_input; -pub mod encryption_box_input; pub mod stdout; -pub mod input_interface; pub mod terminal; pub mod userinfo; pub use address_input::AddressInput; pub use amount_input::AmountInput; pub use confirm_input::ConfirmInput; +pub use encryption_box_input::EncryptionBoxInput; +pub use input_interface::InputInterface; pub use menu::Menu; pub use number_input::NumberInput; pub use signing_box_input::SigningBoxInput; -pub use input_interface::InputInterface; -pub use encryption_box_input::EncryptionBoxInput; pub use terminal::Terminal; -pub use userinfo::UserInfo; \ No newline at end of file +pub use userinfo::UserInfo; diff --git a/src/debot/interfaces/number_input.rs b/src/debot/interfaces/number_input.rs index a745ba79..be4de2d8 100644 --- a/src/debot/interfaces/number_input.rs +++ b/src/debot/interfaces/number_input.rs @@ -1,9 +1,9 @@ +use super::dinterface::{decode_answer_id, decode_int256, decode_prompt}; use crate::debot::term_browser::terminal_input; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; -use super::dinterface::{decode_answer_id, decode_int256, decode_prompt}; use ever_client::encoding::decode_abi_bigint; +use serde_json::{json, Value}; const ID: &str = "c5a9558b2664aed7dc3e6123436d544f13ffe69ab0e259412f48c6d1c8588401"; @@ -87,4 +87,4 @@ impl DebotInterface for NumberInput { _ => Err(format!("function \"{}\" is not implemented", func)), } } -} \ No newline at end of file +} diff --git a/src/debot/interfaces/signing_box_input.rs b/src/debot/interfaces/signing_box_input.rs index 039abde3..7c02e53f 100644 --- a/src/debot/interfaces/signing_box_input.rs +++ b/src/debot/interfaces/signing_box_input.rs @@ -1,15 +1,15 @@ -use super::dinterface::{decode_answer_id, decode_prompt, decode_array}; +use super::dinterface::{decode_answer_id, decode_array, decode_prompt}; -use serde_json::Value; +use crate::debot::term_signing_box::TerminalSigningBox; +use crate::debot::{ChainProcessor, ProcessorError}; +use crate::helpers::TonClient; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; use ever_client::encoding::decode_abi_bigint; -use crate::helpers::TonClient; -use crate::debot::term_signing_box::TerminalSigningBox; -use crate::debot::{ChainProcessor, ProcessorError}; -use tokio::sync::RwLock; -use std::sync::Arc; use serde_json::json; +use serde_json::Value; +use std::sync::Arc; +use tokio::sync::RwLock; pub const ID: &str = "c13024e101c95e71afb1f5fa6d72f633d51e721de0320d73dfd6121a54e4d40a"; @@ -59,35 +59,33 @@ pub struct SigningBoxInput { } impl SigningBoxInput { pub fn new(client: TonClient, processor: Arc>) -> Self { - Self { handles: RwLock::new(vec![]), client, processor } + Self { + handles: RwLock::new(vec![]), + client, + processor, + } } async fn get(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; let prompt = decode_prompt(args)?; - let possible_keys = decode_array( - args, - "possiblePublicKeys", - |elem| { - decode_abi_bigint(elem.as_str()?).ok()?; - Some(elem.as_str().unwrap().to_string()) - } - )?; + let possible_keys = decode_array(args, "possiblePublicKeys", |elem| { + decode_abi_bigint(elem.as_str()?).ok()?; + Some(elem.as_str().unwrap().to_string()) + })?; println!("{}", prompt); let result = self.processor.write().await.next_signing_box(); match result { Err(ProcessorError::InterfaceCallNeeded) => { - let signing_box = TerminalSigningBox::new::<&[u8]>( - self.client.clone(), possible_keys, None - ).await?; + let signing_box = + TerminalSigningBox::new::<&[u8]>(self.client.clone(), possible_keys, None) + .await?; let handle = signing_box.handle(); self.handles.write().await.push(signing_box); Ok((answer_id, json!({ "handle": handle.0}))) } Err(e) => Err(format!("{:?}", e)), - Ok(handle) => { - Ok((answer_id, json!({ "handle": handle}) )) - } + Ok(handle) => Ok((answer_id, json!({ "handle": handle}))), } } } @@ -108,4 +106,4 @@ impl DebotInterface for SigningBoxInput { _ => Err(format!("function \"{}\" is not implemented", func)), } } -} \ No newline at end of file +} diff --git a/src/debot/interfaces/stdout.rs b/src/debot/interfaces/stdout.rs index ac318313..fc54d6cd 100644 --- a/src/debot/interfaces/stdout.rs +++ b/src/debot/interfaces/stdout.rs @@ -1,6 +1,6 @@ -use serde_json::{Value, json}; -use ever_client::debot::{DebotInterface, InterfaceResult}; use ever_client::abi::Abi; +use ever_client::debot::{DebotInterface, InterfaceResult}; +use serde_json::{json, Value}; const STDOUT_ID: &str = "c91dcc3fddb30485a3a07eb7c1e5e2aceaf75f4bc2678111de1f25291cdda80b"; @@ -30,17 +30,16 @@ pub const STDOUT_ABI: &str = r#"{ ] }"#; - pub struct Stdout {} impl Stdout { - pub fn new() -> Self { - Self {} - } + pub fn new() -> Self { + Self {} + } pub fn print(&self, args: &Value) -> InterfaceResult { - let text_vec = hex::decode(args["message"].as_str().unwrap()).unwrap(); - let text = std::str::from_utf8(&text_vec).unwrap(); - println!("{}", text); - Ok((0, json!({}))) + let text_vec = hex::decode(args["message"].as_str().unwrap()).unwrap(); + let text = std::str::from_utf8(&text_vec).unwrap(); + println!("{}", text); + Ok((0, json!({}))) } } @@ -60,4 +59,4 @@ impl DebotInterface for Stdout { _ => Err(format!("function \"{}\" is not implemented", func)), } } -} \ No newline at end of file +} diff --git a/src/debot/interfaces/terminal.rs b/src/debot/interfaces/terminal.rs index 2c07d586..e310f453 100644 --- a/src/debot/interfaces/terminal.rs +++ b/src/debot/interfaces/terminal.rs @@ -1,11 +1,13 @@ -use super::dinterface::{decode_answer_id, decode_bool_arg, decode_prompt, decode_string_arg, Printer}; +use super::dinterface::{ + decode_answer_id, decode_bool_arg, decode_prompt, decode_string_arg, Printer, +}; +use crate::convert::convert_token; use crate::debot::term_browser::terminal_input; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; -use crate::convert::convert_token; use ever_client::encoding::decode_abi_bigint; -use std::io::{Read}; +use serde_json::{json, Value}; +use std::io::Read; pub(super) const ID: &str = "8796536366ee21852db56dccb60bc564598b618c865fc50c8b1ab740bba128e3"; @@ -75,7 +77,7 @@ pub struct Terminal { impl Terminal { pub fn new(printer: Printer) -> Self { - Self {printer} + Self { printer } } fn input_str(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; @@ -89,7 +91,8 @@ impl Terminal { } else { println!("(Ctrl+D to exit)"); } - std::io::stdin().read_to_string(&mut value) + std::io::stdin() + .read_to_string(&mut value) .map_err(|e| format!("input error: {}", e))?; println!(); } else { @@ -144,8 +147,8 @@ impl Terminal { pub async fn print(&self, args: &Value) -> InterfaceResult { let answer_id = decode_answer_id(args)?; let message = decode_string_arg(args, "message")?; - self.printer.print(&message).await; - Ok((answer_id, json!({}))) + self.printer.print(&message).await; + Ok((answer_id, json!({}))) } } @@ -171,4 +174,4 @@ impl DebotInterface for Terminal { _ => Err(format!("function \"{}\" is not implemented", func)), } } -} \ No newline at end of file +} diff --git a/src/debot/interfaces/userinfo.rs b/src/debot/interfaces/userinfo.rs index 60ddf809..624fb851 100644 --- a/src/debot/interfaces/userinfo.rs +++ b/src/debot/interfaces/userinfo.rs @@ -2,9 +2,9 @@ use super::dinterface::decode_answer_id; use crate::config::Config; use crate::debot::term_signing_box::TerminalSigningBox; use crate::helpers::TonClient; -use serde_json::{Value, json}; use ever_client::abi::Abi; use ever_client::debot::{DebotInterface, InterfaceResult}; +use serde_json::{json, Value}; const ID: &str = "a56115147709ed3437efb89460b94a120b7fe94379c795d1ebb0435a847ee580"; diff --git a/src/debot/mod.rs b/src/debot/mod.rs index 55679bb0..a4a8bc52 100644 --- a/src/debot/mod.rs +++ b/src/debot/mod.rs @@ -14,19 +14,19 @@ mod callbacks; mod interfaces; mod pipechain; mod processor; -mod term_signing_box; -mod term_encryption_box; pub mod term_browser; +mod term_encryption_box; +mod term_signing_box; use crate::config::Config; -use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use simplelog::*; -use term_browser::{run_debot_browser, terminal_input, input, action_input}; use crate::helpers::load_ton_address; use callbacks::Callbacks; -use processor::{ChainProcessor, ProcessorError}; -use pipechain::{ApproveKind, PipeChain, ChainLink}; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; pub use interfaces::dinterface::SupportedInterfaces; +use pipechain::{ApproveKind, ChainLink, PipeChain}; +use processor::{ChainProcessor, ProcessorError}; +use simplelog::*; +use term_browser::{action_input, input, run_debot_browser, terminal_input}; pub fn create_debot_command<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("debot") @@ -42,7 +42,7 @@ pub fn create_debot_command<'a, 'b>() -> App<'a, 'b> { Arg::with_name("ADDRESS") .required(true) .help("DeBot TON address."), - ) + ), ) .subcommand( SubCommand::with_name("start") @@ -65,7 +65,7 @@ pub fn create_debot_command<'a, 'b>() -> App<'a, 'b> { .long("signkey") .takes_value(true) .help("Define keypair to auto sign transactions."), - ) + ), ) .subcommand( SubCommand::with_name("invoke") @@ -73,13 +73,13 @@ pub fn create_debot_command<'a, 'b>() -> App<'a, 'b> { .arg( Arg::with_name("ADDRESS") .required(true) - .help("Debot TON address.") + .help("Debot TON address."), ) .arg( Arg::with_name("MESSAGE") .required(true) - .help("Message to DeBot encoded as base64/base64url.") - ) + .help("Message to DeBot encoded as base64/base64url."), + ), ) } @@ -125,7 +125,8 @@ pub async fn debot_command(m: &ArgMatches<'_>, config: Config) -> Result<(), Str async fn fetch_command(m: &ArgMatches<'_>, config: Config) -> Result<(), String> { let addr = m.value_of("ADDRESS"); let pipechain = m.value_of("PIPECHAIN"); - let signkey_path = m.value_of("SIGNKEY") + let signkey_path = m + .value_of("SIGNKEY") .map(|x| x.to_owned()) .or(config.keys_path.clone()); let is_json = config.is_json; @@ -141,12 +142,14 @@ async fn fetch_command(m: &ArgMatches<'_>, config: Config) -> Result<(), String> let result = run_debot_browser(addr.as_str(), config, pipechain, signkey_path).await; match result { Ok(Some(arg)) => { - if !is_json { println!("Returned value:"); } + if !is_json { + println!("Returned value:"); + } println!("{:#}", arg); Ok(()) } Err(err) if err.contains("NoMoreChainlinks") => Ok(()), - result => result.map(|_| ()) + result => result.map(|_| ()), } } diff --git a/src/debot/pipechain.rs b/src/debot/pipechain.rs index a11cce56..de82bf17 100644 --- a/src/debot/pipechain.rs +++ b/src/debot/pipechain.rs @@ -2,8 +2,12 @@ use serde::{Deserialize, Serialize}; use serde_json::Value; use std::default::Default; -fn default_init_method() -> String { "start".to_string() } -fn default_mandatory() -> bool { false } +fn default_init_method() -> String { + "start".to_string() +} +fn default_mandatory() -> bool { + false +} #[allow(clippy::enum_variant_names)] #[derive(Deserialize, Clone, PartialEq)] @@ -52,6 +56,6 @@ pub enum ChainLink { ifeq: Option, }, SigningBox { - handle: u32 + handle: u32, }, -} \ No newline at end of file +} diff --git a/src/debot/processor.rs b/src/debot/processor.rs index 83a26162..c608b6d7 100644 --- a/src/debot/processor.rs +++ b/src/debot/processor.rs @@ -1,8 +1,8 @@ +use super::{ApproveKind, ChainLink, PipeChain}; +use ever_client::abi::{Abi, CallSet}; +use ever_client::debot::DebotActivity; use serde_json::Value; -use super::{ApproveKind, PipeChain, ChainLink}; use std::vec::IntoIter; -use ever_client::debot::DebotActivity; -use ever_client::abi::{CallSet, Abi}; #[derive(Debug)] pub enum ProcessorError { @@ -22,9 +22,12 @@ pub struct ChainProcessor { } impl ChainProcessor { - pub fn new(mut pipechain: PipeChain ) -> Self { + pub fn new(mut pipechain: PipeChain) -> Self { let chain_vec = std::mem::take(&mut pipechain.chain); - Self { pipechain, chain_iter: chain_vec.into_iter() } + Self { + pipechain, + chain_iter: chain_vec.into_iter(), + } } pub fn abi(&self) -> Option { @@ -57,28 +60,32 @@ impl ChainProcessor { return None; } match &self.pipechain.init_args { - Some(args) => CallSet::some_with_function_and_input(&self.pipechain.init_method, args.clone()), + Some(args) => { + CallSet::some_with_function_and_input(&self.pipechain.init_method, args.clone()) + } None => CallSet::some_with_function(&self.pipechain.init_method), } - } pub fn next_input( &mut self, in_interface: &str, in_method: &str, - _in_params: &Value + _in_params: &Value, ) -> Result, ProcessorError> { - let chlink = self.chain_iter.next().ok_or( - if self.interactive() { - ProcessorError::InterfaceCallNeeded - } else { - ProcessorError::NoMoreChainlinks - } - )?; + let chlink = self.chain_iter.next().ok_or(if self.interactive() { + ProcessorError::InterfaceCallNeeded + } else { + ProcessorError::NoMoreChainlinks + })?; match chlink { - ChainLink::Input {interface, method, params, mandatory} => { + ChainLink::Input { + interface, + method, + params, + mandatory, + } => { if interface != in_interface { if !mandatory { self.next_input(in_interface, in_method, _in_params) @@ -90,34 +97,33 @@ impl ChainProcessor { } else { Ok(params) } - }, + } _ => Err(ProcessorError::UnexpectedChainLinkKind), } } pub fn next_signing_box(&mut self) -> Result { - let chlink = self.chain_iter.next().ok_or( - if self.interactive() { - ProcessorError::InterfaceCallNeeded - } else { - ProcessorError::NoMoreChainlinks - } - )?; + let chlink = self.chain_iter.next().ok_or(if self.interactive() { + ProcessorError::InterfaceCallNeeded + } else { + ProcessorError::NoMoreChainlinks + })?; match chlink { - ChainLink::SigningBox {handle} => { - Ok(handle) - }, + ChainLink::SigningBox { handle } => Ok(handle), _ => Err(ProcessorError::UnexpectedChainLinkKind), } } pub fn next_approve(&mut self, activity: &DebotActivity) -> Result { - let app_kind = match activity { - DebotActivity::Transaction {..} => ApproveKind::ApproveOnChainCall, + DebotActivity::Transaction { .. } => ApproveKind::ApproveOnChainCall, }; - let auto_approve = self.pipechain.auto_approve.as_ref().map(|vec| vec.iter().any(|x| *x == app_kind)); + let auto_approve = self + .pipechain + .auto_approve + .as_ref() + .map(|vec| vec.iter().any(|x| *x == app_kind)); let chlink = self.chain_iter.next(); if chlink.is_none() { @@ -133,15 +139,22 @@ impl ChainProcessor { // TODO: ? let chlink = chlink.unwrap(); match chlink { - ChainLink::OnchainCall { approve, iflq: _, ifeq: _ } => { - match activity { - DebotActivity::Transaction {msg: _, dst: _, out: _, fee: _, setcode: _, signkey: _, signing_box_handle: _} => { - Ok(approve) - } - } + ChainLink::OnchainCall { + approve, + iflq: _, + ifeq: _, + } => match activity { + DebotActivity::Transaction { + msg: _, + dst: _, + out: _, + fee: _, + setcode: _, + signkey: _, + signing_box_handle: _, + } => Ok(approve), }, - _ => Err(ProcessorError::UnexpectedChainLinkKind) + _ => Err(ProcessorError::UnexpectedChainLinkKind), } } } - diff --git a/src/debot/term_browser.rs b/src/debot/term_browser.rs index 44fa6644..c2eabd1e 100644 --- a/src/debot/term_browser.rs +++ b/src/debot/term_browser.rs @@ -11,17 +11,19 @@ * limitations under the License. */ use super::term_signing_box::TerminalSigningBox; +use super::{Callbacks, ChainLink, ChainProcessor, PipeChain, SupportedInterfaces}; use crate::config::Config; -use crate::helpers::{create_client, load_ton_address, load_abi, TonClient}; -use std::io::{self, BufRead, Write}; -use std::sync::Arc; +use crate::helpers::{create_client, load_abi, load_ton_address, TonClient}; +use ever_client::abi::{ + decode_message, encode_internal_message, Abi, CallSet, ParamsOfDecodeMessage, + ParamsOfEncodeInternalMessage, +}; +use ever_client::boc::{parse_message, ParamsOfParse}; +use ever_client::debot::{DEngine, DebotInfo, DebotInterfaceExecutor, DEBOT_WC}; use serde_json::json; -use ever_client::abi::{ Abi, CallSet, ParamsOfEncodeInternalMessage, ParamsOfDecodeMessage, - encode_internal_message, decode_message}; -use ever_client::boc::{ParamsOfParse, parse_message}; -use ever_client::debot::{DebotInterfaceExecutor, DEngine, DebotInfo, DEBOT_WC}; use std::collections::{HashMap, VecDeque}; -use super::{Callbacks, ChainLink, PipeChain, ChainProcessor, SupportedInterfaces}; +use std::io::{self, BufRead, Write}; +use std::sync::Arc; const BROWSER_ID: &str = "0000000000000000000000000000000000000000000000000000000000000000"; /// Stores Debot info needed for DBrowser. @@ -51,7 +53,12 @@ struct TerminalBrowser { } impl TerminalBrowser { - async fn new(client: TonClient, addr: &str, config: Config, pipechain: PipeChain) -> Result { + async fn new( + client: TonClient, + addr: &str, + config: Config, + pipechain: PipeChain, + ) -> Result { let processor = ChainProcessor::new(pipechain); let start = processor.default_start(); let interactive = processor.interactive(); @@ -70,9 +77,12 @@ impl TerminalBrowser { exit_arg: None, }; let _ = browser.fetch_debot(addr, start, !interactive).await?; - let abi = browser.bots.get(addr) + let abi = browser + .bots + .get(addr) .ok_or(format!("DeBot not found: address {}", addr))? - .abi.clone(); + .abi + .clone(); if !start && init_message.is_none() { init_message = Some( @@ -99,23 +109,30 @@ impl TerminalBrowser { Ok(browser) } - async fn fetch_debot(&mut self, addr: &str, call_start: bool, autorun: bool) -> Result { + async fn fetch_debot( + &mut self, + addr: &str, + call_start: bool, + autorun: bool, + ) -> Result { let debot_addr = load_ton_address(addr, &self.config)?; - let callbacks = Arc::new( - Callbacks::new(self.client.clone(), self.config.clone(), self.processor.clone()) - ); - let callbacks_ref = Arc::clone(&callbacks); - let mut dengine = DEngine::new_with_client( - debot_addr.clone(), - None, + let callbacks = Arc::new(Callbacks::new( self.client.clone(), - callbacks - ); + self.config.clone(), + self.processor.clone(), + )); + let callbacks_ref = Arc::clone(&callbacks); + let mut dengine = + DEngine::new_with_client(debot_addr.clone(), None, self.client.clone(), callbacks); let info: DebotInfo = dengine.init().await?.into(); let abi_version = info.dabi_version.clone(); let abi_ref = info.dabi.as_ref(); let def_config = Config::default(); - let abi = load_abi(abi_ref.ok_or("DeBot ABI is not defined".to_string())?, &def_config).await?; + let abi = load_abi( + abi_ref.ok_or("DeBot ABI is not defined".to_string())?, + &def_config, + ) + .await?; if !autorun { Self::print_info(&info); } @@ -145,7 +162,7 @@ impl TerminalBrowser { dengine, callbacks: callbacks_ref, info, - } + }, ); Ok(abi_version) } @@ -156,14 +173,22 @@ impl TerminalBrowser { interface_id: String, debot_addr: &str, ) -> Result<(), String> { - let debot = self.bots.get_mut(debot_addr) + let debot = self + .bots + .get_mut(debot_addr) .ok_or_else(|| "Internal browser error: debot not found".to_owned())?; - if let Some(result) = self.interfaces.try_execute(&msg, &interface_id, &debot.info.dabi_version).await { + if let Some(result) = self + .interfaces + .try_execute(&msg, &interface_id, &debot.info.dabi_version) + .await + { let (func_id, return_args) = result?; log::debug!("response: {} ({})", func_id, return_args); let call_set = match func_id { 0 => None, - _ => CallSet::some_with_function_and_input(&format!("0x{:x}", func_id), return_args), + _ => { + CallSet::some_with_function_and_input(&format!("0x{:x}", func_id), return_args) + } }; let response_msg = encode_internal_message( self.client.clone(), @@ -173,7 +198,7 @@ impl TerminalBrowser { call_set, value: "1000000000000000".to_owned(), ..Default::default() - } + }, ) .map_err(|e| format!("{}", e))? .message; @@ -191,8 +216,15 @@ impl TerminalBrowser { if self.bots.get_mut(addr).is_none() { self.fetch_debot(addr, false, !self.interactive).await?; } - let debot = self.bots.get_mut(addr).ok_or("Internal error: debot not found")?; - debot.dengine.send(msg).await.map_err(|e| format!("Debot failed: {}", e))?; + let debot = self + .bots + .get_mut(addr) + .ok_or("Internal error: debot not found")?; + debot + .dengine + .send(msg) + .await + .map_err(|e| format!("Debot failed: {}", e))?; debot.callbacks.take_messages(&mut self.msg_queue); Ok(()) } @@ -216,12 +248,13 @@ impl TerminalBrowser { let arg = if let Some(abi) = abi { let decoded = decode_message( self.client.clone(), - ParamsOfDecodeMessage { + ParamsOfDecodeMessage { abi, message, ..Default::default() - }, - ).map_err(|e| format!("{}", e))?; + }, + ) + .map_err(|e| format!("{}", e))?; decoded.value.unwrap_or(json!({})) } else { json!({"message": message}) @@ -229,7 +262,6 @@ impl TerminalBrowser { self.exit_arg = Some(arg); Ok(()) } - } pub(crate) fn input(prefix: &str, reader: &mut R, writer: &mut W) -> String @@ -249,16 +281,14 @@ where println!("failed to read line: {}", e); return input_str; } - argc = input_str - .split_whitespace() - .count(); + argc = input_str.split_whitespace().count(); } input_str.trim().to_owned() } pub(crate) fn terminal_input(prompt: &str, mut validator: F) -> String where - F: FnMut(&String) -> Result<(), String> + F: FnMut(&String) -> Result<(), String>, { let stdio = io::stdin(); let mut reader = stdio.lock(); @@ -315,7 +345,7 @@ pub async fn run_debot_browser( let mut sbox = TerminalSigningBox::new(ton.clone(), vec![], Some(input)).await?; let sbox_handle = sbox.leak(); for cl in pipechain.chain.iter_mut() { - if let ChainLink::SigningBox{handle} = cl { + if let ChainLink::SigningBox { handle } = cl { *handle = sbox_handle.0; } } @@ -324,17 +354,16 @@ pub async fn run_debot_browser( loop { let mut next_msg = browser.msg_queue.pop_front(); while let Some(msg) = next_msg { - let parsed = parse_message( - ton.clone(), - ParamsOfParse { boc: msg.clone() }, - ) - .map_err(|e| format!("{}", e))? - .parsed; + let parsed = parse_message(ton.clone(), ParamsOfParse { boc: msg.clone() }) + .map_err(|e| format!("{}", e))? + .parsed; - let msg_dest = parsed["dst"].as_str() + let msg_dest = parsed["dst"] + .as_str() .ok_or("invalid message in the queue: no dst address".to_string())?; - let msg_src = parsed["src"].as_str() + let msg_src = parsed["src"] + .as_str() .ok_or("invalid message in the queue: no src address".to_string())?; let wc_and_addr: Vec<_> = msg_dest.split(':').collect(); @@ -357,16 +386,20 @@ pub async fn run_debot_browser( // Next block is deprecated. Remove it let not_found_err = "Internal error: DeBot not found"; - let action = browser.bots.get(addr) + let action = browser + .bots + .get(addr) .ok_or_else(|| not_found_err.to_owned())? .callbacks .select_action(); match action { Some(act) => { - let debot = browser.bots.get_mut(addr) + let debot = browser + .bots + .get_mut(addr) .ok_or_else(|| not_found_err.to_owned())?; debot.dengine.execute_action(&act).await? - }, + } None => break, } // --------------------------------------- diff --git a/src/debot/term_encryption_box.rs b/src/debot/term_encryption_box.rs index ae0b7f9e..f6a82475 100644 --- a/src/debot/term_encryption_box.rs +++ b/src/debot/term_encryption_box.rs @@ -1,12 +1,12 @@ use super::term_browser::input; use crate::crypto::load_keypair; use crate::helpers::{TonClient, HD_PATH}; -use std::io::{self}; use ever_client::crypto::{ - register_encryption_box, remove_encryption_box, - EncryptionBoxHandle, RegisteredEncryptionBox, ChaCha20ParamsEB, ChaCha20EncryptionBox, - NaclBoxParamsEB, NaclEncryptionBox, NaclSecretBoxParamsEB, NaclSecretEncryptionBox + register_encryption_box, remove_encryption_box, ChaCha20EncryptionBox, ChaCha20ParamsEB, + EncryptionBoxHandle, NaclBoxParamsEB, NaclEncryptionBox, NaclSecretBoxParamsEB, + NaclSecretEncryptionBox, RegisteredEncryptionBox, }; +use std::io::{self}; #[derive(Clone, Copy)] pub(crate) enum EncryptionBoxType { @@ -58,26 +58,34 @@ impl TerminalEncryptionBox { EncryptionBoxType::SecretNaCl => { register_encryption_box( params.context.clone(), - NaclSecretEncryptionBox::new(NaclSecretBoxParamsEB { - key, - nonce: params.nonce, - }, - Some(HD_PATH.to_owned())) + NaclSecretEncryptionBox::new( + NaclSecretBoxParamsEB { + key, + nonce: params.nonce, + }, + Some(HD_PATH.to_owned()), + ), ) - .await.map_err(|e| e.to_string())?.handle - }, + .await + .map_err(|e| e.to_string())? + .handle + } EncryptionBoxType::NaCl => { register_encryption_box( params.context.clone(), - NaclEncryptionBox::new(NaclBoxParamsEB { - their_public: params.their_pubkey, - secret: key, - nonce: params.nonce, - }, - Some(HD_PATH.to_owned())) + NaclEncryptionBox::new( + NaclBoxParamsEB { + their_public: params.their_pubkey, + secret: key, + nonce: params.nonce, + }, + Some(HD_PATH.to_owned()), + ), ) - .await.map_err(|e| e.to_string())?.handle - }, + .await + .map_err(|e| e.to_string())? + .handle + } EncryptionBoxType::ChaCha20 => { register_encryption_box( params.context.clone(), @@ -86,11 +94,14 @@ impl TerminalEncryptionBox { key, nonce: params.nonce, }, - Some(HD_PATH.to_owned()) - ).map_err(|e| e.to_string())? + Some(HD_PATH.to_owned()), + ) + .map_err(|e| e.to_string())?, ) - .await.map_err(|e| e.to_string())?.handle - }, + .await + .map_err(|e| e.to_string())? + .handle + } }; Ok(Self { handle: registered_box, @@ -101,4 +112,3 @@ impl TerminalEncryptionBox { self.handle.clone() } } - diff --git a/src/debot/term_signing_box.rs b/src/debot/term_signing_box.rs index 7efbb7fe..e492f408 100644 --- a/src/debot/term_signing_box.rs +++ b/src/debot/term_signing_box.rs @@ -1,10 +1,10 @@ use super::term_browser::input; use crate::crypto::load_keypair; use crate::helpers::{read_keys, TonClient}; -use std::io::{self, BufRead, Write, Read, BufReader}; use ever_client::crypto::{ get_signing_box, remove_signing_box, KeyPair, RegisteredSigningBox, SigningBoxHandle, }; +use std::io::{self, BufRead, BufReader, Read, Write}; pub(super) struct TerminalSigningBox { handle: SigningBoxHandle, @@ -12,8 +12,11 @@ pub(super) struct TerminalSigningBox { } impl TerminalSigningBox { - pub async fn new(client: TonClient, possible_keys: Vec, reader: Option>) -> Result - { + pub async fn new( + client: TonClient, + possible_keys: Vec, + reader: Option>, + ) -> Result { let keys = { if let Some(mut reader) = reader { let mut writer = io::stdout(); @@ -118,8 +121,7 @@ mod tests { use std::fs::File; const PUBLIC: &str = "9711a04f0b19474272bc7bae5472a8fbbb6ef71ce9c193f5ec3f5af808069a41"; - const PRIVATE: &str = - "cdf2a820517fa783b9b6094d15e650af92d485084ab217fc2c859f02d49623f3"; + const PRIVATE: &str = "cdf2a820517fa783b9b6094d15e650af92d485084ab217fc2c859f02d49623f3"; const SEED: &str = "episode polar pistol excite essence van cover fox visual gown yellow minute"; const KEYS_FILE: &str = "./keys.json"; diff --git a/src/debug.rs b/src/debug.rs index b268ee9c..87d9d7bc 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -10,39 +10,45 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use crate::{contract_data_from_matches_or_config_alias, FullConfig, print_args, - unpack_alternative_params}; +use crate::config::Config; +use crate::crypto::load_keypair; +use crate::decode::msg_printer::serialize_msg; +use crate::deploy::prepare_deploy_message; +use crate::helpers::{ + abi_from_matches_or_config, construct_account_from_tvc, create_client, create_client_local, + create_client_verbose, get_blockchain_config, load_abi, load_debug_info, load_params, + load_ton_address, now_ms, query_account_field, query_with_limit, wc_from_matches_or_config, + CallbackType, +}; use crate::message::prepare_message; -use clap::{ArgMatches, SubCommand, Arg, App}; +use crate::replay::{fetch, replay, CONFIG_ADDR, DUMP_ACCOUNT, DUMP_CONFIG, DUMP_NONE}; +use crate::{ + contract_data_from_matches_or_config_alias, print_args, unpack_alternative_params, FullConfig, +}; +use clap::{App, Arg, ArgMatches, SubCommand}; +use ever_assembler::DbgInfo; +use ever_block::CommonMessage::Std; +use ever_block::{ + Account, CommonMessage, ConfigParamEnum, CurrencyCollection, Deserializable, GasLimitsPrices, + InRefValue, Message, MsgAddressInt, Serializable, TrComputePhase, Transaction, + TransactionTickTock, +}; +use ever_block::{AccountId, Cell, UInt256}; +use ever_client::abi::{encode_message, CallSet, FunctionHeader, ParamsOfEncodeMessage, Signer}; use ever_client::boc::internal::deserialize_cell_from_base64; use ever_client::error::ClientError; -use crate::config::Config; -use crate::helpers::{load_ton_address, create_client, load_abi, now_ms, construct_account_from_tvc, - query_account_field, query_with_limit, create_client_verbose, - abi_from_matches_or_config, load_debug_info, wc_from_matches_or_config, - get_blockchain_config, load_params, create_client_local, CallbackType}; -use crate::replay::{ - fetch, CONFIG_ADDR, replay, DUMP_NONE, DUMP_CONFIG, DUMP_ACCOUNT -}; -use std::io::{Write, BufRead}; -use std::collections::{HashSet, HashMap}; -use ever_block::{Message, Account, Serializable, Deserializable, Transaction, MsgAddressInt, CurrencyCollection, GasLimitsPrices, ConfigParamEnum, TransactionTickTock, InRefValue, TrComputePhase, CommonMessage}; -use ever_block::{UInt256, Cell, AccountId}; -use ever_client::abi::{CallSet, Signer, FunctionHeader, encode_message, ParamsOfEncodeMessage}; +use ever_client::net::{query_collection, OrderBy, ParamsOfQueryCollection, SortDirection}; use ever_executor::{ - BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, TransactionExecutor, TickTockTransactionExecutor + BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, TickTockTransactionExecutor, + TransactionExecutor, }; -use std::sync::{Arc, atomic::AtomicU64}; -use ever_client::net::{OrderBy, ParamsOfQueryCollection, query_collection, SortDirection}; -use crate::crypto::load_keypair; +use ever_vm::executor::{EngineTraceInfo, EngineTraceInfoType}; +use serde_json::{json, Value}; +use std::collections::{HashMap, HashSet}; use std::fmt; use std::fs::File; -use serde_json::{Value, json}; -use ever_assembler::DbgInfo; -use ever_block::CommonMessage::Std; -use ever_vm::executor::{EngineTraceInfo, EngineTraceInfoType}; -use crate::decode::msg_printer::serialize_msg; -use crate::deploy::prepare_deploy_message; +use std::io::{BufRead, Write}; +use std::sync::{atomic::AtomicU64, Arc}; const SDK_EXECUTION_ERROR_CODE: u32 = 414; pub const DEFAULT_TRACE_PATH: &str = "./trace.log"; @@ -74,8 +80,7 @@ struct DebugLogger { impl DebugLogger { fn new(path: String) -> Self { if std::path::Path::new(&path).exists() { - std::fs::remove_file(&path) - .expect("Failed to remove old trace log."); + std::fs::remove_file(&path).expect("Failed to remove old trace log."); } DebugLogger { @@ -94,14 +99,14 @@ impl log::Log for DebugLogger { match record.target() { "tvm" | "executor" => { match std::fs::OpenOptions::new() - .append(true) .create(true) .open(&self.tvm_trace) .as_mut() { Ok(file) => { - let _ = file.write(format!("{}\n", record.args()).as_bytes()) + let _ = file + .write(format!("{}\n", record.args()).as_bytes()) .expect("Failed to write trace"); } Err(_) => { @@ -129,12 +134,11 @@ impl log::Log for DebugLogger { pub fn init_debug_logger(trace_path: &str) -> Result<(), String> { if trace_path == "nul" { - return Ok(()) + return Ok(()); } let logger = Box::new(DebugLogger::new(trace_path.to_string())); log::set_max_level(log::LevelFilter::Trace); - log::set_boxed_logger(logger) - .map_err(|e| format!("Failed to set logger {trace_path}: {e}")) + log::set_boxed_logger(logger).map_err(|e| format!("Failed to set logger {trace_path}: {e}")) } pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { @@ -249,10 +253,11 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .arg(config_path_arg.clone()) .arg(update_arg.clone().requires("BOC")) .arg(now_arg.clone()) - .arg(Arg::with_name("MESSAGE") - .takes_value(true) - .required(true) - .help("Message in Base64 or path to file with message.") + .arg( + Arg::with_name("MESSAGE") + .takes_value(true) + .required(true) + .help("Message in Base64 or path to file with message."), ); let run_cmd = SubCommand::with_name("run") @@ -288,29 +293,39 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .arg(sign_arg.clone()) .arg(now_arg.clone()) .arg(config_path_arg.clone()) - .arg(Arg::with_name("TVC") - .required(true) - .takes_value(true) - .help("Path to the TVC file with contract stateinit.")) - .arg(Arg::with_name("WC") - .takes_value(true) - .allow_hyphen_values(true) - .long("--wc") - .help("Workchain ID")) + .arg( + Arg::with_name("TVC") + .required(true) + .takes_value(true) + .help("Path to the TVC file with contract stateinit."), + ) + .arg( + Arg::with_name("WC") + .takes_value(true) + .allow_hyphen_values(true) + .long("--wc") + .help("Workchain ID"), + ) .arg(params_arg.clone()) .arg(method_arg.clone()) .arg( - update_arg.clone() - .help("Store account in same file, but with BOC extension.")) - .arg(Arg::with_name("INITIAL_BALANCE") - .long("--initial_balance") - .takes_value(true) - .help("Initial balance in nanotokens.")) - .arg(Arg::with_name("INIT_BALANCE") - .long("--init_balance") - .help("Do not fetch account from the network, but create dummy account with big balance.")); - - let call_cmd = run_cmd.clone().name("call") + update_arg + .clone() + .help("Store account in same file, but with BOC extension."), + ) + .arg( + Arg::with_name("INITIAL_BALANCE") + .long("--initial_balance") + .takes_value(true) + .help("Initial balance in nanotokens."), + ) + .arg(Arg::with_name("INIT_BALANCE").long("--init_balance").help( + "Do not fetch account from the network, but create dummy account with big balance.", + )); + + let call_cmd = run_cmd + .clone() + .name("call") .about("Play call locally with trace") .arg(sign_arg.clone()) .arg(update_arg.clone()); @@ -378,7 +393,10 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .subcommand(msg_cmd) } -pub async fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { +pub async fn debug_command( + matches: &ArgMatches<'_>, + full_config: &FullConfig, +) -> Result<(), String> { let config = &full_config.config; if let Some(matches) = matches.subcommand_matches("transaction") { return debug_transaction_command(matches, config, false).await; @@ -407,7 +425,11 @@ pub async fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) - Err("unknown command".to_owned()) } -async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is_account: bool) -> Result<(), String> { +async fn debug_transaction_command( + matches: &ArgMatches<'_>, + config: &Config, + is_account: bool, +) -> Result<(), String> { let trace_path = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); let config_path = matches.value_of("CONFIG_PATH"); let contract_path = matches.value_of("CONTRACT_PATH"); @@ -421,12 +443,16 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is let address = query_address(tx_id.unwrap(), config).await?; (tx_id.unwrap().to_string(), address) } else { - let address = - Some(matches.value_of("ADDRESS") - .map(|s| s.to_string()) - .or(config.addr.clone()) - .ok_or("ADDRESS is not defined. Supply it in the config file or command line." - .to_string())?); + let address = Some( + matches + .value_of("ADDRESS") + .map(|s| s.to_string()) + .or(config.addr.clone()) + .ok_or( + "ADDRESS is not defined. Supply it in the config file or command line." + .to_string(), + )?, + ); if !config.is_json { print_args!(address, trace_path, config_path, contract_path); } @@ -440,9 +466,7 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is "" } else { match config_path { - Some(config_path) => { - config_path - }, + Some(config_path) => config_path, _ => { if !config.is_json { println!("Fetching config contract transactions..."); @@ -453,9 +477,7 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is } }; let contract_path = match contract_path { - Some(contract_path) => { - contract_path - }, + Some(contract_path) => contract_path, _ => { if !config.is_json { println!("Fetching contract transactions..."); @@ -492,8 +514,9 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is || init_debug_logger(trace_path), dump_mask, config, - blockchain_config - ).await?; + blockchain_config, + ) + .await?; decode_messages(&tr, load_decode_abi(matches, config), config).await?; if !config.is_json { @@ -502,7 +525,10 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is Ok(()) } -async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +async fn replay_transaction_command( + matches: &ArgMatches<'_>, + config: &Config, +) -> Result<(), String> { let tx_id = matches.value_of("TX_ID"); let config_path = matches.value_of("CONFIG_PATH"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); @@ -527,19 +553,22 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - limit: Some(1), order: None, }, - ).await - .map_err(|e| format!("Failed to query transaction: {}", e))?; + ) + .await + .map_err(|e| format!("Failed to query transaction: {}", e))?; if trans.result.is_empty() { return Err("Transaction with specified id was not found".to_string()); } let trans = trans.result[0].clone(); - let block_lt = trans["block"]["start_lt"].as_str() + let block_lt = trans["block"]["start_lt"] + .as_str() .ok_or("Failed to parse block_lt.".to_string())?; let block_lt = u64::from_str_radix(&block_lt[2..], 16) .map_err(|e| format!("Failed to convert block_lt: {}", e))?; - let boc = trans["boc"].as_str() + let boc = trans["boc"] + .as_str() .ok_or("Failed to parse boc.".to_string())?; let trans = Transaction::construct_from_base64(boc) @@ -550,8 +579,13 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; - let msg = trans.in_msg_cell().map(|c| Message::construct_from_cell(c) - .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; + let msg = trans + .in_msg_cell() + .map(|c| { + Message::construct_from_cell(c) + .map_err(|e| format!("failed to construct message: {}", e)) + }) + .transpose()?; init_debug_logger(output.unwrap())?; @@ -565,8 +599,9 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - trans.logical_time(), false, false, - config - ).await; + config, + ) + .await; if do_update && result_trans.is_ok() { Account::construct_from_cell(account.clone()) @@ -580,7 +615,7 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - match result_trans { Ok(result_trans) => { - decode_messages(&result_trans,load_decode_abi(matches, config), config).await?; + decode_messages(&result_trans, load_decode_abi(matches, config), config).await?; if !config.is_json { println!("Execution finished."); } @@ -599,14 +634,16 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - fn parse_now(matches: &ArgMatches<'_>) -> Result { Ok(match matches.value_of("NOW") { - Some(now) => now.parse() + Some(now) => now + .parse() .map_err(|e| format!("Failed to convert now to u64: {}", e))?, - _ => now_ms() + _ => now_ms(), }) } fn load_decode_abi(matches: &ArgMatches<'_>, config: &Config) -> Option { - let abi = matches.value_of("DECODE_ABI") + let abi = matches + .value_of("DECODE_ABI") .map(|s| s.to_owned()) .or(abi_from_matches_or_config(matches, config).ok()); match abi { @@ -618,26 +655,35 @@ fn load_decode_abi(matches: &ArgMatches<'_>, config: &Config) -> Option } None } - } - _ => None + }, + _ => None, } } -async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_getter: bool) -> Result<(), String> { +async fn debug_call_command( + matches: &ArgMatches<'_>, + full_config: &FullConfig, + is_getter: bool, +) -> Result<(), String> { let contract_data = contract_data_from_matches_or_config_alias(matches, full_config)?; let input = contract_data.address.as_ref(); let output = matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH); - let method = matches.value_of("METHOD").or(full_config.config.method.as_deref()) + let method = matches + .value_of("METHOD") + .or(full_config.config.method.as_deref()) .ok_or("Method is not defined. Supply it in the config file or command line.")?; let is_boc = matches.is_present("BOC"); let is_tvc = matches.is_present("TVC"); let abi = load_abi(contract_data.abi.as_ref().unwrap(), &full_config.config).await?; - let params = Some(unpack_alternative_params( - matches, - contract_data.abi.as_ref().unwrap(), - method, - &full_config.config - ).await?); + let params = Some( + unpack_alternative_params( + matches, + contract_data.abi.as_ref().unwrap(), + method, + &full_config.config, + ) + .await?, + ); if !full_config.config.is_json { let keys = &contract_data.keys; @@ -649,9 +695,7 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, let ton_client; let mut account = if is_tvc { ton_client = create_client_local()?; - construct_account_from_tvc(input, - matches.value_of("ACCOUNT_ADDRESS"), - Some(u64::MAX))? + construct_account_from_tvc(input, matches.value_of("ACCOUNT_ADDRESS"), Some(u64::MAX))? } else if is_boc { ton_client = create_client_local()?; Account::construct_from_file(input) @@ -678,7 +722,8 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, None, full_config.config.is_json, None, - ).await? + ) + .await? .message } else { let keys = contract_data.keys.map(|k| load_keypair(&k)).transpose()?; @@ -693,23 +738,23 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, let call_set = CallSet { function_name: method.to_string(), input: Some(params), - header: Some(header) + header: Some(header), }; let msg_params = ParamsOfEncodeMessage { abi, address: account.get_addr().map(|addr| addr.to_string()), call_set: Some(call_set), signer: if keys.is_some() { - Signer::Keys { keys: keys.unwrap() } + Signer::Keys { + keys: keys.unwrap(), + } } else { Signer::None }, ..Default::default() }; - encode_message( - ton_client, - msg_params - ).await + encode_message(ton_client, msg_params) + .await .map_err(|e| format!("Failed to encode message: {}", e))? .message }; @@ -720,13 +765,15 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, if is_getter { account.set_balance(CurrencyCollection::with_grams(u64::MAX)); } - let mut acc_root = account.serialize() + let mut acc_root = account + .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; let trace_path = output; init_debug_logger(trace_path)?; - let bc_config = get_blockchain_config(&full_config.config, matches.value_of("CONFIG_PATH")).await?; + let bc_config = + get_blockchain_config(&full_config.config, matches.value_of("CONFIG_PATH")).await?; let trans = execute_debug( bc_config, &mut acc_root, @@ -738,12 +785,18 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_getter, false, &full_config.config, - ).await; + ) + .await; let mut out_res = vec![]; let msg_string = match trans { Ok(trans) => { - out_res = decode_messages(&trans, load_decode_abi(matches, &full_config.config), &full_config.config).await?; + out_res = decode_messages( + &trans, + load_decode_abi(matches, &full_config.config), + &full_config.config, + ) + .await?; "Execution finished.".to_string() } Err(e) => { @@ -808,8 +861,10 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res Message::construct_from_file(message) } else { Message::construct_from_base64(message) - }.map_err(|e| format!("Failed to decode message: {}", e))?; - let mut acc_root = account.serialize() + } + .map_err(|e| format!("Failed to decode message: {}", e))?; + let mut acc_root = account + .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; let trace_path = output.unwrap(); @@ -826,17 +881,16 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res now, false, false, - config - ).await; + config, + ) + .await; let (msg_string, error) = match result { Ok(trans) => { - decode_messages(&trans,load_decode_abi(matches, config), config).await?; + decode_messages(&trans, load_decode_abi(matches, config), config).await?; ("Execution finished.".to_string(), None) } - Err(e) => { - (format!("Execution failed: {}", e), Some(e)) - } + Err(e) => (format!("Execution failed: {}", e), Some(e)), }; if matches.is_present("UPDATE_BOC") { @@ -855,7 +909,7 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res } match error { Some(e) => Err(e), - None => Ok(()) + None => Ok(()), } } @@ -863,18 +917,17 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu let tvc = matches.value_of("TVC"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); let opt_abi = Some(abi_from_matches_or_config(matches, config)?); - let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) + let debug_info = matches + .value_of("DBG_INFO") + .map(|s| s.to_string()) .or(load_debug_info(opt_abi.as_ref().unwrap())); - let sign = matches.value_of("KEYS") + let sign = matches + .value_of("KEYS") .map(|s| s.to_string()) .or(config.keys_path.clone()); let method = matches.value_of("METHOD").unwrap_or("constructor"); - let params = Some(unpack_alternative_params( - matches, - opt_abi.as_ref().unwrap(), - method, - config - ).await?); + let params = + Some(unpack_alternative_params(matches, opt_abi.as_ref().unwrap(), method, config).await?); let wc = wc_from_matches_or_config(matches, config)?; if !config.is_json { print_args!(tvc, params, sign, opt_abi, output, debug_info); @@ -888,8 +941,9 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu wc, config, None, - method.to_string() - ).await?; + method.to_string(), + ) + .await?; let initial_balance_opt = if let Some(initial_balance) = matches.value_of("INITIAL_BALANCE") { initial_balance.parse().ok() } else if matches.is_present("INIT_BALANCE") { @@ -898,25 +952,19 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu None }; let ton_client = create_client(config)?; - let enc_msg = encode_message(ton_client.clone(), msg.clone()).await + let enc_msg = encode_message(ton_client.clone(), msg.clone()) + .await .map_err(|e| format!("failed to create inbound message: {}", e))?; let account = if let Some(initial_balance) = initial_balance_opt { let address = AccountId::from_string(address.split(':').collect::>()[1]) .map_err(|e| format!("{}", e))?; - let addr = MsgAddressInt::with_standart( - None, - wc as i8, - address - ).map_err(|e| format!("{}", e))?; + let addr = + MsgAddressInt::with_standart(None, wc as i8, address).map_err(|e| format!("{}", e))?; let balance = CurrencyCollection::with_grams(initial_balance); Account::with_address_and_ballance(&addr, &balance) } else { - let account = query_account_field( - ton_client.clone(), - &address, - "boc" - ).await?; + let account = query_account_field(ton_client.clone(), &address, "boc").await?; Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? }; @@ -924,7 +972,8 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu let message = Message::construct_from_base64(&enc_msg.message) .map_err(|e| format!("Failed to construct message: {}", e))?; - let mut acc_root = account.serialize() + let mut acc_root = account + .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; let trace_path = output.unwrap(); @@ -943,18 +992,23 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu false, false, config, - ).await; + ) + .await; let msg_string = match trans { Ok(trans) => { if matches.is_present("UPDATE_BOC") { let account = Account::construct_from_cell(acc_root) - .map_err(|e| format!("Failed to construct account after debug deploy: {e}"))?; + .map_err(|e| format!("Failed to construct account after debug deploy: {e}"))?; let output = std::path::PathBuf::from(tvc.unwrap()).with_extension("boc"); - account.write_to_file(&output) - .map_err(|e| format!("Failed to serialize account after debug deploy {:?}: {e}", output))?; + account.write_to_file(&output).map_err(|e| { + format!( + "Failed to serialize account after debug deploy {:?}: {e}", + output + ) + })?; } - decode_messages(&trans,load_decode_abi(matches, config), config).await?; + decode_messages(&trans, load_decode_abi(matches, config), config).await?; "Execution finished.".to_string() } Err(e) => { @@ -968,21 +1022,28 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu Ok(()) } -pub async fn decode_messages(tr: &Transaction, abi: Option, config: &Config) -> Result, String> { +pub async fn decode_messages( + tr: &Transaction, + abi: Option, + config: &Config, +) -> Result, String> { let msgs = &tr.out_msgs; if !msgs.is_empty() { log::debug!(target: "executor", "Output messages:\n----------------"); } - let msgs = msgs.export_vector() + let msgs = msgs + .export_vector() .map_err(|e| format!("Failed to parse out messages: {}", e))?; let mut res = vec![]; let mut output = vec![]; for InRefValue(common_msg) in msgs { let msg = common_msg.get_std().unwrap(); - let mut ser_msg = serialize_msg(msg, abi.clone(), config).await + let mut ser_msg = serialize_msg(msg, abi.clone(), config) + .await .map_err(|e| format!("Failed to serialize message: {}", e))?; - let msg_cell = msg.serialize() + let msg_cell = msg + .serialize() .map_err(|e| format!("Failed to serialize out message: {}", e))?; ser_msg["id"] = msg_cell.repr_hash().as_hex_string().into(); let msg_bytes = ever_block::write_boc(&msg_cell) @@ -996,14 +1057,12 @@ pub async fn decode_messages(tr: &Transaction, abi: Option, config: &Con output.push(ser_msg); } if config.is_json { - let description = tr.read_description() + let description = tr + .read_description() .map_err(|e| format!("Failed to read transaction description: {e}"))?; let (exit_code, gas_usage) = match description.compute_phase_ref() { - Some(TrComputePhase::Vm(compute)) => ( - compute.exit_code, - compute.gas_used.as_u64() - ), - _ => (0, 0) + Some(TrComputePhase::Vm(compute)) => (compute.exit_code, compute.gas_used.as_u64()), + _ => (0, 0), }; // let _tr = match ever_block_json::debug_transaction(tr.clone()) { // Ok(tr) => serde_json::from_str::(&tr).unwrap(), @@ -1040,16 +1099,17 @@ async fn query_address(tr_id: &str, config: &Config) -> Result { }), "account_addr", None, - Some(1) - ).await - .map_err(|e| format!("Failed to query address: {}", e))?; + Some(1), + ) + .await + .map_err(|e| format!("Failed to query address: {}", e))?; match query_result.len() { 0 => Err("Transaction was not found".to_string()), _ => Ok(query_result[0]["account_addr"] .to_string() .trim_start_matches(|c| c == '"') .trim_end_matches(|c| c == '"') - .to_string()) + .to_string()), } } @@ -1057,7 +1117,7 @@ struct TrDetails { transaction_id: String, timestamp: String, source_address: String, - message_type: String + message_type: String, } impl fmt::Display for TrDetails { @@ -1071,7 +1131,10 @@ impl fmt::Display for TrDetails { async fn query_transactions(address: &str, config: &Config) -> Result, String> { let ton_client = create_client(config)?; - let order = vec![OrderBy{ path: "lt".to_string(), direction: SortDirection::DESC }]; + let order = vec![OrderBy { + path: "lt".to_string(), + direction: SortDirection::DESC, + }]; let query_result = query_with_limit( ton_client, "transactions", @@ -1082,21 +1145,21 @@ async fn query_transactions(address: &str, config: &Config) -> Result Err("Transaction list is empty.".to_string()), - _ => { - Ok(query_result.iter().map(|query| { - TrDetails{ - transaction_id: query["id"].to_string(), - timestamp: query["now_string"].to_string(), - source_address: query["in_message"]["src"].to_string(), - message_type: query["in_message"]["msg_type_name"].to_string() - } - }).collect::>()) - } + _ => Ok(query_result + .iter() + .map(|query| TrDetails { + transaction_id: query["id"].to_string(), + timestamp: query["now_string"].to_string(), + source_address: query["in_message"]["src"].to_string(), + message_type: query["in_message"]["msg_type_name"].to_string(), + }) + .collect::>()), } } @@ -1105,15 +1168,24 @@ fn choose_transaction(transactions: Vec) -> Result { for index in 1..=transactions.len() { println!("{}){}", index, transactions[index - 1]); } - println!("\n\nEnter number of the chosen transaction (from 1 to {}):", transactions.len()); + println!( + "\n\nEnter number of the chosen transaction (from 1 to {}):", + transactions.len() + ); let mut input = String::new(); std::io::stdin().read_line(&mut input).unwrap(); - let chosen: usize = input.trim().parse() + let chosen: usize = input + .trim() + .parse() .map_err(|e| format!("Failed to parse user input as integer: {}", e))?; if !(1..=transactions.len()).contains(&chosen) { return Err("Wrong transaction number".to_string()); } - Ok(transactions[chosen-1].transaction_id.trim_start_matches(|c| c == '"').trim_end_matches(|c| c == '"').to_string()) + Ok(transactions[chosen - 1] + .transaction_id + .trim_start_matches(|c| c == '"') + .trim_end_matches(|c| c == '"') + .to_string()) } pub async fn execute_debug_params(debug_params: &DebugParams<'_>) -> Result { @@ -1125,7 +1197,7 @@ pub async fn execute_debug_params(debug_params: &DebugParams<'_>) -> Result None + None => None, }; execute_debug( debug_params.bc_config.clone(), @@ -1138,7 +1210,8 @@ pub async fn execute_debug_params(debug_params: &DebugParams<'_>) -> Result = if message.is_some() { Box::new(OrdinaryTransactionExecutor::new(bc_config)) } else { - let tt = if is_tock { TransactionTickTock::Tock } else { TransactionTickTock::Tick }; + let tt = if is_tock { + TransactionTickTock::Tock + } else { + TransactionTickTock::Tick + }; Box::new(TickTockTransactionExecutor::new(bc_config, tt)) }; let params = ExecuteParams { @@ -1192,22 +1270,20 @@ pub async fn execute_debug( }; let common_message: Option = message.map(|m| Std(m.clone())); - executor.execute_with_libs_and_params( - common_message.as_ref(), - account_root, - params - ).map_err(|e| { - let exit_code = match e.downcast_ref() { - Some(ever_executor::ExecutorError::NoAcceptError(exit_code, _)) => *exit_code, - None => ever_vm::error::tvm_exception_or_custom_code(&e), - _ => return format!("Debug failed: {}", e) - }; - let result = json!({ - "exit_code": exit_code, - "message": e.to_string(), - }); - format!("{:#}", result) - }) + executor + .execute_with_libs_and_params(common_message.as_ref(), account_root, params) + .map_err(|e| { + let exit_code = match e.downcast_ref() { + Some(ever_executor::ExecutorError::NoAcceptError(exit_code, _)) => *exit_code, + None => ever_vm::error::tvm_exception_or_custom_code(&e), + _ => return format!("Debug failed: {}", e), + }; + let result = json!({ + "exit_code": exit_code, + "message": e.to_string(), + }); + format!("{:#}", result) + }) } fn trace_callback(info: &EngineTraceInfo, debug_info: Option<&DbgInfo>) { @@ -1230,7 +1306,7 @@ fn trace_callback(info: &EngineTraceInfo, debug_info: Option<&DbgInfo>) { info.gas_cmd ); - if let Ok(position) = get_position(info, debug_info){ + if let Ok(position) = get_position(info, debug_info) { log::info!(target: "tvm", "Position: {}", position); } else { log::info!(target: "tvm", "Position: Undefined"); @@ -1255,33 +1331,34 @@ fn get_position(info: &EngineTraceInfo, debug_info: Option<&DbgInfo>) -> Result< match debug_info.get(&cell_hash) { Some(offset_map) => match offset_map.get(&offset) { Some(pos) => Ok(format!("{}:{}", pos.filename, pos.line)), - None => Err("-:0 (offset not found))".to_string()) + None => Err("-:0 (offset not found))".to_string()), }, - None => Err("-:0 (cell hash not found)".to_string()) + None => Err("-:0 (cell hash not found)".to_string()), } } fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> CallbackType { if let Some(matches) = matches { let opt_abi = abi_from_matches_or_config(matches, config); - let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) - .or( - if opt_abi.is_ok() { + let debug_info = + matches + .value_of("DBG_INFO") + .map(|s| s.to_string()) + .or(if opt_abi.is_ok() { load_debug_info(opt_abi.as_ref().unwrap()) } else { None - } - ); + }); let debug_info = if let Some(dbg_path) = debug_info { match File::open(&dbg_path) { - Ok(file ) => match serde_json::from_reader(file) { + Ok(file) => match serde_json::from_reader(file) { Ok(info) => Some(info), Err(e) => { eprintln!("Failed to serde debug info from file {dbg_path}: {e}"); None - }, + } }, - Err(e) => { + Err(e) => { eprintln!("Failed to open file {dbg_path}: {e}"); None } @@ -1301,42 +1378,50 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Callb } } -const RENDER_NONE: u8 = 0x00; -const RENDER_GAS: u8 = 0x01; +const RENDER_NONE: u8 = 0x00; +const RENDER_GAS: u8 = 0x01; -pub async fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +pub async fn sequence_diagram_command( + matches: &ArgMatches<'_>, + config: &Config, +) -> Result<(), String> { let filename = matches.value_of("ADDRESSES").unwrap(); - let file = std::fs::File::open(filename) - .map_err(|e| format!("Failed to open file: {}", e))?; + let file = std::fs::File::open(filename).map_err(|e| format!("Failed to open file: {}", e))?; - let mut addresses = vec!(); + let mut addresses = vec![]; let lines = std::io::BufReader::new(file).lines(); for line in lines.map_while(Result::ok) { - if !line.is_empty() && !line.starts_with('#'){ + if !line.is_empty() && !line.starts_with('#') { addresses.push(load_ton_address(&line, config)?); } } if addresses.iter().collect::>().len() < addresses.len() { - return Err("Addresses are not unique".to_owned()) + return Err("Addresses are not unique".to_owned()); } let mut output = std::fs::File::create(format!("{}.plantuml", filename)) .map_err(|e| format!("Failed to create file: {}", e))?; - make_sequence_diagram(config, addresses, RENDER_NONE, &mut output).await.map(|res| { - println!("{}", res); - }) + make_sequence_diagram(config, addresses, RENDER_NONE, &mut output) + .await + .map(|res| { + println!("{}", res); + }) } fn infer_address_width(input: &[String], min_width: usize) -> Result { - let max_width = input.iter().fold(0, |acc, item| { - std::cmp::max(acc, item.len()) - }); - let addresses = input.iter().map(|address| - format!("{:>max_width$}", address) - ).collect::>(); + let max_width = input + .iter() + .fold(0, |acc, item| std::cmp::max(acc, item.len())); + let addresses = input + .iter() + .map(|address| format!("{:>max_width$}", address)) + .collect::>(); let mut width = min_width; loop { - let set = addresses.iter().map(|s| s.split_at(width).1).collect::>(); + let set = addresses + .iter() + .map(|s| s.split_at(width).1) + .collect::>(); if set.len() == addresses.len() { break; } @@ -1354,11 +1439,14 @@ struct TransactionExt { tr: Transaction, } -async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result, String> { +async fn fetch_transactions( + config: &Config, + addresses: &Vec, +) -> Result, String> { let context = create_client_verbose(config)?; let retry_strategy = tokio_retry::strategy::ExponentialBackoff::from_millis(10).take(5); - let mut txns = vec!(); + let mut txns = vec![]; for address in addresses { let mut lt = String::from("0x0"); loop { @@ -1376,15 +1464,18 @@ async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result< } })), result: "lt boc id workchain_id".to_owned(), - order: Some(vec![ - OrderBy { path: "lt".to_owned(), direction: SortDirection::ASC } - ]), + order: Some(vec![OrderBy { + path: "lt".to_owned(), + direction: SortDirection::ASC, + }]), limit: None, }, - ).await + ) + .await }; - let transactions = tokio_retry::Retry::spawn(retry_strategy.clone(), action).await + let transactions = tokio_retry::Retry::spawn(retry_strategy.clone(), action) + .await .map_err(|e| format!("Failed to fetch transactions: {}", e))?; if transactions.result.is_empty() { @@ -1404,11 +1495,22 @@ async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result< }); } - let last = transactions.result.last().ok_or("Failed to get last txn".to_string())?; - lt = last["lt"].as_str().ok_or("Failed to parse value".to_string())?.to_owned(); + let last = transactions + .result + .last() + .ok_or("Failed to get last txn".to_string())?; + lt = last["lt"] + .as_str() + .ok_or("Failed to parse value".to_string())? + .to_owned(); } } - txns.sort_by(|tr1, tr2| tr1.tr.logical_time().partial_cmp(&tr2.tr.logical_time()).unwrap()); + txns.sort_by(|tr1, tr2| { + tr1.tr + .logical_time() + .partial_cmp(&tr2.tr.logical_time()) + .unwrap() + }); Ok(txns) } @@ -1421,8 +1523,11 @@ fn map_inbound_messages_onto_tr(txns: &Vec) -> HashMap) -> Result, String> { - let mut messages = vec!(); +fn sort_outbound_messages( + tr: &Transaction, + map: &HashMap, +) -> Result, String> { + let mut messages = vec![]; tr.iterate_out_msgs(|common_msg| { let msg = common_msg.get_std().unwrap().clone(); let hash = msg.serialize().unwrap().repr_hash(); @@ -1433,7 +1538,8 @@ fn sort_outbound_messages(tr: &Transaction, map: &HashMap) }; messages.push((lt, msg)); Ok(true) - }).unwrap(); + }) + .unwrap(); messages.sort_by(|(lt1, _), (lt2, _)| lt2.partial_cmp(lt1).unwrap()); Ok(messages.iter().map(|(_, v)| v.clone()).collect()) } @@ -1442,14 +1548,21 @@ async fn make_sequence_diagram( config: &Config, addresses: Vec, render_flags: u8, - output: &mut File + output: &mut File, ) -> Result { let _name_length = infer_address_width(&addresses, 6)?; let name_length = ACCOUNT_WIDTH; - let name_map = addresses.iter().enumerate().map(|(index, address)| { - (address.clone(), (index, address.split_at(name_length).0.to_owned())) - }).collect::>(); + let name_map = addresses + .iter() + .enumerate() + .map(|(index, address)| { + ( + address.clone(), + (index, address.split_at(name_length).0.to_owned()), + ) + }) + .collect::>(); let txns = fetch_transactions(config, &addresses).await?; let inbound_map = map_inbound_messages_onto_tr(&txns); @@ -1466,7 +1579,12 @@ async fn make_sequence_diagram( writeln!(output, "@startuml").unwrap(); for address in addresses { let (index, name) = &name_map[&address]; - writeln!(output, "participant \"[[{url_account_prefix}{} {}]]\" as {}", address, name, index).unwrap(); + writeln!( + output, + "participant \"[[{url_account_prefix}{} {}]]\" as {}", + address, name, index + ) + .unwrap(); } let mut last_own_index = None; @@ -1485,27 +1603,44 @@ async fn make_sequence_diagram( let in_msg = common_message.get_std().unwrap(); let msg_id = in_msg_cell.hash().to_hex_string(); let msg_name = msg_id.split_at(MESSAGE_WIDTH).0; - if let Some(src) = in_msg.src_ref() { // internal message + if let Some(src) = in_msg.src_ref() { + // internal message let src_address = src.to_string(); if let Some((src_index, _)) = name_map.get(&src_address) { // message from an inner account - writeln!(output, "{} ->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", - src_index, own_index, msg_id, msg_name, id, tr_name).unwrap(); + writeln!( + output, + "{} ->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", + src_index, own_index, msg_id, msg_name, id, tr_name + ) + .unwrap(); } else { // message from an out of the scope account - writeln!(output, "[->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", - own_index, msg_id, msg_name, id, tr_name).unwrap(); + writeln!( + output, + "[->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", + own_index, msg_id, msg_name, id, tr_name + ) + .unwrap(); } - } else { // external message + } else { + // external message assert!(in_msg.is_inbound_external()); - writeln!(output, "[o->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", - own_index, msg_id, msg_name, id, tr_name).unwrap(); + writeln!( + output, + "[o->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", + own_index, msg_id, msg_name, id, tr_name + ) + .unwrap(); } - } else if last_own_index == Some(own_index) { // rendered, adjacent, and active participant stays unchanged + } else if last_own_index == Some(own_index) { + // rendered, adjacent, and active participant stays unchanged writeln!(output, "{} [hidden]-> {}", own_index, own_index).unwrap(); } - let desc = tr.read_description().map_err(|e| format!("Failed to read tr desc: {}", e))?; + let desc = tr + .read_description() + .map_err(|e| format!("Failed to read tr desc: {}", e))?; let (tr_color, tr_gas) = match desc.compute_phase_ref() { None | Some(ever_block::TrComputePhase::Skipped(_)) => ("", None), Some(ever_block::TrComputePhase::Vm(tr_compute_phase_vm)) => { @@ -1525,21 +1660,26 @@ async fn make_sequence_diagram( let out_hash = out_msg.serialize().unwrap().repr_hash(); let out_id = out_hash.to_hex_string(); let out_name = out_id.split_at(MESSAGE_WIDTH).0; - if let Some(out_address) = out_msg.dst_ref() { // internal message + if let Some(out_address) = out_msg.dst_ref() { + // internal message let out_address = out_address.to_string(); if let Some((out_index, _)) = name_map.get(&out_address) { // message to an inner account if let Some(tr) = inbound_map.get(&out_hash) { // message spawns a known transaction - let tr_id = tr.serialize().unwrap().repr_hash().to_hex_string(); + let tr_id = tr.serialize().unwrap().repr_hash().to_hex_string(); let tr_name = tr_id.split_at(MESSAGE_WIDTH).0; writeln!(output, "{} ->> {} : m:[[{url_message_prefix}{} {}]]\\nt:[[{url_txn_prefix}{} {}]]", own_index, out_index, out_id, out_name, tr_id, tr_name).unwrap(); last_tr_id = Some(tr_id); } else { // transaction spawned by the message is out of the scope - writeln!(output, "{} ->> {} : m:[[{url_message_prefix}{} {}]]", - own_index, out_index, out_id, out_name).unwrap(); + writeln!( + output, + "{} ->> {} : m:[[{url_message_prefix}{} {}]]", + own_index, out_index, out_id, out_name + ) + .unwrap(); } } else { // message to an out of the scope account @@ -1547,9 +1687,15 @@ async fn make_sequence_diagram( own_index, out_id, out_name, out_address, out_address.split_at(ACCOUNT_WIDTH).0).unwrap(); } - } else { // external message + } else { + // external message assert!(out_msg.is_outbound_external()); - writeln!(output, "{} ->>o] : m:[[{url_message_prefix}{} {}]]", own_index, out_id, out_name).unwrap(); + writeln!( + output, + "{} ->>o] : m:[[{url_message_prefix}{} {}]]", + own_index, out_id, out_name + ) + .unwrap(); } rendered.insert(out_hash); } @@ -1605,7 +1751,7 @@ impl<'a> DebugParams<'a> { pub async fn debug_error(e: &ClientError, debug_params: DebugParams<'_>) -> Result<(), String> { let result = format!("{:#}", e); if e.code != SDK_EXECUTION_ERROR_CODE || !debug_params.check_debug() { - return Err(result) + return Err(result); } if debug_params.config.is_json { println!("{:#}", json!({"Error": e})); diff --git a/src/decode.rs b/src/decode.rs index 0f68b140..e1fa1cd4 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -10,13 +10,17 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use crate::{load_abi, print_args}; use crate::config::Config; use crate::decode::msg_printer::tree_of_cells_into_base64; -use crate::helpers::{decode_msg_body, print_account, create_client_local, create_client_verbose, query_account_field, abi_from_matches_or_config, load_ton_address, load_ton_abi, create_client, query_message}; -use clap::{ArgMatches, SubCommand, Arg, App, AppSettings}; -use ever_block::{Cell, SliceData, write_boc, read_single_root_boc}; -use ever_block::{Account, Deserializable, Serializable, AccountStatus, StateInit}; +use crate::helpers::{ + abi_from_matches_or_config, create_client, create_client_local, create_client_verbose, + decode_msg_body, load_ton_abi, load_ton_address, print_account, query_account_field, + query_message, +}; +use crate::{load_abi, print_args}; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; +use ever_block::{read_single_root_boc, write_boc, Cell, SliceData}; +use ever_block::{Account, AccountStatus, Deserializable, Serializable, StateInit}; use ever_client::abi::{decode_account_data, ParamsOfDecodeAccountData}; use serde::Serialize; use serde_json::json; @@ -25,17 +29,23 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> { let tvc_cmd = SubCommand::with_name("stateinit") .setting(AppSettings::AllowLeadingHyphen) .about("Decodes tvc data (including compiler version) from different sources.") - .arg(Arg::with_name("TVC") - .long("--tvc") - .conflicts_with("BOC") - .help("Contract is passed via path to the TVC file.")) - .arg(Arg::with_name("BOC") - .long("--boc") - .conflicts_with("TVC") - .help("Contract is passed via path to the account BOC file.")) - .arg(Arg::with_name("INPUT") - .required(true) - .help("Contract address or path to the file with contract data.")); + .arg( + Arg::with_name("TVC") + .long("--tvc") + .conflicts_with("BOC") + .help("Contract is passed via path to the TVC file."), + ) + .arg( + Arg::with_name("BOC") + .long("--boc") + .conflicts_with("TVC") + .help("Contract is passed via path to the account BOC file."), + ) + .arg( + Arg::with_name("INPUT") + .required(true) + .help("Contract address or path to the file with contract data."), + ); SubCommand::with_name("decode") .about("Decode commands.") .setting(AppSettings::AllowLeadingHyphen) @@ -151,7 +161,12 @@ async fn decode_account_from_boc(m: &ArgMatches<'_>, config: &Config) -> Result< print_account_data(&account, tvc_path, config, true).await } -pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, config: &Config, decode_stateinit: bool) -> Result<(), String> { +pub async fn print_account_data( + account: &Account, + tvc_path: Option<&str>, + config: &Config, + decode_stateinit: bool, +) -> Result<(), String> { if account.is_none() { if !config.is_json { println!("\nAccount is None"); @@ -181,29 +196,32 @@ pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, confi _ => "Undefined".to_owned(), }; - let trans_lt = account.last_tr_time() + let trans_lt = account + .last_tr_time() .map_or("Undefined".to_owned(), |v| format!("{:#x}", v)); let paid = format!("{}", account.last_paid()); let (si, code_hash) = match state_init { Some(state_init) => { - let code = state_init.code.clone() + let code = state_init + .code + .clone() .ok_or("failed to obtain code from the StateInit")?; let ton = create_client_local()?; ( serde_json::to_string_pretty( - &msg_printer::serialize_state_init(state_init, ton) - .await?) - .map_err(|e| format!("Failed to serialize stateInit: {}", e))?, - Some(code.repr_hash().to_hex_string()) + &msg_printer::serialize_state_init(state_init, ton).await?, + ) + .map_err(|e| format!("Failed to serialize stateInit: {}", e))?, + Some(code.repr_hash().to_hex_string()), ) - }, - _ => ("Undefined".to_owned(), None) + } + _ => ("Undefined".to_owned(), None), }; let data = tree_of_cells_into_base64(account.get_data().as_ref())?; - let data = hex::encode(base64::decode(data) - .map_err(|e| format!("Failed to decode base64: {}", e))?); + let data = + hex::encode(base64::decode(data).map_err(|e| format!("Failed to decode base64: {}", e))?); print_account( config, Some(state), @@ -217,7 +235,9 @@ pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, confi ); if tvc_path.is_some() && state_init.is_some() { - state_init.unwrap().write_to_file(tvc_path.unwrap()) + state_init + .unwrap() + .write_to_file(tvc_path.unwrap()) .map_err(|e| format!("{}", e))?; } @@ -231,7 +251,9 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( print_args!(msg, abi); } if m.is_present("BASE64") && !config.is_json { - println!("Flag --base64 is deprecated. Command can be used for base64 input without this flag.") + println!( + "Flag --base64 is deprecated. Command can be used for base64 input without this flag." + ) } let input = msg.unwrap(); let decoded_message = if std::path::Path::new(input).exists() { @@ -244,16 +266,16 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( .map_err(|_| format!("Failed to decode message from file: {e}"))?; let message_bytes = base64::decode(&message_str) .map_err(|e2| format!("Failed to decode message data: {e2}"))?; - decode_message(message_bytes, abi).await + decode_message(message_bytes, abi) + .await .map_err(|e2| format!("Failed to decode message from file: {e2}"))? } } } else { - let base64_decode = base64::decode(input) - .map_err(|e| format!("{e}")); + let base64_decode = base64::decode(input).map_err(|e| format!("{e}")); let msg_decode = match base64_decode { Ok(base64_decode) => decode_message(base64_decode, abi.clone()).await, - Err(e) => Err(e) + Err(e) => Err(e), }; match msg_decode { Ok(result) => result, @@ -263,7 +285,8 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( .map_err(|e2| format!("Failed to decode message, specify path to the file, message id or message in base64.\nBase64 error: {e}\nQuery error: {e2}"))?; let message_bytes = base64::decode(&query_boc) .map_err(|e2| format!("Failed to decode queried message: {e2}"))?; - decode_message(message_bytes, abi).await + decode_message(message_bytes, abi) + .await .map_err(|e2| format!("Failed to decode queried message: {e2}"))? } } @@ -286,11 +309,12 @@ async fn decode_tvc_fields(m: &ArgMatches<'_>, config: &Config) -> Result<(), St let res = decode_account_data( ton, ParamsOfDecodeAccountData { - abi, - data: b64, - ..Default::default() - } - ).map_err(|e| format!("failed to decode data: {}", e))?; + abi, + data: b64, + ..Default::default() + }, + ) + .map_err(|e| format!("failed to decode data: {}", e))?; if !config.is_json { println!("TVC fields:"); } @@ -313,11 +337,12 @@ async fn decode_account_fields(m: &ArgMatches<'_>, config: &Config) -> Result<() let res = decode_account_data( ton, ParamsOfDecodeAccountData { - abi, - data, - ..Default::default() - } - ).map_err(|e| format!("failed to decode data: {}", e))?; + abi, + data, + ..Default::default() + }, + ) + .map_err(|e| format!("failed to decode data: {}", e))?; if !config.is_json { println!("Account fields:"); } @@ -329,11 +354,16 @@ async fn decode_account_fields(m: &ArgMatches<'_>, config: &Config) -> Result<() struct SortedFunctionHeader { pubkey: Option, time: Option, - expire: Option + expire: Option, } -async fn decode_body(body_base64: &str, abi_path: &str, is_json: bool, config: &Config) -> Result<(), String> { - let body_vec = base64::decode(body_base64) +async fn decode_body( + body_base64: &str, + abi_path: &str, + is_json: bool, + config: &Config, +) -> Result<(), String> { + let body_vec = base64::decode(body_base64) .map_err(|e| format!("body is not a valid base64 string: {}", e))?; let empty_boc = write_boc(&Cell::default()) @@ -347,15 +377,18 @@ async fn decode_body(body_base64: &str, abi_path: &str, is_json: bool, config: & let (mut res, is_external) = { match decode_msg_body(ton.clone(), abi_path, body_base64, false, config).await { Ok(res) => (res, true), - Err(_) => (decode_msg_body(ton.clone(), abi_path, body_base64, true, config).await?, false), + Err(_) => ( + decode_msg_body(ton.clone(), abi_path, body_base64, true, config).await?, + false, + ), } }; let mut signature = None; - let cell = read_single_root_boc(body_vec) - .map_err(|e| format!("Failed to create cell: {}", e))?; - let orig_slice = SliceData::load_cell(cell) - .map_err(|e| format!("Failed to load cell: {}", e))?; + let cell = + read_single_root_boc(body_vec).map_err(|e| format!("Failed to create cell: {}", e))?; + let orig_slice = + SliceData::load_cell(cell).map_err(|e| format!("Failed to load cell: {}", e))?; if is_external { let mut slice = orig_slice.clone(); let flag = slice.get_next_bit(); @@ -368,15 +401,18 @@ async fn decode_body(body_base64: &str, abi_path: &str, is_json: bool, config: & } let contr = load_ton_abi(abi_path, config).await?; - let (_, func_id, _) = ever_abi::Function::decode_header(contr.version(), orig_slice.clone(), contr.header(), !is_external) - .map_err(|e| format!("Failed to decode header: {}", e))?; + let (_, func_id, _) = ever_abi::Function::decode_header( + contr.version(), + orig_slice.clone(), + contr.header(), + !is_external, + ) + .map_err(|e| format!("Failed to decode header: {}", e))?; let output = res.value.take().ok_or("failed to obtain the result")?; - let header = res.header.map(|hdr| { - SortedFunctionHeader { - pubkey: hdr.pubkey, - time: hdr.time, - expire: hdr.expire - } + let header = res.header.map(|hdr| SortedFunctionHeader { + pubkey: hdr.pubkey, + time: hdr.time, + expire: hdr.expire, }); if is_json { let mut result = json!({}); @@ -408,7 +444,10 @@ fn load_state_init(m: &ArgMatches<'_>) -> Result { let stat_init = if m.is_present("BOC") { let account = Account::construct_from_file(input) .map_err(|e| format!(" failed to load account from the boc file {}: {}", input, e))?; - account.state_init().ok_or("Failed to load stateInit from the BOC.")?.to_owned() + account + .state_init() + .ok_or("Failed to load stateInit from the BOC.")? + .to_owned() } else { StateInit::construct_from_file(input) .map_err(|e| format!("failed to load StateInit from the tvc file: {}", e))? @@ -440,27 +479,33 @@ async fn decode_tvc_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), S let boc = query_account_field(ton.clone(), &input, "boc").await?; let account = Account::construct_from_base64(&boc) .map_err(|e| format!("Failed to query account BOC: {}", e))?; - account.state_init().ok_or("Failed to load stateInit from the BOC.")?.to_owned() + account + .state_init() + .ok_or("Failed to load stateInit from the BOC.")? + .to_owned() }; if !config.is_json { println!("Decoded data:"); } let result = msg_printer::serialize_state_init(&state, ton.clone()).await?; - println!("{}", serde_json::to_string_pretty(&result) - .map_err(|e| format!("Failed to serialize json: {}", e))?); + println!( + "{}", + serde_json::to_string_pretty(&result) + .map_err(|e| format!("Failed to serialize json: {}", e))? + ); Ok(()) } pub mod msg_printer { - use serde_json::{Value, json}; - use ever_block::{CurrencyCollection, StateInit, Message, CommonMsgInfo, Grams}; + use crate::helpers::{create_client_local, decode_msg_body, TonClient}; + use crate::Config; use ever_block::write_boc; use ever_block::Cell; - use crate::helpers::{TonClient, create_client_local, decode_msg_body}; + use ever_block::{CommonMsgInfo, CurrencyCollection, Grams, Message, StateInit}; use ever_client::boc::{get_compiler_version, ParamsOfGetCompilerVersion}; - use crate::Config; + use serde_json::{json, Value}; pub fn tree_of_cells_into_base64(root_cell: Option<&Cell>) -> Result { match root_cell { @@ -469,17 +514,12 @@ pub mod msg_printer { .map_err(|e| format!("failed to serialize tree of cells: {}", e))?; Ok(base64::encode(bytes)) } - None => Ok("".to_string()) + None => Ok("".to_string()), } } async fn get_code_version(ton: TonClient, code: String) -> String { - let result = get_compiler_version( - ton, - ParamsOfGetCompilerVersion { - code, - } - ); + let result = get_compiler_version(ton, ParamsOfGetCompilerVersion { code }); if let Ok(result) = result { if let Some(version) = result.version { @@ -489,7 +529,7 @@ pub mod msg_printer { "Undefined".to_owned() } - pub async fn serialize_state_init (state: &StateInit, ton: TonClient) -> Result { + pub async fn serialize_state_init(state: &StateInit, ton: TonClient) -> Result { let code = tree_of_cells_into_base64(state.code.as_ref())?; Ok(json!({ "split_depth" : state.split_depth.as_ref().map(|x| format!("{:?}", (x.as_u32()))).unwrap_or("None".to_string()), @@ -506,11 +546,15 @@ pub mod msg_printer { } fn serialize_msg_type(header: &CommonMsgInfo) -> Value { - json!(match header { - CommonMsgInfo::IntMsgInfo(_) => "internal", - CommonMsgInfo::ExtInMsgInfo(_) => "external inbound", - CommonMsgInfo::ExtOutMsgInfo(_) => "external outbound", - }.to_owned() + " message") + json!( + match header { + CommonMsgInfo::IntMsgInfo(_) => "internal", + CommonMsgInfo::ExtInMsgInfo(_) => "external inbound", + CommonMsgInfo::ExtOutMsgInfo(_) => "external outbound", + } + .to_owned() + + " message" + ) } fn serialize_grams(grams: &Grams) -> Value { @@ -523,10 +567,12 @@ pub mod msg_printer { return grams; } let mut other = json!({}); - cc.other.iterate_with_keys(|key: u32, value| { - other[key.to_string()] = json!(value.to_string()); - Ok(true) - }).ok(); + cc.other + .iterate_with_keys(|key: u32, value| { + other[key.to_string()] = json!(value.to_string()); + Ok(true) + }) + .ok(); json!({ "value" : grams, "other" : other, @@ -548,14 +594,14 @@ pub mod msg_printer { "created_lt" : &header.created_lt.to_string(), "created_at" : &header.created_at.to_string(), }) - }, + } CommonMsgInfo::ExtInMsgInfo(header) => { json!({ "source" : &header.src.to_string(), "destination" : &header.dst.to_string(), "import_fee" : &serialize_grams(&header.import_fee), }) - }, + } CommonMsgInfo::ExtOutMsgInfo(header) => { json!({ "source" : &header.src.to_string(), @@ -567,7 +613,12 @@ pub mod msg_printer { } } - pub async fn serialize_body(body_vec: Vec, abi_path: &str, ton: TonClient, config: &Config) -> Result { + pub async fn serialize_body( + body_vec: Vec, + abi_path: &str, + ton: TonClient, + config: &Config, + ) -> Result { let empty_boc = write_boc(&Cell::default()) .map_err(|e| format!("failed to serialize tree of cells: {}", e))?; if body_vec.cmp(&empty_boc) == std::cmp::Ordering::Equal { @@ -577,7 +628,9 @@ pub mod msg_printer { let mut res = { match decode_msg_body(ton.clone(), abi_path, &body_base64, false, config).await { Ok(res) => res, - Err(_) => decode_msg_body(ton.clone(), abi_path, &body_base64, true, config).await?, + Err(_) => { + decode_msg_body(ton.clone(), abi_path, &body_base64, true, config).await? + } } }; let output = res.value.take().ok_or("failed to obtain the result")?; @@ -594,8 +647,12 @@ pub mod msg_printer { Ok(decoded) } - pub async fn serialize_msg(msg: &Message, abi_path: Option, config: &Config) -> Result { - let mut res = json!({ }); + pub async fn serialize_msg( + msg: &Message, + abi_path: Option, + config: &Config, + ) -> Result { + let mut res = json!({}); let ton = create_client_local()?; res["Type"] = serialize_msg_type(msg.header()); res["Header"] = serialize_msg_header(msg.header()); @@ -609,7 +666,7 @@ pub mod msg_printer { let abi_path = abi_path.unwrap(); let body_vec = write_boc(&msg.body().unwrap().into_cell()) .map_err(|e| format!("failed to serialize body: {}", e))?; - res["BodyCall"] = match serialize_body(body_vec, &abi_path, ton, config).await { + res["BodyCall"] = match serialize_body(body_vec, &abi_path, ton, config).await { Ok(res) => res, Err(_) => { json!("Undefined") @@ -620,7 +677,6 @@ pub mod msg_printer { } } - #[cfg(test)] mod tests { use super::*; @@ -628,14 +684,18 @@ mod tests { #[tokio::test] async fn test_decode_msg_json() { let msg_boc = std::fs::read("tests/samples/wallet.boc").unwrap(); - let out = decode_message(msg_boc, Some("tests/samples/wallet.abi.json".to_owned())).await.unwrap(); - let _ : serde_json::Value = serde_json::from_str(&out).unwrap(); + let out = decode_message(msg_boc, Some("tests/samples/wallet.abi.json".to_owned())) + .await + .unwrap(); + let _: serde_json::Value = serde_json::from_str(&out).unwrap(); } #[tokio::test] async fn test_decode_body_json() { let body = "te6ccgEBAQEARAAAgwAAALqUCTqWL8OX7JivfJrAAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMQAAAAAAAAAAAAAAAEeGjADA=="; let config = Config::default(); - decode_body(body, "tests/samples/wallet.abi.json", true, &config).await.unwrap(); + decode_body(body, "tests/samples/wallet.abi.json", true, &config) + .await + .unwrap(); } } diff --git a/src/deploy.rs b/src/deploy.rs index 683ed1d8..80a1ceb1 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -10,20 +10,16 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use crate::helpers::{create_client_verbose, create_client_with_signature_id, load_abi, now_ms}; +use crate::call::{emulate_locally, process_message, send_message_and_wait}; use crate::config::FullConfig; use crate::crypto::load_keypair; -use crate::call::{ - emulate_locally, - process_message, - send_message_and_wait, -}; +use crate::helpers::{create_client_verbose, create_client_with_signature_id, load_abi, now_ms}; +use crate::message::{display_generated_message, EncodedMessage}; +use crate::{Config, SignatureIDType}; use ever_client::abi::{ - encode_message, Signer, CallSet, DeploySet, ParamsOfEncodeMessage, Abi, FunctionHeader, + encode_message, Abi, CallSet, DeploySet, FunctionHeader, ParamsOfEncodeMessage, Signer, }; use ever_client::crypto::KeyPair; -use crate::{Config, SignatureIDType}; -use crate::message::{display_generated_message, EncodedMessage}; pub async fn deploy_contract( full_config: &mut FullConfig, @@ -43,9 +39,20 @@ pub async fn deploy_contract( println!("Deploying..."); } - let (msg, addr) = prepare_deploy_message(tvc, abi, params, keys_file.clone(), wc, &full_config.config, None, method).await?; + let (msg, addr) = prepare_deploy_message( + tvc, + abi, + params, + keys_file.clone(), + wc, + &full_config.config, + None, + method, + ) + .await?; - let enc_msg = encode_message(ton.clone(), msg.clone()).await + let enc_msg = encode_message(ton.clone(), msg.clone()) + .await .map_err(|e| format!("failed to create inbound message: {}", e))?; if config.local_run || is_fee { @@ -57,12 +64,10 @@ pub async fn deploy_contract( if config.async_call { let abi = load_abi(abi, config).await?; - send_message_and_wait(ton, - Some(abi), - enc_msg.message, - config).await?; + send_message_and_wait(ton, Some(abi), enc_msg.message, config).await?; } else { - process_message(ton.clone(), msg, config).await + process_message(ton.clone(), msg, config) + .await .map_err(|e| format!("{:#}", e))?; } @@ -94,9 +99,19 @@ pub async fn generate_deploy_message( ) -> Result<(), String> { let (client, signature_id) = create_client_with_signature_id(config, signature_id)?; - let (msg, addr) = prepare_deploy_message(tvc, abi, params, keys_file, - wc, config, signature_id, method.clone()).await?; - let msg = encode_message(client, msg).await + let (msg, addr) = prepare_deploy_message( + tvc, + abi, + params, + keys_file, + wc, + config, + signature_id, + method.clone(), + ) + .await?; + let msg = encode_message(client, msg) + .await .map_err(|e| format!("failed to create inbound message: {}", e))?; let msg = EncodedMessage { @@ -127,8 +142,8 @@ pub async fn prepare_deploy_message( let keys = keys_file.map(|k| load_keypair(&k)).transpose()?; - let tvc_bytes = std::fs::read(tvc) - .map_err(|e| format!("failed to read smart contract file {tvc}: {e}"))?; + let tvc_bytes = + std::fs::read(tvc).map_err(|e| format!("failed to read smart contract file {tvc}: {e}"))?; prepare_deploy_message_params( &tvc_bytes, @@ -138,8 +153,9 @@ pub async fn prepare_deploy_message( params, keys, wc, - signature_id - ).await + signature_id, + ) + .await } pub async fn prepare_deploy_message_params( @@ -161,8 +177,9 @@ pub async fn prepare_deploy_message_params( wc, keys.as_ref().map(|k| k.public.clone()), None, - abi.clone() - ).await? + abi.clone(), + ) + .await? } else { let tvc_cell = ever_block::boc::read_single_root_boc(tvc_bytes).unwrap(); let tvc_hash = tvc_cell.repr_hash(); @@ -190,13 +207,16 @@ pub async fn prepare_deploy_message_params( } else { Signer::None }; - Ok((ParamsOfEncodeMessage { - abi, - address: Some(address.clone()), - deploy_set, - call_set, - signer, - signature_id, - ..Default::default() - }, address)) + Ok(( + ParamsOfEncodeMessage { + abi, + address: Some(address.clone()), + deploy_set, + call_set, + signer, + signature_id, + ..Default::default() + }, + address, + )) } diff --git a/src/depool.rs b/src/depool.rs index 1ab71442..cb6bb145 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -11,27 +11,21 @@ * limitations under the License. */ use crate::config::Config; -use crate::{convert, print_args}; use crate::depool_abi::{DEPOOL_ABI, PARTICIPANT_ABI}; use crate::helpers::{ - create_client, - create_client_local, - create_client_verbose, - load_abi, - load_ton_address, - now, - TonClient, - answer_filter, - events_filter, - print_message, + answer_filter, create_client, create_client_local, create_client_verbose, events_filter, + load_abi, load_ton_address, now, print_message, TonClient, }; -use crate::multisig::{MultisigArgs, CallArgs}; -use clap::{App, ArgMatches, SubCommand, Arg, AppSettings}; +use crate::multisig::{CallArgs, MultisigArgs}; +use crate::{convert, print_args}; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use serde_json::json; -use ever_client::abi::{ParamsOfEncodeMessageBody, CallSet, ParamsOfDecodeMessageBody}; -use ever_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection}; use crate::call; +use ever_client::abi::{CallSet, ParamsOfDecodeMessageBody, ParamsOfEncodeMessageBody}; +use ever_client::net::{ + OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection, +}; +use serde_json::json; use std::collections::HashMap; pub fn create_depool_command<'a, 'b>() -> App<'a, 'b> { @@ -220,7 +214,7 @@ pub fn create_depool_command<'a, 'b>() -> App<'a, 'b> { /// /// Depool command -/// +/// /// Stores parameters for request from wallet to depool struct DepoolCmd<'a> { /// Reference to command line arguments @@ -242,26 +236,36 @@ impl<'a> DepoolCmd<'a> { pub async fn stake_ordinary( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { let mut value = parse_value(m)?; let body = encode_add_ordinary_stake(value).await?; value += Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn stake_vesting( m: &'a ArgMatches<'_>, config: &'a Config, depool: &'a str, - with_lock: bool + with_lock: bool, ) -> Result, String> { let mut value = parse_value(m)?; - let withdrawal_period = m.value_of("WPERIOD") + let withdrawal_period = m + .value_of("WPERIOD") .ok_or("withdrawal period is not defined.".to_string())?; - let total_period = m.value_of("TPERIOD") + let total_period = m + .value_of("TPERIOD") .ok_or("total period is not defined.".to_string())?; - let beneficiary = m.value_of("BENEFICIARY") + let beneficiary = m + .value_of("BENEFICIARY") .ok_or("beneficiary is not defined.".to_string())?; let beneficiary = load_ton_address(beneficiary, config)?; @@ -287,43 +291,72 @@ impl<'a> DepoolCmd<'a> { encode_add_vesting_stake(value, &beneficiary, tp, wp).await? }; value += Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn stake_remove( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { let stake = parse_value(m)?; let body = encode_remove_stake(stake).await?; let value = Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn stake_withdraw_part( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { let stake = parse_value(m)?; let body = encode_withdraw_stake(stake).await?; let value = Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn stake_transfer( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { - let dest = m.value_of("DEST") + let dest = m + .value_of("DEST") .ok_or("destination address is not defined.".to_owned())?; let dest = load_ton_address(dest, config)?; let stake = parse_value(m)?; let body = encode_transfer_stake(&dest, stake).await?; let value = Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn donor( @@ -332,11 +365,19 @@ impl<'a> DepoolCmd<'a> { depool: &'a str, for_vesting: bool, ) -> Result, String> { - let donor = m.value_of("DONOR") + let donor = m + .value_of("DONOR") .ok_or("donor is not defined.".to_string())?; let body = encode_set_donor(for_vesting, donor).await?; let value = Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn withdraw( @@ -347,34 +388,57 @@ impl<'a> DepoolCmd<'a> { ) -> Result, String> { let body = encode_set_withdraw(enable).await?; let value = Self::depool_fee(config)?; - Ok(Self {m, depool, value, body, config, with_answer: true}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: true, + }) } pub async fn replenish( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { let value = parse_value(m)?; let body = encode_replenish_stake().await?; - Ok(Self {m, depool, value, body, config, with_answer: false}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: false, + }) } pub async fn ticktock( m: &'a ArgMatches<'_>, config: &'a Config, - depool: &'a str + depool: &'a str, ) -> Result, String> { let value = 1000000000; let body = encode_ticktock().await?; - Ok(Self {m, depool, value, body, config, with_answer: false}) + Ok(Self { + m, + depool, + value, + body, + config, + with_answer: false, + }) } pub async fn execute(mut self) -> Result<(), String> { let body = std::mem::take(&mut self.body); - let call_args = CallArgs::submit_with_args(self.m, self.depool, &format!("{}", self.value), true, body).await?; + let call_args = + CallArgs::submit_with_args(self.m, self.depool, &format!("{}", self.value), true, body) + .await?; let msig_args = MultisigArgs::new(self.m, self.config, call_args)?; - + let since = now(); let depool = self.depool.to_owned(); let wallet = msig_args.address().to_owned(); @@ -397,7 +461,9 @@ impl<'a> DepoolCmd<'a> { result: "id body created_at created_at_string".to_owned(), timeout: Some(self.config.timeout), }, - ).await.map_err(|e| println!("failed to query message: {}", e)); + ) + .await + .map_err(|e| println!("failed to query message: {}", e)); if message.is_err() { println!("Request failed. Check the contract balance to be great enough to cover transfer value with possible fees."); @@ -438,19 +504,24 @@ impl<'a> DepoolCmd<'a> { result: "id body created_at created_at_string value".to_owned(), timeout: Some(self.config.timeout), }, - ).await.map_err(|e| println!("failed to query answer: {}", e)); + ) + .await + .map_err(|e| println!("failed to query answer: {}", e)); if message.is_ok() { let message = message.unwrap().result; println!("\nAnswer: "); - let (name, args) = print_message(client.clone(), &message, PARTICIPANT_ABI, true).await?; + let (name, args) = + print_message(client.clone(), &message, PARTICIPANT_ABI, true).await?; if name == "receiveAnswer" { let args: serde_json::Value = serde_json::from_str(&args) .map_err(|e| format!("failed to deserialize args: {}", e))?; - let status = args["errcode"].as_str() + let status = args["errcode"] + .as_str() .ok_or("failed to serialize the error code")? .parse::() .map_err(|e| format!("failed to parse the error code: {}", e))?; - let comment = args["comment"].as_str() + let comment = args["comment"] + .as_str() .ok_or("failed to serialize the comment")?; if statuses.contains_key(&status) { println!("Answer status: {}\nComment: {}", statuses[&status], comment); @@ -474,8 +545,9 @@ impl<'a> DepoolCmd<'a> { } } -fn parse_value(m: &ArgMatches<'_>) -> Result { - let amount = m.value_of("VALUE") +fn parse_value(m: &ArgMatches<'_>) -> Result { + let amount = m + .value_of("VALUE") .ok_or("value is not defined.".to_string())?; let amount = u64::from_str_radix(&convert::convert_token(amount)?, 10) .map_err(|e| format!(r#"failed to parse stake value: {}"#, e))?; @@ -483,12 +555,16 @@ fn parse_value(m: &ArgMatches<'_>) -> Result { } pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<(), String> { - let depool = m.value_of("ADDRESS") + let depool = m + .value_of("ADDRESS") .map(|s| s.to_owned()) .or(config.addr.clone()) - .ok_or("depool address is not defined. Supply it in the config file or in command line.".to_string())?; - let depool = load_ton_address(&depool, config) - .map_err(|e| format!("invalid depool address: {}", e))?; + .ok_or( + "depool address is not defined. Supply it in the config file or in command line." + .to_string(), + )?; + let depool = + load_ton_address(&depool, config).map_err(|e| format!("invalid depool address: {}", e))?; let mut set_wait_answer = |m: &ArgMatches| { if m.is_present("WAIT_ANSWER") { @@ -497,80 +573,112 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( }; set_wait_answer(m); if let Some(m) = m.subcommand_matches("donor") { - let matches = m.subcommand_matches("vesting").or(m.subcommand_matches("lock")); + let matches = m + .subcommand_matches("vesting") + .or(m.subcommand_matches("lock")); if let Some(matches) = matches { let is_vesting = m.subcommand_matches("vesting").is_some(); set_wait_answer(matches); - return DepoolCmd::donor(matches, config, &depool, is_vesting).await?.execute().await; + return DepoolCmd::donor(matches, config, &depool, is_vesting) + .await? + .execute() + .await; } } if let Some(m) = m.subcommand_matches("stake") { if let Some(m) = m.subcommand_matches("ordinary") { set_wait_answer(m); - return DepoolCmd::stake_ordinary(m, config, &depool).await?.execute().await; + return DepoolCmd::stake_ordinary(m, config, &depool) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("vesting") { set_wait_answer(m); - return DepoolCmd::stake_vesting(m, config, &depool, false).await?.execute().await; + return DepoolCmd::stake_vesting(m, config, &depool, false) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("lock") { set_wait_answer(m); - return DepoolCmd::stake_vesting(m, config, &depool, true).await?.execute().await; + return DepoolCmd::stake_vesting(m, config, &depool, true) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("remove") { set_wait_answer(m); - return DepoolCmd::stake_remove(m, config, &depool).await?.execute().await; + return DepoolCmd::stake_remove(m, config, &depool) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("withdrawPart") { set_wait_answer(m); - return DepoolCmd::stake_withdraw_part(m, config, &depool).await?.execute().await; + return DepoolCmd::stake_withdraw_part(m, config, &depool) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("transfer") { set_wait_answer(m); - return DepoolCmd::stake_transfer(m, config, &depool).await?.execute().await; + return DepoolCmd::stake_transfer(m, config, &depool) + .await? + .execute() + .await; } } if let Some(m) = m.subcommand_matches("withdraw") { - let matches = m.subcommand_matches("on") - .or(m.subcommand_matches("off")); + let matches = m.subcommand_matches("on").or(m.subcommand_matches("off")); let enable_withdraw = m.subcommand_matches("on").is_some(); if let Some(m) = matches { set_wait_answer(m); - return DepoolCmd::withdraw(m, config, &depool, enable_withdraw).await?.execute().await; + return DepoolCmd::withdraw(m, config, &depool, enable_withdraw) + .await? + .execute() + .await; } } if let Some(m) = m.subcommand_matches("events") { - return events_command(m, config, &depool).await + return events_command(m, config, &depool).await; } if let Some(m) = m.subcommand_matches("answers") { - return answer_command(m, config, &depool).await + return answer_command(m, config, &depool).await; } if let Some(m) = m.subcommand_matches("replenish") { - return DepoolCmd::replenish(m, config, &depool).await?.execute().await; + return DepoolCmd::replenish(m, config, &depool) + .await? + .execute() + .await; } if let Some(m) = m.subcommand_matches("ticktock") { - return DepoolCmd::ticktock(m, config, &depool).await?.execute().await; + return DepoolCmd::ticktock(m, config, &depool) + .await? + .execute() + .await; } Err("unknown depool command".to_owned()) } async fn answer_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Result<(), String> { - let wallet = m.value_of("MSIG") + let wallet = m + .value_of("MSIG") .map(|s| s.to_string()) .or(config.wallet.clone()) .ok_or("multisig wallet address is not defined.".to_string())?; - let since = m.value_of("SINCE") + let since = m + .value_of("SINCE") .map(|s| { - u32::from_str_radix(s, 10) - .map_err(|e| format!(r#"cannot parse "since" option: {}"#, e)) + u32::from_str_radix(s, 10).map_err(|e| format!(r#"cannot parse "since" option: {}"#, e)) }) .transpose()? .unwrap_or(0); let ton = create_client_verbose(config)?; - let wallet = load_ton_address(&wallet, config) - .map_err(|e| format!("invalid depool address: {}", e))?; + let wallet = + load_ton_address(&wallet, config).map_err(|e| format!("invalid depool address: {}", e))?; let messages = ever_client::net::query_collection( ton.clone(), @@ -578,10 +686,15 @@ async fn answer_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Re collection: "messages".to_owned(), filter: Some(answer_filter(depool, &wallet, since)), result: "id value body created_at created_at_string".to_owned(), - order: Some(vec![OrderBy{ path: "created_at".to_owned(), direction: SortDirection::DESC }]), + order: Some(vec![OrderBy { + path: "created_at".to_owned(), + direction: SortDirection::DESC, + }]), ..Default::default() }, - ).await.map_err(|e| format!("failed to query depool messages: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query depool messages: {}", e))?; println!("{} answers found", messages.result.len()); for messages in &messages.result { print_answer(ton.clone(), messages).await?; @@ -590,7 +703,7 @@ async fn answer_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Re Ok(()) } -async fn print_answer(ton: TonClient, message: &serde_json::Value) -> Result <(), String> { +async fn print_answer(ton: TonClient, message: &serde_json::Value) -> Result<(), String> { println!("Answer:"); print_message(ton, message, PARTICIPANT_ABI, true).await?; Ok(()) @@ -606,7 +719,8 @@ async fn events_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Re let depool = Some(depool); print_args!(depool, since); if !wait_for { - let since = since.map(|s| { + let since = since + .map(|s| { u32::from_str_radix(s, 10) .map_err(|e| format!(r#"cannot parse "since" option: {}"#, e)) }) @@ -619,16 +733,21 @@ async fn events_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Re } async fn print_event(ton: TonClient, event: &serde_json::Value) -> Result<(), String> { - println!("event {}", event["id"].as_str() - .ok_or("failed to serialize event id")?); + println!( + "event {}", + event["id"].as_str().ok_or("failed to serialize event id")? + ); - let body = event["body"].as_str() + let body = event["body"] + .as_str() .ok_or("failed to serialize event body")?; let def_config = Config::default(); let result = ever_client::abi::decode_message_body( ton.clone(), ParamsOfDecodeMessageBody { - abi: load_abi(DEPOOL_ABI, &def_config).await.map_err(|e| format!("failed to load depool abi: {}", e))?, + abi: load_abi(DEPOOL_ABI, &def_config) + .await + .map_err(|e| format!("failed to load depool abi: {}", e))?, body: body.to_owned(), is_internal: false, ..Default::default() @@ -638,14 +757,22 @@ async fn print_event(ton: TonClient, event: &serde_json::Value) -> Result<(), St ("unknown".to_owned(), "{}".to_owned()) } else { let result = result.unwrap(); - (result.name, serde_json::to_string(&result.value) - .map_err(|e| format!("failed to serialize the result: {}", e))?) + ( + result.name, + serde_json::to_string(&result.value) + .map_err(|e| format!("failed to serialize the result: {}", e))?, + ) }; - println!("{} {} ({})\n{}\n", + println!( + "{} {} ({})\n{}\n", name, - event["created_at"].as_u64().ok_or("failed to serialize event field")?, - event["created_at_string"].as_str().ok_or("failed to serialize event field")?, + event["created_at"] + .as_u64() + .ok_or("failed to serialize event field")?, + event["created_at_string"] + .as_str() + .ok_or("failed to serialize event field")?, args ); Ok(()) @@ -661,10 +788,15 @@ async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), Str collection: "messages".to_owned(), filter: Some(events_filter(depool, since)), result: "id body created_at created_at_string".to_owned(), - order: Some(vec![OrderBy{ path: "created_at".to_owned(), direction: SortDirection::DESC }]), + order: Some(vec![OrderBy { + path: "created_at".to_owned(), + direction: SortDirection::DESC, + }]), ..Default::default() }, - ).await.map_err(|e| format!("failed to query depool events: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query depool events: {}", e))?; println!("{} events found", events.result.len()); for event in &events.result { print_event(ton.clone(), event).await?; @@ -685,8 +817,9 @@ async fn wait_for_event(config: &Config, depool: &str) -> Result<(), String> { result: "id body created_at created_at_string".to_owned(), timeout: Some(config.timeout), }, - - ).await.map_err(|e| println!("failed to query event: {}", e)); + ) + .await + .map_err(|e| println!("failed to query event: {}", e)); if event.is_ok() { print_event(ton.clone(), &event.unwrap().result).await?; } @@ -705,7 +838,8 @@ async fn encode_body(func: &str, params: serde_json::Value) -> Result Result { encode_body("withdrawAll", json!({})) } else { encode_body("cancelWithdrawal", json!({})) - }.await + } + .await } async fn encode_add_ordinary_stake(stake: u64) -> Result { - encode_body("addOrdinaryStake", json!({ - "stake": stake - })).await + encode_body( + "addOrdinaryStake", + json!({ + "stake": stake + }), + ) + .await } async fn encode_replenish_stake() -> Result { - encode_body("receiveFunds", json!({})).await + encode_body("receiveFunds", json!({})).await } async fn encode_ticktock() -> Result { - encode_body("ticktock", json!({})).await + encode_body("ticktock", json!({})).await } async fn encode_add_vesting_stake( @@ -738,24 +877,35 @@ async fn encode_add_vesting_stake( tperiod: u32, wperiod: u32, ) -> Result { - encode_body("addVestingStake", json!({ - "stake": stake, - "beneficiary": beneficiary, - "withdrawalPeriod": wperiod, - "totalPeriod": tperiod - })).await + encode_body( + "addVestingStake", + json!({ + "stake": stake, + "beneficiary": beneficiary, + "withdrawalPeriod": wperiod, + "totalPeriod": tperiod + }), + ) + .await } async fn encode_set_donor(is_vesting: bool, donor: &str) -> Result { if is_vesting { - encode_body("setVestingDonor", json!({ - "donor": donor - })) + encode_body( + "setVestingDonor", + json!({ + "donor": donor + }), + ) } else { - encode_body("setLockDonor", json!({ - "donor": donor - })) - }.await + encode_body( + "setLockDonor", + json!({ + "donor": donor + }), + ) + } + .await } async fn encode_add_lock_stake( @@ -764,29 +914,45 @@ async fn encode_add_lock_stake( tperiod: u32, wperiod: u32, ) -> Result { - encode_body("addLockStake", json!({ - "stake": stake, - "beneficiary": beneficiary, - "withdrawalPeriod": wperiod, - "totalPeriod": tperiod - })).await + encode_body( + "addLockStake", + json!({ + "stake": stake, + "beneficiary": beneficiary, + "withdrawalPeriod": wperiod, + "totalPeriod": tperiod + }), + ) + .await } async fn encode_remove_stake(target_value: u64) -> Result { - encode_body("withdrawFromPoolingRound", json!({ - "withdrawValue": target_value - })).await + encode_body( + "withdrawFromPoolingRound", + json!({ + "withdrawValue": target_value + }), + ) + .await } async fn encode_withdraw_stake(target_value: u64) -> Result { - encode_body("withdrawPart", json!({ - "withdrawValue": target_value - })).await + encode_body( + "withdrawPart", + json!({ + "withdrawValue": target_value + }), + ) + .await } async fn encode_transfer_stake(dest: &str, amount: u64) -> Result { - encode_body("transferStake", json!({ - "dest": dest, - "amount": amount - })).await -} \ No newline at end of file + encode_body( + "transferStake", + json!({ + "dest": dest, + "amount": amount + }), + ) + .await +} diff --git a/src/depool_abi.rs b/src/depool_abi.rs index 3226d898..eb739e36 100644 --- a/src/depool_abi.rs +++ b/src/depool_abi.rs @@ -419,4 +419,4 @@ pub const DEPOOL_ABI: &str = r#" } ] } -"#; \ No newline at end of file +"#; diff --git a/src/genaddr.rs b/src/genaddr.rs index 0c6f8cbd..146ae9a0 100644 --- a/src/genaddr.rs +++ b/src/genaddr.rs @@ -11,11 +11,11 @@ * limitations under the License. */ use crate::config::Config; -use crate::helpers::{create_client_local, read_keys, load_abi, calc_acc_address, load_abi_str}; +use crate::crypto::{gen_seed_phrase, generate_keypair_from_mnemonic}; +use crate::helpers::{calc_acc_address, create_client_local, load_abi, load_abi_str, read_keys}; +use ever_client::utils::{convert_address, AddressStringFormat, ParamsOfConvertAddress}; use serde_json::json; use std::fs::OpenOptions; -use crate::crypto::{gen_seed_phrase, generate_keypair_from_mnemonic}; -use ever_client::utils::{convert_address, ParamsOfConvertAddress, AddressStringFormat}; pub async fn generate_address( config: &Config, @@ -27,8 +27,8 @@ pub async fn generate_address( initial_data: Option<&str>, update_tvc: bool, ) -> Result<(), String> { - let contract = std::fs::read(tvc) - .map_err(|e| format!("failed to read smart contract file: {}", e))?; + let contract = + std::fs::read(tvc).map_err(|e| format!("failed to read smart contract file: {}", e))?; let abi = load_abi(abi_path, config).await?; if !abi.abi().unwrap().data_map_supported() && !update_tvc { @@ -37,9 +37,8 @@ pub async fn generate_address( let phrase = if new_keys { gen_seed_phrase()? - } else if keys_file.is_some() && - keys_file.unwrap().find(' ').is_some() && !new_keys { - keys_file.unwrap().to_owned() + } else if keys_file.is_some() && keys_file.unwrap().find(' ').is_some() && !new_keys { + keys_file.unwrap().to_owned() } else { "".to_owned() }; @@ -52,8 +51,8 @@ pub async fn generate_address( None }; - - let wc = wc_str.map(|wc| i32::from_str_radix(wc, 10)) + let wc = wc_str + .map(|wc| i32::from_str_radix(wc, 10)) .transpose() .map_err(|e| format!("failed to parse workchain id: {}", e))? .unwrap_or(config.wc); @@ -63,16 +62,15 @@ pub async fn generate_address( wc, keys.as_ref().map(|v| v.public.clone()), initial_data, - abi.clone() - ).await?; + abi.clone(), + ) + .await?; if update_tvc { let initial_data = initial_data.map(|s| s.to_string()); let key_bytes = match keys.as_ref() { - Some(keys) => { - hex::decode(&keys.public) - .map_err(|e| format!("failed to decode public key: {}", e))? - } + Some(keys) => hex::decode(&keys.public) + .map_err(|e| format!("failed to decode public key: {}", e))?, _ => { vec![0; 32] } @@ -98,11 +96,23 @@ pub async fn generate_address( } println!("Raw address: {}", addr); println!("testnet:"); - println!("Non-bounceable address (for init): {}", calc_userfriendly_address(&addr, false, true)?); - println!("Bounceable address (for later access): {}", calc_userfriendly_address(&addr, true, true)?); + println!( + "Non-bounceable address (for init): {}", + calc_userfriendly_address(&addr, false, true)? + ); + println!( + "Bounceable address (for later access): {}", + calc_userfriendly_address(&addr, true, true)? + ); println!("mainnet:"); - println!("Non-bounceable address (for init): {}", calc_userfriendly_address(&addr, false, false)?); - println!("Bounceable address (for later access): {}", calc_userfriendly_address(&addr, true, false)?); + println!( + "Non-bounceable address (for init): {}", + calc_userfriendly_address(&addr, false, false)? + ); + println!( + "Bounceable address (for later access): {}", + calc_userfriendly_address(&addr, true, false)? + ); println!("Succeeded"); } else { @@ -129,26 +139,40 @@ fn calc_userfriendly_address(address: &str, bounce: bool, test: bool) -> Result< create_client_local()?, ParamsOfConvertAddress { address: address.to_owned(), - output_format: AddressStringFormat::Base64{ url: true, bounce, test }, - } + output_format: AddressStringFormat::Base64 { + url: true, + bounce, + test, + }, + }, ) .map(|r| r.address) .map_err(|e| format!("failed to convert address to base64 form: {}", e)) } -fn update_contract_state(tvc_file: &str, pubkey: &[u8], data: Option, abi: &str) -> Result<(), String> { - use std::io::{Seek, Write}; +fn update_contract_state( + tvc_file: &str, + pubkey: &[u8], + data: Option, + abi: &str, +) -> Result<(), String> { use ever_abi::Contract; use ever_sdk::ContractImage; + use std::io::{Seek, Write}; - let data_map_supported : bool = (Contract::load(abi.as_bytes()) - .map_err(|e| format!("unable to load abi: {}", e))?).data_map_supported(); + let data_map_supported: bool = (Contract::load(abi.as_bytes()) + .map_err(|e| format!("unable to load abi: {}", e))?) + .data_map_supported(); - let mut state_init = OpenOptions::new().read(true).write(true).open(tvc_file) + let mut state_init = OpenOptions::new() + .read(true) + .write(true) + .open(tvc_file) .map_err(|e| format!("unable to open contract file: {}", e))?; let mut contract_image = if data_map_supported { - let pubkey_object = pubkey.try_into() + let pubkey_object = pubkey + .try_into() .map_err(|e| format!("unable to load public key: {}", e))?; ContractImage::from_state_init_and_key(&mut state_init, &pubkey_object) .map_err(|e| format!("unable to load contract image with key: {}", e))? @@ -159,7 +183,8 @@ fn update_contract_state(tvc_file: &str, pubkey: &[u8], data: Option, ab if data_map_supported { if data.is_some() { - contract_image.update_data(true, &data.unwrap(), abi) + contract_image + .update_data(true, &data.unwrap(), abi) .map_err(|e| format!("unable to update contract image data: {}", e))?; } } else { @@ -168,21 +193,22 @@ fn update_contract_state(tvc_file: &str, pubkey: &[u8], data: Option, ab } else { Some(hex::encode(pubkey)) }; - let js_init_data = crate::helpers::insert_pubkey_to_init_data( - pk, - data.as_deref() - )?; - contract_image.update_data(false, js_init_data.as_str(), abi) + let js_init_data = crate::helpers::insert_pubkey_to_init_data(pk, data.as_deref())?; + contract_image + .update_data(false, js_init_data.as_str(), abi) .map_err(|e| format!("unable to update contract image data: {}", e))?; } - let vec_bytes = contract_image.serialize() + let vec_bytes = contract_image + .serialize() .map_err(|e| format!("unable to serialize contract image: {}", e))?; - state_init.seek(std::io::SeekFrom::Start(0)) + state_init + .seek(std::io::SeekFrom::Start(0)) .map_err(|e| format!("failed to access the tvc file: {}", e))?; - state_init.write_all(&vec_bytes) + state_init + .write_all(&vec_bytes) .map_err(|e| format!("failed to update the tvc file: {}", e))?; Ok(()) -} \ No newline at end of file +} diff --git a/src/getconfig.rs b/src/getconfig.rs index 0744a7f9..f9162e28 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -11,15 +11,20 @@ * limitations under the License. */ -use num_bigint::BigUint; use crate::config::Config; -use crate::helpers::{create_client_verbose, query_with_limit, now, now_ms, TonClient}; -use serde_json::{json, Value}; +use crate::helpers::{create_client_verbose, now, now_ms, query_with_limit, TonClient}; use ever_abi::{Contract, Token, TokenValue, Uint}; -use ever_block::{ExternalInboundMessageHeader, Grams, Message, MsgAddressInt, MsgAddressExt, Serializable}; -use ever_client::net::{OrderBy, SortDirection}; +use ever_block::{ + ed25519_create_private_key, ed25519_sign_with_secret, BuilderData, Cell, IBitstring, SliceData, + MAX_SAFE_DEPTH, +}; +use ever_block::{ + ExternalInboundMessageHeader, Grams, Message, MsgAddressExt, MsgAddressInt, Serializable, +}; use ever_client::boc::{get_blockchain_config, ParamsOfGetBlockchainConfig}; -use ever_block::{BuilderData, Cell, IBitstring, SliceData, ed25519_create_private_key, ed25519_sign_with_secret,MAX_SAFE_DEPTH}; +use ever_client::net::{OrderBy, SortDirection}; +use num_bigint::BigUint; +use serde_json::{json, Value}; const PREFIX_UPDATE_CONFIG_MESSAGE_DATA: &str = "43665021"; @@ -240,8 +245,8 @@ const QUERY_FIELDS: &str = r#" } "#; const OPTIONAL_CONFIGS: [&str; 3] = [ -"p5", -r#"p40 { + "p5", + r#"p40 { collations_score_weight min_samples_count min_slashing_protection_score @@ -251,13 +256,13 @@ r#"p40 { z_param_numerator z_param_denominator }"#, -r#"p42 { + r#"p42 { threshold payouts { license_type payout_percent } -}"# +}"#, ]; async fn query_config(ton: &TonClient, result: &str) -> Result, String> { @@ -268,16 +273,21 @@ async fn query_config(ton: &TonClient, result: &str) -> Result, St json!({ "key_block": { "eq": true }, "workchain_id": { "eq": -1 } }), &result, - Some(vec!(OrderBy{ path: "seq_no".to_string(), direction: SortDirection::DESC })), + Some(vec![OrderBy { + path: "seq_no".to_string(), + direction: SortDirection::DESC, + }]), Some(1), - ).await { + ) + .await + { Ok(result) => { if result.is_empty() { - Ok(None) + Ok(None) } else { - Ok(Some(result[0]["master"]["config"].clone())) + Ok(Some(result[0]["master"]["config"].clone())) } - }, + } Err(e) => { if e.message.contains("Server responded with code 400") { Ok(None) @@ -310,9 +320,10 @@ pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result print!("Config: "); } println!("{:#}", Value::from(config_value)); - }, + } Some(index) => { - index.parse::() + index + .parse::() .map_err(|e| format!(r#"failed to parse "index": {}"#, e))?; let config_name = format!("p{}", index); let config_value = if let Some(v) = config_value.get(&config_name) { @@ -338,27 +349,44 @@ pub async fn gen_update_config_message( seqno: Option<&str>, config_master_file: &str, new_param_file: &str, - is_json: bool + is_json: bool, ) -> Result<(), String> { let config_master_address = std::fs::read(&*(config_master_file.to_string() + ".addr")) .map_err(|e| format!(r#"failed to read "config_master": {}"#, e))?; - let config_account = ever_block::AccountId::from_raw(config_master_address, 32*8); + let config_account = ever_block::AccountId::from_raw(config_master_address, 32 * 8); - let private_key_of_config_account = std::fs::read(&*(config_master_file.to_string() + ".pk")) - .map_err(|e| format!(r#"failed to read "config_master": {}"#, e))?; + let private_key_of_config_account = + std::fs::read(&*(config_master_file.to_string() + ".pk")) + .map_err(|e| format!(r#"failed to read "config_master": {}"#, e))?; let config_str = std::fs::read_to_string(new_param_file) .map_err(|e| format!(r#"failed to read "new_param_file": {}"#, e))?; let (config_cell, key_number) = serialize_config_param(&config_str)?; let message = if let Some(abi) = abi { - prepare_message_new_config_param_solidity(abi, config_cell, key_number, config_account, &private_key_of_config_account)? + prepare_message_new_config_param_solidity( + abi, + config_cell, + key_number, + config_account, + &private_key_of_config_account, + )? } else { - let seqno = seqno.unwrap().parse().map_err(|e| format!(r#"failed to parse "seqno": {}"#, e))?; - prepare_message_new_config_param(config_cell, seqno, key_number, config_account, &private_key_of_config_account)? + let seqno = seqno + .unwrap() + .parse() + .map_err(|e| format!(r#"failed to parse "seqno": {}"#, e))?; + prepare_message_new_config_param( + config_cell, + seqno, + key_number, + config_account, + &private_key_of_config_account, + )? }; - let msg_bytes = message.write_to_bytes() + let msg_bytes = message + .write_to_bytes() .map_err(|e| format!(r#"failed to serialize message": {}"#, e))?; let msg_hex = hex::encode(msg_bytes); @@ -374,7 +402,8 @@ pub async fn gen_update_config_message( pub fn serialize_config_param(config_str: &str) -> Result<(Cell, u32), String> { let config_json: serde_json::Value = serde_json::from_str(config_str) .map_err(|e| format!(r#"failed to parse "new_param_file": {}"#, e))?; - let config_json = config_json.as_object() + let config_json = config_json + .as_object() .ok_or(r#""new_param_file" is not json object"#.to_string())?; if config_json.len() != 1 { Err(r#""new_param_file" is not a valid json"#.to_string())?; @@ -393,15 +422,29 @@ pub fn serialize_config_param(config_str: &str) -> Result<(Cell, u32), String> { .parse::() .map_err(|e| format!(r#""new_param_file" is not a valid json: {}"#, e))?; - let config_params = ever_block_json::parse_config(config_json) - .map_err(|e| format!(r#"failed to parse config params from "new_param_file": {}"#, e))?; - - let config_param = config_params.config(key_number) - .map_err(|e| format!(r#"failed to parse config params from "new_param_file": {}"#, e))? - .ok_or(format!(r#"Not found config number {} in parsed config_params"#, key_number))?; + let config_params = ever_block_json::parse_config(config_json).map_err(|e| { + format!( + r#"failed to parse config params from "new_param_file": {}"#, + e + ) + })?; + + let config_param = config_params + .config(key_number) + .map_err(|e| { + format!( + r#"failed to parse config params from "new_param_file": {}"#, + e + ) + })? + .ok_or(format!( + r#"Not found config number {} in parsed config_params"#, + key_number + ))?; let mut cell = BuilderData::default(); - config_param.write_to_cell(&mut cell) + config_param + .write_to_cell(&mut cell) .map_err(|e| format!(r#"failed to serialize config param": {}"#, e))?; let config_cell = cell.references()[0].clone(); @@ -413,7 +456,7 @@ fn prepare_message_new_config_param( seqno: u32, key_number: u32, config_account: SliceData, - private_key_of_config_account: &[u8] + private_key_of_config_account: &[u8], ) -> Result { let prefix = hex::decode(PREFIX_UPDATE_CONFIG_MESSAGE_DATA).unwrap(); let since_the_epoch = now() + 100; // timestamp + 100 secs @@ -425,11 +468,17 @@ fn prepare_message_new_config_param( cell.append_i32(key_number as i32).unwrap(); cell.checked_append_reference(config_param.clone()).unwrap(); - let msg_signature = ed25519_sign_with_secret(private_key_of_config_account, cell.finalize(MAX_SAFE_DEPTH).unwrap().repr_hash().as_slice()) - .map_err(|e| format!("Failed to sign: {e}"))?; + let msg_signature = ed25519_sign_with_secret( + private_key_of_config_account, + cell.finalize(MAX_SAFE_DEPTH) + .unwrap() + .repr_hash() + .as_slice(), + ) + .map_err(|e| format!("Failed to sign: {e}"))?; let mut cell = BuilderData::default(); - cell.append_raw(&msg_signature, 64*8).unwrap(); + cell.append_raw(&msg_signature, 64 * 8).unwrap(); cell.append_raw(prefix.as_slice(), 32).unwrap(); cell.append_u32(seqno).unwrap(); cell.append_u32(since_the_epoch).unwrap(); @@ -437,7 +486,8 @@ fn prepare_message_new_config_param( cell.checked_append_reference(config_param).unwrap(); let config_contract_address = MsgAddressInt::with_standart(None, -1, config_account).unwrap(); - let mut header = ExternalInboundMessageHeader::new(MsgAddressExt::AddrNone, config_contract_address); + let mut header = + ExternalInboundMessageHeader::new(MsgAddressExt::AddrNone, config_contract_address); header.import_fee = Grams::zero(); let body = SliceData::load_builder(cell).unwrap(); let message = Message::with_ext_in_header_and_body(header, body); @@ -450,11 +500,11 @@ fn prepare_message_new_config_param_solidity( config_param: Cell, key_number: u32, config_account: SliceData, - private_key_of_config_account: &[u8] + private_key_of_config_account: &[u8], ) -> Result { - let secret = ed25519_create_private_key(private_key_of_config_account) - .map_err(|err| err.to_string())?; - + let secret = + ed25519_create_private_key(private_key_of_config_account).map_err(|err| err.to_string())?; + let config_contract_address = MsgAddressInt::with_standart(None, -1, config_account).unwrap(); let since_the_epoch = now_ms(); @@ -467,14 +517,19 @@ fn prepare_message_new_config_param_solidity( Token::new("data", TokenValue::Cell(config_param)), ]; - let abi = std::fs::read(abi) - .map_err(|err| format!("cannot read abi file {}: {}", abi, err))?; - let contract = Contract::load(&*abi) - .map_err(|err| err.to_string())?; - let function = contract.function("set_config_param") + let abi = std::fs::read(abi).map_err(|err| format!("cannot read abi file {}: {}", abi, err))?; + let contract = Contract::load(&*abi).map_err(|err| err.to_string())?; + let function = contract + .function("set_config_param") .map_err(|err| err.to_string())?; let body = function - .encode_input(&header, ¶meters, false, Some(&secret), Some(config_contract_address.clone())) + .encode_input( + &header, + ¶meters, + false, + Some(&secret), + Some(config_contract_address.clone()), + ) .and_then(SliceData::load_builder) .map_err(|err| format!("cannot prepare message body {}", err))?; @@ -498,26 +553,32 @@ pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), S "blocks", json!({ "workchain_id": { "eq":-1 }, "key_block": { "eq":true }}), "boc", - Some(vec![OrderBy{ path: "seq_no".to_owned(), direction: SortDirection::DESC }]), + Some(vec![OrderBy { + path: "seq_no".to_owned(), + direction: SortDirection::DESC, + }]), Some(1), - ).await.map_err(|e| format!("failed to query last key block: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query last key block: {}", e))?; if last_key_block_query.is_empty() { return Err("Key block not found".to_string()); } - let block = last_key_block_query[0]["boc"].as_str() - .ok_or("Failed to query last block BOC.")?.to_owned(); + let block = last_key_block_query[0]["boc"] + .as_str() + .ok_or("Failed to query last block BOC.")? + .to_owned(); let bc_config = get_blockchain_config( ton.clone(), - ParamsOfGetBlockchainConfig { - block_boc: block, - }, - ).map_err(|e| format!("Failed to get blockchain config: {}", e))?; + ParamsOfGetBlockchainConfig { block_boc: block }, + ) + .map_err(|e| format!("Failed to get blockchain config: {}", e))?; - let bc_config = base64::decode(bc_config.config_boc) - .map_err(|e| format!("Failed to decode BOC: {}", e))?; + let bc_config = + base64::decode(bc_config.config_boc).map_err(|e| format!("Failed to decode BOC: {}", e))?; std::fs::write(path, bc_config) .map_err(|e| format!("Failed to write data to the file {}: {}", path, e))?; if !config.is_json { diff --git a/src/helpers.rs b/src/helpers.rs index ffeab694..ea8a7963 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -10,31 +10,33 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use std::env; -use std::path::PathBuf; +use crate::call::parse_params; use crate::config::{Config, LOCALNET}; use crate::debug::debug_level_from_env; +use crate::replay::{construct_blockchain_config, CONFIG_ADDR}; use crate::SignatureIDType; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; +use crate::{resolve_net_name, FullConfig}; +use clap::ArgMatches; +use ever_block::{ + Account, CurrencyCollection, Deserializable, MsgAddressInt, Serializable, StateInit, +}; use ever_client::abi::{ Abi, AbiConfig, AbiContract, DecodedMessageBody, DeploySet, ParamsOfDecodeMessageBody, ParamsOfEncodeMessage, Signer, }; use ever_client::crypto::{CryptoConfig, KeyPair, MnemonicDictionary}; use ever_client::error::ClientError; -use ever_client::net::{query_collection, OrderBy, ParamsOfQueryCollection, NetworkConfig}; +use ever_client::net::{query_collection, NetworkConfig, OrderBy, ParamsOfQueryCollection}; use ever_client::{ClientConfig, ClientContext}; -use ever_block::{Account, MsgAddressInt, Deserializable, CurrencyCollection, StateInit, Serializable}; -use std::str::FromStr; -use clap::ArgMatches; -use serde_json::{Value, json}; use ever_executor::BlockchainConfig; -use url::Url; -use crate::call::parse_params; -use crate::{FullConfig, resolve_net_name}; -use crate::replay::{CONFIG_ADDR, construct_blockchain_config}; use ever_vm::executor::{Engine, EngineTraceInfo}; +use serde_json::{json, Value}; +use std::env; +use std::path::PathBuf; +use std::str::FromStr; +use std::sync::Arc; +use std::time::{Duration, SystemTime}; +use url::Url; pub const HD_PATH: &str = "m/44'/396'/0'/0/0"; pub const WORD_COUNT: u8 = 12; @@ -47,7 +49,10 @@ pub type CallbackType = Arc; pub fn default_config_name() -> String { env::current_dir() .map(|dir| { - dir.join(PathBuf::from(CONFIG_BASE_NAME)).to_str().unwrap().to_string() + dir.join(PathBuf::from(CONFIG_BASE_NAME)) + .to_str() + .unwrap() + .to_string() }) .unwrap_or(CONFIG_BASE_NAME.to_string()) } @@ -85,8 +90,8 @@ impl log::Log for SimpleLogger { pub fn read_keys(filename: &str) -> Result { let keys_str = std::fs::read_to_string(filename) .map_err(|e| format!("failed to read the keypair file: {}", e))?; - let keys: KeyPair = serde_json::from_str(&keys_str) - .map_err(|e| format!("failed to load keypair: {}", e))?; + let keys: KeyPair = + serde_json::from_str(&keys_str).map_err(|e| format!("failed to load keypair: {}", e))?; Ok(keys) } @@ -96,8 +101,12 @@ pub fn load_ton_address(addr: &str, config: &Config) -> Result { } else { addr.to_owned() }; - let _ = MsgAddressInt::from_str(&addr) - .map_err(|e| format!("Address is specified in the wrong format. Error description: {}", e))?; + let _ = MsgAddressInt::from_str(&addr).map_err(|e| { + format!( + "Address is specified in the wrong format. Error description: {}", + e + ) + })?; Ok(addr) } @@ -125,14 +134,17 @@ pub fn get_server_endpoints(config: &Config) -> Vec { 0 => vec![config.url.clone()], _ => config.endpoints.clone(), }; - cur_endpoints.iter_mut().map(|end| { + cur_endpoints + .iter_mut() + .map(|end| { let mut end = end.trim_end_matches('/').to_owned(); - if config.project_id.is_some() { - end.push('/'); - end.push_str(&config.project_id.clone().unwrap()); - } - end.to_owned() - }).collect::>() + if config.project_id.is_some() { + end.push('/'); + end.push_str(&config.project_id.clone().unwrap()); + } + end.to_owned() + }) + .collect::>() } pub fn create_client(config: &Config) -> Result { @@ -141,7 +153,10 @@ pub fn create_client(config: &Config) -> Result { println!("Connecting to:\n\tUrl: {}", config.url); println!("\tEndpoints: {:?}\n", modified_endpoints); } - let endpoints_cnt = if resolve_net_name(&config.url).unwrap_or(config.url.clone()).eq(LOCALNET) { + let endpoints_cnt = if resolve_net_name(&config.url) + .unwrap_or(config.url.clone()) + .eq(LOCALNET) + { 1_u8 } else { modified_endpoints.len() as u8 @@ -161,10 +176,10 @@ pub fn create_client(config: &Config) -> Result { server_address: Some(config.url.to_owned()), sending_endpoint_count: endpoints_cnt, endpoints: if modified_endpoints.is_empty() { - None - } else { - Some(modified_endpoints) - }, + None + } else { + Some(modified_endpoints) + }, message_retries_count: config.retries as i8, message_processing_timeout: 30000, wait_for_timeout: config.timeout, @@ -187,11 +202,14 @@ pub fn create_client_verbose(config: &Config) -> Result { create_client(config) } -pub fn create_client_with_signature_id(config: &Config, signature_id: Option,) -> Result<(Arc, Option), String> { +pub fn create_client_with_signature_id( + config: &Config, + signature_id: Option, +) -> Result<(Arc, Option), String> { match signature_id { - Some(SignatureIDType::Online) => Ok((create_client_verbose(config)?,None)), - Some(SignatureIDType::Value(x)) =>Ok((create_client_local()?, Some(x))), - _ => Ok((create_client_local()?,None)), + Some(SignatureIDType::Online) => Ok((create_client_verbose(config)?, None)), + Some(SignatureIDType::Value(x)) => Ok((create_client_local()?, Some(x))), + _ => Ok((create_client_local()?, None)), } } @@ -201,16 +219,21 @@ pub async fn query_raw( filter: Option<&str>, limit: Option<&str>, order: Option<&str>, - result: &str -) -> Result<(), String> -{ + result: &str, +) -> Result<(), String> { let context = create_client_verbose(config)?; - let filter = filter.map(serde_json::from_str).transpose() + let filter = filter + .map(serde_json::from_str) + .transpose() .map_err(|e| format!("Failed to parse filter field: {}", e))?; - let limit = limit.map(|s| s.parse::()).transpose() + let limit = limit + .map(|s| s.parse::()) + .transpose() .map_err(|e| format!("Failed to parse limit field: {}", e))?; - let order = order.map(serde_json::from_str).transpose() + let order = order + .map(serde_json::from_str) + .transpose() .map_err(|e| format!("Failed to parse order field: {}", e))?; let query = ever_client::net::query_collection( @@ -221,8 +244,10 @@ pub async fn query_raw( limit, order, result: result.to_owned(), - } - ).await.map_err(|e| format!("Failed to execute query: {}", e))?; + }, + ) + .await + .map_err(|e| format!("Failed to execute query: {}", e))?; println!("{:#}", Value::Array(query.result)); Ok(()) @@ -246,14 +271,11 @@ pub async fn query_with_limit( limit, }, ) - .await - .map(|r| r.result) + .await + .map(|r| r.result) } -pub async fn query_message( - ton: TonClient, - message_id: &str, -) -> Result { +pub async fn query_message(ton: TonClient, message_id: &str) -> Result { let messages = query_with_limit( ton.clone(), "messages", @@ -261,17 +283,24 @@ pub async fn query_message( "boc", None, Some(1), - ).await - .map_err(|e| format!("failed to query account data: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query account data: {}", e))?; if messages.is_empty() { Err("message with specified id was not found.".to_string()) - } - else { - Ok(messages[0]["boc"].as_str().ok_or("Failed to obtain message boc.".to_string())?.to_string()) + } else { + Ok(messages[0]["boc"] + .as_str() + .ok_or("Failed to obtain message boc.".to_string())? + .to_string()) } } -pub async fn query_account_field(ton: TonClient, address: &str, field: &str) -> Result { +pub async fn query_account_field( + ton: TonClient, + address: &str, + field: &str, +) -> Result { let accounts = query_with_limit( ton.clone(), "accounts", @@ -279,8 +308,9 @@ pub async fn query_account_field(ton: TonClient, address: &str, field: &str) -> field, None, Some(1), - ).await - .map_err(|e| format!("failed to query account data: {}", e))?; + ) + .await + .map_err(|e| format!("failed to query account data: {}", e))?; if accounts.is_empty() { return Err(format!("account with address {} not found", address)); } @@ -291,7 +321,6 @@ pub async fn query_account_field(ton: TonClient, address: &str, field: &str) -> Ok(data.unwrap().to_string()) } - pub async fn decode_msg_body( ton: TonClient, abi_path: &str, @@ -299,7 +328,6 @@ pub async fn decode_msg_body( is_internal: bool, config: &Config, ) -> Result { - let abi = load_abi(abi_path, config).await?; ever_client::abi::decode_message_body( ton, @@ -320,11 +348,14 @@ pub async fn load_abi_str(abi_path: &str, config: &Config) -> Result Result { @@ -334,8 +365,7 @@ pub async fn load_abi(abi_path: &str, config: &Config) -> Result { pub async fn load_ton_abi(abi_path: &str, config: &Config) -> Result { let abi_str = load_abi_str(abi_path, config).await?; - ever_abi::Contract::load(abi_str.as_bytes()) - .map_err(|e| format!("Failed to load ABI: {}", e)) + ever_abi::Contract::load(abi_str.as_bytes()).map_err(|e| format!("Failed to load ABI: {}", e)) } pub async fn load_file_with_url(url: &str, timeout: u64) -> Result, String> { @@ -352,10 +382,8 @@ pub async fn load_file_with_url(url: &str, timeout: u64) -> Result, Stri .await .map_err(|e| format!("Failed to get response bytes: {e}"))?; Ok(res.to_vec()) - } - pub async fn calc_acc_address( tvc: &[u8], wc: i32, @@ -363,35 +391,34 @@ pub async fn calc_acc_address( init_data: Option<&str>, abi: Abi, ) -> Result { - let data_map_supported = abi.abi().unwrap().data_map_supported(); let ton = create_client_local()?; - let dset= - if data_map_supported { - let init_data_json = init_data - .map(serde_json::from_str) - .transpose() - .map_err(|e| format!("initial data is not in json: {}", e))?; - - DeploySet { - tvc: Some(base64::encode(tvc)), - workchain_id: Some(wc), - initial_data: init_data_json, - initial_pubkey: pubkey.clone(), - ..Default::default() - } - } else { - let init_data_json = insert_pubkey_to_init_data(pubkey.clone(), init_data)?; - let js = serde_json::from_str(init_data_json.as_str()).map_err(|e| format!("initial data is not in json: {}", e))?; - DeploySet { - tvc: Some(base64::encode(tvc)), - workchain_id: Some(wc), - initial_data: js, - initial_pubkey: None, // initial_pubkey: pubkey.clone(), - ..Default::default() - } - }; + let dset = if data_map_supported { + let init_data_json = init_data + .map(serde_json::from_str) + .transpose() + .map_err(|e| format!("initial data is not in json: {}", e))?; + + DeploySet { + tvc: Some(base64::encode(tvc)), + workchain_id: Some(wc), + initial_data: init_data_json, + initial_pubkey: pubkey.clone(), + ..Default::default() + } + } else { + let init_data_json = insert_pubkey_to_init_data(pubkey.clone(), init_data)?; + let js = serde_json::from_str(init_data_json.as_str()) + .map_err(|e| format!("initial data is not in json: {}", e))?; + DeploySet { + tvc: Some(base64::encode(tvc)), + workchain_id: Some(wc), + initial_data: js, + initial_pubkey: None, // initial_pubkey: pubkey.clone(), + ..Default::default() + } + }; let result = ever_client::abi::encode_message( ton.clone(), ParamsOfEncodeMessage { @@ -428,14 +455,20 @@ pub fn events_filter(addr: &str, since: u32) -> serde_json::Value { }) } -pub async fn print_message(ton: TonClient, message: &Value, abi: &str, is_internal: bool) -> Result<(String, String), String> { +pub async fn print_message( + ton: TonClient, + message: &Value, + abi: &str, + is_internal: bool, +) -> Result<(String, String), String> { println!("Id: {}", message["id"].as_str().unwrap_or("Undefined")); let value = message["value"].as_str().unwrap_or("0x0"); let value = u64::from_str_radix(value.trim_start_matches("0x"), 16) .map_err(|e| format!("failed to decode msg value: {}", e))?; let value: f64 = value as f64 / 1e9; println!("Value: {:.9}", value); - println!("Created at: {} ({})", + println!( + "Created at: {} ({})", message["created_at"].as_u64().unwrap_or(0), message["created_at_string"].as_str().unwrap_or("Undefined") ); @@ -457,8 +490,11 @@ pub async fn print_message(ton: TonClient, message: &Value, abi: &str, is_intern ("unknown".to_owned(), "{}".to_owned()) } else { let result = result.unwrap(); - (result.name, serde_json::to_string(&result.value) - .map_err(|e| format!("failed to serialize the result: {}", e))?) + ( + result.name, + serde_json::to_string(&result.value) + .map_err(|e| format!("failed to serialize the result: {}", e))?, + ) }; println!("Decoded body:\n{} {}\n", name, args); return Ok((name, args)); @@ -477,7 +513,7 @@ pub fn json_account( code_hash: Option, state_init: Option, ) -> Value { - let mut res = json!({ }); + let mut res = json!({}); if acc_type.is_some() { res["acc_type"] = json!(acc_type.unwrap()); } @@ -505,7 +541,6 @@ pub fn json_account( res } - pub fn print_account( config: &Config, acc_type: Option, @@ -561,22 +596,27 @@ pub fn print_account( } } -pub fn construct_account_from_tvc(tvc_path: &str, address: Option<&str>, balance: Option) -> Result { +pub fn construct_account_from_tvc( + tvc_path: &str, + address: Option<&str>, + balance: Option, +) -> Result { Account::active_by_init_code_hash( match address { Some(address) => MsgAddressInt::from_str(address) .map_err(|e| format!("Failed to set address: {}", e))?, - _ => MsgAddressInt::default() + _ => MsgAddressInt::default(), }, match balance { Some(balance) => CurrencyCollection::with_grams(balance), - _ => CurrencyCollection::default() + _ => CurrencyCollection::default(), }, 0, StateInit::construct_from_file(tvc_path) .map_err(|e| format!(" failed to load TVC from the file {}: {}", tvc_path, e))?, - true - ).map_err(|e| format!(" failed to create account with the stateInit: {}",e)) + true, + ) + .map_err(|e| format!(" failed to create account with the stateInit: {}", e)) } pub fn check_dir(path: &str) -> Result<(), String> { @@ -598,38 +638,43 @@ pub async fn load_account( source_type: &AccountSource, source: &str, ton_client: Option, - config: &Config + config: &Config, ) -> Result<(Account, String), String> { match source_type { AccountSource::Network => { let ton_client = match ton_client { Some(ton_client) => ton_client, - None => { - create_client(config)? - } + None => create_client(config)?, }; - let boc = query_account_field(ton_client.clone(),source, "boc").await?; - Ok((Account::construct_from_base64(&boc) - .map_err(|e| format!("Failed to construct account: {}", e))?, - boc)) - }, + let boc = query_account_field(ton_client.clone(), source, "boc").await?; + Ok(( + Account::construct_from_base64(&boc) + .map_err(|e| format!("Failed to construct account: {}", e))?, + boc, + )) + } _ => { let account = if source_type == &AccountSource::Boc { - Account::construct_from_file(source) - .map_err(|e| format!(" failed to load account from the file {}: {}", source, e))? + Account::construct_from_file(source).map_err(|e| { + format!(" failed to load account from the file {}: {}", source, e) + })? } else { construct_account_from_tvc(source, None, None)? }; - let account_bytes = account.write_to_bytes() + let account_bytes = account + .write_to_bytes() .map_err(|e| format!(" failed to load data from the account: {}", e))?; Ok((account, base64::encode(account_bytes))) - }, + } } } - pub fn load_debug_info(abi: &str) -> Option { - check_file_exists(abi, &[".json", ".abi"], &[".dbg.json", ".debug.json", ".map.json"]) + check_file_exists( + abi, + &[".json", ".abi"], + &[".dbg.json", ".debug.json", ".map.json"], + ) } pub fn load_abi_from_tvc(tvc: &str) -> Option { @@ -652,23 +697,26 @@ pub fn check_file_exists(path: &str, trim: &[&str], ending: &[&str]) -> Option, config: &Config) -> Result { - matches.value_of("ABI") +pub fn abi_from_matches_or_config( + matches: &ArgMatches<'_>, + config: &Config, +) -> Result { + matches + .value_of("ABI") .map(|s| s.to_string()) .or(config.abi_path.clone()) .ok_or("ABI file is not defined. Supply it in the config file or command line.".to_string()) } pub fn parse_lifetime(lifetime: Option<&str>, config: &Config) -> Result { - Ok(lifetime.map(|val| { - u32::from_str_radix(val, 10) - .map_err(|e| format!("failed to parse lifetime: {}", e)) - }) + Ok(lifetime + .map(|val| { + u32::from_str_radix(val, 10).map_err(|e| format!("failed to parse lifetime: {}", e)) + }) .transpose()? .unwrap_or(config.lifetime)) } - #[macro_export] macro_rules! print_args { ($( $arg:expr ),* ) => { @@ -693,7 +741,12 @@ pub fn load_params(params: &str) -> Result { } } -pub async fn unpack_alternative_params(matches: &ArgMatches<'_>, abi_path: &str, method: &str, config: &Config) -> Result { +pub async fn unpack_alternative_params( + matches: &ArgMatches<'_>, + abi_path: &str, + method: &str, + config: &Config, +) -> Result { if let Some(params) = matches.values_of("PARAMS") { let params = params.collect(); parse_params(params, abi_path, method, config).await @@ -702,8 +755,9 @@ pub async fn unpack_alternative_params(matches: &ArgMatches<'_>, abi_path: &str, } } -pub fn wc_from_matches_or_config(matches: &ArgMatches<'_>, config: &Config) -> Result { - Ok(matches.value_of("WC") +pub fn wc_from_matches_or_config(matches: &ArgMatches<'_>, config: &Config) -> Result { + Ok(matches + .value_of("WC") .map(|v| i32::from_str_radix(v, 10)) .transpose() .map_err(|e| format!("failed to parse workchain id: {}", e))? @@ -718,28 +772,43 @@ pub struct ContractData { pub fn contract_data_from_matches_or_config_alias( matches: &ArgMatches<'_>, - full_config: &FullConfig + full_config: &FullConfig, ) -> Result { - let address = matches.value_of("ADDRESS") + let address = matches + .value_of("ADDRESS") .map(|s| s.to_string()) .or(full_config.config.addr.clone()) - .ok_or("ADDRESS is not defined. Supply it in the config file or command line.".to_string())?; + .ok_or( + "ADDRESS is not defined. Supply it in the config file or command line.".to_string(), + )?; let (address, abi, keys) = if full_config.aliases.contains_key(&address) { let alias = full_config.aliases.get(&address).unwrap(); - (alias.address.clone(), alias.abi_path.clone(), alias.key_path.clone()) + ( + alias.address.clone(), + alias.abi_path.clone(), + alias.key_path.clone(), + ) } else { (Some(address), None, None) }; - let abi = matches.value_of("ABI") + let abi = matches + .value_of("ABI") .map(|s| s.to_string()) .or(full_config.config.abi_path.clone()) .or(abi) - .ok_or("ABI file is not defined. Supply it in the config file or command line.".to_string())?; - let keys = matches.value_of("KEYS") + .ok_or( + "ABI file is not defined. Supply it in the config file or command line.".to_string(), + )?; + let keys = matches + .value_of("KEYS") .map(|s| s.to_string()) .or(full_config.config.keys_path.clone()) .or(keys); - Ok(ContractData { address, abi: Some(abi), keys }) + Ok(ContractData { + address, + abi: Some(abi), + keys, + }) } pub fn blockchain_config_from_default_json() -> Result { @@ -998,27 +1067,27 @@ pub fn blockchain_config_from_default_json() -> Result // loads blockchain config from the config contract boc, if it is none tries to load config contract // from the network, if it is unavailable returns default. -pub async fn get_blockchain_config(cli_config: &Config, config_contract_boc_path: Option<&str>) -> - Result { +pub async fn get_blockchain_config( + cli_config: &Config, + config_contract_boc_path: Option<&str>, +) -> Result { match config_contract_boc_path { Some(config_path) => { - let acc = Account::construct_from_file(config_path) - .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; + let acc = Account::construct_from_file(config_path).map_err(|e| { + format!("Failed to load config contract account from file {config_path}: {e}") + })?; construct_blockchain_config(&acc) - }, + } None => { let ton_client = create_client(cli_config)?; - let config = query_account_field( - ton_client.clone(), - CONFIG_ADDR, - "boc", - ).await; - let config_account = config.and_then(|config| + let config = query_account_field(ton_client.clone(), CONFIG_ADDR, "boc").await; + let config_account = config.and_then(|config| { Account::construct_from_base64(&config) - .map_err(|e| format!("Failed to construct config account: {e}"))); + .map_err(|e| format!("Failed to construct config account: {e}")) + }); match config_account { Ok(config) => construct_blockchain_config(&config), - Err(_) => blockchain_config_from_default_json() + Err(_) => blockchain_config_from_default_json(), } } } @@ -1030,11 +1099,17 @@ pub fn decode_data(data: &str, param_name: &str) -> Result, String> { } else if let Ok(data) = hex::decode(data) { Ok(data) } else { - Err(format!("the {} parameter should be base64 or hex encoded", param_name)) + Err(format!( + "the {} parameter should be base64 or hex encoded", + param_name + )) } } -pub fn insert_pubkey_to_init_data(pubkey: Option, opt_init_data: Option<&str>) -> Result { +pub fn insert_pubkey_to_init_data( + pubkey: Option, + opt_init_data: Option<&str>, +) -> Result { let init_data = opt_init_data.unwrap_or("{}"); let mut js_init_data = serde_json::from_str(init_data) @@ -1043,14 +1118,14 @@ pub fn insert_pubkey_to_init_data(pubkey: Option, opt_init_data: Option< Value::Object(obj) => { if obj.contains_key(&"_pubkey".to_string()) && pubkey.is_some() { return Err("Public key was set via init data and via command-line option --genkey/--setkey. \ -Please, use one way to set public key.".to_owned()) +Please, use one way to set public key.".to_owned()); } if let Some(pk) = pubkey { let pubkey_str = format!("0x{}", pk); obj.insert("_pubkey".to_string(), Value::String(pubkey_str)); } } - _ => panic!("js_init_data is not Value::Object") + _ => panic!("js_init_data is not Value::Object"), } Ok(js_init_data.to_string()) -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index 3c1ece6a..57da905a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,53 +20,56 @@ mod call; mod config; mod convert; mod crypto; -mod decode; mod debot; +mod debug; +mod decode; mod deploy; mod depool; mod depool_abi; mod genaddr; mod getconfig; mod helpers; +mod message; mod multisig; -mod sendfile; -mod voting; mod replay; -mod debug; mod run; +mod sendfile; mod test; -mod message; +mod voting; -use account::{get_account, calc_storage, wait_for_change}; +use crate::account::dump_accounts; +use account::{calc_storage, get_account, wait_for_change}; use call::{call_contract, call_contract_with_msg}; -use clap::{ArgMatches, SubCommand, Arg, AppSettings, App}; -use config::{Config, set_config, clear_config}; -use crypto::{generate_mnemonic, extract_pubkey, generate_keypair}; +use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; +use config::{clear_config, set_config, Config}; +use crypto::{extract_pubkey, generate_keypair, generate_mnemonic}; use debot::{create_debot_command, debot_command}; -use decode::{create_decode_command, decode_command}; use debug::{create_debug_command, debug_command}; +use decode::{create_decode_command, decode_command}; use deploy::{deploy_contract, generate_deploy_message}; use depool::{create_depool_command, depool_command}; +use ever_client::abi::{CallSet, ParamsOfEncodeMessageBody}; use genaddr::generate_address; -use getconfig::{query_global_config, dump_blockchain_config}; -use helpers::{load_ton_address, load_abi, create_client_local, query_raw, - contract_data_from_matches_or_config_alias}; +use getconfig::{dump_blockchain_config, query_global_config}; +use helpers::{ + contract_data_from_matches_or_config_alias, create_client_local, load_abi, load_ton_address, + query_raw, +}; use multisig::{create_multisig_command, multisig_command}; use replay::{fetch_block_command, fetch_command, replay_command}; use serde_json::{json, Value}; use std::collections::BTreeMap; use std::env; use std::process::exit; -use test::{create_test_command, test_command, test_sign_command, create_test_sign_command}; -use ever_client::abi::{ParamsOfEncodeMessageBody, CallSet}; +use test::{create_test_command, create_test_sign_command, test_command, test_sign_command}; use voting::{create_proposal, decode_proposal, vote}; -use crate::account::dump_accounts; -use crate::config::{FullConfig, resolve_net_name}; +use crate::config::{resolve_net_name, FullConfig}; use crate::getconfig::gen_update_config_message; -use crate::helpers::{abi_from_matches_or_config, AccountSource, default_config_name, - global_config_path, load_abi_from_tvc, load_params, parse_lifetime, - unpack_alternative_params, wc_from_matches_or_config +use crate::helpers::{ + abi_from_matches_or_config, default_config_name, global_config_path, load_abi_from_tvc, + load_params, parse_lifetime, unpack_alternative_params, wc_from_matches_or_config, + AccountSource, }; use crate::message::generate_message; use crate::run::{run_command, run_get_method}; @@ -99,12 +102,14 @@ fn main() { .expect("Can't create Engine tokio runtime"); let result = runtime.block_on(async move { main_internal().await }); if let Err(err_str) = result { - if !err_str.is_empty() { println!("{}", err_str); } + if !err_str.is_empty() { + println!("{}", err_str); + } exit(1) } } -async fn main_internal() -> Result <(), String> { +async fn main_internal() -> Result<(), String> { let version_string = env!("CARGO_PKG_VERSION"); let abi_arg = Arg::with_name("ABI") @@ -183,9 +188,9 @@ async fn main_internal() -> Result <(), String> { .arg(method_opt_arg.clone()) .arg(multi_params_arg.clone()); - let address_boc_tvc_arg = Arg::with_name("ADDRESS") - .takes_value(true) - .help("Contract address or path to the saved account state if --boc or --tvc flag is specified."); + let address_boc_tvc_arg = Arg::with_name("ADDRESS").takes_value(true).help( + "Contract address or path to the saved account state if --boc or --tvc flag is specified.", + ); let method_arg = Arg::with_name("METHOD") .required(true) @@ -215,8 +220,7 @@ async fn main_internal() -> Result <(), String> { .setting(AppSettings::AllowLeadingHyphen) .setting(AppSettings::TrailingVarArg) .setting(AppSettings::DontCollapseArgsInUsage) - .arg(address_boc_tvc_arg.clone() - .long("--addr")) + .arg(address_boc_tvc_arg.clone().long("--addr")) .arg(abi_arg.clone()) .arg(method_opt_arg.clone()) .arg(multi_params_arg.clone()) @@ -242,26 +246,29 @@ async fn main_internal() -> Result <(), String> { .arg(tvc_flag.clone()) .arg(bc_config_arg.clone()); - let version_cmd = SubCommand::with_name("version") - .about("Prints build and version info."); + let version_cmd = SubCommand::with_name("version").about("Prints build and version info."); let genphrase_cmd = SubCommand::with_name("genphrase") .about("Generates a seed phrase for keypair.") .version(version_string) .author(author) - .arg(Arg::with_name("DUMP_KEYPAIR") - .long("--dump") - .takes_value(true) - .help("Path where to dump keypair generated from the phrase")); + .arg( + Arg::with_name("DUMP_KEYPAIR") + .long("--dump") + .takes_value(true) + .help("Path where to dump keypair generated from the phrase"), + ); let genpubkey_cmd = SubCommand::with_name("genpubkey") .about("Generates a public key from the seed phrase.") .version(version_string) .author(author) - .arg(Arg::with_name("PHRASE") - .takes_value(true) - .required(true) - .help("Seed phrase (12 words). Should be specified in quotes.")); + .arg( + Arg::with_name("PHRASE") + .takes_value(true) + .required(true) + .help("Seed phrase (12 words). Should be specified in quotes."), + ); let getkeypair_cmd = SubCommand::with_name("getkeypair") .about("Generates a keypair from the seed phrase or private key and saves it to the file.") @@ -346,7 +353,6 @@ async fn main_internal() -> Result <(), String> { .takes_value(true) .help("Contract address."); - let params_arg = Arg::with_name("PARAMS") .required(true) .takes_value(true) @@ -368,10 +374,12 @@ async fn main_internal() -> Result <(), String> { .about("Sends a prepared message to the contract.") .version(version_string) .author(author) - .arg(Arg::with_name("MESSAGE") - .required(true) - .takes_value(true) - .help("Message to send. Message data should be specified in quotes.")) + .arg( + Arg::with_name("MESSAGE") + .required(true) + .takes_value(true) + .help("Message to send. Message data should be specified in quotes."), + ) .arg(abi_arg.clone()); let message_cmd = SubCommand::with_name("message") @@ -419,8 +427,7 @@ async fn main_internal() -> Result <(), String> { .about("Runs contract function locally.") .version(version_string) .author(author) - .arg(address_boc_tvc_arg.clone() - .required(true)) + .arg(address_boc_tvc_arg.clone().required(true)) .arg(method_arg.clone()) .arg(params_arg.clone()) .arg(abi_arg.clone()) @@ -505,25 +512,31 @@ async fn main_internal() -> Result <(), String> { .help("Alias name."); let alias_cmd = SubCommand::with_name("alias") .about("Commands to work with aliases map") - .subcommand(SubCommand::with_name("add") - .about("Add alias to the aliases map.") - .arg(alias_arg.clone()) - .arg(Arg::with_name("ADDRESS") - .long("--addr") - .takes_value(true) - .help("Contract address.")) - .arg(keys_arg.clone()) - .arg(Arg::with_name("ABI") - .long("--abi") - .takes_value(true) - .help("Path or link to the contract ABI file or pure json ABI data."))) - .subcommand(SubCommand::with_name("remove") - .about("Remove alias from the aliases map.") - .arg(alias_arg.clone())) - .subcommand(SubCommand::with_name("print") - .about("Print the aliases map.")) - .subcommand(SubCommand::with_name("reset") - .about("Clear the aliases map.")); + .subcommand( + SubCommand::with_name("add") + .about("Add alias to the aliases map.") + .arg(alias_arg.clone()) + .arg( + Arg::with_name("ADDRESS") + .long("--addr") + .takes_value(true) + .help("Contract address."), + ) + .arg(keys_arg.clone()) + .arg( + Arg::with_name("ABI") + .long("--abi") + .takes_value(true) + .help("Path or link to the contract ABI file or pure json ABI data."), + ), + ) + .subcommand( + SubCommand::with_name("remove") + .about("Remove alias from the aliases map.") + .arg(alias_arg.clone()), + ) + .subcommand(SubCommand::with_name("print").about("Print the aliases map.")) + .subcommand(SubCommand::with_name("reset").about("Clear the aliases map.")); let url_arg = Arg::with_name("URL") .required(true) @@ -531,20 +544,24 @@ async fn main_internal() -> Result <(), String> { .help("Url of the endpoints list."); let config_endpoint_cmd = SubCommand::with_name("endpoint") .about("Commands to work with the endpoints map.") - .subcommand(SubCommand::with_name("add") - .about("Add endpoints list.") - .arg(url_arg.clone()) - .arg(Arg::with_name("ENDPOINTS") - .required(true) - .takes_value(true) - .help("List of endpoints (comma separated)."))) - .subcommand(SubCommand::with_name("remove") - .about("Remove endpoints list.") - .arg(url_arg.clone())) - .subcommand(SubCommand::with_name("reset") - .about("Reset the endpoints map.")) - .subcommand(SubCommand::with_name("print") - .about("Print current endpoints map.")); + .subcommand( + SubCommand::with_name("add") + .about("Add endpoints list.") + .arg(url_arg.clone()) + .arg( + Arg::with_name("ENDPOINTS") + .required(true) + .takes_value(true) + .help("List of endpoints (comma separated)."), + ), + ) + .subcommand( + SubCommand::with_name("remove") + .about("Remove endpoints list.") + .arg(url_arg.clone()), + ) + .subcommand(SubCommand::with_name("reset").about("Reset the endpoints map.")) + .subcommand(SubCommand::with_name("print").about("Print current endpoints map.")); let config_cmd = SubCommand::with_name("config") .setting(AppSettings::AllowLeadingHyphen) @@ -682,53 +699,71 @@ async fn main_internal() -> Result <(), String> { .version(version_string) .author(author) .arg(address_arg.clone()) - .arg(Arg::with_name("TIMEOUT") - .long("--timeout") - .takes_value(true) - .help("Timeout in seconds (default value is 30).")); + .arg( + Arg::with_name("TIMEOUT") + .long("--timeout") + .takes_value(true) + .help("Timeout in seconds (default value is 30)."), + ); let query_raw = SubCommand::with_name("query-raw") .about("Executes a raw GraphQL query.") .version(version_string) .author(author) - .arg(Arg::with_name("COLLECTION") - .required(true) - .takes_value(true) - .help("Collection to query.")) - .arg(Arg::with_name("RESULT") - .required(true) - .takes_value(true) - .help("Result fields to print.")) - .arg(Arg::with_name("FILTER") - .long("--filter") - .takes_value(true) - .help("Query filter parameter.")) - .arg(Arg::with_name("LIMIT") - .long("--limit") - .takes_value(true) - .help("Query limit parameter.")) - .arg(Arg::with_name("ORDER") - .long("--order") - .takes_value(true) - .help("Query order parameter.")); + .arg( + Arg::with_name("COLLECTION") + .required(true) + .takes_value(true) + .help("Collection to query."), + ) + .arg( + Arg::with_name("RESULT") + .required(true) + .takes_value(true) + .help("Result fields to print."), + ) + .arg( + Arg::with_name("FILTER") + .long("--filter") + .takes_value(true) + .help("Query filter parameter."), + ) + .arg( + Arg::with_name("LIMIT") + .long("--limit") + .takes_value(true) + .help("Query limit parameter."), + ) + .arg( + Arg::with_name("ORDER") + .long("--order") + .takes_value(true) + .help("Query order parameter."), + ); let fee_cmd = SubCommand::with_name("fee") .about("Calculates fees for executing message or account storage fee.") - .subcommand(SubCommand::with_name("storage") - .setting(AppSettings::AllowLeadingHyphen) - .about("Gets account storage fee for specified period in nanotons.") - .version(version_string) - .author(author) - .arg(address_arg.clone()) - .arg(Arg::with_name("PERIOD") - .long("--period") - .short("-p") - .takes_value(true) - .help("Time period in seconds (default value is 1 year)."))) - .subcommand(deploy_cmd.clone() - .about("Executes deploy locally, calculates fees and prints table of fees in nanotons.")) - .subcommand(call_cmd.clone() - .about("Executes call locally, calculates fees and prints table of all fees in nanotons.")); + .subcommand( + SubCommand::with_name("storage") + .setting(AppSettings::AllowLeadingHyphen) + .about("Gets account storage fee for specified period in nanotons.") + .version(version_string) + .author(author) + .arg(address_arg.clone()) + .arg( + Arg::with_name("PERIOD") + .long("--period") + .short("-p") + .takes_value(true) + .help("Time period in seconds (default value is 1 year)."), + ), + ) + .subcommand(deploy_cmd.clone().about( + "Executes deploy locally, calculates fees and prints table of fees in nanotons.", + )) + .subcommand(call_cmd.clone().about( + "Executes call locally, calculates fees and prints table of all fees in nanotons.", + )); let proposal_cmd = SubCommand::with_name("proposal") .help("Proposal control commands.") @@ -781,24 +816,31 @@ async fn main_internal() -> Result <(), String> { .takes_value(true) .help("Proposal transaction id."))); - let getconfig_cmd = SubCommand::with_name("getconfig") - .about("Reads the global configuration parameter with defined index.") - .arg(Arg::with_name("INDEX") - .takes_value(true) - .help("Parameter index. If not specified, command will print all config parameters.")); + let getconfig_cmd = + SubCommand::with_name("getconfig") + .about("Reads the global configuration parameter with defined index.") + .arg(Arg::with_name("INDEX").takes_value(true).help( + "Parameter index. If not specified, command will print all config parameters.", + )); let update_config_param_cmd = SubCommand::with_name("update_config") .about("Generates message with update of config params.") .arg(abi_arg.clone()) - .arg(Arg::with_name("SEQNO") - .takes_value(true) - .help("Current seqno from config contract")) - .arg(Arg::with_name("CONFIG_MASTER_KEY_FILE") - .takes_value(true) - .help("path to config-master files")) - .arg(Arg::with_name("NEW_PARAM_FILE") - .takes_value(true) - .help("New config param value")); + .arg( + Arg::with_name("SEQNO") + .takes_value(true) + .help("Current seqno from config contract"), + ) + .arg( + Arg::with_name("CONFIG_MASTER_KEY_FILE") + .takes_value(true) + .help("path to config-master files"), + ) + .arg( + Arg::with_name("NEW_PARAM_FILE") + .takes_value(true) + .help("New config param value"), + ); let bcconfig_cmd = SubCommand::with_name("dump") .about("Commands to dump network entities.") @@ -826,41 +868,57 @@ async fn main_internal() -> Result <(), String> { let nodeid_cmd = SubCommand::with_name("nodeid") .about("Calculates node ID from the validator public key") - .arg(Arg::with_name("KEY") - .long("--pubkey") - .takes_value(true) - .help("Validator public key.")) - .arg(Arg::with_name("KEY_PAIR") - .long("--keypair") - .takes_value(true) - .help("Validator seed phrase or path to the file with keypair.")); + .arg( + Arg::with_name("KEY") + .long("--pubkey") + .takes_value(true) + .help("Validator public key."), + ) + .arg( + Arg::with_name("KEY_PAIR") + .long("--keypair") + .takes_value(true) + .help("Validator seed phrase or path to the file with keypair."), + ); let sendfile_cmd = SubCommand::with_name("sendfile") .about("Sends the boc file with an external inbound message to account.") - .arg(Arg::with_name("BOC") - .required(true) - .takes_value(true) - .help("Message boc file.")); + .arg( + Arg::with_name("BOC") + .required(true) + .takes_value(true) + .help("Message boc file."), + ); let fetch_block_cmd = SubCommand::with_name("fetch-block") .about("Fetches a block.") - .arg(Arg::with_name("BLOCKID") - .required(true) - .takes_value(true) - .help("Block ID.")) - .arg(Arg::with_name("OUTPUT") - .required(true) - .takes_value(true) - .help("Output file name")); + .arg( + Arg::with_name("BLOCKID") + .required(true) + .takes_value(true) + .help("Block ID."), + ) + .arg( + Arg::with_name("OUTPUT") + .required(true) + .takes_value(true) + .help("Output file name"), + ); let fetch_cmd = SubCommand::with_name("fetch") .about("Fetches account's zerostate and transactions.") .setting(AppSettings::AllowLeadingHyphen) - .arg(address_arg.clone().help("Account address to fetch zerostate and txns for.")) - .arg(Arg::with_name("OUTPUT") - .required(true) - .takes_value(true) - .help("Output file name")); + .arg( + address_arg + .clone() + .help("Account address to fetch zerostate and txns for."), + ) + .arg( + Arg::with_name("OUTPUT") + .required(true) + .takes_value(true) + .help("Output file name"), + ); let replay_cmd = SubCommand::with_name("replay") .about("Replays account's transactions starting from zerostate.") @@ -884,37 +942,44 @@ async fn main_internal() -> Result <(), String> { .short("-e") .conflicts_with("CONFIG_TXNS")); - let version = format!("{}\nCOMMIT_ID: {}\nBUILD_DATE: {}\nCOMMIT_DATE: {}\nGIT_BRANCH: {}", - env!("CARGO_PKG_VERSION"), - env!("BUILD_GIT_COMMIT"), - env!("BUILD_TIME"), - env!("BUILD_GIT_DATE"), - env!("BUILD_GIT_BRANCH")); + let version = format!( + "{}\nCOMMIT_ID: {}\nBUILD_DATE: {}\nCOMMIT_DATE: {}\nGIT_BRANCH: {}", + env!("CARGO_PKG_VERSION"), + env!("BUILD_GIT_COMMIT"), + env!("BUILD_TIME"), + env!("BUILD_GIT_DATE"), + env!("BUILD_GIT_BRANCH") + ); let matches = App::new("ever_cli") .version(&*version) .author(author) - .about("TONLabs console tool for TON") - .arg(Arg::with_name("NETWORK") - .help("Network to connect.") - .short("-u") - .long("--url") - .takes_value(true)) - .arg(Arg::with_name("CONFIG") - .help("Path to the ever-cli configuration file.") - .short("-c") - .long("--config") - .takes_value(true)) - .arg(Arg::with_name("JSON") - .help("Cli prints output in json format.") - .short("-j") - .long("--json")) + .about("EverX console tool for TON") + .arg( + Arg::with_name("NETWORK") + .help("Network to connect.") + .short("-u") + .long("--url") + .takes_value(true), + ) + .arg( + Arg::with_name("CONFIG") + .help("Path to the ever-cli configuration file.") + .short("-c") + .long("--config") + .takes_value(true), + ) + .arg( + Arg::with_name("JSON") + .help("Cli prints output in json format.") + .short("-j") + .long("--json"), + ) .subcommand(version_cmd) .subcommand(genphrase_cmd) .subcommand(genpubkey_cmd) .subcommand(getkeypair_cmd) .subcommand(genaddr_cmd) - .subcommand(deploy_cmd - .arg(alias_arg_long.clone())) + .subcommand(deploy_cmd.arg(alias_arg_long.clone())) .subcommand(deploy_message_cmd) .subcommand(call_cmd) .subcommand(send_cmd) @@ -948,33 +1013,39 @@ async fn main_internal() -> Result <(), String> { .subcommand(update_config_param_cmd) .setting(AppSettings::SubcommandRequired); - let matches = matches.get_matches_safe() - .map_err(|e| match e.kind { - clap::ErrorKind::VersionDisplayed => { println!(); exit(0); }, - clap::ErrorKind::HelpDisplayed => { println!("{}", e); exit(0); }, - _ => { - eprintln!("{}", e); - format!("{:#}", json!({"Error": e.message})) - } - })?; + let matches = matches.get_matches_safe().map_err(|e| match e.kind { + clap::ErrorKind::VersionDisplayed => { + println!(); + exit(0); + } + clap::ErrorKind::HelpDisplayed => { + println!("{}", e); + exit(0); + } + _ => { + eprintln!("{}", e); + format!("{:#}", json!({"Error": e.message})) + } + })?; let is_json = matches.is_present("JSON"); - command_parser(&matches, is_json).await - .map_err(|e| { - if e.is_empty() { - e - } else if is_json { - let e = serde_json::from_str(&e).unwrap_or(Value::String(e)); - format!("{:#}", json!({"Error": e})) - } else { - format!("Error: {e}") - } - }) + command_parser(&matches, is_json).await.map_err(|e| { + if e.is_empty() { + e + } else if is_json { + let e = serde_json::from_str(&e).unwrap_or(Value::String(e)); + format!("{:#}", json!({"Error": e})) + } else { + format!("Error: {e}") + } + }) } -async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), String> { - let config_file = matches.value_of("CONFIG").map(|v| v.to_string()) +async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result<(), String> { + let config_file = matches + .value_of("CONFIG") + .map(|v| v.to_string()) .or(env::var("EVER_CLI_CONFIG").ok()) .unwrap_or(default_config_name()); @@ -989,8 +1060,12 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), if let Some(url) = matches.value_of("NETWORK") { let resolved_url = resolve_net_name(url).unwrap_or(url.to_owned()); - let empty : Vec = Vec::new(); - config.endpoints = full_config.endpoints_map.get(&resolved_url).unwrap_or(&empty).clone(); + let empty: Vec = Vec::new(); + config.endpoints = full_config + .endpoints_map + .get(&resolved_url) + .unwrap_or(&empty) + .clone(); config.url = resolved_url; } @@ -1196,7 +1271,8 @@ async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), S is_internal: true, ..Default::default() }, - ).await + ) + .await .map_err(|e| format!("failed to encode body: {}", e)) .map(|r| r.body)?; @@ -1211,7 +1287,11 @@ async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), S Ok(()) } -async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Result<(), String> { +async fn call_command( + matches: &ArgMatches<'_>, + config: &Config, + call: CallType, +) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let method = matches.value_of("METHOD"); let params = matches.value_of("PARAMS"); @@ -1222,14 +1302,24 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) let abi = Some(abi_from_matches_or_config(matches, config)?); - let keys = matches.value_of("KEYS") + let keys = matches + .value_of("KEYS") .or(matches.value_of("SIGN")) .map(|s| s.to_string()) .or(config.keys_path.clone()); let params = Some(load_params(params.unwrap())?); if !config.is_json { - print_args!(address, method, params, abi, keys, signature_id, lifetime, output); + print_args!( + address, + method, + params, + abi, + keys, + signature_id, + lifetime, + output + ); } let address = load_ton_address(address.unwrap(), config)?; @@ -1244,27 +1334,35 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) ¶ms.unwrap(), keys, is_fee, - ).await - }, + ) + .await + } CallType::Msg => { - let lifetime = lifetime.map(|val| { + let lifetime = lifetime + .map(|val| { u32::from_str_radix(val, 10) .map_err(|e| format!("Failed to parse lifetime: {e}")) }) .transpose()? .unwrap_or(DEF_MSG_LIFETIME); - let timestamp = matches.value_of("TIMESTAMP").map(|val| { - u64::from_str_radix(val, 10) - .map_err(|e| format!("Failed to parse timestamp: {e}")) - }).transpose()?; - let signature_id = matches.value_of("SIGNATURE_ID").map(|val| { - if val == "online" { - return Ok::(SignatureIDType::Online); - } - let sid = i32::from_str_radix(val, 10) - .map_err(|e| format!("Failed to parse SIGNATURE_ID: {e}"))?; - Ok(SignatureIDType::Value(sid)) - }).transpose()?; + let timestamp = matches + .value_of("TIMESTAMP") + .map(|val| { + u64::from_str_radix(val, 10) + .map_err(|e| format!("Failed to parse timestamp: {e}")) + }) + .transpose()?; + let signature_id = matches + .value_of("SIGNATURE_ID") + .map(|val| { + if val == "online" { + return Ok::(SignatureIDType::Online); + } + let sid = i32::from_str_radix(val, 10) + .map_err(|e| format!("Failed to parse SIGNATURE_ID: {e}"))?; + Ok(SignatureIDType::Value(sid)) + }) + .transpose()?; generate_message( config, address.as_str(), @@ -1277,26 +1375,38 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) output, timestamp, signature_id, - ).await - }, + ) + .await + } } } async fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { let config = &full_config.config; - let method = Some(matches.value_of("METHOD").or(config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")?); + let method = Some( + matches + .value_of("METHOD") + .or(config.method.as_deref()) + .ok_or("Method is not defined. Supply it in the config file or command line.")?, + ); let contract_data = contract_data_from_matches_or_config_alias(matches, full_config)?; let params = unpack_alternative_params( matches, contract_data.abi.as_ref().unwrap(), method.unwrap(), - config - ).await?; + config, + ) + .await?; let params = Some(load_params(¶ms)?); if !config.is_json { - print_args!(contract_data.address, method, params, contract_data.abi, contract_data.keys); + print_args!( + contract_data.address, + method, + params, + contract_data.abi, + contract_data.keys + ); } let address = load_ton_address(contract_data.address.unwrap().as_str(), config)?; @@ -1309,37 +1419,41 @@ async fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Re ¶ms.unwrap(), contract_data.keys, false, - ).await + ) + .await } async fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let method = matches.value_of("METHOD"); let params = matches.values_of("PARAMS"); - let params = params.map(|values| { - json!(values.collect::>()).to_string() - }); + let params = params.map(|values| json!(values.collect::>()).to_string()); if !config.is_json { print_args!(address, method, params); } - let source_type = if matches.is_present("TVC") { - AccountSource::Tvc - } else if matches.is_present("BOC") { - AccountSource::Boc - } else { - AccountSource::Network - }; - let address = if source_type != AccountSource::Network { + let source_type = run::get_account_source(matches); + let address = if source_type != AccountSource::Network { address.unwrap().to_string() } else { load_ton_address(address.unwrap(), config)? }; let bc_config = matches.value_of("BCCONFIG"); - run_get_method(config, &address, method.unwrap(), params, source_type, bc_config).await + run_get_method( + config, + &address, + method.unwrap(), + params, + source_type, + bc_config, + ) + .await } - -async fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, deploy_type: DeployType) -> Result<(), String> { +async fn deploy_command( + matches: &ArgMatches<'_>, + full_config: &mut FullConfig, + deploy_type: DeployType, +) -> Result<(), String> { let config = &full_config.config; let tvc = matches.value_of("TVC"); let wc = wc_from_matches_or_config(matches, config)?; @@ -1347,57 +1461,90 @@ async fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, let output = matches.value_of("OUTPUT"); let abi = Some(abi_from_matches_or_config(matches, config)?); let signature_id = matches.value_of("SIGNATURE_ID"); - let keys = matches.value_of("KEYS") - .or(matches.value_of("SIGN")) - .map(|s| s.to_string()) - .or(config.keys_path.clone()); + let keys = matches + .value_of("KEYS") + .or(matches.value_of("SIGN")) + .map(|s| s.to_string()) + .or(config.keys_path.clone()); let alias = matches.value_of("ALIAS"); let method = matches.value_of("METHOD").unwrap_or("constructor"); - let params = Some(unpack_alternative_params( - matches, - abi.as_ref().unwrap(), - method, - config - ).await?); + let params = + Some(unpack_alternative_params(matches, abi.as_ref().unwrap(), method, config).await?); if !config.is_json { let opt_wc = Some(format!("{}", wc)); print_args!(tvc, params, abi, keys, signature_id, opt_wc, alias); } match deploy_type { - DeployType::Full => deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), - ¶ms.unwrap(), keys, wc, false, alias, - method.to_string()).await, + DeployType::Full => { + deploy_contract( + full_config, + tvc.unwrap(), + &abi.unwrap(), + ¶ms.unwrap(), + keys, + wc, + false, + alias, + method.to_string(), + ) + .await + } DeployType::MsgOnly => { - let signature_id = matches.value_of("SIGNATURE_ID").map(|val| { - if val == "online" { - return Ok::(SignatureIDType::Online); - } - let sid = i32::from_str_radix(val, 10) - .map_err(|e| format!("Failed to parse SIGNATURE_ID: {e}"))?; - Ok(SignatureIDType::Value(sid)) - }).transpose()?; - generate_deploy_message(tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, raw, - output, config, signature_id, method.to_string()).await - }, - DeployType::Fee => deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), - ¶ms.unwrap(), keys, wc, true, None, - method.to_string()).await, + let signature_id = matches + .value_of("SIGNATURE_ID") + .map(|val| { + if val == "online" { + return Ok::(SignatureIDType::Online); + } + let sid = i32::from_str_radix(val, 10) + .map_err(|e| format!("Failed to parse SIGNATURE_ID: {e}"))?; + Ok(SignatureIDType::Value(sid)) + }) + .transpose()?; + generate_deploy_message( + tvc.unwrap(), + &abi.unwrap(), + ¶ms.unwrap(), + keys, + wc, + raw, + output, + config, + signature_id, + method.to_string(), + ) + .await + } + DeployType::Fee => { + deploy_contract( + full_config, + tvc.unwrap(), + &abi.unwrap(), + ¶ms.unwrap(), + keys, + wc, + true, + None, + method.to_string(), + ) + .await + } } } -async fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) -> Result<(), String> { +async fn deployx_command( + matches: &ArgMatches<'_>, + full_config: &mut FullConfig, +) -> Result<(), String> { let config = &full_config.config; let tvc = matches.value_of("TVC"); let wc = wc_from_matches_or_config(matches, config)?; let method = matches.value_of("METHOD").unwrap_or("constructor"); let abi = Some(abi_from_matches_or_config(matches, config)?); - let params = Some(unpack_alternative_params( - matches, - abi.as_ref().unwrap(), - method, - config - ).await?); - let keys = matches.value_of("KEYS") + let params = + Some(unpack_alternative_params(matches, abi.as_ref().unwrap(), method, config).await?); + let keys = matches + .value_of("KEYS") .map(|s| s.to_string()) .or(config.keys_path.clone()); @@ -1406,11 +1553,25 @@ async fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) let opt_wc = Some(format!("{}", wc)); print_args!(tvc, params, abi, keys, opt_wc, alias); } - deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, - false, alias, method.to_string()).await + deploy_contract( + full_config, + tvc.unwrap(), + &abi.unwrap(), + ¶ms.unwrap(), + keys, + wc, + false, + alias, + method.to_string(), + ) + .await } -fn config_command(matches: &ArgMatches, mut full_config: FullConfig, is_json: bool) -> Result<(), String> { +fn config_command( + matches: &ArgMatches, + mut full_config: FullConfig, + is_json: bool, +) -> Result<(), String> { let mut result = Ok(()); if matches.is_present("GLOBAL") { full_config = FullConfig::from_file(&global_config_path()); @@ -1472,29 +1633,43 @@ async fn genaddr_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() let update_tvc = matches.is_present("SAVE"); let abi = match abi_from_matches_or_config(matches, config) { Ok(abi) => Some(abi), - Err(err) => { - match load_abi_from_tvc(tvc.unwrap()) { - Some(abi) => Some(abi), - None => return Err(err) - } - } + Err(err) => match load_abi_from_tvc(tvc.unwrap()) { + Some(abi) => Some(abi), + None => return Err(err), + }, }; let is_update_tvc = if update_tvc { Some("true") } else { None }; if !config.is_json { print_args!(tvc, abi, wc, keys, init_data, is_update_tvc); } - generate_address(config, tvc.unwrap(), &abi.unwrap(), wc, keys, new_keys, init_data, update_tvc).await + generate_address( + config, + tvc.unwrap(), + &abi.unwrap(), + wc, + keys, + new_keys, + init_data, + update_tvc, + ) + .await } async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - let addresses_list = matches.values_of("ADDRESS") + let addresses_list = matches + .values_of("ADDRESS") .map(|val| val.collect::>()) .or(config.addr.as_ref().map(|addr| vec![addr.as_str()])) - .ok_or("Address was not found. It must be specified as option or in the config file." - .to_string())?; - if addresses_list.len() > 1 && - (matches.is_present("DUMPTVC") || matches.is_present("DUMPTVC")) { - return Err("`DUMPTVC` and `DUMPBOC` options are not applicable to a list of addresses.".to_string()); + .ok_or( + "Address was not found. It must be specified as option or in the config file." + .to_string(), + )?; + if addresses_list.len() > 1 && (matches.is_present("DUMPTVC") || matches.is_present("DUMPTVC")) + { + return Err( + "`DUMPTVC` and `DUMPBOC` options are not applicable to a list of addresses." + .to_string(), + ); } let is_boc = matches.is_present("BOC"); let mut formatted_list = vec![]; @@ -1504,7 +1679,7 @@ async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() formatted_list.push(formatted); } else { if !std::path::Path::new(address).exists() { - return Err(format!("File {} doesn't exist.", address)); + return Err(format!("File {} doesn't exist.", address)); } formatted_list.push(address.to_string()); } @@ -1536,7 +1711,10 @@ async fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Res async fn account_wait_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS").unwrap(); let address = load_ton_address(address, config)?; - let timeout = matches.value_of("TIMEOUT").unwrap_or("30").parse::() + let timeout = matches + .value_of("TIMEOUT") + .unwrap_or("30") + .parse::() .map_err(|e| format!("failed to parse timeout: {}", e))?; wait_for_change(config, &address, timeout).await } @@ -1557,12 +1735,12 @@ async fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() print_args!(address, period); } let address = load_ton_address(address.unwrap(), config)?; - let period = period.map(|val| { - u32::from_str_radix(val, 10) - .map_err(|e| format!("failed to parse period: {}", e)) - }) - .transpose()? - .unwrap_or(DEF_STORAGE_PERIOD); + let period = period + .map(|val| { + u32::from_str_radix(val, 10).map_err(|e| format!("failed to parse period: {}", e)) + }) + .transpose()? + .unwrap_or(DEF_STORAGE_PERIOD); calc_storage(config, address.as_str(), period).await } @@ -1586,8 +1764,9 @@ async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> R dest.unwrap(), comment.unwrap(), lifetime, - offline - ).await + offline, + ) + .await } async fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1602,7 +1781,15 @@ async fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Res let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; - vote(config, address.as_str(), keys, id.unwrap(), lifetime, offline).await?; + vote( + config, + address.as_str(), + keys, + id.unwrap(), + lifetime, + offline, + ) + .await?; println!("{{}}"); Ok(()) } @@ -1633,7 +1820,14 @@ async fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Res if !config.is_json { print_args!(seqno, config_master, new_param); } - gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), config.is_json).await + gen_update_config_message( + abi, + seqno, + config_master.unwrap(), + new_param.unwrap(), + config.is_json, + ) + .await } async fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1651,13 +1845,14 @@ fn nodeid_command(matches: &ArgMatches, config: &Config) -> Result<(), String> { print_args!(key, keypair); } let nodeid = if let Some(key) = key { - let vec = hex::decode(key) - .map_err(|e| format!("failed to decode public key: {}", e))?; + let vec = hex::decode(key).map_err(|e| format!("failed to decode public key: {}", e))?; convert::nodeid_from_pubkey(&vec)? } else if let Some(pair) = keypair { let pair = crypto::load_keypair(pair)?; - convert::nodeid_from_pubkey(&hex::decode(pair.public.clone()) - .map_err(|e| format!("failed to decode public key: {}", e))?)? + convert::nodeid_from_pubkey( + &hex::decode(pair.public.clone()) + .map_err(|e| format!("failed to decode public key: {}", e))?, + )? } else { return Err("Either public key or key pair parameter should be provided".to_owned()); }; diff --git a/src/message.rs b/src/message.rs index 9cf84aef..9ab3dcbe 100644 --- a/src/message.rs +++ b/src/message.rs @@ -11,13 +11,15 @@ * limitations under the License. */ -use chrono::{Local, TimeZone}; -use serde_json::json; -use ever_client::abi::{Abi, CallSet, encode_message, FunctionHeader, ParamsOfEncodeMessage, Signer}; -use crate::SignatureIDType; use crate::config::Config; -use crate::helpers::{create_client_with_signature_id, load_abi, load_ton_address, now, TonClient}; use crate::crypto::load_keypair; +use crate::helpers::{create_client_with_signature_id, load_abi, load_ton_address, now, TonClient}; +use crate::SignatureIDType; +use chrono::{Local, TimeZone}; +use ever_client::abi::{ + encode_message, Abi, CallSet, FunctionHeader, ParamsOfEncodeMessage, Signer, +}; +use serde_json::json; pub struct EncodedMessage { pub message_id: String, @@ -41,9 +43,18 @@ pub async fn prepare_message( println!("Generating external inbound message..."); } - let msg_params = prepare_message_params(addr, abi, method, params, header.clone(), keys, signature_id)?; + let msg_params = prepare_message_params( + addr, + abi, + method, + params, + header.clone(), + keys, + signature_id, + )?; - let msg = encode_message(ton, msg_params).await + let msg = encode_message(ton, msg_params) + .await .map_err(|e| format!("failed to create inbound message: {}", e))?; Ok(EncodedMessage { @@ -54,7 +65,7 @@ pub async fn prepare_message( }) } -pub fn prepare_message_params ( +pub fn prepare_message_params( addr: &str, abi: Abi, method: &str, @@ -87,9 +98,12 @@ pub fn prepare_message_params ( }) } -pub fn print_encoded_message(msg: &EncodedMessage, is_json:bool) { +pub fn print_encoded_message(msg: &EncodedMessage, is_json: bool) { let expire = if msg.expire.is_some() { - let expire_at = Local.timestamp_opt(msg.expire.unwrap() as i64, 0).single().unwrap(); + let expire_at = Local + .timestamp_opt(msg.expire.unwrap() as i64, 0) + .single() + .unwrap(); expire_at.to_rfc2822() } else { "unknown".to_string() @@ -106,8 +120,7 @@ pub fn print_encoded_message(msg: &EncodedMessage, is_json:bool) { pub fn pack_message(msg: &EncodedMessage, method: &str, is_raw: bool) -> Result, String> { let res = if is_raw { - base64::decode(&msg.message) - .map_err(|e| format!("failed to decode message: {}", e))? + base64::decode(&msg.message).map_err(|e| format!("failed to decode message: {}", e))? } else { let json_msg = json!({ "msg": { @@ -126,31 +139,37 @@ pub fn pack_message(msg: &EncodedMessage, method: &str, is_raw: bool) -> Result< } pub fn unpack_message(str_msg: &str) -> Result<(EncodedMessage, String), String> { - let bytes = hex::decode(str_msg) - .map_err(|e| format!("couldn't unpack message: {}", e))?; + let bytes = hex::decode(str_msg).map_err(|e| format!("couldn't unpack message: {}", e))?; - let str_msg = std::str::from_utf8(&bytes) - .map_err(|e| format!("message is corrupted: {}", e))?; + let str_msg = + std::str::from_utf8(&bytes).map_err(|e| format!("message is corrupted: {}", e))?; - let json_msg: serde_json::Value = serde_json::from_str(str_msg) - .map_err(|e| format!("couldn't decode message: {}", e))?; + let json_msg: serde_json::Value = + serde_json::from_str(str_msg).map_err(|e| format!("couldn't decode message: {}", e))?; - let method = json_msg["method"].as_str() + let method = json_msg["method"] + .as_str() .ok_or(r#"couldn't find "method" key in message"#)? .to_owned(); - let message_id = json_msg["msg"]["message_id"].as_str() + let message_id = json_msg["msg"]["message_id"] + .as_str() .ok_or(r#"couldn't find "message_id" key in message"#)? .to_owned(); - let message = json_msg["msg"]["message"].as_str() + let message = json_msg["msg"]["message"] + .as_str() .ok_or(r#"couldn't find "message" key in message"#)? .to_owned(); let expire = json_msg["msg"]["expire"].as_u64().map(|x| x as u32); - let address = json_msg["msg"]["address"].as_str() + let address = json_msg["msg"]["address"] + .as_str() .ok_or(r#"couldn't find "address" key in message"#)? .to_owned(); let msg = EncodedMessage { - message_id, message, expire, address + message_id, + message, + expire, + address, }; Ok((msg, method)) } @@ -166,13 +185,12 @@ pub async fn generate_message( is_raw: bool, output: Option<&str>, timestamp: Option, - signature_id: Option + signature_id: Option, ) -> Result<(), String> { + let (client, signature_id) = create_client_with_signature_id(config, signature_id)?; - let (client,signature_id) = create_client_with_signature_id(config,signature_id)?; - - let ton_addr = load_ton_address(addr, config) - .map_err(|e| format!("failed to parse address: {}", e))?; + let ton_addr = + load_ton_address(addr, config).map_err(|e| format!("failed to parse address: {}", e))?; let abi = load_abi(abi, config).await?; @@ -193,7 +211,8 @@ pub async fn generate_message( keys, config.is_json, signature_id, - ).await?; + ) + .await?; display_generated_message(&msg, method, is_raw, output, config.is_json)?; diff --git a/src/multisig.rs b/src/multisig.rs index 34218230..018b77db 100644 --- a/src/multisig.rs +++ b/src/multisig.rs @@ -20,10 +20,10 @@ use crate::helpers::{ create_client_local, create_client_verbose, load_file_with_url, load_ton_address, now_ms, }; use clap::{App, AppSettings, Arg, ArgMatches, SubCommand}; -use serde_json::json; use ever_client::abi::{ encode_message_body, Abi, AbiContract, AbiParam, CallSet, ParamsOfEncodeMessageBody, }; +use serde_json::json; const SAFEMULTISIG_LINK: &str = "https://github.com/everx-labs/ton-labs-contracts/blob/master/solidity/safemultisig/SafeMultisigWallet.tvc?raw=true"; const SETCODEMULTISIG_LINK: &str = "https://github.com/everx-labs/ton-labs-contracts/blob/master/solidity/setcodemultisig/SetcodeMultisigWallet.tvc?raw=true"; @@ -328,7 +328,7 @@ impl MultisigArgs { name: "stateInit".to_owned(), param_type: "optional(cell)".to_owned(), components: vec![], - init: false + init: false, }); } if let Some(f) = abi.functions.iter_mut().find(|e| &e.name == "constructor") { @@ -336,7 +336,7 @@ impl MultisigArgs { name: "lifetime".to_owned(), param_type: "uint32".to_owned(), components: vec![], - init: false + init: false, }); } } diff --git a/src/replay.rs b/src/replay.rs index ebda27da..eb9dd381 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -11,56 +11,73 @@ * limitations under the License. */ +use anyhow::format_err; +use clap::ArgMatches; +use serde::{Deserialize, Serialize}; +use serde_json::Value; use std::{ fs::File, - io::{self, BufRead, Lines, Write, Read}, + io::{self, BufRead, Lines, Read, Write}, process::exit, - sync::{Arc, atomic::AtomicU64} + sync::{atomic::AtomicU64, Arc}, }; -use clap::ArgMatches; -use anyhow::format_err; -use serde::{Deserialize, Serialize}; -use serde_json::Value; -use ever_block::{Account, ConfigParams, Deserializable, Message, Serializable, Transaction, TransactionDescr, Block, HashmapAugType, CommonMessage}; +use ever_block::{write_boc, BuilderData, SliceData, UInt256}; +use ever_block::{ + Account, Block, CommonMessage, ConfigParams, Deserializable, HashmapAugType, Message, + Serializable, Transaction, TransactionDescr, +}; use ever_client::net::{ - AggregationFn, FieldAggregation, OrderBy, ParamsOfAggregateCollection, - ParamsOfQueryCollection, SortDirection, aggregate_collection, query_collection, + aggregate_collection, query_collection, AggregationFn, FieldAggregation, OrderBy, + ParamsOfAggregateCollection, ParamsOfQueryCollection, SortDirection, +}; +use ever_executor::{ + BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, TickTockTransactionExecutor, + TransactionExecutor, }; -use ever_executor::{BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, - TickTockTransactionExecutor, TransactionExecutor}; -use ever_block::{BuilderData, SliceData, UInt256, write_boc}; -use crate::{config::Config, helpers::CallbackType}; use crate::helpers::{create_client, get_blockchain_config}; +use crate::{config::Config, helpers::CallbackType}; -pub static CONFIG_ADDR: &str = "-1:5555555555555555555555555555555555555555555555555555555555555555"; +pub static CONFIG_ADDR: &str = + "-1:5555555555555555555555555555555555555555555555555555555555555555"; -pub const DUMP_NONE: u8 = 0x00; -pub const DUMP_ACCOUNT: u8 = 0x01; -pub const DUMP_CONFIG: u8 = 0x02; +pub const DUMP_NONE: u8 = 0x00; +pub const DUMP_ACCOUNT: u8 = 0x01; +pub const DUMP_CONFIG: u8 = 0x02; pub const DUMP_EXECUTOR_CONFIG: u8 = 0x04; -pub const DUMP_ALL: u8 = 0xFF; +pub const DUMP_ALL: u8 = 0xFF; pub fn construct_blockchain_config(config_account: &Account) -> Result { - construct_blockchain_config_err(config_account).map_err(|e| format!("Failed to construct config: {}", e)) + construct_blockchain_config_err(config_account) + .map_err(|e| format!("Failed to construct config: {}", e)) } -fn construct_blockchain_config_err(config_account: &Account) -> ever_block::Result { +fn construct_blockchain_config_err( + config_account: &Account, +) -> ever_block::Result { let config_cell = config_account - .get_data().ok_or(format_err!("Failed to get account's data"))? - .reference(0).ok(); - let config_params = ConfigParams::with_address_and_params( - UInt256::with_array([0x55; 32]), config_cell); + .get_data() + .ok_or(format_err!("Failed to get account's data"))? + .reference(0) + .ok(); + let config_params = + ConfigParams::with_address_and_params(UInt256::with_array([0x55; 32]), config_cell); BlockchainConfig::with_config(config_params) } -pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bound: Option, rewrite_file: bool) -> Result<(), String> { +pub async fn fetch( + config: &Config, + account_address: &str, + filename: &str, + lt_bound: Option, + rewrite_file: bool, +) -> Result<(), String> { if !rewrite_file && std::path::Path::new(filename).exists() { if !config.is_json { println!("File exists"); } - return Ok(()) + return Ok(()); } let context = create_client(config)?; @@ -85,23 +102,28 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo ParamsOfAggregateCollection { collection: "transactions".to_owned(), filter: Some(filter), - fields: Some(vec![ - FieldAggregation { - field: "fn".to_owned(), - aggregation_fn: AggregationFn::COUNT - }, - ]), + fields: Some(vec![FieldAggregation { + field: "fn".to_owned(), + aggregation_fn: AggregationFn::COUNT, + }]), }, ) .await .map_err(|e| format!("Failed to fetch txns count: {}", e))?; let tr_count = u64::from_str_radix( - tr_count.values.as_array().ok_or("Failed to parse value".to_string())?.first().ok_or("Failed to parse value".to_string())? - .as_str().ok_or("Failed to parse value".to_string())?, 10) - .map_err(|e| format!("Failed to parse decimal int: {}", e))?; + tr_count + .values + .as_array() + .ok_or("Failed to parse value".to_string())? + .first() + .ok_or("Failed to parse value".to_string())? + .as_str() + .ok_or("Failed to parse value".to_string())?, + 10, + ) + .map_err(|e| format!("Failed to parse decimal int: {}", e))?; - let file = File::create(filename) - .map_err(|e| format!("Failed to create file: {}", e))?; + let file = File::create(filename).map_err(|e| format!("Failed to create file: {}", e))?; let mut writer = std::io::LineWriter::new(file); let zerostates = query_collection( @@ -119,11 +141,15 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo let mut zerostate_found = false; if let Ok(zerostates) = zerostates { let result = &zerostates.result.to_vec(); - let accounts = result[0]["accounts"].as_array().ok_or("Failed to parse value".to_string())?; + let accounts = result[0]["accounts"] + .as_array() + .ok_or("Failed to parse value".to_string())?; for account in accounts { if account["id"] == account_address { let data = format!("{}\n", account); - writer.write_all(data.as_bytes()).map_err(|e| format!("Failed to write to file: {}", e))?; + writer + .write_all(data.as_bytes()) + .map_err(|e| format!("Failed to write to file: {}", e))?; zerostate_found = true; break; } @@ -132,15 +158,25 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo if !zerostate_found { if !config.is_json { - println!("account {}: zerostate not found, writing out default initial state", account_address); + println!( + "account {}: zerostate not found, writing out default initial state", + account_address + ); } - let data = format!("{{\"id\":\"{}\",\"boc\":\"{}\"}}\n", - account_address, base64::encode(Account::default().write_to_bytes() - .map_err(|e| format!("failed to serialize account: {}", e))?)); - writer.write_all(data.as_bytes()).map_err(|e| format!("Failed to write to file: {}", e))?; + let data = format!( + "{{\"id\":\"{}\",\"boc\":\"{}\"}}\n", + account_address, + base64::encode( + Account::default() + .write_to_bytes() + .map_err(|e| format!("failed to serialize account: {}", e))? + ) + ); + writer + .write_all(data.as_bytes()) + .map_err(|e| format!("Failed to write to file: {}", e))?; } - let retry_strategy = - tokio_retry::strategy::ExponentialBackoff::from_millis(10).take(5); + let retry_strategy = tokio_retry::strategy::ExponentialBackoff::from_millis(10).take(5); let mut count = 0u64; let pb = indicatif::ProgressBar::new(tr_count); @@ -170,15 +206,17 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo filter: Some(filter), result: "id lt block { start_lt } boc".to_owned(), limit: None, - order: Some(vec![ - OrderBy { path: "lt".to_owned(), direction: SortDirection::ASC } - ]), + order: Some(vec![OrderBy { + path: "lt".to_owned(), + direction: SortDirection::ASC, + }]), }, ); query.await }; - let transactions = tokio_retry::Retry::spawn(retry_strategy.clone(), action).await + let transactions = tokio_retry::Retry::spawn(retry_strategy.clone(), action) + .await .map_err(|e| format!("Failed to fetch transactions: {}", e))?; if transactions.result.is_empty() { @@ -187,11 +225,19 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo for txn in &transactions.result { let data = format!("{}\n", txn); - writer.write_all(data.as_bytes()).map_err(|e| format!("Failed to write to file: {}", e))?; + writer + .write_all(data.as_bytes()) + .map_err(|e| format!("Failed to write to file: {}", e))?; } - let last = transactions.result.last().ok_or("Failed to get last txn".to_string())?; - lt = last["lt"].as_str().ok_or("Failed to parse value".to_string())?.to_owned(); + let last = transactions + .result + .last() + .ok_or("Failed to get last txn".to_string())?; + lt = last["lt"] + .as_str() + .ok_or("Failed to parse value".to_string())? + .to_owned(); count += transactions.result.len() as u64; pb.set_position(std::cmp::min(count, tr_count)); } @@ -217,18 +263,19 @@ impl Default for State { account: Account::default(), account_addr: "".to_string(), tr: None, - lines: None + lines: None, } } } impl State { fn new(filename: &str) -> Result { - let file = File::open(filename) - .map_err(|e| format!("failed to open file {}: {}", filename, e))?; + let file = + File::open(filename).map_err(|e| format!("failed to open file {}: {}", filename, e))?; let mut lines = io::BufReader::new(file).lines(); - let first_line = lines.next() + let first_line = lines + .next() .ok_or("file is empty")? .map_err(|e| format!("failed to read first line: {}", e))?; let value = serde_json::from_str::(first_line.as_str()) @@ -236,10 +283,18 @@ impl State { let boc = value["boc"].as_str().ok_or("failed to decode boc")?; let account = Account::construct_from_base64(boc) .map_err(|e| format!("failed to load account from the boc: {}", e))?; - let account_addr = String::from(value["id"].as_str() - .ok_or("failed to load account address")?); - - Ok(Self { account, account_addr, tr: None, lines: Some(lines) }) + let account_addr = String::from( + value["id"] + .as_str() + .ok_or("failed to load account address")?, + ); + + Ok(Self { + account, + account_addr, + tr: None, + lines: Some(lines), + }) } pub fn next_transaction(&mut self) -> Option<()> { @@ -250,7 +305,8 @@ impl State { let id = String::from(value["id"].as_str()?); let boc = value["boc"].as_str()?; let tr = Transaction::construct_from_base64(boc).ok()?; - let block_lt = u64::from_str_radix(&value["block"]["start_lt"].as_str()?[2..], 16).ok()?; + let block_lt = + u64::from_str_radix(&value["block"]["start_lt"].as_str()?[2..], 16).ok()?; self.tr = Some(TransactionExt { id, block_lt, tr }); } None => { @@ -308,7 +364,10 @@ pub async fn replay( let config_account = config_state.account.clone(); let state = choose(&mut account_state, &mut config_state); - let tr = state.tr.as_ref().ok_or("failed to obtain state transaction")?; + let tr = state + .tr + .as_ref() + .ok_or("failed to obtain state transaction")?; if iterate_config && (cur_block_lt == 0 || cur_block_lt != tr.block_lt) { assert!(tr.block_lt > cur_block_lt); @@ -316,24 +375,36 @@ pub async fn replay( config = construct_blockchain_config(&config_account)?; } - let mut account_root = state.account.serialize() + let mut account_root = state + .account + .serialize() .map_err(|e| format!("Failed to serialize: {}", e))?; let account_old_hash_local = account_root.repr_hash(); - let account_old_hash_remote = tr.tr.read_state_update() - .map_err(|e| format!("failed to read state update: {}", e))?.old_hash; + let account_old_hash_remote = tr + .tr + .read_state_update() + .map_err(|e| format!("failed to read state update: {}", e))? + .old_hash; if account_old_hash_local != account_old_hash_remote { if !cli_config.is_json { - println!("FAILURE\nOld hashes mismatch:\nremote {}\nlocal {}", - account_old_hash_remote.to_hex_string(), - account_old_hash_local.to_hex_string()); + println!( + "FAILURE\nOld hashes mismatch:\nremote {}\nlocal {}", + account_old_hash_remote.to_hex_string(), + account_old_hash_local.to_hex_string() + ); } exit(1); } if tr.id == txnid { if dump_mask & DUMP_ACCOUNT != 0 { - let path = format!("{}-{}.boc", account_address.split(':').last().unwrap_or(""), txnid); - account_root.write_to_file(&path) + let path = format!( + "{}-{}.boc", + account_address.split(':').last().unwrap_or(""), + txnid + ); + account_root + .write_to_file(&path) .map_err(|e| format!("Failed to write account: {}", e))?; if !cli_config.is_json { println!("Contract account was dumped to {}", path); @@ -341,9 +412,11 @@ pub async fn replay( } if dump_mask & DUMP_CONFIG != 0 { let path = format!("config-{}.boc", txnid); - let account = config_account.serialize() + let account = config_account + .serialize() .map_err(|e| format!("Failed to serialize config account: {}", e))?; - account.write_to_file(&path) + account + .write_to_file(&path) .map_err(|e| format!("Failed to write config account: {}", e))?; if !cli_config.is_json { println!("Config account was dumped to {}", path); @@ -351,20 +424,27 @@ pub async fn replay( } if dump_mask & DUMP_EXECUTOR_CONFIG != 0 { // config.boc suitable for creating ever-executor tests - let cell = config_account.get_data() + let cell = config_account + .get_data() .ok_or("Failed to get config data")?; let mut config_data = SliceData::load_cell(cell) .map_err(|e| format!("Failed to load config data cell: {}", e))?; let mut cfg = BuilderData::default(); - cfg.append_raw(&config_data.get_next_bytes(32) - .map_err(|e| format!("Failed to read config data: {}", e))?, 256) - .map_err(|e| format!("Failed to append config data: {}", e))?; - let cell = config_data.reference(0) + cfg.append_raw( + &config_data + .get_next_bytes(32) + .map_err(|e| format!("Failed to read config data: {}", e))?, + 256, + ) + .map_err(|e| format!("Failed to append config data: {}", e))?; + let cell = config_data + .reference(0) .map_err(|e| format!("Failed to get config zero reference: {}", e))?; cfg.checked_append_reference(cell) .map_err(|e| format!("Failed to append config reference: {}", e))?; let path = format!("config-{}-test.boc", txnid); - cfg.into_cell().map_err(|e| format!("Failed to finalize builder: {}", e))? + cfg.into_cell() + .map_err(|e| format!("Failed to finalize builder: {}", e))? .write_to_file(&path) .map_err(|e| format!("Failed to write config data: {}", e))?; if !cli_config.is_json { @@ -374,8 +454,14 @@ pub async fn replay( if trace_callback.is_some() { init_trace_last_logger()?; let executor = Box::new(OrdinaryTransactionExecutor::new(config.clone())); - let msg = tr.tr.in_msg_cell().map(|c| Message::construct_from_cell(c) - .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; + let msg = tr + .tr + .in_msg_cell() + .map(|c| { + Message::construct_from_cell(c) + .map_err(|e| format!("failed to construct message: {}", e)) + }) + .transpose()?; let params = ExecuteParams { block_unixtime: tr.tr.now(), block_lt: tr.tr.logical_time(), @@ -384,29 +470,40 @@ pub async fn replay( ..ExecuteParams::default() }; let common_message: Option = msg.map(CommonMessage::Std); - let tr = executor.execute_with_libs_and_params( - common_message.as_ref(), - &mut account_root, - params).map_err(|e| format!("Failed to execute txn: {}", e))?; + let tr = executor + .execute_with_libs_and_params( + common_message.as_ref(), + &mut account_root, + params, + ) + .map_err(|e| format!("Failed to execute txn: {}", e))?; return Ok(tr); } } - let executor: Box = - match tr.tr.read_description() - .map_err(|e| format!("failed to read transaction: {}", e))? { - TransactionDescr::TickTock(desc) => { - Box::new(TickTockTransactionExecutor::new(config.clone(), desc.tt)) - } - TransactionDescr::Ordinary(_) => { - Box::new(OrdinaryTransactionExecutor::new(config.clone())) - } - _ => { - panic!("Unknown transaction type"); - } - }; + let executor: Box = match tr + .tr + .read_description() + .map_err(|e| format!("failed to read transaction: {}", e))? + { + TransactionDescr::TickTock(desc) => { + Box::new(TickTockTransactionExecutor::new(config.clone(), desc.tt)) + } + TransactionDescr::Ordinary(_) => { + Box::new(OrdinaryTransactionExecutor::new(config.clone())) + } + _ => { + panic!("Unknown transaction type"); + } + }; - let msg = tr.tr.in_msg_cell().map(|c| Message::construct_from_cell(c) - .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; + let msg = tr + .tr + .in_msg_cell() + .map(|c| { + Message::construct_from_cell(c) + .map_err(|e| format!("failed to construct message: {}", e)) + }) + .transpose()?; let params = ExecuteParams { block_unixtime: tr.tr.now(), @@ -415,28 +512,36 @@ pub async fn replay( ..ExecuteParams::default() }; let common_message: Option = msg.map(CommonMessage::Std); - let tr_local = executor.execute_with_libs_and_params( - common_message.as_ref(), - &mut account_root, - params).map_err(|e| format!("Failed to execute txn: {}", e))?; + let tr_local = executor + .execute_with_libs_and_params(common_message.as_ref(), &mut account_root, params) + .map_err(|e| format!("Failed to execute txn: {}", e))?; state.account = Account::construct_from_cell(account_root.clone()) .map_err(|e| format!("Failed to construct account: {}", e))?; - let account_new_hash_local = tr_local.read_state_update() + let account_new_hash_local = tr_local + .read_state_update() .map_err(|e| format!("failed to read state update: {}", e))? .new_hash; - let account_new_hash_remote = tr.tr.read_state_update() + let account_new_hash_remote = tr + .tr + .read_state_update() .map_err(|e| format!("failed to read state update: {}", e))? .new_hash; if account_new_hash_local != account_new_hash_remote { if !cli_config.is_json { - println!("FAILURE\nNew hashes mismatch:\nremote {}\nlocal {}\nTR id: {}", - account_new_hash_remote.to_hex_string(), - account_new_hash_local.to_hex_string(), tr.id); + println!( + "FAILURE\nNew hashes mismatch:\nremote {}\nlocal {}\nTR id: {}", + account_new_hash_remote.to_hex_string(), + account_new_hash_local.to_hex_string(), + tr.id + ); } - let local_desc = tr_local.read_description() + let local_desc = tr_local + .read_description() .map_err(|e| format!("failed to read description: {}", e))?; - let remote_desc = tr.tr.read_description() + let remote_desc = tr + .tr + .read_description() .map_err(|e| format!("failed to read description: {}", e))?; assert_eq!(remote_desc, local_desc); exit(2); @@ -456,8 +561,8 @@ pub async fn replay( } pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> ever_block::Status { - let context = create_client(config) - .map_err(|e| format_err!(format!("Failed to create ctx: {}", e)))?; + let context = + create_client(config).map_err(|e| format_err!(format!("Failed to create ctx: {}", e)))?; let block = query_collection( context.clone(), @@ -472,18 +577,25 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve limit: None, order: None, }, - ).await?; + ) + .await?; if block.result.len() != 1 { - return Err(format_err!("Failed to fetch the block")) + return Err(format_err!("Failed to fetch the block")); } - let mut accounts = vec!(); + let mut accounts = vec![]; - let wid = block.result.first().unwrap()["workchain_id"].as_i64().unwrap(); - let end_lt = block.result.first().unwrap()["end_lt"].as_str().unwrap().trim_start_matches("0x"); + let wid = block.result.first().unwrap()["workchain_id"] + .as_i64() + .unwrap(); + let end_lt = block.result.first().unwrap()["end_lt"] + .as_str() + .unwrap() + .trim_start_matches("0x"); let end_lt = u64::from_str_radix(end_lt, 16).unwrap(); - let block = Block::construct_from_base64(block.result.first().unwrap()["boc"].as_str().unwrap())?; + let block = + Block::construct_from_base64(block.result.first().unwrap()["boc"].as_str().unwrap())?; let extra = block.read_extra()?; let account_blocks = extra.read_account_blocks()?; @@ -491,7 +603,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve let mut slice = account_block.account_id().clone(); let id = UInt256::construct_from(&mut slice)?; let account_name = format!("{}:{}", wid, id.to_hex_string()); - let mut txns = vec!(); + let mut txns = vec![]; account_block.transaction_iterate(|tr| { let cell = tr.serialize()?; let bytes = write_boc(&cell)?; @@ -503,24 +615,34 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve })?; if accounts.is_empty() { - return Err(format_err!("The block is empty")) + return Err(format_err!("The block is empty")); } for (account, _) in &accounts { println!("Fetching transactions of {}", account); - fetch(config, + fetch( + config, account.as_str(), format!("{}.txns", account).as_str(), - Some(end_lt), false).await.map_err(|e| format_err!(e))?; + Some(end_lt), + false, + ) + .await + .map_err(|e| format_err!(e))?; } let config_txns_path = format!("{}.txns", CONFIG_ADDR); if !std::path::Path::new(config_txns_path.as_str()).exists() { println!("Fetching transactions of {}", CONFIG_ADDR); - fetch(config, + fetch( + config, CONFIG_ADDR, config_txns_path.as_str(), - Some(end_lt), false).await.map_err(|e| format_err!(e))?; + Some(end_lt), + false, + ) + .await + .map_err(|e| format_err!(e))?; } let acc = accounts[0].0.as_str(); @@ -529,34 +651,50 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve let config_path = format!("config-{}.boc", txnid); if !std::path::Path::new(config_path.as_str()).exists() { println!("Computing config: replaying {} up to {}", acc, txnid); - replay(format!("{}.txns", acc).as_str(),config_txns_path.as_str(), - txnid, None, || Ok(()), DUMP_CONFIG, - config, None - ).await.map_err(|e| format_err!(e))?; + replay( + format!("{}.txns", acc).as_str(), + config_txns_path.as_str(), + txnid, + None, + || Ok(()), + DUMP_CONFIG, + config, + None, + ) + .await + .map_err(|e| format_err!(e))?; } else { println!("Using pre-computed config {}", config_path); } println!("Pre-replaying block accounts"); - let tasks: Vec<_> = accounts.iter().map(|(account, txns)| { - let account_filename = account.split(':').last().unwrap_or("").to_owned(); - let _config = config.clone().to_owned(); - let txnid = txns[0].0.clone(); - tokio::spawn(async move { - if !std::path::Path::new(format!("{}-{}.boc", account_filename, txnid).as_str()).exists() { - replay( - format!("{}.txns", account_filename).as_str(), - format!("{}.txns", CONFIG_ADDR).as_str(), - &txnid, - None, - || Ok(()), - DUMP_ACCOUNT, - &_config, - None, - ).await.map_err(|e| format_err!(e)).unwrap(); - } + let tasks: Vec<_> = accounts + .iter() + .map(|(account, txns)| { + let account_filename = account.split(':').last().unwrap_or("").to_owned(); + let _config = config.clone().to_owned(); + let txnid = txns[0].0.clone(); + tokio::spawn(async move { + if !std::path::Path::new(format!("{}-{}.boc", account_filename, txnid).as_str()) + .exists() + { + replay( + format!("{}.txns", account_filename).as_str(), + format!("{}.txns", CONFIG_ADDR).as_str(), + &txnid, + None, + || Ok(()), + DUMP_ACCOUNT, + &_config, + None, + ) + .await + .map_err(|e| format_err!(e)) + .unwrap(); + } + }) }) - }).collect(); + .collect(); futures::future::join_all(tasks).await; println!("Writing block"); @@ -567,7 +705,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve let mut block = BlockDescr { id: block_id.to_string(), config_boc: base64::encode(&config_data), - accounts: vec!(), + accounts: vec![], }; for (account, txns) in &accounts { @@ -575,7 +713,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> eve let mut account_file = File::open(format!("{}-{}.boc", account, txnid))?; let mut account_data = Vec::new(); account_file.read_to_end(&mut account_data)?; - let mut transactions = vec!(); + let mut transactions = vec![]; for (_, txn) in txns { transactions.push(txn.clone()); } @@ -605,20 +743,25 @@ struct BlockAccountDescr { } pub async fn fetch_block_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - fetch_block(config, + fetch_block( + config, m.value_of("BLOCKID").ok_or("Missing block id")?, - m.value_of("OUTPUT").ok_or("Missing output filename")? - ).await.map_err(|e| e.to_string())?; + m.value_of("OUTPUT").ok_or("Missing output filename")?, + ) + .await + .map_err(|e| e.to_string())?; Ok(()) } pub async fn fetch_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - fetch(config, + fetch( + config, m.value_of("ADDRESS").ok_or("Missing account address")?, m.value_of("OUTPUT").ok_or("Missing output filename")?, None, - true - ).await?; + true, + ) + .await?; if config.is_json { println!("{{}}"); } else { @@ -631,11 +774,23 @@ pub async fn replay_command(m: &ArgMatches<'_>, cli_config: &Config) -> Result<( let (config_txns, bc_config) = if m.is_present("DEFAULT_CONFIG") { ("", Some(get_blockchain_config(cli_config, None).await?)) } else { - (m.value_of("CONFIG_TXNS").ok_or("Missing config txns filename")?, None) + ( + m.value_of("CONFIG_TXNS") + .ok_or("Missing config txns filename")?, + None, + ) }; - let _ = replay(m.value_of("INPUT_TXNS").ok_or("Missing input txns filename")?, - config_txns, m.value_of("TXNID").ok_or("Missing final txn id")?, - None, ||{Ok(())}, DUMP_ALL, cli_config, bc_config - ).await?; + let _ = replay( + m.value_of("INPUT_TXNS") + .ok_or("Missing input txns filename")?, + config_txns, + m.value_of("TXNID").ok_or("Missing final txn id")?, + None, + || Ok(()), + DUMP_ALL, + cli_config, + bc_config, + ) + .await?; Ok(()) } diff --git a/src/run.rs b/src/run.rs index d579ce07..9d3b0838 100644 --- a/src/run.rs +++ b/src/run.rs @@ -11,44 +11,81 @@ * limitations under the License. */ -use clap::ArgMatches; -use serde_json::{Map, Value}; -use ever_block::{Account, Deserializable, Serializable}; -use ever_client::abi::FunctionHeader; -use ever_client::tvm::{ExecutionOptions, ParamsOfRunGet, ParamsOfRunTvm, run_get, run_tvm}; -use crate::config::{Config, FullConfig}; use crate::call::print_json_result; -use crate::debug::{debug_error, DebugParams, init_debug_logger}; -use crate::helpers::{create_client, now, now_ms, TonClient, - contract_data_from_matches_or_config_alias, abi_from_matches_or_config, - AccountSource, create_client_local, create_client_verbose, load_abi, - load_account, load_params, unpack_alternative_params, get_blockchain_config}; +use crate::config::{Config, FullConfig}; +use crate::debug::{debug_error, init_debug_logger, DebugParams}; +use crate::helpers::{ + abi_from_matches_or_config, contract_data_from_matches_or_config_alias, create_client, + create_client_local, create_client_verbose, get_blockchain_config, load_abi, load_account, + load_params, now, now_ms, unpack_alternative_params, AccountSource, TonClient, +}; use crate::message::prepare_message; use crate::replay::construct_blockchain_config; +use clap::ArgMatches; +use ever_abi::token::Tokenizer; +use ever_abi::Function; +use ever_block::{Account, Deserializable, Serializable}; +use ever_client::abi::FunctionHeader; +use ever_client::abi::{Abi, StackItemToJson, TokenValueToStackItem}; +use ever_client::tvm::{ + run_get, run_solidity_getter, run_tvm, ExecutionOptions, ParamsOfRunGet, ParamsOfRunTvm, +}; +use ever_vm::stack::integer::IntegerData; +use ever_vm::stack::StackItem; +use serde_json::{Map, Value}; -pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_alternative: bool) -> Result<(), String> { - let config = &full_config.config; - let (address, abi_path) = if is_alternative { +fn get_address_and_abi_path( + matches: &ArgMatches<'_>, + full_config: &FullConfig, + is_alternative: bool, +) -> Result<(String, String), String> { + Ok(if is_alternative { let contract_data = contract_data_from_matches_or_config_alias(matches, full_config)?; (contract_data.address.unwrap(), contract_data.abi.unwrap()) } else { - (matches.value_of("ADDRESS").unwrap().to_string(), - abi_from_matches_or_config(matches, config)?) - }; - let account_source = if matches.is_present("TVC") { + ( + matches.value_of("ADDRESS").unwrap().to_string(), + abi_from_matches_or_config(matches, &full_config.config)?, + ) + }) +} + +fn get_method( + matches: &ArgMatches<'_>, + conf: &Config, + is_alternative: bool, +) -> Result { + Ok(if is_alternative { + matches + .value_of("METHOD") + .or(conf.method.as_deref()) + .ok_or("Method is not defined. Supply it in the config file or command line.")? + .to_string() + } else { + matches.value_of("METHOD").unwrap().to_string() + }) +} + +pub fn get_account_source(matches: &ArgMatches<'_>) -> AccountSource { + if matches.is_present("TVC") { AccountSource::Tvc } else if matches.is_present("BOC") { AccountSource::Boc } else { AccountSource::Network - }; + } +} - let method = if is_alternative { - matches.value_of("METHOD").or(config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")? - } else { - matches.value_of("METHOD").unwrap() - }; +pub async fn run_command( + matches: &ArgMatches<'_>, + full_config: &FullConfig, + is_alternative: bool, +) -> Result<(), String> { + let config = &full_config.config; + let (address, abi_path) = get_address_and_abi_path(matches, full_config, is_alternative)?; + let account_source = get_account_source(matches); + + let method = get_method(matches, &full_config.config, is_alternative)?; let trace_path; let ton_client = if account_source == AccountSource::Network { trace_path = format!("run_{}_{}.log", address, method); @@ -58,56 +95,66 @@ pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_ create_client_local()? }; - let (account, account_boc) = load_account( - &account_source, - &address, - Some(ton_client.clone()), - config - ).await?; + let (account, account_boc) = + load_account(&account_source, &address, Some(ton_client.clone()), config).await?; let address = match account_source { AccountSource::Network => address, AccountSource::Boc => account.get_addr().unwrap().to_string(), AccountSource::Tvc => "0".repeat(64), }; - run(matches, config, Some(ton_client), &address, account_boc, abi_path, is_alternative, trace_path).await + run( + matches, + config, + ton_client, + &address, + account_boc, + abi_path, + is_alternative, + trace_path, + ) + .await } async fn run( matches: &ArgMatches<'_>, config: &Config, - ton_client: Option, + ton_client: TonClient, address: &str, account_boc: String, abi_path: String, is_alternative: bool, trace_path: String, ) -> Result<(), String> { - let method = if is_alternative { - matches.value_of("METHOD").or(config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")? + let abi = load_abi(&abi_path, config).await?; + let contract = abi.abi().map_err(|e| format!("{}", e))?; + + let method = get_method(matches, config, is_alternative)?; + let params = if is_alternative { + unpack_alternative_params(matches, &abi_path, &method, config).await? } else { - matches.value_of("METHOD").unwrap() + matches.value_of("PARAMS").unwrap().to_string() }; + let params = load_params(¶ms)?; + + if let Ok(f) = contract.getter(method.as_str()) { + return run_sol_getter( + matches, + config, + ton_client, + account_boc, + method.as_str(), + f, + params, + &abi, + ) + .await; + } + let bc_config = matches.value_of("BCCONFIG"); if !config.is_json { println!("Running get-method..."); } - let ton_client = match ton_client { - Some(ton_client) => { ton_client }, - None => { - create_client_local()? - } - }; - - let abi = load_abi(&abi_path, config).await?; - let params = if is_alternative { - unpack_alternative_params(matches, &abi_path, method, config).await? - } else { - matches.value_of("PARAMS").unwrap().to_string() - }; - - let params = load_params(¶ms)?; let expire_at = config.lifetime + now(); let header = FunctionHeader { @@ -119,13 +166,14 @@ async fn run( ton_client.clone(), address, abi.clone(), - method, + &method, ¶ms, Some(header), None, config.is_json, None, - ).await?; + ) + .await?; let execution_options = prepare_execution_options(bc_config)?; let result = run_tvm( @@ -138,7 +186,8 @@ async fn run( execution_options, ..Default::default() }, - ).await; + ) + .await; let result = match result { Ok(result) => result, @@ -167,7 +216,7 @@ async fn run( match res { Some(data) => { print_json_result(data, config)?; - }, + } None => { println!("Failed to decode output messages. Check that abi matches the contract."); println!("Messages in base64:\n{:?}", result.out_messages); @@ -177,6 +226,66 @@ async fn run( Ok(()) } +async fn run_sol_getter( + matches: &ArgMatches<'_>, + config: &Config, + ton_client: TonClient, + account_boc: String, + method: &str, + function: &Function, + params: String, + abi: &Abi, +) -> Result<(), String> { + if !config.is_json { + println!("Running get-method..."); + } + + let bc_config = matches.value_of("BCCONFIG"); + let js_params: Value = serde_json::from_str(¶ms).map_err(|e| format!("{}", e))?; + let input_tokens = Tokenizer::tokenize_all_params(function.input_params(), &js_params) + .map_err(|e| format!("{}", e))?; + let mut stack_items: Vec = vec![]; + let abi_version = *abi.abi().unwrap().version(); + for token in input_tokens { + let item = TokenValueToStackItem::convert_token_to_vm_type(token.value, &abi_version) + .map_err(|e| e.to_string())?; + stack_items.push(item); + } + let crc = ever_client::crypto::ton_crc16_from_raw_data(method.as_bytes().to_vec()); + let function_id = ((crc as u32) & 0xffff) | 0x10000; + stack_items.push(ever_vm::int!(function_id)); + + let execution_options = prepare_execution_options(bc_config)?; + let result = run_solidity_getter( + ton_client.clone(), + ParamsOfRunTvm { + account: account_boc.clone(), + execution_options, + ..Default::default() + }, + stack_items, + ) + .await; + + let out_stack_items = match result { + Ok(items) => items, + Err(e) => { + return Err(format!("{:#}", e)); + } + }; + let js_result = StackItemToJson::convert_vm_items_to_json( + &out_stack_items, + &function.outputs, + &abi_version, + ) + .map_err(|e| e.to_string())?; + if !config.is_json { + println!("Succeeded."); + } + println!("{}", js_result); + Ok(()) +} + fn prepare_execution_options(bc_config: Option<&str>) -> Result, String> { if let Some(config) = bc_config { let mut bytes = std::fs::read(config) @@ -185,8 +294,10 @@ fn prepare_execution_options(bc_config: Option<&str>) -> Result) -> Result, source_type: AccountSource, bc_config: Option<&str>) -> Result<(), String> { +pub async fn run_get_method( + config: &Config, + addr: &str, + method: &str, + params: Option, + source_type: AccountSource, + bc_config: Option<&str>, +) -> Result<(), String> { let ton = if source_type == AccountSource::Network { create_client_verbose(config)? } else { @@ -207,7 +325,8 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O let (_, acc_boc) = load_account(&source_type, addr, Some(ton.clone()), config).await?; - let params = params.map(|p| serde_json::from_str(&p)) + let params = params + .map(|p| serde_json::from_str(&p)) .transpose() .map_err(|e| format!("arguments are not in json format: {}", e))?; @@ -224,9 +343,10 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O execution_options, ..Default::default() }, - ).await - .map_err(|e| format!("run failed: {}", e))? - .output; + ) + .await + .map_err(|e| format!("run failed: {}", e))? + .output; if !config.is_json { println!("Succeeded."); @@ -238,7 +358,7 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O for (i, val) in array.iter().enumerate() { res.insert(format!("value{}", i), val.to_owned()); } - }, + } _ => { res.insert("value0".to_owned(), result); } diff --git a/src/sendfile.rs b/src/sendfile.rs index a02522b1..d0c99545 100644 --- a/src/sendfile.rs +++ b/src/sendfile.rs @@ -10,17 +10,17 @@ * See the License for the specific EVERX DEV software governing permissions and * limitations under the License. */ -use crate::helpers::create_client_verbose; -use crate::config::Config; use crate::call::send_message_and_wait; +use crate::config::Config; +use crate::helpers::create_client_verbose; pub async fn sendfile(config: &Config, msg_boc: &str) -> Result<(), String> { let ton = create_client_verbose(config)?; - let boc_vec = std::fs::read(msg_boc) - .map_err(|e| format!("failed to read boc file: {}", e))?; + let boc_vec = std::fs::read(msg_boc).map_err(|e| format!("failed to read boc file: {}", e))?; let tvm_msg = ever_sdk::Contract::deserialize_message(&boc_vec[..]) .map_err(|e| format!("failed to parse message from boc: {}", e))?; - let dst = tvm_msg.dst() + let dst = tvm_msg + .dst() .ok_or("failed to parse dst address".to_string())?; if !config.is_json { @@ -31,4 +31,4 @@ pub async fn sendfile(config: &Config, msg_boc: &str) -> Result<(), String> { println!("Succeded."); } Ok(()) -} \ No newline at end of file +} diff --git a/src/test.rs b/src/test.rs index eddd1ceb..060fa26e 100644 --- a/src/test.rs +++ b/src/test.rs @@ -16,12 +16,14 @@ use crate::crypto::{self, load_keypair}; use crate::debug::{decode_messages, execute_debug, init_debug_logger, DEFAULT_TRACE_PATH}; use crate::getconfig::serialize_config_param; use crate::helpers::{ - create_client_local, decode_data, get_blockchain_config, load_abi, now_ms, unpack_alternative_params, load_params, + create_client_local, decode_data, get_blockchain_config, load_abi, load_params, now_ms, + unpack_alternative_params, }; use crate::FullConfig; use clap::{App, Arg, ArgMatches, SubCommand}; -use serde_json::json; -use std::path::PathBuf; +use ever_block::{ + ed25519_sign_with_secret, read_single_root_boc, write_boc, BuilderData, SliceData, +}; use ever_block::{ Account, ConfigParams, CurrencyCollection, Deserializable, Message, Serializable, TickTock, }; @@ -29,7 +31,8 @@ use ever_client::abi::{ encode_internal_message, encode_message, CallSet, DeploySet, FunctionHeader, ParamsOfEncodeInternalMessage, ParamsOfEncodeMessage, Signer as AbiSigner, }; -use ever_block::{read_single_root_boc, write_boc, SliceData, BuilderData, ed25519_sign_with_secret}; +use serde_json::json; +use std::path::PathBuf; pub fn create_test_sign_command<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("sign") @@ -272,7 +275,8 @@ async fn test_deploy(matches: &ArgMatches<'_>, config: &Config) -> Result<(), St .address .parse() .map_err(|e| format!("Failed to set address {}: {e}", enc_msg.address))?; - let balance = balance.parse() + let balance = balance + .parse() .map_err(|e| format!("Failed to parse initial balance: {e}"))?; let balance = CurrencyCollection::with_grams(balance); @@ -292,8 +296,9 @@ async fn test_deploy(matches: &ArgMatches<'_>, config: &Config) -> Result<(), St .map_err(|e| format!("Failed to create deploy internal message: {e}"))?; message = Message::construct_from_base64(&enc_msg.message).unwrap(); if let Some(header) = message.int_header_mut() { - header.value.grams = balance.parse() - .map_err(|e| format!("Failed to parse initial balance: {e}"))?; + header.value.grams = balance + .parse() + .map_err(|e| format!("Failed to parse initial balance: {e}"))?; } account = Account::default(); } diff --git a/src/voting.rs b/src/voting.rs index 578e0da6..a3f9ce1b 100644 --- a/src/voting.rs +++ b/src/voting.rs @@ -11,164 +11,166 @@ * limitations under the License. */ use crate::config::Config; -use crate::{call, message}; use crate::helpers::{create_client_local, decode_msg_body}; use crate::multisig::{encode_transfer_body, MSIG_ABI, TRANSFER_WITH_COMMENT}; +use crate::{call, message}; use serde_json::json; pub async fn create_proposal( - config: &Config, - addr: &str, - keys: Option<&str>, - dest: &str, - text: &str, - lifetime: u32, - offline: bool, + config: &Config, + addr: &str, + keys: Option<&str>, + dest: &str, + text: &str, + lifetime: u32, + offline: bool, ) -> Result<(), String> { - - let payload = encode_transfer_body(text).await?; - - let params = json!({ - "dest": dest, - "value": 1000000, - "bounce": false, - "allBalance": false, - "payload": payload, - }).to_string(); - - let keys = keys.map(|s| s.to_owned()); - - if offline { - message::generate_message( - config, - addr, - MSIG_ABI, - "submitTransaction", - ¶ms, - keys, - lifetime, - false, - None, - None, - None, - ).await - } else { - - call::call_contract( - config, - addr, - MSIG_ABI, - "submitTransaction", - ¶ms, - keys, - false, - ).await - } + let payload = encode_transfer_body(text).await?; + + let params = json!({ + "dest": dest, + "value": 1000000, + "bounce": false, + "allBalance": false, + "payload": payload, + }) + .to_string(); + + let keys = keys.map(|s| s.to_owned()); + + if offline { + message::generate_message( + config, + addr, + MSIG_ABI, + "submitTransaction", + ¶ms, + keys, + lifetime, + false, + None, + None, + None, + ) + .await + } else { + call::call_contract( + config, + addr, + MSIG_ABI, + "submitTransaction", + ¶ms, + keys, + false, + ) + .await + } } pub async fn vote( - config: &Config, - addr: &str, - keys: Option<&str>, - trid: &str, - lifetime: u32, - offline: bool, + config: &Config, + addr: &str, + keys: Option<&str>, + trid: &str, + lifetime: u32, + offline: bool, ) -> Result<(), String> { - - let params = json!({ - "transactionId": trid, - }).to_string(); - - let keys = keys.map(|s| s.to_owned()); - - if offline { - message::generate_message( - config, - addr, - MSIG_ABI, - "confirmTransaction", - ¶ms, - keys, - lifetime, - false, - None, - None, - None, - ).await - } else { - call::call_contract( - config, - addr, - MSIG_ABI, - "confirmTransaction", - ¶ms, - keys, - false, - ).await - } + let params = json!({ + "transactionId": trid, + }) + .to_string(); + + let keys = keys.map(|s| s.to_owned()); + + if offline { + message::generate_message( + config, + addr, + MSIG_ABI, + "confirmTransaction", + ¶ms, + keys, + lifetime, + false, + None, + None, + None, + ) + .await + } else { + call::call_contract( + config, + addr, + MSIG_ABI, + "confirmTransaction", + ¶ms, + keys, + false, + ) + .await + } } -pub async fn decode_proposal( - config: &Config, - addr: &str, - proposal_id: &str, -) -> Result<(), String> { - - // change to run - let result = call::call_contract_with_result( - config, - addr, - MSIG_ABI, - "getTransactions", - "{}", - None, - false, - ).await?; - - let txns = result["transactions"].as_array() - .ok_or(r#"failed to decode result: "transactions" array not found"#.to_string())?; - - for txn in txns { - let txn_id = txn["id"].as_str() - .ok_or(r#"failed to parse transaction in list: "id" not found"#.to_string())?; - - if txn_id == proposal_id { - let body = txn["payload"].as_str() - .ok_or(r#"failed to parse transaction in list: "payload" not found"#.to_string())?; - let ton = create_client_local()?; - let result = decode_msg_body( - ton.clone(), - TRANSFER_WITH_COMMENT, - body, - true, - config, - ) - .await - .map_err(|e| format!("failed to decode proposal payload: {}", e))?; - - let comment = String::from_utf8( - hex::decode( - result.value.ok_or("failed to get result value")?["comment"].as_str() - .ok_or("failed to obtain result comment")? - ).map_err(|e| format!("failed to parse comment from transaction payload: {}", e))? - ).map_err(|e| format!("failed to convert comment to string: {}", e))?; - - if !config.is_json { - println!("Comment: {}", comment); - } else { - println!("{{"); - println!(" \"Comment\": \"{}\"", comment); - println!("}}"); - } - return Ok(()); - } - } - if !config.is_json { - println!("Proposal with id {} not found", proposal_id); - } else { - println!("{{"); - println!(" \"Error\": \"Proposal with id {} not found\"", proposal_id); - println!("}}"); - } - Ok(()) -} \ No newline at end of file +pub async fn decode_proposal(config: &Config, addr: &str, proposal_id: &str) -> Result<(), String> { + // change to run + let result = call::call_contract_with_result( + config, + addr, + MSIG_ABI, + "getTransactions", + "{}", + None, + false, + ) + .await?; + + let txns = result["transactions"] + .as_array() + .ok_or(r#"failed to decode result: "transactions" array not found"#.to_string())?; + + for txn in txns { + let txn_id = txn["id"] + .as_str() + .ok_or(r#"failed to parse transaction in list: "id" not found"#.to_string())?; + + if txn_id == proposal_id { + let body = txn["payload"] + .as_str() + .ok_or(r#"failed to parse transaction in list: "payload" not found"#.to_string())?; + let ton = create_client_local()?; + let result = decode_msg_body(ton.clone(), TRANSFER_WITH_COMMENT, body, true, config) + .await + .map_err(|e| format!("failed to decode proposal payload: {}", e))?; + + let comment = String::from_utf8( + hex::decode( + result.value.ok_or("failed to get result value")?["comment"] + .as_str() + .ok_or("failed to obtain result comment")?, + ) + .map_err(|e| format!("failed to parse comment from transaction payload: {}", e))?, + ) + .map_err(|e| format!("failed to convert comment to string: {}", e))?; + + if !config.is_json { + println!("Comment: {}", comment); + } else { + println!("{{"); + println!(" \"Comment\": \"{}\"", comment); + println!("}}"); + } + return Ok(()); + } + } + if !config.is_json { + println!("Proposal with id {} not found", proposal_id); + } else { + println!("{{"); + println!( + " \"Error\": \"Proposal with id {} not found\"", + proposal_id + ); + println!("}}"); + } + Ok(()) +} diff --git a/tests/_network_test.rs b/tests/_network_test.rs index 53e3359d..b6eb2b1e 100644 --- a/tests/_network_test.rs +++ b/tests/_network_test.rs @@ -1,62 +1,61 @@ use assert_cmd::Command; mod common; -use common::{GIVER_V2_ADDR, BIN_NAME, GIVER_V2_ABI, GIVER_V2_KEY, NETWORK}; +use common::{BIN_NAME, GIVER_V2_ABI, GIVER_V2_ADDR, GIVER_V2_KEY, NETWORK}; #[test] fn test_network() -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("clear"); - cmd.assert() - .success(); + cmd.arg("config").arg("clear"); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("endpoint") - .arg("reset"); - cmd.assert() - .success(); + cmd.arg("config").arg("endpoint").arg("reset"); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("--global") - .arg("clear"); - cmd.assert() - .success(); + cmd.arg("config").arg("--global").arg("clear"); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("config") .arg("--global") .arg("endpoint") .arg("reset"); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("--url") - .arg(&*NETWORK); - cmd.assert() - .success(); + cmd.arg("config").arg("--url").arg(&*NETWORK); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME).unwrap(); - let res = cmd.arg("call") + let res = cmd + .arg("call") .arg("--abi") .arg(GIVER_V2_ABI) .arg(GIVER_V2_ADDR) .arg("--sign") .arg(GIVER_V2_KEY) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":10000000,"bounce":false}}"#, GIVER_V2_ADDR)) + .arg(format!( + r#"{{"dest":"{}","value":10000000,"bounce":false}}"#, + GIVER_V2_ADDR + )) .assert(); let res = res.get_output().stdout.clone(); let res = String::from_utf8(res); if res.is_err() { - return Err(string_error::into_err("Failed to decode output.".to_string())); + return Err(string_error::into_err( + "Failed to decode output.".to_string(), + )); } - if res.unwrap().contains("Fetch first block failed: Can not send http request:") { - return Err(string_error::into_err("Node SE is not running. If it is CI run, just restart it.".to_string())); + if res + .unwrap() + .contains("Fetch first block failed: Can not send http request:") + { + return Err(string_error::into_err( + "Node SE is not running. If it is CI run, just restart it.".to_string(), + )); } Ok(()) -} \ No newline at end of file +} diff --git a/tests/browser.rs b/tests/browser.rs index 2d1ed655..6539e31c 100644 --- a/tests/browser.rs +++ b/tests/browser.rs @@ -1,12 +1,12 @@ -use std::thread::sleep; -use std::time::Duration; use assert_cmd::Command; use predicates::prelude::*; +use std::thread::sleep; +use std::time::Duration; // uncomment for debug // use std::io::Write; use serde_json::json; mod common; -use common::{BIN_NAME, NETWORK, giver_v2, grep_address}; +use common::{giver_v2, grep_address, BIN_NAME, NETWORK}; fn get_debot_paths(name: &str) -> (String, String, String) { ( @@ -64,8 +64,7 @@ fn deploy_debot(name: &str) -> Result> { .arg(&addr) .arg("setABI") .arg(format!(r#"{{"dabi":"{}"}}"#, hex::encode(abi_string))); - cmd.assert() - .success(); + cmd.assert().success(); Ok(addr) } @@ -105,8 +104,7 @@ fn test_userinfo() -> Result<(), Box> { .arg(&wallet) .arg("--pubkey") .arg(&key); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("call") @@ -117,8 +115,7 @@ fn test_userinfo() -> Result<(), Box> { .arg(&addr) .arg("setParams") .arg(format!(r#"{{"wallet":"{}","key":"{}"}}"#, wallet, key)); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.timeout(std::time::Duration::from_secs(2)) @@ -144,7 +141,10 @@ fn test_pipechain_inputs() -> Result<(), Box> { let mut val: serde_json::Value = serde_json::from_str(&chain)?; val["debotAddress"] = json!(addr); let return_value = val["initArgs"]["arg7"].clone(); - std::fs::write(path_to_pipechain_tmp, serde_json::to_string_pretty(&val).unwrap())?; + std::fs::write( + path_to_pipechain_tmp, + serde_json::to_string_pretty(&val).unwrap(), + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.timeout(std::time::Duration::from_secs(2)) @@ -154,9 +154,7 @@ fn test_pipechain_inputs() -> Result<(), Box> { .arg(&addr) .arg("--pipechain") .arg(path_to_pipechain_tmp); - let assert = cmd - .assert() - .success(); + let assert = cmd.assert().success(); std::fs::remove_file(path_to_pipechain_tmp)?; @@ -202,7 +200,10 @@ fn test_address_input() -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.timeout(std::time::Duration::from_secs(2)) - .write_stdin(format!("y\n{}", "0:ea5be6a13f20fcdfddc2c2b0d317dfeab56718249b090767e5940137b7af89f1")) + .write_stdin(format!( + "y\n{}", + "0:ea5be6a13f20fcdfddc2c2b0d317dfeab56718249b090767e5940137b7af89f1" + )) .arg("debot") .arg("fetch") .arg(&addr); @@ -227,8 +228,12 @@ fn test_amount_input() -> Result<(), Box> { let _cmd = cmd .assert() .success() - .stdout(predicate::str::contains("Enter amount of tons with decimals:")) - .stdout(predicate::str::contains("(>= 0.000000000 and <= 100.000000000)")) + .stdout(predicate::str::contains( + "Enter amount of tons with decimals:", + )) + .stdout(predicate::str::contains( + "(>= 0.000000000 and <= 100.000000000)", + )) .stdout(predicate::str::contains("AmountInput tests completed!")); Ok(()) } @@ -297,8 +302,7 @@ fn test_pipechain_signing() -> Result<(), Box> { val["debotAddress"] = json!(addr); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd - .arg("-j") + cmd.arg("-j") .arg("debot") .arg("start") .arg(&addr) diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 95e55fe0..be5f78f7 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,24 +1,26 @@ use assert_cmd::Command; use lazy_static::*; -use std::env; -use serde_json::{Value, Map}; use predicates::prelude::*; +use serde_json::{Map, Value}; +use std::env; pub const BIN_NAME: &str = "ever-cli"; pub const GIVER_ADDR: &str = "0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94"; pub const GIVER_ABI: &str = "tests/samples/giver.abi.json"; -pub const GIVER_V2_ADDR: &str = "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415"; +pub const GIVER_V2_ADDR: &str = + "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415"; pub const GIVER_V2_ABI: &str = "tests/samples/giver_v2.abi.json"; pub const GIVER_V2_KEY: &str = "tests/samples/giver_v2.key"; lazy_static! { - pub static ref NETWORK: String = env::var("TON_NETWORK_ADDRESS") - .unwrap_or("http://127.0.0.1/".to_string()); + pub static ref NETWORK: String = + env::var("TON_NETWORK_ADDRESS").unwrap_or("http://127.0.0.1/".to_string()); } pub fn get_config() -> Result, Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("config") + let out = cmd + .arg("config") .arg("--list") .output() .expect("Failed to get config."); @@ -30,17 +32,18 @@ pub fn get_config() -> Result, Box> { Ok(obj) } - -pub fn set_config(config: &[&str], argument: &[&str], config_path: Option<&str>) -> Result<(), Box> { +pub fn set_config( + config: &[&str], + argument: &[&str], + config_path: Option<&str>, +) -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; if config_path.is_some() { - cmd.arg("--config") - .arg(config_path.unwrap()); + cmd.arg("--config").arg(config_path.unwrap()); } cmd.arg("config"); for i in 0..config.len() { - cmd.arg(config[i]) - .arg(argument[i]); + cmd.arg(config[i]).arg(argument[i]); } cmd.assert() .success() @@ -56,8 +59,7 @@ pub fn giver(addr: &str) { .arg(GIVER_ADDR) .arg("sendGrams") .arg(format!(r#"{{"dest":"{}","amount":1000000000}}"#, addr)); - cmd.assert() - .success(); + cmd.assert().success(); } pub fn giver_v2(addr: &str) { @@ -69,21 +71,26 @@ pub fn giver_v2(addr: &str) { .arg("--sign") .arg(GIVER_V2_KEY) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, addr)); - cmd.assert() - .success(); + .arg(format!( + r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, + addr + )); + cmd.assert().success(); } pub fn grep_address(output: &[u8]) -> String { let mut addr = String::from_utf8_lossy(output).to_string(); addr.replace_range(..addr.find("0:").unwrap_or(0), ""); - addr.replace_range(addr.find("testnet").unwrap_or(addr.len())-1.., ""); + addr.replace_range(addr.find("testnet").unwrap_or(addr.len()) - 1.., ""); addr } pub fn grep_message_id(output: &[u8]) -> String { let mut message_id = String::from_utf8_lossy(output).to_string(); - let index = message_id.find("MessageId: ").map(|i| i + "MessageId: ".len()).unwrap_or(0); + let index = message_id + .find("MessageId: ") + .map(|i| i + "MessageId: ".len()) + .unwrap_or(0); message_id.replace_range(..index, ""); if message_id.len() >= 64 { message_id.replace_range(64.., ""); @@ -94,10 +101,11 @@ pub fn grep_message_id(output: &[u8]) -> String { pub fn generate_key_and_address( key_path: &str, tvc_path: &str, - abi_path: &str + abi_path: &str, ) -> Result> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genaddr") + let out = cmd + .arg("genaddr") .arg("--genkey") .arg(key_path) .arg(tvc_path) @@ -111,14 +119,15 @@ pub fn generate_key_and_address( pub fn generate_phrase_and_key(key_path: &str) -> Result> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genphrase") + let out = cmd + .arg("genphrase") .arg("--dump") .arg(key_path) .output() .expect("Failed to generate a seed phrase."); let mut seed = String::from_utf8_lossy(&out.stdout).to_string(); seed.replace_range(..seed.find('"').unwrap_or(0) + 1, ""); - seed.replace_range(seed.find("Keypair").unwrap_or(seed.len())-2.., ""); + seed.replace_range(seed.find("Keypair").unwrap_or(seed.len()) - 2.., ""); Ok(seed) } diff --git a/tests/json_output_test.rs b/tests/json_output_test.rs index f5138a01..0fe50a8a 100644 --- a/tests/json_output_test.rs +++ b/tests/json_output_test.rs @@ -3,26 +3,30 @@ use serde_json::Value; use std::fs; mod common; -use common::{BIN_NAME, NETWORK, giver_v2, generate_key_and_address, GIVER_ADDR, - GIVER_V2_ADDR, GIVER_ABI, generate_phrase_and_key, GIVER_V2_KEY}; +use common::{ + generate_key_and_address, generate_phrase_and_key, giver_v2, BIN_NAME, GIVER_ABI, GIVER_ADDR, + GIVER_V2_ADDR, GIVER_V2_KEY, NETWORK, +}; const DEPOOL_ABI: &str = "tests/samples/fakeDepool.abi.json"; const DEPOOL_TVC: &str = "tests/samples/fakeDepool.tvc"; - fn run_command_and_decode_json(command: &str) -> Result<(), Box> { _run_command_and_decode_json(command, true) } -fn _run_command_and_decode_json(command: &str, local_node: bool) -> Result<(), Box> { +fn _run_command_and_decode_json( + command: &str, + local_node: bool, +) -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - println!("Command: {}",command); + println!("Command: {}", command); cmd.arg("-j"); if local_node { - cmd.arg("--url") - .arg(&*NETWORK); + cmd.arg("--url").arg(&*NETWORK); } - let out = cmd.args(command.split(' ').collect::>()) + let out = cmd + .args(command.split(' ').collect::>()) .output() .expect("Failed to execute command."); @@ -32,17 +36,26 @@ fn _run_command_and_decode_json(command: &str, local_node: bool) -> Result<(), B .map_err(|e| format!("Failed to decode command output: {}", e))?; println!("OUT: {}", out); - let _ : Value = serde_json::from_str(out) - .map_err(|e| format!("Failed to decode output as json: {}", e))?; + let _: Value = + serde_json::from_str(out).map_err(|e| format!("Failed to decode output as json: {}", e))?; Ok(()) } #[test] fn test_json_output_1() -> Result<(), Box> { run_command_and_decode_json(&format!("account {}", GIVER_V2_ADDR))?; - run_command_and_decode_json(&format!("body --abi {} addOrdinaryStake {{\"stake\":65535}}", DEPOOL_ABI))?; - run_command_and_decode_json(&format!("call {} sendGrams {{\"dest\":\"{}\",\"amount\":1111111}} --abi {}", GIVER_ADDR, GIVER_ADDR, GIVER_ABI))?; - run_command_and_decode_json(&format!("callx --addr {} sendGrams --dest {} --amount 1111111 --abi {}", GIVER_ADDR, GIVER_ADDR, GIVER_ABI))?; + run_command_and_decode_json(&format!( + "body --abi {} addOrdinaryStake {{\"stake\":65535}}", + DEPOOL_ABI + ))?; + run_command_and_decode_json(&format!( + "call {} sendGrams {{\"dest\":\"{}\",\"amount\":1111111}} --abi {}", + GIVER_ADDR, GIVER_ADDR, GIVER_ABI + ))?; + run_command_and_decode_json(&format!( + "callx --addr {} sendGrams --dest {} --amount 1111111 --abi {}", + GIVER_ADDR, GIVER_ADDR, GIVER_ABI + ))?; run_command_and_decode_json(r#"config endpoint add randomurl randomendpoint"#)?; run_command_and_decode_json(r#"config endpoint print"#)?; run_command_and_decode_json(r#"config endpoint remove randomurl"#)?; @@ -56,19 +69,39 @@ fn test_json_output_2() -> Result<(), Box> { let depool_addr = generate_key_and_address(key_path, DEPOOL_TVC, DEPOOL_ABI)?; giver_v2(&depool_addr); - run_command_and_decode_json(r#"decode msg tests/samples/wallet.boc --abi tests/samples/wallet.abi.json"#)?; - run_command_and_decode_json(r#"decode body te6ccgEBAQEARAAAgwAAALqUCTqWL8OX7JivfJrAAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMQAAAAAAAAAAAAAAAEeGjADA== --abi tests/samples/wallet.abi.json"#)?; + run_command_and_decode_json( + r#"decode msg tests/samples/wallet.boc --abi tests/samples/wallet.abi.json"#, + )?; + run_command_and_decode_json( + r#"decode body te6ccgEBAQEARAAAgwAAALqUCTqWL8OX7JivfJrAAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMQAAAAAAAAAAAAAAAEeGjADA== --abi tests/samples/wallet.abi.json"#, + )?; run_command_and_decode_json(&format!("decode stateinit {}", GIVER_ADDR))?; - run_command_and_decode_json(r#"decode account data --abi tests/test_abi_v2.1.abi.json --tvc tests/decode_fields.tvc"#)?; + run_command_and_decode_json( + r#"decode account data --abi tests/test_abi_v2.1.abi.json --tvc tests/decode_fields.tvc"#, + )?; run_command_and_decode_json(r#"decode account boc tests/account.boc"#)?; - run_command_and_decode_json(&format!("fee deploy --abi {} --sign {} {} {{}}", DEPOOL_ABI, key_path, DEPOOL_TVC))?; - run_command_and_decode_json(&format!("deploy --abi {} --sign {} {} {{}}", DEPOOL_ABI, key_path, DEPOOL_TVC))?; + run_command_and_decode_json(&format!( + "fee deploy --abi {} --sign {} {} {{}}", + DEPOOL_ABI, key_path, DEPOOL_TVC + ))?; + run_command_and_decode_json(&format!( + "deploy --abi {} --sign {} {} {{}}", + DEPOOL_ABI, key_path, DEPOOL_TVC + ))?; let depool_addr = generate_key_and_address(key_path, DEPOOL_TVC, DEPOOL_ABI)?; giver_v2(&depool_addr); - run_command_and_decode_json(&format!("deployx --abi {} --keys {} {}", DEPOOL_ABI, key_path, DEPOOL_TVC))?; - run_command_and_decode_json(&format!("deploy_message --raw --abi {} -o fakeDepool.msg --sign {} {} {{}}", DEPOOL_ABI, key_path, DEPOOL_TVC))?; - run_command_and_decode_json(r#"dump account 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94"#)?; + run_command_and_decode_json(&format!( + "deployx --abi {} --keys {} {}", + DEPOOL_ABI, key_path, DEPOOL_TVC + ))?; + run_command_and_decode_json(&format!( + "deploy_message --raw --abi {} -o fakeDepool.msg --sign {} {} {{}}", + DEPOOL_ABI, key_path, DEPOOL_TVC + ))?; + run_command_and_decode_json( + r#"dump account 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94"#, + )?; let command = format!("run --abi {} {} getData {{}}", DEPOOL_ABI, depool_addr); run_command_and_decode_json(&command)?; let command = format!("runx --abi {} --addr {} getData ", DEPOOL_ABI, depool_addr); @@ -82,26 +115,46 @@ fn test_json_output_2() -> Result<(), Box> { #[test] fn test_json_output_3() -> Result<(), Box> { run_command_and_decode_json("--config 123.conf config clear")?; - _run_command_and_decode_json(r#"-c 123.conf config --project_id b2ad82504ee54fccb5bc6db8cbb3df1e --access_key 27377cc9027d4de792f100eb869e18e8"#, false)?; - _run_command_and_decode_json(r#"-c 123.conf --url net.ton.dev dump config conf.boc"#, false)?; + _run_command_and_decode_json( + r#"-c 123.conf config --project_id b2ad82504ee54fccb5bc6db8cbb3df1e --access_key 27377cc9027d4de792f100eb869e18e8"#, + false, + )?; + _run_command_and_decode_json( + r#"-c 123.conf --url net.ton.dev dump config conf.boc"#, + false, + )?; fs::remove_file("conf.boc")?; _run_command_and_decode_json(r#"-c 123.conf --url net.ton.dev getconfig 1"#, false)?; _run_command_and_decode_json(r#"-c 123.conf --url net.ton.dev getconfig"#, false)?; fs::remove_file("123.conf")?; run_command_and_decode_json(&format!("fee storage {}", GIVER_ADDR))?; - run_command_and_decode_json(&format!("fee call {} sendGrams {{\"dest\":\"{}\",\"amount\":1111111}} --abi {}", GIVER_ADDR, GIVER_ADDR, GIVER_ABI))?; - run_command_and_decode_json(r#"genaddr tests/samples/wallet.tvc --genkey tests/json_test1.key"#)?; + run_command_and_decode_json(&format!( + "fee call {} sendGrams {{\"dest\":\"{}\",\"amount\":1111111}} --abi {}", + GIVER_ADDR, GIVER_ADDR, GIVER_ABI + ))?; + run_command_and_decode_json( + r#"genaddr tests/samples/wallet.tvc --genkey tests/json_test1.key"#, + )?; fs::remove_file("tests/json_test1.key")?; run_command_and_decode_json(r#"genphrase"#)?; // run_command_and_decode_json(r#"genpubkey "jar denial ozone coil heart tattoo science stay wire about act equip""#)?; let key_path = "json3_test.key"; let _ = generate_phrase_and_key(key_path)?; - run_command_and_decode_json(r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendTransaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw --output fakeDepool1.msg"#)?; - run_command_and_decode_json(r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendTransaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw"#)?; + run_command_and_decode_json( + r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendTransaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw --output fakeDepool1.msg"#, + )?; + run_command_and_decode_json( + r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendTransaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw"#, + )?; run_command_and_decode_json(&format!("multisig deploy -k {} -l 1000000000", key_path))?; - run_command_and_decode_json(r#"nodeid --pubkey cde8fbf86c44e4ed2095f83b6f3c97b7aec55a77e06e843f8b9ffeab66ad4b32"#)?; + run_command_and_decode_json( + r#"nodeid --pubkey cde8fbf86c44e4ed2095f83b6f3c97b7aec55a77e06e843f8b9ffeab66ad4b32"#, + )?; run_command_and_decode_json(r#"nodeid --keypair tests/samples/exp.json"#)?; - run_command_and_decode_json(&format!("proposal vote 0:28a3738f08f5b3410e92aab20f702d64160e2891aaaed881f27d59ff518078d1 12313 {}", key_path))?; + run_command_and_decode_json(&format!( + "proposal vote 0:28a3738f08f5b3410e92aab20f702d64160e2891aaaed881f27d59ff518078d1 12313 {}", + key_path + ))?; run_command_and_decode_json(r#"runget --boc tests/account_fift.boc past_election_ids"#)?; run_command_and_decode_json(r#"sendfile fakeDepool1.msg"#)?; run_command_and_decode_json(&format!("debug call {} sendGrams {{\"dest\":\"{}\",\"amount\":1111111}} --abi {} -c tests/config.boc", GIVER_ADDR, GIVER_ADDR, GIVER_ABI))?; @@ -114,17 +167,32 @@ fn test_json_output_3() -> Result<(), Box> { #[test] fn test_json_output_4() -> Result<(), Box> { - run_command_and_decode_json("account 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a23")?; - run_command_and_decode_json(&format!("body --abi {} addOrdinaryStake {{\"stake1\":65535}}", DEPOOL_ABI))?; + run_command_and_decode_json( + "account 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a23", + )?; + run_command_and_decode_json(&format!( + "body --abi {} addOrdinaryStake {{\"stake1\":65535}}", + DEPOOL_ABI + ))?; run_command_and_decode_json("convert tokens 0.12345678a")?; run_command_and_decode_json(&format!("call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a95 sendGrams {{\"dest\":\"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94\",\"amount\":1111111}} --abi {}", GIVER_ABI))?; run_command_and_decode_json(&format!("callx --addr 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a95 sendGrams --dest 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 --amount 1111111 --abi {}", GIVER_ABI))?; run_command_and_decode_json(r#"config endpoint remove random"#)?; - run_command_and_decode_json(&format!("decode msg tests/samples/wallet.boc --abi {}", DEPOOL_ABI))?; - run_command_and_decode_json(&format!("decode msg tests/account_fift.tvc --abi {}", DEPOOL_ABI))?; + run_command_and_decode_json(&format!( + "decode msg tests/samples/wallet.boc --abi {}", + DEPOOL_ABI + ))?; + run_command_and_decode_json(&format!( + "decode msg tests/account_fift.tvc --abi {}", + DEPOOL_ABI + ))?; run_command_and_decode_json(&format!("decode body te6ccgEBAQEARAAAgwAAALqUCTqWL8OX7JivfJrAAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMQAAAAAAAAAAAAAAAEeGjADA== --abi {}", DEPOOL_ABI))?; - run_command_and_decode_json(r#"decode stateinit 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a65"#)?; - run_command_and_decode_json(r#"decode account data --abi tests/test_abi_v2.1.abi.json --tvc tests/account_fift.tvc"#)?; + run_command_and_decode_json( + r#"decode stateinit 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a65"#, + )?; + run_command_and_decode_json( + r#"decode account data --abi tests/test_abi_v2.1.abi.json --tvc tests/account_fift.tvc"#, + )?; run_command_and_decode_json(r#"decode account boc tests/account_fift.tvc"#)?; run_command_and_decode_json(r#"sendfile tests/account.boc"#)?; @@ -135,28 +203,55 @@ fn test_json_output_4() -> Result<(), Box> { fn test_json_output_5() -> Result<(), Box> { run_command_and_decode_json(&format!("fee deploy --abi tests/samples/fakeDepool.abi.json --sign {} tests/samples/fakeDepool.tvc {{}}", GIVER_V2_KEY))?; run_command_and_decode_json(&format!("deploy --abi tests/samples/fakeDepool.abi.json --sign {} tests/samples/fakeDepool.tvc {{}}", GIVER_V2_KEY))?; - run_command_and_decode_json(&format!("deployx --abi tests/samples/fakeDepool.abi.json --keys {} tests/samples/fakeDepool.tvc ", GIVER_V2_KEY))?; + run_command_and_decode_json(&format!( + "deployx --abi tests/samples/fakeDepool.abi.json --keys {} tests/samples/fakeDepool.tvc ", + GIVER_V2_KEY + ))?; run_command_and_decode_json(&format!("deploy_message --raw --abi tests/samples/fakeDepool.abi.json --sign {} tests/account.boc {{}}", GIVER_V2_KEY))?; - run_command_and_decode_json(r#"dump config 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94.boc"#)?; - run_command_and_decode_json(r#"fee storage 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a11"#)?; - run_command_and_decode_json(r#"fee call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a95 sendGrams {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111} --abi tests/samples/giver.abi.json"#)?; - run_command_and_decode_json(&format!("genaddr tests/account.boc --abi tests/samples/wallet.abi.json --setkey {}", GIVER_V2_KEY))?; + run_command_and_decode_json( + r#"dump config 841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94.boc"#, + )?; + run_command_and_decode_json( + r#"fee storage 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a11"#, + )?; + run_command_and_decode_json( + r#"fee call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a95 sendGrams {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111} --abi tests/samples/giver.abi.json"#, + )?; + run_command_and_decode_json(&format!( + "genaddr tests/account.boc --abi tests/samples/wallet.abi.json --setkey {}", + GIVER_V2_KEY + ))?; // run_command_and_decode_json(r#"genpubkey "jar denial ozone coil heart tattoo science stay wire about act""#)?; run_command_and_decode_json(r#"getconfig 1"#)?; - run_command_and_decode_json(r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendansaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw"#)?; + run_command_and_decode_json( + r#"message 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendansaction {"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","value":1000000000,"bounce":true} --abi tests/samples/wallet.abi.json --raw"#, + )?; run_command_and_decode_json(&format!("multisig deploy -k {}", GIVER_V2_KEY))?; - run_command_and_decode_json(&format!("multisig deploy -k {} -l 1000000000", GIVER_V2_KEY))?; + run_command_and_decode_json(&format!( + "multisig deploy -k {} -l 1000000000", + GIVER_V2_KEY + ))?; run_command_and_decode_json(r#"nodeid --pubkey cde8fbf86c"#)?; run_command_and_decode_json(r#"nodeid --keypair tests/account.boc"#)?; // run_command_and_decode_json(&format!("proposal vote 0:28a3738f08f5b3410e92aab20f702d64160e2891aaaed881f27d59ff518078d1 12313 {}", GIVER_V2_KEY))?; // run_command_and_decode_json(r#"proposal decode 0:28a3738f08f5b3410e92aab20f702d64160e2891aaaed881f27d59ff518078d1 12313"#)?; - let command = format!("run --abi tests/samples/fakeDepool.abi.json {} getDat {{}}", GIVER_ADDR); + let command = format!( + "run --abi tests/samples/fakeDepool.abi.json {} getDat {{}}", + GIVER_ADDR + ); run_command_and_decode_json(&command)?; - let command = format!("runx --abi tests/samples/fakeDepool.abi.json --addr {} gtData ", GIVER_ADDR); + let command = format!( + "runx --abi tests/samples/fakeDepool.abi.json --addr {} gtData ", + GIVER_ADDR + ); run_command_and_decode_json(&command)?; run_command_and_decode_json(r#"runget --boc tests/account_fift.boc past_election_is"#)?; run_command_and_decode_json(r#"send --abi tests/samples/fakeDepool.abi.json 65465"#)?; - run_command_and_decode_json(r#"debug call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendGram1 '{"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111}' --abi tests/samples/giver.abi.json -c tests/config.boc"#)?; - run_command_and_decode_json(r#" --optionss call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendGram '{"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111}' --abi tests/samples/giver.abi.json"#)?; + run_command_and_decode_json( + r#"debug call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendGram1 '{"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111}' --abi tests/samples/giver.abi.json -c tests/config.boc"#, + )?; + run_command_and_decode_json( + r#" --optionss call 0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94 sendGram '{"dest":"0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94","amount":1111111}' --abi tests/samples/giver.abi.json"#, + )?; Ok(()) } diff --git a/tests/mnemonic.rs b/tests/mnemonic.rs index 531940f6..6a94a570 100644 --- a/tests/mnemonic.rs +++ b/tests/mnemonic.rs @@ -8,34 +8,43 @@ use common::BIN_NAME; #[test] fn test_has_mnemonic_checks() -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("genpubkey").arg("abuse boss fly battle rubber wasp afraid hamster guide essence vibrant tattoo"); + cmd.arg("genpubkey") + .arg("abuse boss fly battle rubber wasp afraid hamster guide essence vibrant tattoo"); cmd.assert() .success() .stdout(predicate::str::contains("Succeeded.")) - .stdout(predicate::str::contains("Public key: 0cd34af58fc9cef235e1ad3aafb3d9c18c388b99c7089842eb9a49538e18d67d")); - + .stdout(predicate::str::contains( + "Public key: 0cd34af58fc9cef235e1ad3aafb3d9c18c388b99c7089842eb9a49538e18d67d", + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("genpubkey"); cmd.assert() .failure() - .stderr(predicate::str::contains("The following required arguments were not provided:")) + .stderr(predicate::str::contains( + "The following required arguments were not provided:", + )) .stderr(predicate::str::contains("")); - //just test check exits all other checks in test_invalid_mnemonic - const WRONG_SEED: &str = "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry "; + //just test check exits all other checks in test_invalid_mnemonic + const WRONG_SEED: &str = + "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry "; const WRONG_SEED_ERROR_TEXT: &str = "Invalid bip39 phrase"; - + let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("genpubkey").arg(WRONG_SEED); cmd.assert() - .failure() + .failure() .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("getkeypair").arg("-o").arg("test.json").arg("-p").arg(WRONG_SEED); + cmd.arg("getkeypair") + .arg("-o") + .arg("test.json") + .arg("-p") + .arg(WRONG_SEED); cmd.assert() - .failure() + .failure() .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -48,7 +57,7 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() + .failure() .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -68,10 +77,9 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--bounce") .arg("true"); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - - + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("deploy") .arg("tests/samples/wallet.tvc") @@ -81,15 +89,15 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("--addr") - .arg("0:2bb4a0e8391e7ea8877f4825064924bd41ce110fce97e939d3323999e1efbb13") - .assert() - .success(); + cmd.arg("config") + .arg("--addr") + .arg("0:2bb4a0e8391e7ea8877f4825064924bd41ce110fce97e939d3323999e1efbb13") + .assert() + .success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -101,8 +109,8 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("-s") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -115,8 +123,8 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("-s") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -135,9 +143,9 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") .arg("stake") @@ -154,10 +162,9 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("30") .arg("--sign") .arg(WRONG_SEED); - cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + cmd.assert() + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -170,8 +177,8 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -186,8 +193,8 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -200,9 +207,8 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("multisig") @@ -218,18 +224,15 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("nodeid") - .arg("--keypair") - .arg(WRONG_SEED); + cmd.arg("nodeid").arg("--keypair").arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); - + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("message") .arg("0:2bb4a0e8391e7ea8877f4825064924bd41ce110fce97e939d3323999e1efbb13") @@ -244,9 +247,9 @@ fn test_has_mnemonic_checks() -> Result<(), Box> { .arg("--sign") .arg(WRONG_SEED); cmd.assert() - .failure() - .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); + .failure() + .stdout(predicate::str::contains(WRONG_SEED_ERROR_TEXT)); //TODO debot - //TODO proposal + //TODO proposal Ok(()) -} \ No newline at end of file +} diff --git a/tests/samples/AddressInput.sol b/tests/samples/AddressInput.sol index de6afbf6..2f833927 100644 --- a/tests/samples/AddressInput.sol +++ b/tests/samples/AddressInput.sol @@ -28,9 +28,9 @@ contract AddressInputDebot is Debot { ) { name = "AddressInput example DeBot"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "How to use the AddressInput interface"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello, i am an AddressInput example DeBot."; language = "en"; diff --git a/tests/samples/AmountInput.sol b/tests/samples/AmountInput.sol index e960d320..f120553c 100644 --- a/tests/samples/AmountInput.sol +++ b/tests/samples/AmountInput.sol @@ -28,9 +28,9 @@ contract AmountInputDebot is Debot { ) { name = "AmountInput example DeBot"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "How to use the AmountInput interface"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello, i am an AmountInput example DeBot."; language = "en"; diff --git a/tests/samples/ConfirmInput.sol b/tests/samples/ConfirmInput.sol index fbc14c1d..79f40ac4 100644 --- a/tests/samples/ConfirmInput.sol +++ b/tests/samples/ConfirmInput.sol @@ -27,9 +27,9 @@ contract ConfirmInputDebot is Debot { ) { name = "ConfirmInput example DeBot"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "How to use the ConfirmInput interface"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello, i am an ConfirmInput example DeBot."; language = "en"; diff --git a/tests/samples/Debot.sol b/tests/samples/Debot.sol index c1e56b58..44ea4a1f 100644 --- a/tests/samples/Debot.sol +++ b/tests/samples/Debot.sol @@ -24,7 +24,7 @@ abstract contract Debot { /// @notice Returns DeBot metadata. /// @return name String with name of debot, e.g. "DePool". /// @return version Semver version of debot, that will be converted to string like "x.y.z". - /// @return publisher String with info about who has deployed debot to blokchain, e.g. "TON Labs". + /// @return publisher String with info about who has deployed debot to blokchain, e.g. "EverX". /// @return caption (10-20 ch.) String with short description, e.g. "Work with Smthg". /// @return author String with name of author of DeBot, e.g. "Ivan Ivanov". /// @return support Free TON address of author for questions and donations. diff --git a/tests/samples/NumberInput.sol b/tests/samples/NumberInput.sol index 23391da4..0ed3a695 100644 --- a/tests/samples/NumberInput.sol +++ b/tests/samples/NumberInput.sol @@ -27,9 +27,9 @@ contract NumberInputDebot is Debot { ) { name = "NumberInput example DeBot"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "How to use the NumberInput interface"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello, i am an NumberInput example DeBot."; language = "en"; diff --git a/tests/samples/PipechainTest.sol b/tests/samples/PipechainTest.sol index c3b490dc..b8a2f4aa 100644 --- a/tests/samples/PipechainTest.sol +++ b/tests/samples/PipechainTest.sol @@ -37,9 +37,9 @@ contract Invoked is Debot { ) { name = "InvokeTest"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "For testing invokes"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello"; language = "en"; diff --git a/tests/samples/PipechainTest_2.sol b/tests/samples/PipechainTest_2.sol index c3b490dc..b8a2f4aa 100644 --- a/tests/samples/PipechainTest_2.sol +++ b/tests/samples/PipechainTest_2.sol @@ -37,9 +37,9 @@ contract Invoked is Debot { ) { name = "InvokeTest"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "For testing invokes"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello"; language = "en"; diff --git a/tests/samples/SafeMultisigWallet.sol b/tests/samples/SafeMultisigWallet.sol index 8e1a7689..cb74c842 100644 --- a/tests/samples/SafeMultisigWallet.sol +++ b/tests/samples/SafeMultisigWallet.sol @@ -10,7 +10,6 @@ interface IAccept { } /// @title Multisignature wallet -/// @author Tonlabs (https://everx.dev) contract MultisigWallet is IAccept { /* diff --git a/tests/samples/Terminal.sol b/tests/samples/Terminal.sol index 45f7faa5..4a13ccb8 100644 --- a/tests/samples/Terminal.sol +++ b/tests/samples/Terminal.sol @@ -27,9 +27,9 @@ contract TerminalDebot is Debot { ) { name = "Terminal DeBot"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "How to use the Terminal interface"; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Hello, i am a Terminal example DeBot."; language = "en"; diff --git a/tests/samples/sample1.sol b/tests/samples/sample1.sol index 24aaea13..cbb169da 100644 --- a/tests/samples/sample1.sol +++ b/tests/samples/sample1.sol @@ -33,9 +33,9 @@ contract ExampleContract is Debot { ) { name = "SigningBoxInput"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "Test for SigningBoxInput."; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Test DeBot."; language = "en"; diff --git a/tests/samples/sample2.sol b/tests/samples/sample2.sol index dab65e41..6298b5d7 100644 --- a/tests/samples/sample2.sol +++ b/tests/samples/sample2.sol @@ -42,9 +42,9 @@ contract Sample2 is Debot { ) { name = "UserInfo"; version = "0.1.0"; - publisher = "TON Labs"; + publisher = "EverX"; caption = "Test for UserInfo."; - author = "TON Labs"; + author = "EverX"; support = address(0); hello = "Test DeBot."; language = "en"; diff --git a/tests/samples/wallet.sol b/tests/samples/wallet.sol index 9cf63cca..23fe7e46 100644 --- a/tests/samples/wallet.sol +++ b/tests/samples/wallet.sol @@ -2,7 +2,7 @@ pragma solidity >=0.6.0; pragma AbiHeader expire; /// @title Simple wallet -/// @author Tonlabs +/// @author EverX contract Wallet { /* * Storage diff --git a/tests/test_cli.rs b/tests/test_cli.rs index 768ba21e..12a8f4b1 100644 --- a/tests/test_cli.rs +++ b/tests/test_cli.rs @@ -1,16 +1,17 @@ -use predicates::prelude::*; use assert_cmd::Command; +use predicates::prelude::*; +use serde_json::{json, Value}; use std::env; -use std::thread::sleep; -use std::time::{SystemTime, Duration}; use std::fs; -use serde_json::{json, Value}; +use std::thread::sleep; +use std::time::{Duration, SystemTime}; mod common; -use common::{BIN_NAME, NETWORK, giver_v2, grep_address, set_config, GIVER_V2_ABI, - GIVER_V2_ADDR, GIVER_V2_KEY, generate_key_and_address, GIVER_ABI, - generate_phrase_and_key}; use crate::common::grep_message_id; +use common::{ + generate_key_and_address, generate_phrase_and_key, giver_v2, grep_address, set_config, + BIN_NAME, GIVER_ABI, GIVER_V2_ABI, GIVER_V2_ADDR, GIVER_V2_KEY, NETWORK, +}; const DEPOOL_ABI: &str = "tests/samples/fakeDepool.abi.json"; const DEPOOL_ABI_V21: &str = "tests/depool.abi.json"; @@ -18,7 +19,8 @@ const DEPOOL_TVC: &str = "tests/samples/fakeDepool.tvc"; const SAFEMSIG_ABI: &str = "tests/samples/SafeMultisigWallet.abi.json"; const SAFEMSIG_ABI_LINK: &str = "https://raw.githubusercontent.com/everx-labs/ton-labs-contracts/master/solidity/safemultisig/SafeMultisigWallet.abi.json"; const SAFEMSIG_TVC: &str = "tests/samples/SafeMultisigWallet.tvc"; -const SAFEMSIG_SEED: &str = "blanket time net universe ketchup maid way poem scatter blur limit drill"; +const SAFEMSIG_SEED: &str = + "blanket time net universe ketchup maid way poem scatter blur limit drill"; const SAFEMSIG_ADDR: &str = "0:d5f5cfc4b52d2eb1bd9d3a8e51707872c7ce0c174facddd0e06ae5ffd17d2fcd"; const SAFEMSIG_CONSTR_ARG: &str = r#"{"owners":["0xc8bd66f90d61f7e1e1a6151a0dbe9d8640666920d8c0cf399cbfb72e089d2e41"],"reqConfirms":1}"#; const SAVED_CONFIG: &str = "tests/config_contract.saved"; @@ -32,13 +34,17 @@ fn now_ms() -> u64 { fn generate_public_key(seed: &str) -> Result> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genpubkey") + let out = cmd + .arg("genpubkey") .arg(seed) .output() .expect("Failed to generate a public key phrase."); let mut key = String::from_utf8_lossy(&out.stdout).to_string(); - key.replace_range(..key.find("Public key: ").unwrap_or(0) + "Public key: ".len(), ""); - key.replace_range(key.find("\n\n").unwrap_or(key.len())-1.., ""); + key.replace_range( + ..key.find("Public key: ").unwrap_or(0) + "Public key: ".len(), + "", + ); + key.replace_range(key.find("\n\n").unwrap_or(key.len()) - 1.., ""); Ok(key) } @@ -80,35 +86,37 @@ fn wait_for_cmd_res(cmd: &mut Command, expected: &str) -> Result<(), Box { if res.contains(expected) { break; } - }, + } Err(_) => { - return Err(string_error::into_err("Failed to decode command output.".to_string())); + return Err(string_error::into_err( + "Failed to decode command output.".to_string(), + )); } } attempts -= 1; if attempts == 0 { - return Err(string_error::into_err("Failed to fetch command result.".to_string())); + return Err(string_error::into_err( + "Failed to fetch command result.".to_string(), + )); } sleep(Duration::new(1, 0)); } Ok(()) } - #[test] fn test_config_1() -> Result<(), Box> { let config_path = "test1.config"; set_config( &["--url", "--retries", "--timeout", "--wc"], &[&*NETWORK, "10", "25000", "-2"], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -118,7 +126,10 @@ fn test_config_1() -> Result<(), Box> { .arg("--list"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#""url": "{}""#, &*NETWORK))) + .stdout(predicate::str::contains(format!( + r#""url": "{}""#, + &*NETWORK + ))) .stdout(predicate::str::contains(r#""retries": 10"#)) .stdout(predicate::str::contains(r#""timeout": 25000"#)) .stdout(predicate::str::contains(r#""wc": -2"#)); @@ -135,11 +146,7 @@ fn test_deploy_alias() -> Result<(), Box> { let key_path = "test_deploy_alias.key"; let alias = "msig"; - set_config( - &["--url"], - &[&*NETWORK], - Some(config_path) - )?; + set_config(&["--url"], &[&*NETWORK], Some(config_path))?; let address = generate_key_and_address(key_path, wallet_tvc, wallet_abi)?; giver_v2(&address); @@ -181,7 +188,6 @@ fn test_deploy_alias() -> Result<(), Box> { Ok(()) } - #[test] fn test_config_aliases() -> Result<(), Box> { let config_path = "test_alias.config"; @@ -211,9 +217,15 @@ fn test_config_aliases() -> Result<(), Box> { cmd.assert() .success() .stdout(predicate::str::contains(r#""msig": {"#)) - .stdout(predicate::str::contains(r#""abi_path": "tests/samples/SafeMultisigWallet.abi.json","#)) - .stdout(predicate::str::contains(r#""address": "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415","#)) - .stdout(predicate::str::contains(r#""key_path": "tests/deploy_test.key""#)); + .stdout(predicate::str::contains( + r#""abi_path": "tests/samples/SafeMultisigWallet.abi.json","#, + )) + .stdout(predicate::str::contains( + r#""address": "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415","#, + )) + .stdout(predicate::str::contains( + r#""key_path": "tests/deploy_test.key""#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -224,9 +236,15 @@ fn test_config_aliases() -> Result<(), Box> { cmd.assert() .success() .stdout(predicate::str::contains(r#""msig": {"#)) - .stdout(predicate::str::contains(r#""abi_path": "tests/samples/SafeMultisigWallet.abi.json","#)) - .stdout(predicate::str::contains(r#""address": "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415","#)) - .stdout(predicate::str::contains(r#""key_path": "tests/deploy_test.key""#)); + .stdout(predicate::str::contains( + r#""abi_path": "tests/samples/SafeMultisigWallet.abi.json","#, + )) + .stdout(predicate::str::contains( + r#""address": "0:ece57bcc6c530283becbbd8a3b24d3c5987cdddc3c8b7b33be6e4a6312490415","#, + )) + .stdout(predicate::str::contains( + r#""key_path": "tests/deploy_test.key""#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -278,9 +296,11 @@ fn test_config_endpoints() -> Result<(), Box> { cmd.assert() .success() .stdout(predicate::str::contains(r#""url": "main.evercloud.dev","#)) - .stdout(predicate::str::contains(r#""endpoints": [ + .stdout(predicate::str::contains( + r#""endpoints": [ "https://mainnet.evercloud.dev" - ]"#)); + ]"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -310,10 +330,12 @@ fn test_config_endpoints() -> Result<(), Box> { cmd.assert() .success() .stdout(predicate::str::contains(r#""url": "myownhost","#)) - .stdout(predicate::str::contains(r#""endpoints": [ + .stdout(predicate::str::contains( + r#""endpoints": [ "1.1.1.1", "my.net.com" - ]"#)); + ]"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -357,8 +379,12 @@ fn test_config_endpoints() -> Result<(), Box> { .arg("main.evercloud.dev"); cmd.assert() .success() - .stdout(predicate::function(|s: &str| !s.contains("main.evercloud.dev"))) - .stdout(predicate::function(|s: &str| !s.contains("https://mainnet.evercloud.dev"))) + .stdout(predicate::function(|s: &str| { + !s.contains("main.evercloud.dev") + })) + .stdout(predicate::function(|s: &str| { + !s.contains("https://mainnet.evercloud.dev") + })) .stdout(predicate::str::contains("http://127.0.0.1/")) .stdout(predicate::str::contains("net.evercloud.dev")) .stdout(predicate::str::contains("https://devnet.evercloud.dev")) @@ -374,8 +400,12 @@ fn test_config_endpoints() -> Result<(), Box> { .arg("print"); cmd.assert() .success() - .stdout(predicate::function(|s: &str| !s.contains("main.evercloud.dev"))) - .stdout(predicate::function(|s: &str| !s.contains("https://mainnet.evercloud.dev"))) + .stdout(predicate::function(|s: &str| { + !s.contains("main.evercloud.dev") + })) + .stdout(predicate::function(|s: &str| { + !s.contains("https://mainnet.evercloud.dev") + })) .stdout(predicate::str::contains("http://127.0.0.1/")) .stdout(predicate::str::contains("net.evercloud.dev")) .stdout(predicate::str::contains("https://devnet.evercloud.dev")) @@ -438,7 +468,9 @@ fn test_fee() -> Result<(), Box> { .arg(GIVER_V2_ADDR) .assert() .success() - .stdout(predicate::str::contains("Storage fee per 31536000 seconds: ")); + .stdout(predicate::str::contains( + "Storage fee per 31536000 seconds: ", + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("fee") @@ -459,7 +491,10 @@ fn test_fee() -> Result<(), Box> { .arg("--sign") .arg(GIVER_V2_KEY) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, GIVER_V2_ADDR)) + .arg(format!( + r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, + GIVER_V2_ADDR + )) .assert() .success() .stdout(predicate::str::contains(r#" "in_msg_fwd_fee":"#)) @@ -626,8 +661,7 @@ fn test_async_deploy() -> Result<(), Box> { giver_v2(&addr); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("account") - .arg(addr.clone()); + cmd.arg("account").arg(addr.clone()); wait_for_cmd_res(&mut cmd, "acc_type: Uninit")?; @@ -658,8 +692,7 @@ fn test_async_deploy() -> Result<(), Box> { fs::remove_file(config_path)?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("account") - .arg(addr.clone()); + cmd.arg("account").arg(addr.clone()); wait_for_cmd_res(&mut cmd, "acc_type: Active")?; @@ -678,7 +711,11 @@ fn test_deploy() -> Result<(), Box> { giver_v2(&addr); - set_config(&["--balance_in_tons", "--url"], &["true", &*NETWORK], Some(config_path))?; + set_config( + &["--balance_in_tons", "--url"], + &["true", &*NETWORK], + Some(config_path), + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -737,7 +774,8 @@ fn test_deploy() -> Result<(), Box> { let data_str = format!(r#"{{"m_seed":{}}}"#, time); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genaddr") + let out = cmd + .arg("genaddr") .arg(tvc_path2) .arg("--abi") .arg(abi_path) @@ -779,7 +817,8 @@ fn test_genaddr_update_key() -> Result<(), Box> { .success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genaddr") + let out = cmd + .arg("genaddr") .arg("--setkey") .arg(key_path) .arg(SAFEMSIG_TVC) @@ -802,7 +841,8 @@ fn test_genaddr_seed() -> Result<(), Box> { let seed = generate_phrase_and_key(key_path)?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genaddr") + let out = cmd + .arg("genaddr") .arg("--setkey") .arg(key_path) .arg(SAFEMSIG_TVC) @@ -812,7 +852,8 @@ fn test_genaddr_seed() -> Result<(), Box> { let msig_addr = grep_address(&out.get_output().stdout); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("genaddr") + let out = cmd + .arg("genaddr") .arg("--setkey") .arg(seed) .arg(SAFEMSIG_TVC) @@ -834,25 +875,25 @@ fn test_nodeid() -> Result<(), Box> { cmd.arg("nodeid") .arg("--pubkey") .arg("cde8fbf86c44e4ed2095f83b6f3c97b7aec55a77e06e843f8b9ffeab66ad4b32"); - cmd.assert() - .success() - .stdout(predicate::str::contains("cdae19f3d5a96d016e74d656ef15e35839b554ae2590bec0dce5e6608cb7f837")); + cmd.assert().success().stdout(predicate::str::contains( + "cdae19f3d5a96d016e74d656ef15e35839b554ae2590bec0dce5e6608cb7f837", + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("nodeid") .arg("--keypair") .arg("tests/samples/exp.json"); - cmd.assert() - .success() - .stdout(predicate::str::contains("e8c5df53b6205e8db639629d2cd2552b354501021a9f223bb72e81e75f37f64a")); + cmd.assert().success().stdout(predicate::str::contains( + "e8c5df53b6205e8db639629d2cd2552b354501021a9f223bb72e81e75f37f64a", + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("nodeid") .arg("--keypair") .arg("ghost frost pool buzz rival mad naive rare shell tooth smart praise"); - cmd.assert() - .success() - .stdout(predicate::str::contains("e8c5df53b6205e8db639629d2cd2552b354501021a9f223bb72e81e75f37f64a")); + cmd.assert().success().stdout(predicate::str::contains( + "e8c5df53b6205e8db639629d2cd2552b354501021a9f223bb72e81e75f37f64a", + )); Ok(()) } @@ -898,13 +939,10 @@ fn test_override_config_path() -> Result<(), Box> { Ok(()) } - #[test] fn test_global_config() -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("config") - .arg("--global") - .arg("clear"); + cmd.arg("config").arg("--global").arg("clear"); cmd.assert() .success() .stdout(predicate::str::contains("url\": \"net.evercloud.dev")) @@ -1014,7 +1052,7 @@ fn test_old_config() -> Result<(), Box> { fn test_sendfile() -> Result<(), Box> { let msg_path = "call.boc"; let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("--url") + cmd.arg("--url") .arg(&*NETWORK) .arg("message") .arg("0:841288ed3b55d9cdafa806807f02a0ae0c169aa5edfe88a789a6482429756a94") @@ -1025,8 +1063,7 @@ fn test_sendfile() -> Result<(), Box> { .arg("--raw") .arg("--output") .arg(msg_path); - cmd.assert() - .success(); + cmd.assert().success(); let config_path = "send.config"; set_config(&["--async_call"], &["true"], Some(config_path))?; @@ -1038,8 +1075,7 @@ fn test_sendfile() -> Result<(), Box> { .arg(config_path) .arg("sendfile") .arg(msg_path); - cmd.assert() - .success(); + cmd.assert().success(); fs::remove_file(config_path)?; fs::remove_file(msg_path)?; @@ -1047,7 +1083,6 @@ fn test_sendfile() -> Result<(), Box> { Ok(()) } - #[test] fn test_account_command() -> Result<(), Box> { env::set_var("RUST_LOG", "debug"); @@ -1089,9 +1124,7 @@ fn test_account_command() -> Result<(), Box> { .stdout(predicate::str::contains("Account not found")); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("account") - .arg("--boc") - .arg("tests/account.boc"); + cmd.arg("account").arg("--boc").arg("tests/account.boc"); cmd.assert() .success() .stdout(predicate::str::contains("acc_type: Active")) @@ -1113,13 +1146,11 @@ fn test_account_command() -> Result<(), Box> { set_config( &["--url", "--addr"], &[&*NETWORK, GIVER_V2_ADDR], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("--config") - .arg(config_path) - .arg("account"); + cmd.arg("--config").arg(config_path).arg("account"); cmd.assert() .success() .stdout(predicate::str::contains("acc_type: Active")) @@ -1131,7 +1162,7 @@ fn test_account_command() -> Result<(), Box> { set_config( &["--url", "--addr"], &[&*NETWORK, "tests/account.boc"], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -1147,13 +1178,11 @@ fn test_account_command() -> Result<(), Box> { .stdout(predicate::str::contains("last_trans_lt:")) .stdout(predicate::str::contains("data_boc:")); - fs::remove_file(config_path)?; env::remove_var("RUST_LOG"); Ok(()) } - #[test] fn test_config_wc() -> Result<(), Box> { let config_path = "test_wc.config"; @@ -1169,8 +1198,7 @@ fn test_config_wc() -> Result<(), Box> { .arg("27377cc9027d4de792f100eb869e18e8") .arg("--wc") .arg("-1"); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -1187,8 +1215,7 @@ fn test_config_wc() -> Result<(), Box> { .arg("config") .arg("--wc") .arg("1"); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -1203,16 +1230,13 @@ fn test_config_wc() -> Result<(), Box> { Ok(()) } - #[test] fn test_account_doesnt_exist() -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("--config") - .arg("default.conf") - .arg("account"); - cmd.assert() - .failure() - .stdout(predicate::str::contains("Error: Address was not found. It must be specified as option or in the config file.")); + cmd.arg("--config").arg("default.conf").arg("account"); + cmd.assert().failure().stdout(predicate::str::contains( + "Error: Address was not found. It must be specified as option or in the config file.", + )); Ok(()) } @@ -1259,7 +1283,9 @@ fn test_decode_msg() -> Result<(), Box> { .success() .stdout(predicate::str::contains(r#"Init": {"#)) .stdout(predicate::str::contains(r#""StateInit": {"#)) - .stdout(predicate::str::contains(r#""data": "te6ccgEBAgEAKAABAcABAEPQAZ6jzp01QGBqmSPd8SBPy4vE1I8GSisk4ihjvGiRJP7g""#)); + .stdout(predicate::str::contains( + r#""data": "te6ccgEBAgEAKAABAcABAEPQAZ6jzp01QGBqmSPd8SBPy4vE1I8GSisk4ihjvGiRJP7g""#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--json") @@ -1290,14 +1316,18 @@ fn test_decode_msg() -> Result<(), Box> { .stdout(predicate::str::contains(r#""value": "0x0000000000000000000000000000000000000000000000000000000000000065""#)); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let output = cmd.arg("call") + let output = cmd + .arg("call") .arg("--abi") .arg(GIVER_V2_ABI) .arg(GIVER_V2_ADDR) .arg("--sign") .arg(GIVER_V2_KEY) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, GIVER_V2_ADDR)) + .arg(format!( + r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, + GIVER_V2_ADDR + )) .output() .expect("Failed to send message."); @@ -1376,7 +1406,9 @@ fn test_decode_body_constructor_for_minus_workchain() -> Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box Result<(), Box> { .arg(DEPOOL_ABI) .arg("addOrdinaryStake") .arg(r#"{"stake":65535}"#); - cmd.assert() - .success() - .stdout(predicate::str::contains("te6ccgEBAQEADgAAGAqsGP0AAAAAAAD//w==")); + cmd.assert().success().stdout(predicate::str::contains( + "te6ccgEBAQEADgAAGAqsGP0AAAAAAAD//w==", + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("run") @@ -1536,8 +1582,7 @@ fn test_depool_body() -> Result<(), Box> { .arg(&wallet_addr) .arg("sendTransaction") .arg(format!(r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":"te6ccgEBAQEADgAAGAqsGP0AAAAAAAD//w=="}}"#, &depool_addr)); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("run") @@ -1630,8 +1675,7 @@ fn test_depool_1() -> Result<(), Box> { .arg(&depool_addr) .arg("events") .arg("-w"); - cmd.assert() - .success(); + cmd.assert().success(); Ok(()) } @@ -1644,7 +1688,11 @@ fn test_depool_2() -> Result<(), Box> { fs::remove_file(key_path)?; let config_path = "fee.conf"; - set_config(&["--depool_fee", "--url"], &["0.7", &*NETWORK], Some(config_path))?; + set_config( + &["--depool_fee", "--url"], + &["0.7", &*NETWORK], + Some(config_path), + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -1730,9 +1778,9 @@ fn test_depool_3() -> Result<(), Box> { .arg(SAFEMSIG_SEED) .arg("--value") .arg("1"); - cmd.assert() - .success() - .stdout(predicate::str::contains(r#"Answer status: TOTAL_PERIOD_MORE_18YEARS"#)); + cmd.assert().success().stdout(predicate::str::contains( + r#"Answer status: TOTAL_PERIOD_MORE_18YEARS"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("run") @@ -1743,7 +1791,10 @@ fn test_depool_3() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "1000000000"#)); let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -1778,9 +1829,15 @@ fn test_depool_3() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "2000000000"#)) - .stdout(predicate::str::contains(format!(r#"receiver": "{}"#, GIVER_V2_ADDR))) + .stdout(predicate::str::contains(format!( + r#"receiver": "{}"#, + GIVER_V2_ADDR + ))) .stdout(predicate::str::contains(r#"withdrawal": "86400"#)) .stdout(predicate::str::contains(r#"total": "86400"#)); @@ -1815,9 +1872,14 @@ fn test_depool_3() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "4000000000"#)) - .stdout(predicate::str::contains(r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012345"#)) + .stdout(predicate::str::contains( + r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012345"#, + )) .stdout(predicate::str::contains(r#"withdrawal": "172800"#)) .stdout(predicate::str::contains(r#"total": "172800"#)); @@ -1848,9 +1910,15 @@ fn test_depool_3() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "2000000000"#)) - .stdout(predicate::str::contains(format!(r#"receiver": "{}"#, GIVER_V2_ADDR))); + .stdout(predicate::str::contains(format!( + r#"receiver": "{}"#, + GIVER_V2_ADDR + ))); Ok(()) } @@ -1887,7 +1955,10 @@ fn test_depool_4() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "3000000000"#)) .stdout(predicate::str::contains(r#"value": "500000000"#)); @@ -1916,7 +1987,10 @@ fn test_depool_4() -> Result<(), Box> { .arg("{}"); cmd.assert() .success() - .stdout(predicate::str::contains(format!(r#"sender": "{}"#, &wallet_addr))) + .stdout(predicate::str::contains(format!( + r#"sender": "{}"#, + &wallet_addr + ))) .stdout(predicate::str::contains(r#"stake": "4000000000"#)) .stdout(predicate::str::contains(r#"value": "500000000"#)); @@ -1946,7 +2020,6 @@ fn test_depool_5() -> Result<(), Box> { .success() .stdout(predicate::str::contains(r#"Succeeded."#)); - let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("run") .arg("--abi") @@ -1954,9 +2027,9 @@ fn test_depool_5() -> Result<(), Box> { .arg(&depool_addr) .arg("getData") .arg("{}"); - cmd.assert() - .success() - .stdout(predicate::str::contains(r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012345"#)); + cmd.assert().success().stdout(predicate::str::contains( + r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012345"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("depool") @@ -1981,14 +2054,12 @@ fn test_depool_5() -> Result<(), Box> { .arg(&depool_addr) .arg("getData") .arg("{}"); - cmd.assert() - .success() - .stdout(predicate::str::contains(r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012346"#)); + cmd.assert().success().stdout(predicate::str::contains( + r#"receiver": "0:0123456789012345012345678901234501234567890123450123456789012346"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("decode") - .arg("stateinit") - .arg(&depool_addr); + cmd.arg("decode").arg("stateinit").arg(&depool_addr); cmd.assert() .success() .stdout(predicate::str::contains(r#"version": "sol 0.52.0"#)) @@ -2038,7 +2109,9 @@ fn test_decode_tvc() -> Result<(), Box> { .arg("tests/decode_fields.tvc") .assert() .success() - .stdout(predicate::str::contains(r#""__pubkey": "0xe8b1d839abe27b2abb9d4a2943a9143a9c7e2ae06799bd24dec1d7a8891ae5dd","#)) + .stdout(predicate::str::contains( + r#""__pubkey": "0xe8b1d839abe27b2abb9d4a2943a9143a9c7e2ae06799bd24dec1d7a8891ae5dd","#, + )) .stdout(predicate::str::contains(r#" "a": "I like it.","#)); let abi_str = fs::read_to_string("tests/test_abi_v2.1.abi.json")?; @@ -2052,7 +2125,9 @@ fn test_decode_tvc() -> Result<(), Box> { .arg("tests/decode_fields.tvc") .assert() .success() - .stdout(predicate::str::contains(r#""__pubkey": "0xe8b1d839abe27b2abb9d4a2943a9143a9c7e2ae06799bd24dec1d7a8891ae5dd","#)) + .stdout(predicate::str::contains( + r#""__pubkey": "0xe8b1d839abe27b2abb9d4a2943a9143a9c7e2ae06799bd24dec1d7a8891ae5dd","#, + )) .stdout(predicate::str::contains(r#" "a": "I like it.","#)); let boc_path = "tests/account.boc"; @@ -2067,7 +2142,6 @@ fn test_decode_tvc() -> Result<(), Box> { .stdout(predicate::str::contains(r#"code_depth": "7"#)) .stdout(predicate::str::contains(r#"data_depth": "1"#)); - let tvc_path = "tests/samples/fakeDepool.tvc"; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("decode") @@ -2217,7 +2291,9 @@ fn test_run_account() -> Result<(), Box> { .assert() .success() .stdout(predicate::str::contains("Succeeded.")) - .stdout(predicate::str::contains(r#"Result: [["1633273052",["1633338588",null]]]"#)); + .stdout(predicate::str::contains( + r#"Result: [["1633273052",["1633338588",null]]]"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("runget") @@ -2227,7 +2303,9 @@ fn test_run_account() -> Result<(), Box> { .assert() .success() .stdout(predicate::str::contains("Succeeded.")) - .stdout(predicate::str::contains(r#"Result: [["1634489970",["1634555506",null]]]"#)); + .stdout(predicate::str::contains( + r#"Result: [["1634489970",["1634555506",null]]]"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("runget") @@ -2239,7 +2317,9 @@ fn test_run_account() -> Result<(), Box> { .assert() .success() .stdout(predicate::str::contains("Succeeded.")) - .stdout(predicate::str::contains(r#"Result: [["1633273052",["1633338588",null]]]"#)); + .stdout(predicate::str::contains( + r#"Result: [["1633273052",["1633338588",null]]]"#, + )); fs::remove_file(config_path)?; @@ -2276,7 +2356,11 @@ fn test_run_account() -> Result<(), Box> { #[test] fn test_run_async_call() -> Result<(), Box> { let config_path = "async_call.conf"; - set_config(&["--url", "--async_call"], &[&*NETWORK, "false"], Some(config_path))?; + set_config( + &["--url", "--async_call"], + &[&*NETWORK, "false"], + Some(config_path), + )?; let time = now_ms(); @@ -2327,7 +2411,11 @@ fn test_run_async_call() -> Result<(), Box> { .success() .stdout(predicate::str::contains(r#""maxQueuedTransactions": "5","#)); - set_config(&["--local_run", "--async_call"], &["true", "false"], Some(config_path))?; + set_config( + &["--local_run", "--async_call"], + &["true", "false"], + Some(config_path), + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -2352,7 +2440,10 @@ fn test_run_async_call() -> Result<(), Box> { .arg("--sign") .arg(GIVER_V2_KEY) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, GIVER_V2_ADDR)) + .arg(format!( + r#"{{"dest":"{}","value":100000000000,"bounce":false}}"#, + GIVER_V2_ADDR + )) .assert() .success() .stdout(predicate::str::contains("Local run succeeded")); @@ -2369,7 +2460,8 @@ fn test_multisig() -> Result<(), Box> { let _ = generate_phrase_and_key(key_path)?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("multisig") + let out = cmd + .arg("multisig") .arg("deploy") .arg("-k") .arg(key_path) @@ -2378,7 +2470,7 @@ fn test_multisig() -> Result<(), Box> { let output = &out.stdout; let mut addr = String::from_utf8_lossy(output).to_string(); addr.replace_range(..addr.find("0:").unwrap_or(0), ""); - addr.replace_range(addr.find("Connecting").unwrap_or(addr.len())-1.., ""); + addr.replace_range(addr.find("Connecting").unwrap_or(addr.len()) - 1.., ""); giver_v2(&addr); @@ -2405,7 +2497,8 @@ fn test_multisig() -> Result<(), Box> { .stdout(predicate::str::contains("Succeeded")); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("multisig") + let out = cmd + .arg("multisig") .arg("deploy") .arg("--setcode") .arg("-k") @@ -2415,7 +2508,7 @@ fn test_multisig() -> Result<(), Box> { let output = &out.stdout; let mut addr = String::from_utf8_lossy(output).to_string(); addr.replace_range(..addr.find("0:").unwrap_or(0), ""); - addr.replace_range(addr.find("Connecting").unwrap_or(addr.len())-1.., ""); + addr.replace_range(addr.find("Connecting").unwrap_or(addr.len()) - 1.., ""); giver_v2(&addr); let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2454,7 +2547,8 @@ fn test_multisig() -> Result<(), Box> { let owners_string = format!(r#"["0x{}","0x{}","0x{}"]"#, key1, key2, key3); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("multisig") + let out = cmd + .arg("multisig") .arg("deploy") .arg("-k") .arg(key_path1) @@ -2467,7 +2561,7 @@ fn test_multisig() -> Result<(), Box> { let output = &out.stdout; let mut addr = String::from_utf8_lossy(output).to_string(); addr.replace_range(..addr.find("0:").unwrap_or(0), ""); - addr.replace_range(addr.find("Connecting").unwrap_or(addr.len())-1.., ""); + addr.replace_range(addr.find("Connecting").unwrap_or(addr.len()) - 1.., ""); giver_v2(&addr); @@ -2549,7 +2643,8 @@ fn test_multisig() -> Result<(), Box> { let seed = generate_phrase_and_key(key_path)?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("multisig") + let out = cmd + .arg("multisig") .arg("deploy") .arg("-k") .arg(seed) @@ -2560,7 +2655,7 @@ fn test_multisig() -> Result<(), Box> { let output = &out.stdout; let mut addr = String::from_utf8_lossy(output).to_string(); addr.replace_range(..addr.find("0:").unwrap_or(0), ""); - addr.replace_range(addr.find("Connecting").unwrap_or(addr.len())-1.., ""); + addr.replace_range(addr.find("Connecting").unwrap_or(addr.len()) - 1.., ""); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("call") @@ -2618,14 +2713,13 @@ fn test_alternative_syntax() -> Result<(), Box> { .arg("1000000000") .arg("--bounce") .arg("false"); - cmd.assert() - .success(); + cmd.assert().success(); let config_path = "alternative.config"; set_config( &["--url", "--abi", "--addr", "--keys"], &[&*NETWORK, SAFEMSIG_ABI, &address, key_path], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2655,24 +2749,26 @@ fn test_alternative_syntax() -> Result<(), Box> { set_config(&["--method"], &["getParameters"], Some(config_path))?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("--config") - .arg(config_path) - .arg("runx"); + cmd.arg("--config").arg(config_path).arg("runx"); cmd.assert() .success() .stdout(predicate::str::contains("Succeeded.")); set_config( &["--method", "--keys", "--abi", "--addr", "--parameters"], - &["sendTransaction", GIVER_V2_KEY, GIVER_V2_ABI, GIVER_V2_ADDR, "tests/test.args"], - Some(config_path))?; + &[ + "sendTransaction", + GIVER_V2_KEY, + GIVER_V2_ABI, + GIVER_V2_ADDR, + "tests/test.args", + ], + Some(config_path), + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("--config") - .arg(config_path) - .arg("callx"); - cmd.assert() - .success(); + cmd.arg("--config").arg(config_path).arg("callx"); + cmd.assert().success(); let test_tvc = "tests/samples/test.tvc"; let test_abi = "tests/samples/test.abi.json"; @@ -2694,7 +2790,9 @@ fn test_alternative_syntax() -> Result<(), Box> { .success() .stdout(predicate::str::contains("Succeeded.")) .stdout(predicate::str::contains("Result: {")) - .stdout(predicate::str::contains(r#""value0": "0x000000000000000000000000000000000000000000000000000000000000000f"#)); + .stdout(predicate::str::contains( + r#""value0": "0x000000000000000000000000000000000000000000000000000000000000000f"#, + )); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("callx") @@ -2710,8 +2808,7 @@ fn test_alternative_syntax() -> Result<(), Box> { .arg("ctype") .arg("--ctype") .arg("14"); - cmd.assert() - .success(); + cmd.assert().success(); fs::remove_file(config_path)?; fs::remove_file(key_path)?; @@ -2721,11 +2818,7 @@ fn test_alternative_syntax() -> Result<(), Box> { #[test] fn test_options_priority() -> Result<(), Box> { let config_path = "options.config"; - set_config( - &["--url"], - &[&*NETWORK], - Some(config_path) - )?; + set_config(&["--url"], &[&*NETWORK], Some(config_path))?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -2738,8 +2831,11 @@ fn test_options_priority() -> Result<(), Box> { set_config( &["--project_id", "--access_key"], - &["b2ad82504ee54fccb5bc6db8cbb3df1e", "27377cc9027d4de792f100eb869e18e8"], - Some(config_path) + &[ + "b2ad82504ee54fccb5bc6db8cbb3df1e", + "27377cc9027d4de792f100eb869e18e8", + ], + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2760,8 +2856,7 @@ fn test_options_priority() -> Result<(), Box> { .arg("clear") .arg("--project_id") .arg("--access_key"); - cmd.assert() - .success(); + cmd.assert().success(); let key_path = "options_msig.key"; @@ -2770,7 +2865,7 @@ fn test_options_priority() -> Result<(), Box> { set_config( &["--abi", "--addr", "--keys", "--method", "--parameters"], &[SAFEMSIG_ABI, &address, key_path, "dummyMethod", "{}"], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2791,13 +2886,26 @@ fn test_options_priority() -> Result<(), Box> { .arg("1000000000") .arg("--bounce") .arg("false"); - cmd.assert() - .success(); + cmd.assert().success(); set_config( - &["--abi", "--addr", "--keys", "--method", "--wc", "--parameters"], - &[GIVER_V2_ABI, GIVER_V2_ADDR, GIVER_V2_KEY, "dummyMethod", "12", "{\"param\":11}"], - Some(config_path) + &[ + "--abi", + "--addr", + "--keys", + "--method", + "--wc", + "--parameters", + ], + &[ + GIVER_V2_ABI, + GIVER_V2_ADDR, + GIVER_V2_KEY, + "dummyMethod", + "12", + "{\"param\":11}", + ], + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2843,10 +2951,13 @@ fn test_options_priority() -> Result<(), Box> { set_config( &["--abi", "--addr", "--keys", "--method", "--parameters"], &[SAFEMSIG_ABI, &address, key_path, "dummyMethod", "{}"], - Some(config_path) + Some(config_path), )?; - let params = format!("{{\"dest\":\"{}\",\"value\":1000000000,\"bounce\":false}}", address.clone()); + let params = format!( + "{{\"dest\":\"{}\",\"value\":1000000000,\"bounce\":false}}", + address.clone() + ); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") .arg(config_path) @@ -2858,13 +2969,26 @@ fn test_options_priority() -> Result<(), Box> { .arg(GIVER_V2_ADDR) .arg("sendTransaction") .arg(params); - cmd.assert() - .success(); + cmd.assert().success(); set_config( - &["--abi", "--addr", "--keys", "--method", "--wc", "--parameters"], - &[GIVER_V2_ABI, GIVER_V2_ADDR, GIVER_V2_KEY, "dummyMethod", "12", "{\"param\":11}"], - Some(config_path) + &[ + "--abi", + "--addr", + "--keys", + "--method", + "--wc", + "--parameters", + ], + &[ + GIVER_V2_ABI, + GIVER_V2_ADDR, + GIVER_V2_KEY, + "dummyMethod", + "12", + "{\"param\":11}", + ], + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2897,7 +3021,6 @@ fn test_options_priority() -> Result<(), Box> { .success() .stdout(predicate::str::contains("maxQueuedTransactions\": \"5")); - fs::remove_file(config_path)?; fs::remove_file(key_path)?; @@ -2911,11 +3034,7 @@ fn test_alternative_parameters() -> Result<(), Box> { let key_path = "arguments.key"; let config_path = "arguments.conf.json"; - set_config( - &["--url"], - &[&*NETWORK], - Some(config_path) - )?; + set_config(&["--url"], &[&*NETWORK], Some(config_path))?; let address = deploy_contract(key_path, tvc_path, abi_path, "{}")?; @@ -2940,8 +3059,7 @@ fn test_alternative_parameters() -> Result<(), Box> { .arg("3") .arg("--method") .arg("4"); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -2962,14 +3080,14 @@ fn test_alternative_parameters() -> Result<(), Box> { .arg("4") .arg("--method") .arg("5"); - cmd.assert() - .success() - .stdout(predicate::str::contains("value0\": \"0x0000000000000000000000000000000000000000000000000000000000000018")); + cmd.assert().success().stdout(predicate::str::contains( + "value0\": \"0x0000000000000000000000000000000000000000000000000000000000000018", + )); set_config( &["--abi", "--addr", "--keys", "--method"], &[abi_path, &address.clone(), key_path, "add"], - Some(config_path) + Some(config_path), )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; @@ -2985,15 +3103,9 @@ fn test_alternative_parameters() -> Result<(), Box> { .arg("3") .arg("--method") .arg("4"); - cmd.assert() - .success(); - - set_config( - &["--method"], - &["get"], - Some(config_path) - )?; + cmd.assert().success(); + set_config(&["--method"], &["get"], Some(config_path))?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -3008,9 +3120,9 @@ fn test_alternative_parameters() -> Result<(), Box> { .arg("4") .arg("--method") .arg("5"); - cmd.assert() - .success() - .stdout(predicate::str::contains("value0\": \"0x0000000000000000000000000000000000000000000000000000000000000022")); + cmd.assert().success().stdout(predicate::str::contains( + "value0\": \"0x0000000000000000000000000000000000000000000000000000000000000022", + )); fs::remove_file(key_path)?; fs::remove_file(config_path)?; @@ -3051,13 +3163,14 @@ fn test_override_url() -> Result<(), Box> { fn test_alternative_paths() -> Result<(), Box> { let key_path = "link_path.key.json"; let config_path = "link_path.config"; - set_config( - &["--url"], - &[&*NETWORK], - Some(config_path) - )?; + set_config(&["--url"], &[&*NETWORK], Some(config_path))?; - let address = deploy_contract(key_path, SAFEMSIG_TVC, SAFEMSIG_ABI_LINK, SAFEMSIG_CONSTR_ARG)?; + let address = deploy_contract( + key_path, + SAFEMSIG_TVC, + SAFEMSIG_ABI_LINK, + SAFEMSIG_CONSTR_ARG, + )?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -3082,15 +3195,13 @@ fn test_alternative_paths() -> Result<(), Box> { .arg(SAFEMSIG_SEED) .arg(&address) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, &address)); - cmd.assert() - .success(); + .arg(format!( + r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, + &address + )); + cmd.assert().success(); - set_config( - &["--abi"], - &[SAFEMSIG_ABI_LINK], - Some(config_path) - )?; + set_config(&["--abi"], &[SAFEMSIG_ABI_LINK], Some(config_path))?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -3104,7 +3215,6 @@ fn test_alternative_paths() -> Result<(), Box> { .success() .stdout(predicate::str::contains("maxQueuedTransactions\": \"5")); - let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") .arg(config_path) @@ -3125,8 +3235,7 @@ fn test_alternative_paths() -> Result<(), Box> { .arg("1") .arg("--payload") .arg(""); - cmd.assert() - .success(); + cmd.assert().success(); let abi_str = fs::read_to_string(SAFEMSIG_ABI)?; @@ -3162,7 +3271,8 @@ fn test_alternative_paths() -> Result<(), Box> { .stdout(predicate::str::contains("Transaction succeeded.")); let mut cmd = Command::cargo_bin(BIN_NAME)?; - let out = cmd.arg("-j") + let out = cmd + .arg("-j") .arg("--config") .arg(config_path) .arg("message") @@ -3172,13 +3282,19 @@ fn test_alternative_paths() -> Result<(), Box> { .arg(SAFEMSIG_SEED) .arg(&address) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, &address)) + .arg(format!( + r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, + &address + )) .output() .expect("Failed to generate message"); let result = String::from_utf8_lossy(&out.stdout).to_string(); let data = serde_json::from_str::(&result).unwrap_or(json!({})); - let message = data["Message"].to_string().trim_end_matches('\"') - .trim_start_matches('\"').to_string(); + let message = data["Message"] + .to_string() + .trim_end_matches('\"') + .trim_start_matches('\"') + .to_string(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -3187,8 +3303,7 @@ fn test_alternative_paths() -> Result<(), Box> { .arg("--abi") .arg(SAFEMSIG_ABI_LINK) .arg(message); - cmd.assert() - .success(); + cmd.assert().success(); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") @@ -3197,9 +3312,11 @@ fn test_alternative_paths() -> Result<(), Box> { .arg("--abi") .arg(SAFEMSIG_ABI_LINK) .arg("sendTransaction") - .arg(format!(r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, &address)); - cmd.assert() - .success(); + .arg(format!( + r#"{{"dest":"{}","value":1000000000,"bounce":true,"flags":1,"payload":""}}"#, + &address + )); + cmd.assert().success(); let tvc_path = "msig.tvc2"; fs::copy(SAFEMSIG_TVC, tvc_path)?; @@ -3253,7 +3370,6 @@ fn test_alternative_paths() -> Result<(), Box> { .success() .stdout(predicate::str::contains("Log saved to ")); - let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") .arg(config_path)