Skip to content

Commit d0a6642

Browse files
committed
feat: dry-run, json and actions refac
1 parent c09a91e commit d0a6642

File tree

19 files changed

+2000
-1038
lines changed

19 files changed

+2000
-1038
lines changed

cli/README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@ Torus blockchain cli using the torus client.
88
99
| Command | Description |
1010
| ------- | ----------- |
11-
| `torurs key list` | Lists all saved keys. |
12-
| `torurs key info <name>` | Prints information about a key prompting for the password if it is encrypted. |
13-
| `torurs key create <name> [-p]` | Generates a new sr25519 key and prompts for a encryption password if `-p` is given. |
14-
| `torurs key delete <name> [-y]` | Deletes a saved key. |
11+
| `torurs agent info <account>` | Shows information about the given agent. |
12+
| `torurs agent register <key> <name> <description> <url> [-y]` | Registers key as an agent. |
13+
| `torurs agent unregister <key> [-y]` | Unregisters key as an agent. |
1514
| `torurs balance <account>` | Shows the account balance. |
1615
| `torurs balance check <account>` | Does the same as the command above. |
1716
| `torurs balance transfer <key> <target_account> <amount> [-y]` | Transfers **amount** from **key** to **address**. |
17+
| `torurs key list` | Lists all saved keys. |
18+
| `torurs key info <name>` | Shows information about a key prompting for the password if it is encrypted. |
19+
| `torurs key create <name> [-p]` | Generates a new sr25519 key and prompts for a encryption password if `-p` is given. |
20+
| `torurs key delete <name> [-y]` | Deletes a saved key. |
21+
| `torurs namespace info <account>` | Shows all namespaces related to the given account. |
22+
| `torurs namespace register <key> <path>` | Registers a namespace on the given account. |
23+
| `torurs namespace unregister <key>` | Unregisters a namespace from the given account. |
1824
| `torurs stake <account>` | Prints all keys **account** is staking with the amount. |
1925
| `torurs stake given <account>` | Does the same as the command above. |
2026
| `torurs stake received <account>` | Prints all keys **account** is staked by with the amount. |

cli/src/action/agent.rs

Lines changed: 299 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,299 @@
1+
use std::fmt::Display;
2+
3+
use anyhow::anyhow;
4+
use tabled::Table;
5+
use torus_client::{client::TorusClient, subxt::utils::AccountId32};
6+
7+
use crate::{
8+
action::{Action, ActionContext},
9+
keypair::Keypair,
10+
store::{get_account, get_key},
11+
util::format_torus,
12+
};
13+
14+
pub struct AgentInfoAction {
15+
account: AccountId32,
16+
}
17+
18+
impl Action for AgentInfoAction {
19+
type Params = String;
20+
type ResponseData = AgentInfoResponse;
21+
22+
async fn create(_ctx: &impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
23+
let account = get_account(&key)?;
24+
Ok(Self { account })
25+
}
26+
27+
async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
28+
get_agent_info(ctx, &self.account)
29+
.await?
30+
.ok_or(anyhow::anyhow!("Not an agent."))
31+
}
32+
}
33+
34+
#[derive(serde::Serialize, tabled::Tabled)]
35+
pub struct AgentInfoResponse {
36+
address: String,
37+
name: String,
38+
metadata: String,
39+
url: String,
40+
last_update_block: u64,
41+
registration_block: u64,
42+
}
43+
44+
impl AgentInfoResponse {
45+
fn new(
46+
address: String,
47+
name: Vec<u8>,
48+
metadata: Vec<u8>,
49+
url: Vec<u8>,
50+
last_update_block: u64,
51+
registration_block: u64,
52+
) -> Self {
53+
Self {
54+
address,
55+
name: String::from_utf8_lossy(&name[..]).to_string(),
56+
metadata: String::from_utf8_lossy(&metadata[..]).to_string(),
57+
url: String::from_utf8_lossy(&url[..]).to_string(),
58+
last_update_block,
59+
registration_block,
60+
}
61+
}
62+
}
63+
64+
impl Display for AgentInfoResponse {
65+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66+
let table = Table::kv(std::iter::once(self));
67+
write!(f, "{table}")
68+
}
69+
}
70+
71+
pub struct RegisterAgentAction {
72+
keypair: Keypair,
73+
name: String,
74+
metadata: String,
75+
url: String,
76+
}
77+
78+
impl Action for RegisterAgentAction {
79+
type Params = (String, String, String, String);
80+
type ResponseData = AgentInfoResponse;
81+
82+
async fn create(
83+
ctx: &impl ActionContext,
84+
(key, name, metadata, url): Self::Params,
85+
) -> anyhow::Result<Self> {
86+
let key = get_key(&key)?;
87+
let (_, keypair) = ctx.decrypt(&key)?;
88+
89+
Ok(Self {
90+
keypair,
91+
name,
92+
metadata,
93+
url,
94+
})
95+
}
96+
97+
async fn estimate_fee(&self, ctx: &impl ActionContext) -> anyhow::Result<u128> {
98+
let fee = if !ctx.is_testnet() {
99+
let client = TorusClient::for_mainnet().await?;
100+
client
101+
.torus0()
102+
.calls()
103+
.register_agent_fee(
104+
self.name.clone().into(),
105+
self.metadata.clone().into(),
106+
self.url.clone().into(),
107+
self.keypair.clone(),
108+
)
109+
.await?
110+
} else {
111+
let client = TorusClient::for_testnet().await?;
112+
client
113+
.torus0()
114+
.calls()
115+
.register_agent_fee(
116+
self.name.clone().into(),
117+
self.metadata.clone().into(),
118+
self.url.clone().into(),
119+
self.keypair.clone(),
120+
)
121+
.await?
122+
};
123+
124+
Ok(fee)
125+
}
126+
127+
async fn confirmation_phrase(
128+
&self,
129+
ctx: &impl ActionContext,
130+
) -> anyhow::Result<Option<String>> {
131+
let fee = self.estimate_fee(ctx).await?;
132+
Ok(Some(format!(
133+
"Are you sure you want to register {} as an agent? {}\n[y/N]",
134+
self.keypair.ss58_address(),
135+
if fee != 0 {
136+
format!("(there will be a {} torus fee)", format_torus(fee))
137+
} else {
138+
"".to_string()
139+
}
140+
)))
141+
}
142+
143+
async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
144+
if !ctx.is_testnet() {
145+
let client = TorusClient::for_mainnet().await?;
146+
client
147+
.torus0()
148+
.calls()
149+
.register_agent_wait(
150+
self.name.clone().into(),
151+
self.metadata.clone().into(),
152+
self.url.clone().into(),
153+
self.keypair.clone(),
154+
)
155+
.await?;
156+
} else {
157+
let client = TorusClient::for_testnet().await?;
158+
client
159+
.torus0()
160+
.calls()
161+
.register_agent_wait(
162+
self.name.clone().into(),
163+
self.metadata.clone().into(),
164+
self.url.clone().into(),
165+
self.keypair.clone(),
166+
)
167+
.await?;
168+
}
169+
170+
let account = self.keypair.account();
171+
get_agent_info(ctx, &account)
172+
.await?
173+
.ok_or(anyhow!("Something went wrong!"))
174+
}
175+
}
176+
177+
pub struct UnregisterAgentAction {
178+
keypair: Keypair,
179+
}
180+
181+
impl Action for UnregisterAgentAction {
182+
type Params = String;
183+
type ResponseData = UnregisterAgentActionResponse;
184+
185+
async fn create(ctx: &impl ActionContext, key: Self::Params) -> anyhow::Result<Self> {
186+
let key = get_key(&key)?;
187+
let (_, keypair) = ctx.decrypt(&key)?;
188+
189+
Ok(Self { keypair })
190+
}
191+
192+
async fn estimate_fee(&self, ctx: &impl ActionContext) -> anyhow::Result<u128> {
193+
let fee = if !ctx.is_testnet() {
194+
let client = TorusClient::for_mainnet().await?;
195+
client
196+
.torus0()
197+
.calls()
198+
.deregister_agent_fee(self.keypair.clone())
199+
.await?
200+
} else {
201+
let client = TorusClient::for_testnet().await?;
202+
client
203+
.torus0()
204+
.calls()
205+
.deregister_agent_fee(self.keypair.clone())
206+
.await?
207+
};
208+
209+
Ok(fee)
210+
}
211+
212+
async fn confirmation_phrase(
213+
&self,
214+
ctx: &impl ActionContext,
215+
) -> anyhow::Result<Option<String>> {
216+
let fee = self.estimate_fee(ctx).await?;
217+
Ok(Some(format!(
218+
"Are you sure you want to unregister {} from agent? {}\n[y/N]",
219+
self.keypair.ss58_address(),
220+
if fee != 0 {
221+
format!("(there will be a {} torus fee)", format_torus(fee))
222+
} else {
223+
"".to_string()
224+
}
225+
)))
226+
}
227+
228+
async fn execute(&self, ctx: &impl ActionContext) -> anyhow::Result<Self::ResponseData> {
229+
if !ctx.is_testnet() {
230+
let client = TorusClient::for_mainnet().await?;
231+
client
232+
.torus0()
233+
.calls()
234+
.deregister_agent_wait(self.keypair.clone())
235+
.await?;
236+
} else {
237+
let client = TorusClient::for_testnet().await?;
238+
client
239+
.torus0()
240+
.calls()
241+
.deregister_agent_wait(self.keypair.clone())
242+
.await?;
243+
}
244+
245+
Ok(UnregisterAgentActionResponse)
246+
}
247+
}
248+
249+
#[derive(serde::Serialize)]
250+
pub struct UnregisterAgentActionResponse;
251+
252+
impl Display for UnregisterAgentActionResponse {
253+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254+
write!(f, "Unregistered successfully!")
255+
}
256+
}
257+
258+
async fn get_agent_info(
259+
ctx: &impl ActionContext,
260+
account: &AccountId32,
261+
) -> anyhow::Result<Option<AgentInfoResponse>> {
262+
let agent_info = if ctx.is_testnet() {
263+
let client = TorusClient::for_testnet().await?;
264+
client
265+
.torus0()
266+
.storage()
267+
.agents_get(account)
268+
.await?
269+
.map(|agent| {
270+
AgentInfoResponse::new(
271+
agent.key.to_string(),
272+
agent.name.0,
273+
agent.metadata.0,
274+
agent.url.0,
275+
agent.last_update_block,
276+
agent.registration_block,
277+
)
278+
})
279+
} else {
280+
let client = TorusClient::for_mainnet().await?;
281+
client
282+
.torus0()
283+
.storage()
284+
.agents_get(account)
285+
.await?
286+
.map(|agent| {
287+
AgentInfoResponse::new(
288+
agent.key.to_string(),
289+
agent.name.0,
290+
agent.metadata.0,
291+
agent.url.0,
292+
agent.last_update_block,
293+
agent.registration_block,
294+
)
295+
})
296+
};
297+
298+
Ok(agent_info)
299+
}

0 commit comments

Comments
 (0)