Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
210 changes: 168 additions & 42 deletions cli/src/action/agent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ use std::fmt::Display;

use anyhow::anyhow;
use tabled::Table;
use torus_client::{client::TorusClient, subxt::utils::AccountId32};
use torus_client::{client::TorusClient, interfaces, subxt::utils::AccountId32};

use crate::{
action::{Action, ActionContext},
action::{Action, ActionContext, Changes},
keypair::Keypair,
store::{get_account, get_key},
util::format_torus,
util::to_percent_u8,
};

pub struct AgentInfoAction {
Expand All @@ -19,12 +19,12 @@ impl Action for AgentInfoAction {
type Params = String;
type ResponseData = AgentInfoResponse;

async fn create(_ctx: &impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
async fn create(_ctx: &mut impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
let account = get_account(&key)?;
Ok(Self { account })
}

async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
async fn execute(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Self::ResponseData> {
get_agent_info(ctx, &self.account)
.await?
.ok_or(anyhow::anyhow!("Not an agent."))
Expand Down Expand Up @@ -80,7 +80,7 @@ impl Action for RegisterAgentAction {
type ResponseData = AgentInfoResponse;

async fn create(
ctx: &impl ActionContext,
ctx: &mut impl ActionContext,
(key, name, metadata, url): Self::Params,
) -> anyhow::Result<Self> {
let key = get_key(&key)?;
Expand All @@ -94,8 +94,8 @@ impl Action for RegisterAgentAction {
})
}

async fn estimate_fee(&self, ctx: &impl ActionContext) -> anyhow::Result<u128> {
let fee = if !ctx.is_testnet() {
async fn estimate_fee(&self, ctx: &mut impl ActionContext) -> anyhow::Result<u128> {
let fee = if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
Expand Down Expand Up @@ -124,24 +124,19 @@ impl Action for RegisterAgentAction {
Ok(fee)
}

async fn confirmation_phrase(
&self,
ctx: &impl ActionContext,
) -> anyhow::Result<Option<String>> {
async fn get_changes(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Option<Changes>> {
let fee = self.estimate_fee(ctx).await?;
Ok(Some(format!(
"Are you sure you want to register {} as an agent? {}\n[y/N]",
self.keypair.ss58_address(),
if fee != 0 {
format!("(there will be a {} torus fee)", format_torus(fee))
} else {
"".to_string()
}
)))
Ok(Some(Changes {
changes: vec![format!(
"register an agent with name {} which is not changeable later",
self.name
)],
fee: Some(fee),
}))
}

async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
if !ctx.is_testnet() {
async fn execute(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Self::ResponseData> {
if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
Expand Down Expand Up @@ -182,15 +177,15 @@ impl Action for UnregisterAgentAction {
type Params = String;
type ResponseData = UnregisterAgentActionResponse;

async fn create(ctx: &impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
async fn create(ctx: &mut impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
let key = get_key(&key)?;
let (_, keypair) = ctx.decrypt(&key)?;

Ok(Self { keypair })
}

async fn estimate_fee(&self, ctx: &impl ActionContext) -> anyhow::Result<u128> {
let fee = if !ctx.is_testnet() {
async fn estimate_fee(&self, ctx: &mut impl ActionContext) -> anyhow::Result<u128> {
let fee = if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
Expand All @@ -209,24 +204,20 @@ impl Action for UnregisterAgentAction {
Ok(fee)
}

async fn confirmation_phrase(
&self,
ctx: &impl ActionContext,
) -> anyhow::Result<Option<String>> {
async fn get_changes(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Option<Changes>> {
let fee = self.estimate_fee(ctx).await?;
Ok(Some(format!(
"Are you sure you want to unregister {} from agent? {}\n[y/N]",
self.keypair.ss58_address(),
if fee != 0 {
format!("(there will be a {} torus fee)", format_torus(fee))
} else {
"".to_string()
}
)))

Ok(Some(Changes {
changes: vec![format!(
"Unregister the agent {}",
self.keypair.ss58_address()
)],
fee: Some(fee),
}))
}

async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
if !ctx.is_testnet() {
async fn execute(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Self::ResponseData> {
if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
Expand Down Expand Up @@ -255,8 +246,143 @@ impl Display for UnregisterAgentActionResponse {
}
}

pub struct UpdateAgentAction {
key: Keypair,
url: String,
metadata: Option<String>,
staking_fee: Option<u32>,
weight_control_fee: Option<u32>,
}

impl Action for UpdateAgentAction {
type Params = (String, String, Option<String>, Option<u32>, Option<u32>);
type ResponseData = UpdateAgentActionResponse;

async fn create(
ctx: &mut impl ActionContext,
(key, url, metadata, staking_fee, weight_control_fee): Self::Params,
) -> anyhow::Result<Self> {
let key = get_key(&key)?;
let (_, keypair) = ctx.decrypt(&key)?;

Ok(Self {
key: keypair,
url,
metadata,
staking_fee,
weight_control_fee,
})
}

async fn estimate_fee(&self, ctx: &mut impl ActionContext) -> anyhow::Result<u128> {
let staking_fee = self.staking_fee.map(to_percent_u8).transpose()?;
let weight_control_fee = self.weight_control_fee.map(to_percent_u8).transpose()?;

let fee = if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
.calls()
.update_agent_fee(
self.url.as_bytes().to_vec(),
self.metadata.clone().map(|str| str.as_bytes().to_vec()),
staking_fee.map(
interfaces::mainnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
weight_control_fee.map(
interfaces::mainnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
self.key.clone(),
)
.await?
} else {
let client = TorusClient::for_testnet().await?;
client
.torus0()
.calls()
.update_agent_fee(
self.url.as_bytes().to_vec(),
self.metadata.clone().map(|str| str.as_bytes().to_vec()),
staking_fee.map(
interfaces::testnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
weight_control_fee.map(
interfaces::testnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
self.key.clone(),
)
.await?
};

Ok(fee)
}

async fn get_changes(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Option<Changes>> {
let fee = self.estimate_fee(ctx).await?;
Ok(Some(Changes {
changes: vec![format!(
"Update agent `{}` information",
self.key.ss58_address()
)],
fee: Some(fee),
}))
}

async fn execute(&self, ctx: &mut impl ActionContext) -> anyhow::Result<Self::ResponseData> {
let staking_fee = self.staking_fee.map(to_percent_u8).transpose()?;
let weight_control_fee = self.weight_control_fee.map(to_percent_u8).transpose()?;

if ctx.is_mainnet() {
let client = TorusClient::for_mainnet().await?;
client
.torus0()
.calls()
.update_agent_wait(
self.url.as_bytes().to_vec(),
self.metadata.clone().map(|str| str.as_bytes().to_vec()),
staking_fee.map(
interfaces::mainnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
weight_control_fee.map(
interfaces::mainnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
self.key.clone(),
)
.await?;
} else {
let client = TorusClient::for_testnet().await?;
client
.torus0()
.calls()
.update_agent_wait(
self.url.as_bytes().to_vec(),
self.metadata.clone().map(|str| str.as_bytes().to_vec()),
staking_fee.map(
interfaces::testnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
weight_control_fee.map(
interfaces::testnet::api::runtime_types::sp_arithmetic::per_things::Percent,
),
self.key.clone(),
)
.await?;
}

Ok(UpdateAgentActionResponse)
}
}

#[derive(serde::Serialize)]
pub struct UpdateAgentActionResponse;

impl Display for UpdateAgentActionResponse {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Updated successfully")
}
}

async fn get_agent_info(
ctx: &impl ActionContext,
ctx: &mut impl ActionContext,
account: &AccountId32,
) -> anyhow::Result<Option<AgentInfoResponse>> {
let agent_info = if ctx.is_testnet() {
Expand Down
Loading
Loading