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::*; use crate::*;
use anyhow::Result; #[cfg(feature = "gdev")] // find how to get runtime calls
use sp_core::{crypto::AccountId32, sr25519::Pair};
use subxt::tx::{BaseExtrinsicParamsBuilder, PairSigner};
#[cfg(any(feature = "dev", feature = "gdev"))] // find how to get runtime calls
type Call = runtime::runtime_types::gdev_runtime::RuntimeCall; type Call = runtime::runtime_types::gdev_runtime::RuntimeCall;
type BalancesCall = runtime::runtime_types::pallet_balances::pallet::Call; type BalancesCall = runtime::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: AccountId32, dest: AccountId,
keep_alive: bool, keep_alive: bool,
) -> Result<()> { is_ud: bool,
if keep_alive { ) -> Result<(), subxt::Error> {
client match (keep_alive, is_ud) {
.tx() (true, false) => {
.sign_and_submit_then_watch( submit_call_and_look_event::<
&runtime::tx().balances().transfer(dest.into(), balance), runtime::balances::events::Transfer,
&PairSigner::new(pair), StaticPayload<runtime::balances::calls::types::TransferKeepAlive>,
BaseExtrinsicParamsBuilder::new(), >(
) data,
.await?;
} else {
client
.tx()
.sign_and_submit_then_watch(
&runtime::tx() &runtime::tx()
.balances() .balances()
.transfer_keep_alive(dest.into(), balance), .transfer_keep_alive(dest.into(), balance),
&PairSigner::new(pair),
BaseExtrinsicParamsBuilder::new(),
) )
.await?; .await
}
(false, false) => {
submit_call_and_look_event::<
runtime::balances::events::Transfer,
StaticPayload<runtime::balances::calls::types::TransferAllowDeath>,
>(
data,
&runtime::tx()
.balances()
.transfer_allow_death(dest.into(), balance),
)
.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
}
} }
Ok(())
} }
/// 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<AccountId32>, dests: Vec<AccountId>,
) -> Result<()> { ) -> Result<(), subxt::Error> {
// 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()
...@@ -56,16 +80,10 @@ pub async fn transfer_multiple( ...@@ -56,16 +80,10 @@ pub async fn transfer_multiple(
}) })
}) })
.collect(); .collect();
// wrap these calls in a batch call // wrap these calls in a batch call
client submit_call_and_look_event::<
.tx() runtime::utility::events::BatchCompleted,
.sign_and_submit_then_watch( StaticPayload<runtime::utility::calls::types::Batch>,
&runtime::tx().utility().batch(transactions), >(data, &runtime::tx().utility().batch(transactions))
&PairSigner::new(pair.clone()), .await
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 crate::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
const APP_NAME: &str = "gcli"; const APP_NAME: &str = "gcli";
/// defines structure of config file
#[derive(Serialize, Deserialize, Debug)] #[derive(Serialize, Deserialize, Debug)]
pub struct Config { pub struct Config {
duniter_endpoint: String, /// duniter endpoint
indexer_endpoint: String, 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 { impl std::default::Default for Config {
fn default() -> Self { fn default() -> Self {
Self { Self {
duniter_endpoint: String::from("ws://localhost:9944"), duniter_endpoint: String::from(data::LOCAL_DUNITER_ENDPOINT),
indexer_endpoint: String::from("http://localhost:8080/v1/graphql"), 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 /// load config file and manage error if could not
pub fn load_conf() -> Config { pub fn load_conf() -> Config {
match confy::load(APP_NAME, None) { match confy::load(APP_NAME, None) {
Ok(cfg) => cfg, Ok(cfg) => cfg,
Err(e) => { Err(e) => {
log::warn!("met error while loading config file"); log::warn!(
log::error!("{}", e); "met error while loading config file {}",
log::info!("removing the old conf file and creating a new one"); confy::get_configuration_file_path(APP_NAME, None)
let cfg = Config::default(); .unwrap()
confy::store(APP_NAME, None, &cfg).expect("unable to write default config"); .display()
cfg );
} log::error!("{:?}", e);
} log::info!("using default config instead");
log::info!("call `config save` to overwrite");
Config::default()
}
}
} }
#[derive(Clone, Default, Debug, clap::Parser)] #[derive(Clone, Default, Debug, clap::Parser)]
pub enum Subcommand { pub enum Subcommand {
#[default] #[default]
/// Show config path /// Show config path
Where, Where,
/// Show config /// Show config
Show, Show,
/// Save config as modified by command line arguments
Save,
/// Rest config to default
Default,
} }
/// handle conf command /// handle conf command
pub fn handle_command(data: Data, command: Subcommand) -> anyhow::Result<()> { pub async fn handle_command(data: Data, command: Subcommand) -> Result<(), GcliError> {
// match subcommand // match subcommand
match command { match command {
Subcommand::Where => { Subcommand::Where => {
println!("{}", confy::get_configuration_file_path(APP_NAME, None)?.display()); println!(
} "{}",
Subcommand::Show => { confy::get_configuration_file_path(APP_NAME, None)?.display()
println!("{:?}", data.cfg); );
}
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(()) 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.
// #[allow(clippy::enum_variant_names)]
#[cfg(feature = "gdev")]
#[subxt::subxt(
runtime_metadata_path = "res/metadata.scale",
derive_for_all_types = "Debug"
)]
pub mod runtime {}
// declare custom types
pub type Client = subxt::OnlineClient<Runtime>;
pub type AccountId = subxt::utils::AccountId32;
pub type IdtyId = u32;
pub type BlockNumber = u32;
pub type TxProgress = subxt::tx::TxProgress<Runtime, Client>;
pub type Balance = u64;
pub type AccountData =
runtime::runtime_types::pallet_duniter_account::types::AccountData<Balance, IdtyId>;
pub type AccountInfo = runtime::runtime_types::frame_system::AccountInfo<u32, AccountData>;
pub type Hash = sp_core::H256;
// declare runtime types
pub enum Runtime {}
impl subxt::config::Config for Runtime {
type AssetId = ();
type Hash = Hash;
type AccountId = AccountId;
type Address = sp_runtime::MultiAddress<Self::AccountId, u32>;
type Signature = sp_runtime::MultiSignature;
type Hasher = subxt::config::substrate::BlakeTwo256;
type Header = subxt::config::substrate::SubstrateHeader<BlockNumber, Self::Hasher>;
type ExtrinsicParams = subxt::config::DefaultExtrinsicParams<Self>;
}
// Tip for transaction fee
#[derive(Copy, Clone, Debug, Default, codec::Encode)]
pub struct Tip {
#[codec(compact)]
tip: u64,
}
impl Tip {
pub fn new(amount: u64) -> Self {
Tip { tip: amount }
}
}
impl From<u64> for Tip {
fn from(n: u64) -> Self {
Self::new(n)
}
}
This diff is collapsed.