Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: New command - staking #227

Merged
merged 54 commits into from
Oct 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
54ef498
start
Jul 19, 2023
e2f3af7
added Withdraw, WithdrawAll
Jul 19, 2023
5d00339
added Unstake, UnstakeAll
Jul 19, 2023
7089c69
refactored Withdraw, WithdrawAll
Jul 22, 2023
538253c
added ViewBalance
Jul 22, 2023
2ac06dc
added ValidatorList
Jul 28, 2023
17fd266
refactored
Jul 28, 2023
5f5d1e2
fixed
Jul 28, 2023
39ccfb7
refactored
Jul 28, 2023
bca4e17
added delegated stake for view_account_summary
Jul 28, 2023
3f6b8ef
refactored get_validator_list()
Jul 29, 2023
e8fd341
refactored delegated_stake
Jul 29, 2023
9ddcb47
fixed
Jul 29, 2023
13f1b7b
added Stake, StakeAll
Aug 2, 2023
d94aade
added Deposit, DepositAndStake
Aug 2, 2023
9ad54aa
fixed <non-printable data (0 B)>
Aug 2, 2023
629d0d4
Merge branch 'master' into staking
FroVolod Aug 23, 2023
6acc1cb
Merge branch 'master' into staking
FroVolod Sep 3, 2023
b2646c8
updated to "order networks selection ..." #225
Sep 3, 2023
cc04fe1
added validators url
Sep 3, 2023
66d3b40
Merge branch 'master' into staking
FroVolod Sep 3, 2023
0d7e3b8
Merge branch 'master' into staking
FroVolod Sep 4, 2023
3591c95
Merge branch 'master' into staking
FroVolod Sep 9, 2023
d461b41
fixed unstake message
Sep 10, 2023
4e9af99
Merge branch 'master' into staking
FroVolod Sep 25, 2023
d93fedf
updated to "near-gas"
Sep 26, 2023
e8fbce9
clippy
Sep 26, 2023
70b7eaf
Merge branch 'master' into staking
FroVolod Sep 29, 2023
4fef7c4
updated: interactive-clap = "0.2.5"
Sep 30, 2023
3241e84
Merge branch 'master' into staking
FroVolod Oct 6, 2023
49809df
Merge remote-tracking branch 'origin/master' into staking
Oct 18, 2023
dbf79fc
refactor: optimized and simplified the delegated stake fetching
frol Oct 22, 2023
e6ba1ff
refactor: serde_json::to_vec() instead of .to_string().into_bytes()
Oct 22, 2023
cf8cfb6
Update src/commands/staking/delegate/unstake.rs
FroVolod Oct 22, 2023
4d92ff3
refactored get_validator_list()
Oct 23, 2023
1ebba51
refactored
Oct 24, 2023
1645264
updated input_account_id()
Oct 24, 2023
205d93a
refactored get_validator_list()
Oct 25, 2023
3038d61
added get_used_delegated_validator_list()
Oct 25, 2023
2e7a484
updated GUIDE
Oct 25, 2023
770796d
Update src/commands/staking/delegate/mod.rs
FroVolod Oct 26, 2023
2998e10
renamed Delegate to Delegation
Oct 26, 2023
fa9a653
fixed GUIDE
Oct 26, 2023
33abbb2
fixed GUIDE
Oct 26, 2023
d40363f
docs: Updated the GUIDE
frol Oct 26, 2023
7461a4f
updated StakeDelegationCommand
Oct 26, 2023
877098c
fixed GUIDE
Oct 26, 2023
8559cbc
updated view-balance
Oct 26, 2023
829144a
updated get_used_delegated_validator_list()
Oct 27, 2023
dde9cb8
updated cargo.lock
Oct 30, 2023
371bdf5
Merge remote-tracking branch 'origin/master' into staking
Oct 30, 2023
60f7e5c
fixed GUIDES
frol Oct 31, 2023
07960bb
refactor: common.rs
frol Oct 31, 2023
45c34d1
refactor: Refactored success messages and the `from_previous_context`
frol Oct 31, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
318 changes: 290 additions & 28 deletions docs/GUIDE.en.md

Large diffs are not rendered by default.

321 changes: 296 additions & 25 deletions docs/GUIDE.ru.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,10 @@ impl From<SignerAccountIdContext> for crate::commands::ActionContext {
],
new_account_id.clone())
} else {
let args = json!({
let args = serde_json::to_vec(&json!({
"new_account_id": new_account_id.clone().to_string(),
"new_public_key": item.account_properties.public_key.to_string()
})
.to_string()
.into_bytes();
}))?;

if let Some(linkdrop_account_id) = &network_config.linkdrop_account_id {
if new_account_id.is_sub_account_of(linkdrop_account_id)
Expand Down
6 changes: 3 additions & 3 deletions src/commands/account/storage_management/storage_deposit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ impl SignerAccountIdContext {
actions: vec![near_primitives::transaction::Action::FunctionCall(
near_primitives::transaction::FunctionCallAction {
method_name: "storage_deposit".to_string(),
args: serde_json::json!({ "account_id": &receiver_account_id })
.to_string()
.into_bytes(),
args: serde_json::to_vec(&serde_json::json!({
"account_id": &receiver_account_id
}))?,
gas: crate::common::NearGas::from_tgas(50).as_gas(),
deposit: deposit.as_yoctonear(),
},
Expand Down
6 changes: 2 additions & 4 deletions src/commands/account/storage_management/storage_withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,9 @@ impl SignerAccountIdContext {
actions: vec![near_primitives::transaction::Action::FunctionCall(
near_primitives::transaction::FunctionCallAction {
method_name: "storage_withdraw".to_string(),
args: serde_json::json!({
args: serde_json::to_vec(&serde_json::json!({
"amount": amount.clone().as_yoctonear().to_string()
})
.to_string()
.into_bytes(),
}))?,
gas: crate::common::NearGas::from_tgas(50).as_gas(),
deposit: near_token::NearToken::from_yoctonear(1).as_yoctonear(),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ impl AccountContext {
.blocking_call_view_function(
&contract_account_id,
"storage_balance_of",
serde_json::json!({
serde_json::to_vec(&serde_json::json!({
"account_id": account_id.to_string(),
})
.to_string()
.into_bytes(),
}))?,
block_reference.clone(),
)
.wrap_err_with(|| {
Expand Down
6 changes: 2 additions & 4 deletions src/commands/account/update_social_profile/sign_as.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,9 @@ impl From<SignerContext> for crate::commands::ActionContext {
.blocking_call_view_function(
&contract_account_id,
"get",
serde_json::json!({
serde_json::to_vec(&serde_json::json!({
"keys": vec![format!("{account_id}/profile/**")],
})
.to_string()
.into_bytes(),
}))?,
near_primitives::types::Finality::Final.into(),
)
.wrap_err_with(|| {format!("Failed to fetch query for view method: 'get {account_id}/profile/**'")})?
Expand Down
82 changes: 75 additions & 7 deletions src/commands/account/view_account_summary/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use color_eyre::eyre::Context;
use futures::{StreamExt, TryStreamExt};

use crate::common::{CallResultExt, JsonRpcClientExt, RpcQueryResponseExt};

Expand Down Expand Up @@ -26,9 +27,10 @@ impl ViewAccountSummaryContext {
let account_id: near_primitives::types::AccountId = scope.account_id.clone().into();

move |network_config, block_reference| {
let rpc_query_response = network_config
.json_rpc_client()
.blocking_call_view_account(&account_id, block_reference.clone())
let json_rpc_client = network_config.json_rpc_client();

let rpc_query_response = json_rpc_client
.blocking_call_view_account(&account_id.clone(), block_reference.clone())
.wrap_err_with(|| {
format!(
"Failed to fetch query ViewAccount for <{}>",
Expand All @@ -51,18 +53,43 @@ impl ViewAccountSummaryContext {
})?
.access_key_list_view()?;

let validators_stake = crate::common::get_validators_stake(&json_rpc_client)?;

let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()?;
let concurrency = 10;
let delegated_stake: std::collections::BTreeMap<near_primitives::types::AccountId, near_token::NearToken> = runtime
.block_on(
futures::stream::iter(validators_stake.into_keys())
.map(|validator_account_id| async {
let balance = get_delegated_staked_balance(&json_rpc_client, block_reference, &validator_account_id, &account_id).await?;
Ok::<_, color_eyre::eyre::Report>((
validator_account_id,
balance,
))
})
.buffer_unordered(concurrency)
.filter(|balance_result| futures::future::ready(
if let Ok((_, balance)) = balance_result {
!balance.is_zero()
} else {
true
}
))
.try_collect(),
)?;

let contract_account_id = network_config.get_near_social_account_id_from_network()?;

let social_db = network_config
.json_rpc_client()
.blocking_call_view_function(
&contract_account_id,
"get",
serde_json::json!({
serde_json::to_vec(&serde_json::json!({
"keys": vec![format!("{account_id}/profile/**")],
})
.to_string()
.into_bytes(),
}))?,
block_reference.clone(),
)
.wrap_err_with(|| {format!("Failed to fetch query for view method: 'get {account_id}/profile/**'")})?
Expand All @@ -75,6 +102,7 @@ impl ViewAccountSummaryContext {
&rpc_query_response.block_hash,
&rpc_query_response.block_height,
&account_id,
&delegated_stake,
&account_view,
&access_key_list.keys,
social_db.accounts.get(&account_id)
Expand Down Expand Up @@ -107,3 +135,43 @@ impl ViewAccountSummary {
)
}
}

async fn get_delegated_staked_balance(
json_rpc_client: &near_jsonrpc_client::JsonRpcClient,
block_reference: &near_primitives::types::BlockReference,
staking_pool_account_id: &near_primitives::types::AccountId,
account_id: &near_primitives::types::AccountId,
) -> color_eyre::eyre::Result<near_token::NearToken> {
let account_staked_balance_response = json_rpc_client
.call(near_jsonrpc_client::methods::query::RpcQueryRequest {
block_reference: block_reference.clone(),
request: near_primitives::views::QueryRequest::CallFunction {
account_id: staking_pool_account_id.clone(),
method_name: "get_account_staked_balance".to_string(),
args: near_primitives::types::FunctionArgs::from(serde_json::to_vec(
&serde_json::json!({
"account_id": account_id,
}),
)?),
},
})
.await;
match account_staked_balance_response {
Ok(response) => Ok(near_token::NearToken::from_yoctonear(
response
.call_result()?
.parse_result_from_json::<String>()
.wrap_err("Failed to parse return value of view function call for String.")?
.parse::<u128>()?,
)),
Err(near_jsonrpc_client::errors::JsonRpcError::ServerError(
near_jsonrpc_client::errors::JsonRpcServerError::HandlerError(
near_jsonrpc_client::methods::query::RpcQueryError::NoContractCode { .. }
| near_jsonrpc_client::methods::query::RpcQueryError::ContractExecutionError {
..
},
),
)) => Ok(near_token::NearToken::from_yoctonear(0)),
Err(err) => Err(err.into()),
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub fn function_args(
super::call_function_args_type::FunctionArgsType::JsonArgs => {
let data_json =
serde_json::Value::from_str(&args).wrap_err("Data not in JSON format!")?;
Ok(data_json.to_string().into_bytes())
serde_json::to_vec(&data_json).wrap_err("Internal error!")
}
super::call_function_args_type::FunctionArgsType::TextArgs => Ok(args.into_bytes()),
super::call_function_args_type::FunctionArgsType::Base64Args => {
Expand Down
6 changes: 6 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use strum::{EnumDiscriminants, EnumIter, EnumMessage};
pub mod account;
mod config;
pub mod contract;
mod staking;
mod tokens;
mod transaction;

Expand All @@ -25,6 +26,11 @@ pub enum TopLevelCommand {
))]
/// Use this for token actions: send or view balances of NEAR, FT, or NFT
Tokens(self::tokens::TokensCommands),
#[strum_discriminants(strum(
message = "staking - Manage staking: view, add and withdraw stake"
))]
/// Use this for manage staking: view, add and withdraw stake
Staking(self::staking::Staking),
#[strum_discriminants(strum(
message = "contract - Manage smart-contracts: deploy code, call functions"
))]
Expand Down
89 changes: 89 additions & 0 deletions src/commands/staking/delegate/deposit_and_stake.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(input_context = super::StakeDelegationContext)]
#[interactive_clap(output_context = DepositAndStakeContext)]
pub struct DepositAndStake {
/// Enter the attached amount to be deposited and then staked into the predecessor's internal account (example: 10NEAR or 0.5near or 10000yoctonear):
amount: near_token::NearToken,
#[interactive_clap(skip_default_input_arg)]
/// What is validator account ID?
validator_account_id: crate::types::account_id::AccountId,
#[interactive_clap(named_arg)]
/// Select network
network_config: crate::network_for_transaction::NetworkForTransactionArgs,
}

#[derive(Clone)]
pub struct DepositAndStakeContext(crate::commands::ActionContext);

impl DepositAndStakeContext {
pub fn from_previous_context(
previous_context: super::StakeDelegationContext,
scope: &<DepositAndStake as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
) -> color_eyre::eyre::Result<Self> {
let on_after_getting_network_callback: crate::commands::OnAfterGettingNetworkCallback =
std::sync::Arc::new({
let signer_id = previous_context.account_id.clone();
let validator_account_id: near_primitives::types::AccountId =
scope.validator_account_id.clone().into();
let amount = scope.amount;

move |_network_config| {
Ok(crate::commands::PrepopulatedTransaction {
signer_id: signer_id.clone(),
receiver_id: validator_account_id.clone(),
actions: vec![near_primitives::transaction::Action::FunctionCall(
near_primitives::transaction::FunctionCallAction {
method_name: "deposit_and_stake".to_string(),
args: serde_json::to_vec(&serde_json::json!({}))?,
gas: crate::common::NearGas::from_tgas(50).as_gas(),
deposit: amount.as_yoctonear(),
},
)],
})
}
});

let on_after_sending_transaction_callback: crate::transaction_signature_options::OnAfterSendingTransactionCallback = std::sync::Arc::new({
let signer_id = previous_context.account_id.clone();
let validator_id = scope.validator_account_id.clone();
let amount = scope.amount;

move |outcome_view, _network_config| {
if let near_primitives::views::FinalExecutionStatus::SuccessValue(_) = outcome_view.status {
eprintln!("<{signer_id}> has successfully delegated {amount} to stake with <{validator_id}>.")
}
Ok(())
}
});

Ok(Self(crate::commands::ActionContext {
global_context: previous_context.global_context,
interacting_with_account_ids: vec![
previous_context.account_id.clone(),
scope.validator_account_id.clone().into(),
],
on_after_getting_network_callback,
on_before_signing_callback: std::sync::Arc::new(
|_prepolulated_unsinged_transaction, _network_config| Ok(()),
),
on_before_sending_transaction_callback: std::sync::Arc::new(
|_signed_transaction, _network_config, _message| Ok(()),
),
on_after_sending_transaction_callback,
}))
}
}

impl From<DepositAndStakeContext> for crate::commands::ActionContext {
fn from(item: DepositAndStakeContext) -> Self {
item.0
}
}

impl DepositAndStake {
pub fn input_validator_account_id(
context: &super::StakeDelegationContext,
) -> color_eyre::eyre::Result<Option<crate::types::account_id::AccountId>> {
crate::common::input_staking_pool_validator_account_id(&context.global_context.config)
}
}
Loading
Loading