Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • clients/rust/gcli-v2s
  • d0p1/gcli-v2s
  • flebon/gcli-v2s
  • zicmama/gcli-v2s
  • Nicolas80/gcli-v2s
5 results
Show changes
use crate::{gdev, Client}; use crate::*;
use anyhow::Result; /// define sudo subcommands
use sp_core::{crypto::AccountId32, sr25519::Pair}; #[derive(Clone, Default, Debug, clap::Parser)]
use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; pub enum Subcommand {
/// Nothing
#[default]
#[clap(hide = true)]
Nothing,
/// set sudo keys
SetKey { new_key: AccountId },
/// force valid distance status
SetDistanceOk { identity: IdtyId },
}
/// handle smith commands
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
let data = data.build_client().await?;
match command {
Subcommand::Nothing => todo!(),
Subcommand::SetKey { new_key } => {
set_key(&data, new_key).await?;
}
Subcommand::SetDistanceOk { identity } => {
set_distance_ok(&data, identity).await?;
}
};
pub async fn set_key(pair: Pair, client: Client, new_key: AccountId32) -> Result<()> { Ok(())
client }
.tx()
.sign_and_submit_then_watch( /// set sudo key
&gdev::tx().sudo().set_key(new_key.into()), pub async fn set_key(data: &Data, new_key: AccountId) -> Result<(), subxt::Error> {
&PairSigner::new(pair), submit_call_and_look_event::<
BaseExtrinsicParamsBuilder::new(), runtime::sudo::events::KeyChanged,
) StaticPayload<runtime::sudo::calls::types::SetKey>,
.await?; >(data, &runtime::tx().sudo().set_key(new_key.into()))
.await
}
Ok(()) /// set distance ok
pub async fn set_distance_ok(data: &Data, identity: IdtyId) -> Result<(), subxt::Error> {
let inner = runtime::distance::Call::force_valid_distance_status { identity };
let inner = runtime::Call::Distance(inner);
submit_call_and_look_event::<
runtime::sudo::events::Sudid,
StaticPayload<runtime::sudo::calls::types::Sudo>,
>(data, &runtime::tx().sudo().sudo(inner))
.await
} }
use crate::{gdev, Client}; use crate::*;
use anyhow::Result; #[cfg(feature = "gdev")] // find how to get runtime calls
use sp_core::{crypto::AccountId32, sr25519::Pair}; type Call = runtime::runtime_types::gdev_runtime::RuntimeCall;
use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner}; type BalancesCall = runtime::runtime_types::pallet_balances::pallet::Call;
type Call = gdev::runtime_types::gdev_runtime::Call;
type BalancesCall = gdev::runtime_types::pallet_balances::pallet::Call;
/// transfer balance to target
pub async fn transfer( pub async fn transfer(
pair: Pair, data: &Data,
client: Client, balance: u64,
balance: u64, dest: AccountId,
dest: AccountId32, keep_alive: bool,
keep_alive: bool, is_ud: bool,
) -> Result<()> { ) -> Result<(), subxt::Error> {
if keep_alive { match (keep_alive, is_ud) {
client (true, false) => {
.tx() submit_call_and_look_event::<
.sign_and_submit_then_watch( runtime::balances::events::Transfer,
&gdev::tx().balances().transfer(dest.into(), balance), StaticPayload<runtime::balances::calls::types::TransferKeepAlive>,
&PairSigner::new(pair), >(
BaseExtrinsicParamsBuilder::new(), data,
) &runtime::tx()
.await?; .balances()
} else { .transfer_keep_alive(dest.into(), balance),
client )
.tx() .await
.sign_and_submit_then_watch( }
&gdev::tx() (false, false) => {
.balances() submit_call_and_look_event::<
.transfer_keep_alive(dest.into(), balance), runtime::balances::events::Transfer,
&PairSigner::new(pair), StaticPayload<runtime::balances::calls::types::TransferAllowDeath>,
BaseExtrinsicParamsBuilder::new(), >(
) data,
.await?; &runtime::tx()
} .balances()
.transfer_allow_death(dest.into(), balance),
Ok(()) )
.await
}
(true, true) => {
submit_call_and_look_event::<
runtime::balances::events::Transfer,
StaticPayload<runtime::universal_dividend::calls::types::TransferUdKeepAlive>,
>(
data,
&runtime::tx()
.universal_dividend()
.transfer_ud_keep_alive(dest.into(), balance),
)
.await
}
(false, true) => {
submit_call_and_look_event::<
runtime::balances::events::Transfer,
StaticPayload<runtime::universal_dividend::calls::types::TransferUd>,
>(
data,
&runtime::tx()
.universal_dividend()
.transfer_ud(dest.into(), balance),
)
.await
}
}
} }
/// transfer balance to multiple target
pub async fn transfer_multiple( pub async fn transfer_multiple(
pair: Pair, data: &Data,
client: Client, amount: u64,
amount: u64, dests: Vec<AccountId>,
dests: Vec<AccountId32>, ) -> Result<(), subxt::Error> {
) -> Result<()> { // build the list of transactions from the destination accounts
// build the list of transactions from the destination accounts let transactions: Vec<Call> = dests
let transactions: Vec<Call> = dests .into_iter()
.into_iter() .map(|dest| {
.map(|dest| { Call::Balances(BalancesCall::transfer_keep_alive {
Call::Balances(BalancesCall::transfer_keep_alive { dest: dest.into(),
dest: dest.into(), value: amount,
value: amount, })
}) })
}) .collect();
.collect(); // wrap these calls in a batch call
submit_call_and_look_event::<
// wrap these calls in a batch call runtime::utility::events::BatchCompleted,
client StaticPayload<runtime::utility::calls::types::Batch>,
.tx() >(data, &runtime::tx().utility().batch(transactions))
.sign_and_submit_then_watch( .await
&gdev::tx().utility().batch(transactions),
&PairSigner::new(pair.clone()),
BaseExtrinsicParamsBuilder::new(),
)
.await?;
Ok(())
} }
use crate::*;
/// define universal dividends subcommands
#[derive(Clone, Default, Debug, clap::Parser)]
pub enum Subcommand {
#[default]
/// Claim uds
Claim,
}
/// handle ud commands
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
// build indexer because it is needed for all subcommands
let data = data.build_client().await?.fetch_system_properties().await?;
// match subcommand
match command {
Subcommand::Claim => {
claim_ud(&data).await?;
}
};
Ok(())
}
/// claim universal dividend
pub async fn claim_ud(data: &Data) -> Result<(), subxt::Error> {
submit_call_and_look_event::<
runtime::universal_dividend::events::UdsClaimed,
StaticPayload<runtime::universal_dividend::calls::types::ClaimUds>,
>(data, &runtime::tx().universal_dividend().claim_uds())
.await
}
This diff is collapsed.
use crate::commands::cesium;
use crate::entities::vault_account;
use crate::entities::vault_account::AccountTreeNode;
use crate::keys::CryptoScheme;
use crate::utils::GcliError;
use comfy_table::{Cell, Table};
use std::cell::RefCell;
use std::rc::Rc;
use std::str;
#[deprecated(
note = "Should be removed in a future version when db persistence of vault is present for a while"
)]
pub fn compute_vault_key_files_table(vault_key_addresses: &[String]) -> Result<Table, GcliError> {
let mut table = Table::new();
table.load_preset(comfy_table::presets::UTF8_BORDERS_ONLY);
table.set_header(vec!["Key file"]);
vault_key_addresses.iter().for_each(|address| {
table.add_row(vec![Cell::new(address)]);
});
Ok(table)
}
pub fn compute_vault_accounts_table(
account_tree_nodes: &[Rc<RefCell<AccountTreeNode>>],
) -> Result<Table, GcliError> {
// Calling the new function with show_g1v1 = true to maintain compatibility
compute_vault_accounts_table_with_g1v1(account_tree_nodes, true)
}
pub fn compute_vault_accounts_table_with_g1v1(
account_tree_nodes: &[Rc<RefCell<AccountTreeNode>>],
show_g1v1: bool,
) -> Result<Table, GcliError> {
let mut table = Table::new();
table.load_preset(comfy_table::presets::UTF8_BORDERS_ONLY);
// Prepare header based on options
table.set_header(vec![
if show_g1v1 {
"SS58 Address/G1v1 public key"
} else {
"SS58 Address"
},
"Crypto",
"Path",
"Name",
]);
for account_tree_node in account_tree_nodes {
let _ = add_account_tree_node_to_table_with_g1v1(&mut table, account_tree_node, show_g1v1);
}
Ok(table)
}
fn add_account_tree_node_to_table_with_g1v1(
table: &mut Table,
account_tree_node: &Rc<RefCell<AccountTreeNode>>,
show_g1v1: bool,
) -> Result<(), GcliError> {
let rows = compute_vault_accounts_row_with_g1v1(account_tree_node, show_g1v1)?;
rows.iter().for_each(|row| {
table.add_row(row.clone());
});
for child in &account_tree_node.borrow().children {
let _ = add_account_tree_node_to_table_with_g1v1(table, child, show_g1v1);
}
Ok(())
}
/// Computes one or more row of the table for selected account_tree_node
///
/// For ed25519 keys, will display over 2 rows to also show the base 58 G1v1 public key if show_g1v1 is true
pub fn compute_vault_accounts_row_with_g1v1(
account_tree_node: &Rc<RefCell<AccountTreeNode>>,
show_g1v1: bool,
) -> Result<Vec<Vec<Cell>>, GcliError> {
let empty_string = "".to_string();
let depth_account_tree_node = vault_account::count_depth_account_tree_node(account_tree_node);
let name = if let Some(name) = account_tree_node.borrow().account.name.clone() {
name
} else if let Some(computed_name) =
vault_account::compute_name_account_tree_node(account_tree_node)
{
format!("<{}>", computed_name)
} else {
empty_string.clone()
};
let account_tree_node = account_tree_node.borrow();
let address = if depth_account_tree_node > 0 {
let ancestors = "│ ".repeat(depth_account_tree_node - 1);
format!("{}├ {}", ancestors, account_tree_node.account.address)
} else {
account_tree_node.account.address.to_string()
};
let mut rows: Vec<Vec<Cell>> = vec![];
let (path, crypto) = if let Some(path) = account_tree_node.account.path.clone() {
(path, empty_string.clone())
} else {
let crypto_scheme = CryptoScheme::from(account_tree_node.account.crypto_scheme.unwrap());
let crypto_scheme_str: &str = crypto_scheme.into();
// Add a second line for the G1v1 public key only if show_g1v1 is true and it's an Ed25519 key
let is_ed25519 = crypto_scheme == CryptoScheme::Ed25519;
if show_g1v1 && is_ed25519 {
rows.push(vec![Cell::new(format!(
"└ G1v1: {}",
cesium::compute_g1v1_public_key_from_ed25519_account_id(
&account_tree_node.account.address.0
)
))]);
}
(
format!("<{}>", account_tree_node.account.account_type()),
crypto_scheme_str.to_string(),
)
};
// Add the first line
rows.insert(
0,
vec![
Cell::new(&address),
Cell::new(crypto),
Cell::new(&path),
Cell::new(&name),
],
);
Ok(rows)
}
#[cfg(test)]
mod tests {
mod vault_accounts_table_tests {
use crate::commands::vault::display::{
compute_vault_accounts_table, compute_vault_accounts_table_with_g1v1,
};
use crate::entities::vault_account::tests::account_tree_node_tests::{
mother_account_tree_node, mother_g1v1_account_tree_node,
};
use indoc::indoc;
// Tests for compute_vault_accounts_table (old function)
#[test]
fn test_compute_vault_accounts_table_empty() {
let table = compute_vault_accounts_table(&[]).unwrap();
let expected_table = indoc! {r#"
┌─────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞═════════════════════════════════════════════════════╡
└─────────────────────────────────────────────────────┘"#
};
assert_eq!(table.to_string(), expected_table);
}
#[test]
fn test_compute_vault_accounts_table() {
let account_tree_node = mother_account_tree_node();
let g1v1_account_tree_node = mother_g1v1_account_tree_node();
let table =
compute_vault_accounts_table(&[account_tree_node, g1v1_account_tree_node]).unwrap();
let expected_table = indoc! {r#"
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞══════════════════════════════════════════════════════════════════════════════════════════╡
│ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> Mother │
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
│ ├ 5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 <Mother//1> │
│ │ ├ 5CvdJuB9HLXSi5FS9LW57cyHF13iCv5HDimo2C45KxnxriCT //1 <Mother//1//1> │
│ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 <Base> MotherG1v1 │
│ └ G1v1: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 │
└──────────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table.to_string(), expected_table);
}
#[test]
fn test_compute_vault_accounts_table_partial() {
let mother = mother_account_tree_node();
let child1 = mother.borrow().children[0].clone();
let table = compute_vault_accounts_table(&[child1]).unwrap();
let expected_table = indoc! {r#"
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞═════════════════════════════════════════════════════════════════════════════════════╡
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
└─────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table.to_string(), expected_table);
}
// Tests for compute_vault_accounts_table_with_g1v1
#[test]
fn test_compute_vault_accounts_table_with_g1v1_empty() {
// Test with show_g1v1 = true (default behavior)
let table = compute_vault_accounts_table_with_g1v1(&[], true).unwrap();
let expected_table_with_g1v1 = indoc! {r#"
┌─────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞═════════════════════════════════════════════════════╡
└─────────────────────────────────────────────────────┘"#
};
assert_eq!(table.to_string(), expected_table_with_g1v1);
// Test with show_g1v1 = false
let table = compute_vault_accounts_table_with_g1v1(&[], false).unwrap();
let expected_table_without_g1v1 = indoc! {r#"
┌─────────────────────────────────────┐
│ SS58 Address Crypto Path Name │
╞═════════════════════════════════════╡
└─────────────────────────────────────┘"#
};
assert_eq!(table.to_string(), expected_table_without_g1v1);
}
#[test]
fn test_compute_vault_accounts_table_with_g1v1() {
let account_tree_node = mother_account_tree_node();
let g1v1_account_tree_node = mother_g1v1_account_tree_node();
let account_tree_nodes = vec![account_tree_node, g1v1_account_tree_node];
// Test with show_g1v1 = true (default behavior)
let table_with_g1v1 =
compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true).unwrap();
let expected_table_with_g1v1 = indoc! {r#"
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞══════════════════════════════════════════════════════════════════════════════════════════╡
│ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> Mother │
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
│ ├ 5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 <Mother//1> │
│ │ ├ 5CvdJuB9HLXSi5FS9LW57cyHF13iCv5HDimo2C45KxnxriCT //1 <Mother//1//1> │
│ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 <Base> MotherG1v1 │
│ └ G1v1: 86pW1doyJPVH3jeDPZNQa1UZFBo5zcdvHERcaeE758W7 │
└──────────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table_with_g1v1.to_string(), expected_table_with_g1v1);
// Test with show_g1v1 = false
let table_without_g1v1 =
compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false).unwrap();
let expected_table_without_g1v1 = indoc! {r#"
┌──────────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address Crypto Path Name │
╞══════════════════════════════════════════════════════════════════════════════════════════╡
│ 5DfhGyQdFobKM8NsWvEeAKk5EQQgYe9AydgJ7rMB6E1EqRzV sr25519 <Base> Mother │
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
│ ├ 5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o //1 <Mother//1> │
│ │ ├ 5CvdJuB9HLXSi5FS9LW57cyHF13iCv5HDimo2C45KxnxriCT //1 <Mother//1//1> │
│ 5ET2jhgJFoNQUpgfdSkdwftK8DKWdqZ1FKm5GKWdPfMWhPr4 ed25519 <Base> MotherG1v1 │
└──────────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table_without_g1v1.to_string(), expected_table_without_g1v1);
}
#[test]
fn test_compute_vault_accounts_table_with_g1v1_partial() {
let mother = mother_account_tree_node();
let child1 = mother.borrow().children[0].clone();
let account_tree_nodes = vec![child1];
// Test with show_g1v1 = true (default behavior)
let table_with_g1v1 =
compute_vault_accounts_table_with_g1v1(&account_tree_nodes, true).unwrap();
let expected_table_with_g1v1 = indoc! {r#"
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address/G1v1 public key Crypto Path Name │
╞═════════════════════════════════════════════════════════════════════════════════════╡
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
└─────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table_with_g1v1.to_string(), expected_table_with_g1v1);
// Test with show_g1v1 = false
let table_without_g1v1 =
compute_vault_accounts_table_with_g1v1(&account_tree_nodes, false).unwrap();
let expected_table_without_g1v1 = indoc! {r#"
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ SS58 Address Crypto Path Name │
╞═════════════════════════════════════════════════════════════════════════════════════╡
│ ├ 5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH //0 Child 1 │
│ │ ├ 5Fh5PLQNt1xuEXm71dfDtQdnwceSew4oHewWBLsWAkKspV7d //0 Grandchild 1 │
└─────────────────────────────────────────────────────────────────────────────────────┘"#
};
assert_eq!(table_without_g1v1.to_string(), expected_table_without_g1v1);
}
}
}
use crate::entities::vault_account;
use crate::entities::vault_account::DbAccountId;
use crate::*;
use serde::{Deserialize, Serialize};
const APP_NAME: &str = "gcli";
/// defines structure of config file
#[derive(Serialize, Deserialize, Debug)]
pub struct Config {
/// duniter endpoint
pub duniter_endpoint: String,
/// indexer endpoint
pub indexer_endpoint: String,
/// user address
/// to perform actions, user must provide secret
pub address: Option<AccountId>,
}
impl std::default::Default for Config {
fn default() -> Self {
Self {
duniter_endpoint: String::from(data::LOCAL_DUNITER_ENDPOINT),
indexer_endpoint: String::from(data::LOCAL_INDEXER_ENDPOINT),
address: None,
}
}
}
impl std::fmt::Display for Config {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let address = if let Some(address) = &self.address {
format!("{}", address)
} else {
"(no address)".to_string()
};
writeln!(f, "Ğcli config")?;
writeln!(f, "duniter endpoint {}", self.duniter_endpoint)?;
writeln!(f, "indexer endpoint {}", self.indexer_endpoint)?;
write!(f, "address {address}")
}
}
/// load config file and manage error if could not
pub fn load_conf() -> Config {
match confy::load(APP_NAME, None) {
Ok(cfg) => cfg,
Err(e) => {
log::warn!(
"met error while loading config file {}",
confy::get_configuration_file_path(APP_NAME, None)
.unwrap()
.display()
);
log::error!("{:?}", e);
log::info!("using default config instead");
log::info!("call `config save` to overwrite");
Config::default()
}
}
}
#[derive(Clone, Default, Debug, clap::Parser)]
pub enum Subcommand {
#[default]
/// Show config path
Where,
/// Show config
Show,
/// Save config as modified by command line arguments
Save,
/// Rest config to default
Default,
}
/// handle conf command
pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
// match subcommand
match command {
Subcommand::Where => {
println!(
"{}",
confy::get_configuration_file_path(APP_NAME, None)?.display()
);
}
Subcommand::Show => {
println!("{}", data.cfg);
if let Some(ref account_id) = data.cfg.address {
if let Some(account) = vault_account::find_by_id(
data.connect_db(),
&DbAccountId::from(account_id.clone()),
)
.await?
{
println!("(Vault: {})", account);
}
}
}
Subcommand::Save => {
save(&data.cfg);
}
Subcommand::Default => {
confy::store(APP_NAME, None, Config::default()).expect("unable to write config");
}
};
Ok(())
}
pub fn save(cfg: &Config) {
confy::store(APP_NAME, None, cfg).expect("unable to write config");
println!("Configuration updated!");
}
This diff is collapsed.
use crate::entities::vault_account;
use crate::utils::GcliError;
use sea_orm::sea_query::IndexCreateStatement;
use sea_orm::{ConnectionTrait, Database, DatabaseConnection, Schema};
use std::fs;
use std::path::Path;
pub async fn build_sqlite_connection(
data_dir: &Path,
filename: &str,
) -> Result<DatabaseConnection, GcliError> {
let sqlite_path = data_dir.join(filename);
// Check if the file exists, and create it if it doesn't (otherwise the connection will fail)
if !Path::new(&sqlite_path).exists() {
fs::File::create(sqlite_path.clone())?;
}
let sqlite_path_str = sqlite_path
.into_os_string()
.into_string()
.map_err(|_| GcliError::Input("Invalid SQLite path".to_string()))?;
let sqlite_db_url = format!("sqlite://{}", sqlite_path_str);
let connection = initialize_db(&sqlite_db_url).await?;
Ok(connection)
}
pub async fn initialize_db(db_url: &str) -> Result<DatabaseConnection, GcliError> {
let db = Database::connect(db_url).await?;
let schema = Schema::new(db.get_database_backend());
create_table_if_not_exists(&db, &schema, vault_account::Entity).await?;
Ok(db)
}
async fn create_table_if_not_exists<E: sea_orm::EntityTrait>(
db: &DatabaseConnection,
schema: &Schema,
entity: E,
) -> Result<(), GcliError> {
db.execute(
db.get_database_backend()
.build(schema.create_table_from_entity(entity).if_not_exists()),
)
.await?;
Ok(())
}
/// The only way to add composed unique index...
#[allow(dead_code)]
async fn create_table_if_not_exists_with_index<E: sea_orm::EntityTrait>(
db: &DatabaseConnection,
schema: &Schema,
entity: E,
index: &mut IndexCreateStatement,
) -> Result<(), GcliError> {
db.execute(
db.get_database_backend().build(
schema
.create_table_from_entity(entity)
.index(index)
.if_not_exists(),
),
)
.await?;
Ok(())
}
use crate::*;
use std::str;
// display events in a friendly manner
pub trait DisplayEvent {
fn display(&self, data: &Data) -> String;
}
impl DisplayEvent for runtime::universal_dividend::events::UdsClaimed {
fn display(&self, data: &Data) -> String {
format!(
"claimed {} UD, for a total of {}",
self.count,
data.format_balance(self.total)
)
}
}
impl DisplayEvent for runtime::certification::events::CertAdded {
fn display(&self, _data: &Data) -> String {
format!("new certification {} → {}", self.issuer, self.receiver)
}
}
impl DisplayEvent for runtime::certification::events::CertRenewed {
fn display(&self, _data: &Data) -> String {
format!("renewed cert {:?}", self)
}
}
impl DisplayEvent for runtime::account::events::AccountUnlinked {
fn display(&self, _data: &Data) -> String {
format!("account unlinked: {}", self.0)
}
}
impl DisplayEvent for runtime::technical_committee::events::Voted {
fn display(&self, _data: &Data) -> String {
format!("voted {:?}", self)
}
}
impl DisplayEvent for runtime::identity::events::IdtyCreated {
fn display(&self, _data: &Data) -> String {
format!(
"identity created for {} with index {}",
self.owner_key, self.idty_index
)
}
}
impl DisplayEvent for runtime::identity::events::IdtyConfirmed {
fn display(&self, _data: &Data) -> String {
format!(
"identity confirmed with name \"{}\" (index {}, owner key {})",
str::from_utf8(&self.name.0).unwrap(),
self.idty_index,
self.owner_key
)
}
}
impl DisplayEvent for runtime::identity::events::IdtyChangedOwnerKey {
fn display(&self, _data: &Data) -> String {
format!("identity changed owner key {:?}", self)
}
}
impl DisplayEvent for runtime::distance::events::EvaluationRequested {
fn display(&self, _data: &Data) -> String {
format!("evaluation requested {:?}", self)
}
}
impl DisplayEvent for runtime::smith_members::events::InvitationSent {
fn display(&self, _data: &Data) -> String {
format!("sent smith invitation {:?}", self)
}
}
impl DisplayEvent for runtime::smith_members::events::InvitationAccepted {
fn display(&self, _data: &Data) -> String {
format!("accepted smith invitation {:?}", self)
}
}
impl DisplayEvent for runtime::smith_members::events::SmithCertAdded {
fn display(&self, _data: &Data) -> String {
format!("new smith certification {:?}", self)
}
}
impl DisplayEvent for runtime::smith_members::events::SmithMembershipAdded {
fn display(&self, _data: &Data) -> String {
format!("new smith promoted {:?}", self)
}
}
impl DisplayEvent for runtime::identity::events::IdtyRemoved {
fn display(&self, _data: &Data) -> String {
format!("identity removed {:?}", self)
}
}
impl DisplayEvent for runtime::account::events::AccountLinked {
fn display(&self, _data: &Data) -> String {
format!("account {} linked to identity {}", self.who, self.identity)
}
}
impl DisplayEvent for runtime::oneshot_account::events::OneshotAccountCreated {
fn display(&self, _data: &Data) -> String {
format!("oneshot {:?}", self)
}
}
impl DisplayEvent for runtime::oneshot_account::events::OneshotAccountConsumed {
fn display(&self, _data: &Data) -> String {
format!("oneshot {:?}", self)
}
}
impl DisplayEvent for runtime::authority_members::events::MemberGoOnline {
fn display(&self, _data: &Data) -> String {
format!("smith went online {:?}", self)
}
}
impl DisplayEvent for runtime::authority_members::events::MemberGoOffline {
fn display(&self, _data: &Data) -> String {
format!("smith went offline {:?}", self)
}
}
impl DisplayEvent for runtime::sudo::events::KeyChanged {
fn display(&self, _data: &Data) -> String {
format!("sudo key changed {:?}", self)
}
}
impl DisplayEvent for runtime::balances::events::Transfer {
fn display(&self, data: &Data) -> String {
format!(
"transfered {} ({} → {})",
data.format_balance(self.amount),
self.from,
self.to
)
}
}
impl DisplayEvent for runtime::utility::events::BatchCompleted {
fn display(&self, _data: &Data) -> String {
format!("batch completed {:?}", self)
}
}
impl DisplayEvent for runtime::sudo::events::Sudid {
fn display(&self, _data: &Data) -> String {
format!("SUDO call succeeded {:?}", self)
}
}
impl DisplayEvent for runtime::technical_committee::events::Proposed {
fn display(&self, _data: &Data) -> String {
format!("proposed {:?}", self)
}
}
pub mod vault_account;
This diff is collapsed.
This diff is collapsed.
use graphql_client::GraphQLQuery;
use serde::{Deserialize, Deserializer};
// implementation of byte array
#[derive(Debug, Clone)]
pub struct Bytea {
pub bytes: Vec<u8>,
}
// Hasura uses lowercase type name
#[allow(non_camel_case_types)]
type bytea = Bytea;
// implement deserializing \\x prefixed hexadecimal
impl<'de> Deserialize<'de> for Bytea {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// Deserialize as a string
let hex_string = String::deserialize(deserializer)?;
// Parse the hexadecimal string into a byte vector
let bytes = hex::decode(&hex_string[2..]).map_err(serde::de::Error::custom)?;
Ok(Bytea { bytes })
}
}
// generate code for given graphql query
macro_rules! graphql_query {
($name:ident) => {
#[derive(GraphQLQuery)]
#[graphql(
schema_path = "res/indexer-schema.json",
query_path = "res/indexer-queries.graphql"
)]
pub struct $name;
};
}
// repeat generation for multiple queries
macro_rules! graphql_query_for {
( $($Name:ident),+ ) => {
$( graphql_query!($Name); )+
};
}
// generate code for all queries in indexer-queries.graphql
graphql_query_for!(
IdentityNameByIndex,
IdentityInfo,
IdentityNameByPubkey,
WasIdentityNameByPubkey,
LatestBlock,
BlockByNumber,
GenesisHash,
NamesByIndexes
);
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.