From f84ac8bc45f2b1603353295b8b20687cec43e632 Mon Sep 17 00:00:00 2001 From: Mikhael Skvortsov Date: Wed, 23 Nov 2022 17:12:02 +0300 Subject: [PATCH 1/3] Lift events subcommand to the toplevel --- src/depool.rs | 115 +-------------------------------------------- src/events.rs | 126 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 20 ++++++++ 3 files changed, 147 insertions(+), 114 deletions(-) create mode 100644 src/events.rs diff --git a/src/depool.rs b/src/depool.rs index 36ac9ad4..e351d653 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -21,13 +21,12 @@ use crate::helpers::{ now, TonClient, answer_filter, - events_filter, print_message, }; use crate::multisig::{send_with_body, MSIG_ABI}; use clap::{App, ArgMatches, SubCommand, Arg, AppSettings}; -use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet, ParamsOfDecodeMessageBody}; +use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet}; use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection}; use crate::call::{process_message}; @@ -188,18 +187,6 @@ pub fn create_depool_command<'a, 'b>() -> App<'a, 'b> { .arg(wallet_arg.clone()) .arg(wait_answer.clone()) .arg(keys_arg.clone()))) - .subcommand(SubCommand::with_name("events") - .about("Prints depool events.") - .setting(AppSettings::AllowLeadingHyphen) - .arg(Arg::with_name("SINCE") - .takes_value(true) - .long("--since") - .short("-s") - .help("Prints events since this unixtime.")) - .arg(Arg::with_name("WAITONE") - .long("--wait-one") - .short("-w") - .help("Waits until new event will be emitted.")) ) } struct CommandData<'a> { @@ -313,9 +300,6 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( return set_withdraw_command(&config, &depool, &wallet, &keys, enable_withdraw).await; } } - if let Some(m) = m.subcommand_matches("events") { - return events_command(m, &config, &depool).await - } if let Some(m) = m.subcommand_matches("answers") { return answer_command(m, &config, &depool).await } @@ -372,103 +356,6 @@ async fn print_answer(ton: TonClient, message: &serde_json::Value) -> Result <() Ok(()) } -/* - * Events command - */ - -async fn events_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Result<(), String> { - let since = m.value_of("SINCE"); - let wait_for = m.is_present("WAITONE"); - let depool = Some(depool); - print_args!(depool, since); - if !wait_for { - let since = since.map(|s| { - u32::from_str_radix(s, 10) - .map_err(|e| format!(r#"cannot parse "since" option: {}"#, e)) - }) - .transpose()? - .unwrap_or(0); - get_events(config, depool.unwrap(), since).await - } else { - wait_for_event(config, depool.unwrap()).await - } -} - -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")?); - - let body = event["body"].as_str() - .ok_or("failed to serialize event body")?; - let def_config = Config::default(); - let result = ton_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))?, - body: body.to_owned(), - is_internal: false, - ..Default::default() - }, - ).await; - let (name, args) = if result.is_err() { - ("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))?) - }; - - 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")?, - args - ); - Ok(()) -} - -async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), String> { - let ton = create_client_verbose(&config)?; - let _addr = load_ton_address(depool, &config)?; - - let events = ton_client::net::query_collection( - ton.clone(), - ParamsOfQueryCollection { - 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 }]), - ..Default::default() - }, - ).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?; - } - println!("Done"); - Ok(()) -} - -async fn wait_for_event(config: &Config, depool: &str) -> Result<(), String> { - let ton = create_client_verbose(&config)?; - let _addr = load_ton_address(depool, &config)?; - println!("Waiting for a new event..."); - let event = ton_client::net::wait_for_collection( - ton.clone(), - ParamsOfWaitForCollection { - collection: "messages".to_owned(), - filter: Some(events_filter(depool, now()?)), - result: "id body created_at created_at_string".to_owned(), - timeout: Some(config.timeout), - ..Default::default() - }, - - ).await.map_err(|e| println!("failed to query event: {}", e)); - if event.is_ok() { - print_event(ton.clone(), &event.unwrap().result).await?; - } - Ok(()) -} /* * Stake commands */ diff --git a/src/events.rs b/src/events.rs new file mode 100644 index 00000000..f82be92f --- /dev/null +++ b/src/events.rs @@ -0,0 +1,126 @@ +/* + * Copyright 2022 TON DEV SOLUTIONS LTD. + * + * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use + * this file except in compliance with the License. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific TON DEV software governing permissions and + * limitations under the License. + */ + +use crate::config::Config; +use crate::helpers::{ + create_client_verbose, + load_abi, + load_ton_address, + now, + TonClient, + events_filter, abi_from_matches_or_config, +}; +use clap::ArgMatches; + +use ton_client::abi::{ParamsOfDecodeMessageBody, Abi}; +use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection}; + +pub async fn events_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + let addr = m.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 abi_path = abi_from_matches_or_config(m, config)?; + let abi = load_abi(&abi_path, config).await?; + + let since = m.value_of("SINCE"); + let wait_for = m.is_present("WAITONE"); + + if !wait_for { + let since = since.map(|s| { + u32::from_str_radix(s, 10) + .map_err(|e| format!(r#"cannot parse "since" option: {}"#, e)) + }) + .transpose()? + .unwrap_or(0); + get_events(config, abi, &addr, since).await + } else { + wait_for_event(config, abi, &addr).await + } +} + +async fn print_event(ton: TonClient, abi: &Abi, event: &serde_json::Value) -> Result<(), String> { + println!("event {}", event["id"].as_str() + .ok_or("failed to serialize event id")?); + + let body = event["body"].as_str() + .ok_or("failed to serialize event body")?; + let result = ton_client::abi::decode_message_body( + ton.clone(), + ParamsOfDecodeMessageBody { + abi: abi.clone(), + body: body.to_owned(), + is_internal: false, + ..Default::default() + }, + ).await; + let (name, args) = if result.is_err() { + ("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))?) + }; + + 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")?, + args + ); + Ok(()) +} + +async fn get_events(config: &Config, abi: Abi, addr: &str, since: u32) -> Result<(), String> { + let ton = create_client_verbose(&config)?; + let _addr = load_ton_address(addr, &config)?; + + let events = ton_client::net::query_collection( + ton.clone(), + ParamsOfQueryCollection { + collection: "messages".to_owned(), + filter: Some(events_filter(addr, since)), + result: "id body created_at created_at_string".to_owned(), + 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))?; + println!("{} events found", events.result.len()); + for event in &events.result { + print_event(ton.clone(), &abi, event).await?; + } + println!("Done"); + Ok(()) +} + +async fn wait_for_event(config: &Config, abi: Abi, addr: &str) -> Result<(), String> { + let ton = create_client_verbose(&config)?; + let _addr = load_ton_address(addr, &config)?; + println!("Waiting for a new event..."); + let event = ton_client::net::wait_for_collection( + ton.clone(), + ParamsOfWaitForCollection { + collection: "messages".to_owned(), + filter: Some(events_filter(addr, now()?)), + result: "id body created_at created_at_string".to_owned(), + timeout: Some(config.timeout), + ..Default::default() + }, + + ).await.map_err(|e| println!("failed to query event: {}", e)); + if event.is_ok() { + print_event(ton.clone(), &abi, &event.unwrap().result).await?; + } + Ok(()) +} diff --git a/src/main.rs b/src/main.rs index 7fc761db..5c5c57a4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,6 +30,7 @@ mod debot; mod deploy; mod depool; mod depool_abi; +mod events; mod genaddr; mod getconfig; mod helpers; @@ -53,6 +54,7 @@ use decode::{create_decode_command, decode_command}; use debug::{create_debug_command, debug_command}; use deploy::{deploy_contract, generate_deploy_message}; use depool::{create_depool_command, depool_command}; +use events::events_command; use helpers::{load_ton_address, load_abi, create_client_local, query_raw, contract_data_from_matches_or_config_alias}; use genaddr::generate_address; @@ -864,6 +866,20 @@ async fn main_internal() -> Result <(), String> { .long("--default_config") .short("-e") .conflicts_with("CONFIG_TXNS")); + let events_cmd = SubCommand::with_name("events") + .about("Prints account events.") + .setting(AppSettings::AllowLeadingHyphen) + .arg(abi_arg.clone()) + .arg(address_arg.clone()) + .arg(Arg::with_name("SINCE") + .takes_value(true) + .long("--since") + .short("-s") + .help("Prints events since this unixtime.")) + .arg(Arg::with_name("WAITONE") + .long("--wait-one") + .short("-w") + .help("Waits until new event will be emitted.")); let version = format!("{}\nCOMMIT_ID: {}\nBUILD_DATE: {}\nCOMMIT_DATE: {}\nGIT_BRANCH: {}", env!("CARGO_PKG_VERSION"), @@ -925,6 +941,7 @@ async fn main_internal() -> Result <(), String> { .subcommand(deployx_cmd) .subcommand(runx_cmd) .subcommand(update_config_param_cmd) + .subcommand(events_cmd) .setting(AppSettings::SubcommandRequired); #[cfg(feature = "sold")] let matches = matches.subcommand(create_compile_command()); @@ -1100,6 +1117,9 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), if let Some(m) = matches.subcommand_matches("replay") { return replay_command(m, config).await; } + if let Some(m) = matches.subcommand_matches("events") { + return events_command(m, &config).await + } #[cfg(feature = "sold")] if let Some(m) = matches.subcommand_matches("compile") { return compile_command(m, &config).await; From 301cbfea05a996e335cbe27ec825496c6049d2dd Mon Sep 17 00:00:00 2001 From: Mikhael Skvortsov Date: Wed, 23 Nov 2022 18:04:59 +0300 Subject: [PATCH 2/3] Fix tests --- src/events.rs | 2 +- tests/depool-abi.json | 355 ++++++++++++++++++++++++++++++++++++++++++ tests/test_cli.rs | 14 +- 3 files changed, 363 insertions(+), 8 deletions(-) create mode 100644 tests/depool-abi.json diff --git a/src/events.rs b/src/events.rs index f82be92f..c85e569e 100644 --- a/src/events.rs +++ b/src/events.rs @@ -95,7 +95,7 @@ async fn get_events(config: &Config, abi: Abi, addr: &str, since: u32) -> Result 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 account events: {}", e))?; println!("{} events found", events.result.len()); for event in &events.result { print_event(ton.clone(), &abi, event).await?; diff --git a/tests/depool-abi.json b/tests/depool-abi.json new file mode 100644 index 00000000..082ce8a6 --- /dev/null +++ b/tests/depool-abi.json @@ -0,0 +1,355 @@ +{ + "ABI version": 2, + "header": ["time", "expire"], + "functions": [ + { + "name": "constructor", + "inputs": [ + {"name":"minStake","type":"uint64"}, + {"name":"validatorAssurance","type":"uint64"}, + {"name":"proxyCode","type":"cell"}, + {"name":"validatorWallet","type":"address"}, + {"name":"participantRewardFraction","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "addOrdinaryStake", + "inputs": [ + {"name":"stake","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "withdrawFromPoolingRound", + "inputs": [ + {"name":"withdrawValue","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "addVestingStake", + "inputs": [ + {"name":"stake","type":"uint64"}, + {"name":"beneficiary","type":"address"}, + {"name":"withdrawalPeriod","type":"uint32"}, + {"name":"totalPeriod","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "addLockStake", + "inputs": [ + {"name":"stake","type":"uint64"}, + {"name":"beneficiary","type":"address"}, + {"name":"withdrawalPeriod","type":"uint32"}, + {"name":"totalPeriod","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "withdrawPart", + "inputs": [ + {"name":"withdrawValue","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "withdrawAll", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "cancelWithdrawal", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "setVestingDonor", + "inputs": [ + {"name":"donor","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "setLockDonor", + "inputs": [ + {"name":"donor","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "transferStake", + "inputs": [ + {"name":"dest","type":"address"}, + {"name":"amount","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "participateInElections", + "id": "0x4E73744B", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"validatorKey","type":"uint256"}, + {"name":"stakeAt","type":"uint32"}, + {"name":"maxFactor","type":"uint32"}, + {"name":"adnlAddr","type":"uint256"}, + {"name":"signature","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "ticktock", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "completeRoundWithChunk", + "inputs": [ + {"name":"roundId","type":"uint64"}, + {"name":"chunkSize","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "completeRound", + "inputs": [ + {"name":"roundId","type":"uint64"}, + {"name":"participantQty","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "onStakeAccept", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"comment","type":"uint32"}, + {"name":"elector","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "onStakeReject", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"comment","type":"uint32"}, + {"name":"elector","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "onSuccessToRecoverStake", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"elector","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "onFailToRecoverStake", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"elector","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "terminator", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "setValidatorRewardFraction", + "inputs": [ + {"name":"fraction","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "receiveFunds", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "getLastRoundInfo", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "getParticipantInfo", + "inputs": [ + {"name":"addr","type":"address"} + ], + "outputs": [ + {"name":"total","type":"uint64"}, + {"name":"withdrawValue","type":"uint64"}, + {"name":"reinvest","type":"bool"}, + {"name":"reward","type":"uint64"}, + {"name":"stakes","type":"map(uint64,uint64)"}, + {"components":[{"name":"remainingAmount","type":"uint64"},{"name":"lastWithdrawalTime","type":"uint64"},{"name":"withdrawalPeriod","type":"uint32"},{"name":"withdrawalValue","type":"uint64"},{"name":"owner","type":"address"}],"name":"vestings","type":"map(uint64,tuple)"}, + {"components":[{"name":"remainingAmount","type":"uint64"},{"name":"lastWithdrawalTime","type":"uint64"},{"name":"withdrawalPeriod","type":"uint32"},{"name":"withdrawalValue","type":"uint64"},{"name":"owner","type":"address"}],"name":"locks","type":"map(uint64,tuple)"}, + {"name":"vestingDonor","type":"address"}, + {"name":"lockDonor","type":"address"} + ] + }, + { + "name": "getDePoolInfo", + "inputs": [ + ], + "outputs": [ + {"name":"poolClosed","type":"bool"}, + {"name":"minStake","type":"uint64"}, + {"name":"validatorAssurance","type":"uint64"}, + {"name":"participantRewardFraction","type":"uint8"}, + {"name":"validatorRewardFraction","type":"uint8"}, + {"name":"balanceThreshold","type":"uint64"}, + {"name":"validatorWallet","type":"address"}, + {"name":"proxies","type":"address[]"}, + {"name":"stakeFee","type":"uint64"}, + {"name":"retOrReinvFee","type":"uint64"}, + {"name":"proxyFee","type":"uint64"} + ] + }, + { + "name": "getParticipants", + "inputs": [ + ], + "outputs": [ + {"name":"participants","type":"address[]"} + ] + }, + { + "name": "getDePoolBalance", + "inputs": [ + ], + "outputs": [ + {"name":"value0","type":"int256"} + ] + }, + { + "name": "getRounds", + "inputs": [ + ], + "outputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"supposedElectedAt","type":"uint32"},{"name":"unfreeze","type":"uint32"},{"name":"stakeHeldFor","type":"uint32"},{"name":"vsetHashInElectionPhase","type":"uint256"},{"name":"step","type":"uint8"},{"name":"completionReason","type":"uint8"},{"name":"stake","type":"uint64"},{"name":"recoveredStake","type":"uint64"},{"name":"unused","type":"uint64"},{"name":"isValidatorStakeCompleted","type":"bool"},{"name":"participantReward","type":"uint64"},{"name":"participantQty","type":"uint32"},{"name":"validatorStake","type":"uint64"},{"name":"validatorRemainingStake","type":"uint64"},{"name":"handledStakesAndRewards","type":"uint64"}],"name":"rounds","type":"map(uint64,tuple)"} + ] + } + ], + "data": [ + ], + "events": [ + { + "name": "DePoolClosed", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "RoundStakeIsAccepted", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"comment","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "RoundStakeIsRejected", + "inputs": [ + {"name":"queryId","type":"uint64"}, + {"name":"comment","type":"uint32"} + ], + "outputs": [ + ] + }, + { + "name": "ProxyHasRejectedTheStake", + "inputs": [ + {"name":"queryId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "ProxyHasRejectedRecoverRequest", + "inputs": [ + {"name":"roundId","type":"uint64"} + ], + "outputs": [ + ] + }, + { + "name": "RoundCompleted", + "inputs": [ + {"components":[{"name":"id","type":"uint64"},{"name":"supposedElectedAt","type":"uint32"},{"name":"unfreeze","type":"uint32"},{"name":"stakeHeldFor","type":"uint32"},{"name":"vsetHashInElectionPhase","type":"uint256"},{"name":"step","type":"uint8"},{"name":"completionReason","type":"uint8"},{"name":"stake","type":"uint64"},{"name":"recoveredStake","type":"uint64"},{"name":"unused","type":"uint64"},{"name":"isValidatorStakeCompleted","type":"bool"},{"name":"participantReward","type":"uint64"},{"name":"participantQty","type":"uint32"},{"name":"validatorStake","type":"uint64"},{"name":"validatorRemainingStake","type":"uint64"},{"name":"handledStakesAndRewards","type":"uint64"}],"name":"round","type":"tuple"} + ], + "outputs": [ + ] + }, + { + "name": "StakeSigningRequested", + "inputs": [ + {"name":"electionId","type":"uint32"}, + {"name":"proxy","type":"address"} + ], + "outputs": [ + ] + }, + { + "name": "TooLowDePoolBalance", + "inputs": [ + {"name":"replenishment","type":"uint256"} + ], + "outputs": [ + ] + }, + { + "name": "RewardFractionsChanged", + "inputs": [ + {"name":"validator","type":"uint8"}, + {"name":"participants","type":"uint8"} + ], + "outputs": [ + ] + }, + { + "name": "InternalError", + "inputs": [ + {"name":"ec","type":"uint16"} + ], + "outputs": [ + ] + } + ] +} diff --git a/tests/test_cli.rs b/tests/test_cli.rs index 2537385e..1ae805f0 100644 --- a/tests/test_cli.rs +++ b/tests/test_cli.rs @@ -1610,20 +1610,20 @@ fn test_depool_1() -> Result<(), Box> { .stdout(predicate::str::contains(r#"value": "1000000000"#)); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("depool") - .arg("--addr") - .arg(&depool_addr) - .arg("events"); + cmd.arg("events") + .arg("--abi") + .arg("tests/depool-abi.json") + .arg(&depool_addr); cmd.assert() .success() .stdout(predicate::str::contains(r#"StakeSigningRequested"#)) .stdout(predicate::str::contains(r#"{"electionId":"1","proxy":"0:0000000000000000000000000000000000000000000000000000000000000002"}"#)); let mut cmd = Command::cargo_bin(BIN_NAME)?; - cmd.arg("depool") - .arg("--addr") + cmd.arg("events") + .arg("--abi") + .arg("tests/depool-abi.json") .arg(&depool_addr) - .arg("events") .arg("-w"); cmd.assert() .success(); From 22cf18a4408ec0002113fe6b46b117bdc9022623 Mon Sep 17 00:00:00 2001 From: Mikhael Skvortsov Date: Wed, 23 Nov 2022 18:12:44 +0300 Subject: [PATCH 3/3] Bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 471d296a..267028dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2958,7 +2958,7 @@ dependencies = [ [[package]] name = "tonos-cli" -version = "0.29.1" +version = "0.30.0" dependencies = [ "assert_cmd", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index d82eb110..e8d40c90 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ license = 'Apache-2.0' name = 'tonos-cli' readme = 'README.md' repository = 'https://github.com/tonlabs/tonos-cli' -version = '0.29.1' +version = '0.30.0' [features] sold = ["dep:sold"]