use color_eyre::eyre::ContextCompat;
#[derive(Debug, Clone, interactive_clap::InteractiveClap)]
#[interactive_clap(input_context = super::storage_deposit::ExtraStorageDepositContext)]
#[interactive_clap(output_context = SignerContext)]
pub struct Signer {
#[interactive_clap(skip_default_input_arg)]
signer_account_id: near_cli_rs::types::account_id::AccountId,
#[interactive_clap(named_arg)]
network_config: near_cli_rs::network_for_transaction::NetworkForTransactionArgs,
}
#[derive(Clone)]
pub struct SignerContext {
global_context: near_cli_rs::GlobalContext,
social_db_keys: Vec<String>,
permission_key: near_socialdb_client::PermissionKey,
extra_storage_deposit: near_cli_rs::types::near_token::NearToken,
signer_account_id: near_primitives::types::AccountId,
}
impl SignerContext {
pub fn from_previous_context(
previous_context: super::storage_deposit::ExtraStorageDepositContext,
scope: &<Signer as interactive_clap::ToInteractiveClapContextScope>::InteractiveClapContextScope,
) -> color_eyre::eyre::Result<Self> {
Ok(Self {
global_context: previous_context.global_context,
social_db_keys: vec![format!(
"{}/{}",
scope.signer_account_id, previous_context.social_db_key
)],
permission_key: previous_context.permission_key,
extra_storage_deposit: previous_context.extra_storage_deposit,
signer_account_id: scope.signer_account_id.clone().into(),
})
}
}
impl From<SignerContext> for near_cli_rs::commands::ActionContext {
fn from(item: SignerContext) -> Self {
let social_db_keys = item.social_db_keys.clone();
let permission_key = item.permission_key.clone();
let extra_storage_deposit = item.extra_storage_deposit;
let signer_id = item.signer_account_id.clone();
let on_after_getting_network_callback: near_cli_rs::commands::OnAfterGettingNetworkCallback = std::sync::Arc::new({
move |network_config| {
let near_social_account_id = crate::consts::NEAR_SOCIAL_ACCOUNT_ID.get(network_config.network_name.as_str())
.wrap_err_with(|| format!("The <{}> network does not have a near-social contract.", network_config.network_name))?;
let args = match &permission_key {
near_socialdb_client::PermissionKey::PredecessorId(account_id) => {
serde_json::json!({
"predecessor_id": account_id.to_string(),
"keys": social_db_keys
}).to_string().into_bytes()
}
near_socialdb_client::PermissionKey::PublicKey(public_key) => {
serde_json::json!({
"public_key": public_key.to_string(),
"keys": social_db_keys
}).to_string().into_bytes()
}
};
let prepopulated_transaction = near_cli_rs::commands::PrepopulatedTransaction {
signer_id: signer_id.clone(),
receiver_id: near_social_account_id.clone(),
actions: vec![
near_primitives::transaction::Action::FunctionCall(
near_primitives::transaction::FunctionCallAction {
method_name: "grant_write_permission".to_string(),
args,
gas: near_cli_rs::common::NearGas::from_tgas(100).as_gas(),
deposit: extra_storage_deposit.as_yoctonear(),
},
)
],
};
Ok(prepopulated_transaction)
}
});
let signer_id = item.signer_account_id.clone();
let on_after_sending_transaction_callback: near_cli_rs::transaction_signature_options::OnAfterSendingTransactionCallback = std::sync::Arc::new({
let permission_key = item.permission_key.clone();
move |transaction_info, _network_config| {
if let near_primitives::views::FinalExecutionStatus::SuccessValue(_) = transaction_info.status {
if let near_primitives::views::ActionView::FunctionCall { .. } =
&transaction_info.transaction.actions[0]
{
match &permission_key {
near_socialdb_client::PermissionKey::PredecessorId(account_id) => {
eprintln!("<{signer_id}> has granted <{account_id}> permission to edit their social_db keys");
}
near_socialdb_client::PermissionKey::PublicKey(public_key) => {
eprintln!("<{signer_id}> has granted public key <{public_key}> permission to edit their social_db keys");
}
}
} else {
color_eyre::eyre::bail!(
"Internal error: Unexpected function call arguments",
);
}
} else {
match &permission_key {
near_socialdb_client::PermissionKey::PredecessorId(account_id) => {
color_eyre::eyre::bail!("Could not grant permission to <{}>", account_id);
}
near_socialdb_client::PermissionKey::PublicKey(public_key) => {
color_eyre::eyre::bail!("Could not grant permission to <{}>", public_key);
}
}
};
Ok(())
}
});
Self {
global_context: item.global_context,
interacting_with_account_ids: vec![item.signer_account_id],
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 Signer {
fn input_signer_account_id(
context: &super::storage_deposit::ExtraStorageDepositContext,
) -> color_eyre::eyre::Result<Option<near_cli_rs::types::account_id::AccountId>> {
near_cli_rs::common::input_signer_account_id_from_used_account_list(
&context.global_context.config.credentials_home_dir,
"What is the signer account ID?",
)
}
}