Skip to content
Snippets Groups Projects
main.rs 7.88 KiB
Newer Older
mod cache;
mod commands;
mod indexer;

Pascal Engélibert's avatar
Pascal Engélibert committed
use anyhow::{anyhow, Result};
Éloïs's avatar
Éloïs committed
use clap::Parser;
use codec::Encode;
use sp_core::{
    crypto::{Pair as _, Ss58Codec},
Éloïs's avatar
Éloïs committed
    sr25519::Pair,
};
use std::str::FromStr;
Éloïs's avatar
Éloïs committed

#[subxt::subxt(runtime_metadata_path = "res/metadata.scale")]
pub mod gdev {}
Éloïs's avatar
Éloïs committed

Pascal Engélibert's avatar
Pascal Engélibert committed
pub type Client = subxt::OnlineClient<GdevConfig>;

pub enum GdevConfig {}
impl subxt::config::Config for GdevConfig {
    type Index = u32;
    type BlockNumber = u32;
    type Hash = sp_core::H256;
    type Hashing = subxt::ext::sp_runtime::traits::BlakeTwo256;
    type AccountId = subxt::ext::sp_runtime::AccountId32;
    type Address = subxt::ext::sp_runtime::MultiAddress<Self::AccountId, u32>;
    type Header = subxt::ext::sp_runtime::generic::Header<
        Self::BlockNumber,
        subxt::ext::sp_runtime::traits::BlakeTwo256,
    >;
    type Signature = subxt::ext::sp_runtime::MultiSignature;
    type Extrinsic = subxt::ext::sp_runtime::OpaqueExtrinsic;
    type ExtrinsicParams = subxt::tx::BaseExtrinsicParams<Self, Tip>;
}
Éloïs's avatar
Éloïs committed

#[derive(Copy, Clone, Debug, Default, 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)
    }
}

Éloïs's avatar
Éloïs committed
#[derive(Parser, Debug)]
#[clap(author, version, about, long_about = None)]
pub struct Args {
Éloïs's avatar
Éloïs committed
    #[clap(subcommand)]
    pub subcommand: Subcommand,

    /// Indexer URL
    #[clap(short, long, default_value = "https://idx.gdev.cgeek.fr/v1/graphql")]
    indexer: String,
    /// Do not use indexer
    #[clap(long)]
    no_indexer: bool,
Éloïs's avatar
Éloïs committed
    /// Secret key or BIP39 mnemonic
    /// (eventually followed by derivation path)
    #[clap(short, long)]
    secret: Option<String>,
    /// Address
    #[clap(short, long)]
    address: Option<String>,
Éloïs's avatar
Éloïs committed
    /// Websocket RPC endpoint
    #[clap(short, long, default_value = "ws://localhost:9944")]
Éloïs's avatar
Éloïs committed
    url: String,
}

#[derive(Debug, clap::Subcommand)]
pub enum Subcommand {
    CreateOneshot {
        balance: u64,
        dest: sp_core::crypto::AccountId32,
    },
    ConsumeOneshot {
        dest: sp_core::crypto::AccountId32,
        #[clap(long = "oneshot")]
        dest_oneshot: bool,
    },
    ConsumeOneshotWithRemaining {
        balance: u64,
        dest: sp_core::crypto::AccountId32,
        #[clap(long = "one")]
        dest_oneshot: bool,
        remaining_to: sp_core::crypto::AccountId32,
        #[clap(long = "rem-one")]
        remaining_to_oneshot: bool,
    },
    /// List upcoming expirations that require an action
    Expire {
        /// Show certs that expire within less than this number of blocks
        #[clap(short, long, default_value_t = 100800)]
        blocks: u32,
        /// Show authorities that should rotate keys within less than this number of sessions
        #[clap(short, long, default_value_t = 100)]
        sessions: u32,
    },
Éloïs's avatar
Éloïs committed
    /// Generate a revocation document for the provided account
    GenRevocDoc,
    OneshotBalance {
        account: sp_core::crypto::AccountId32,
    },
Éloïs's avatar
Éloïs committed
    #[clap(hide = true)]
    Repart {
        // Number of transactions per block to target
        target: u32,
        #[clap(short = 'o', long = "old-repart")]
        // Old/actual repartition
        actual_repart: Option<u32>,
    },
    #[clap(hide = true)]
    SpamRoll { actual_repart: usize },
Pascal Engélibert's avatar
Pascal Engélibert committed
    SudoSetKey {
        new_key: sp_core::crypto::AccountId32,
    },
    Transfer {
        balance: u64,
        dest: sp_core::crypto::AccountId32,
        #[clap(short = 'k')]
        keep_alive: bool,
    },
Éloïs's avatar
Éloïs committed
}

#[tokio::main(flavor = "current_thread")]
async fn main() -> Result<()> {
    env_logger::init();

    let args = Args::parse();

    let (account_id, pair) = match (&args.address, &args.secret) {
        (Some(address), Some(secret)) => {
            let pair = Pair::from_string(secret, None)
                .map_err(|_| anyhow!("Invalid secret {}", secret))?;
            let address = sp_core::crypto::AccountId32::from_string(address)
                .map_err(|_| anyhow!("Invalid address {}", address))?;
            assert_eq!(
                address,
                pair.public().into(),
                "Secret and address do not match."
            );
            (Some(pair.public().into()), Some(pair))
        }
        (None, Some(secret)) => {
            let pair = Pair::from_string(secret, None)
                .map_err(|_| anyhow!("Invalid secret {}", secret))?;
            (Some(pair.public().into()), Some(pair))
        }
        (Some(address), None) => (
            Some(
                sp_core::crypto::AccountId32::from_str(address)
                    .map_err(|_| anyhow!("Invalid address {}", address))?,
            ),
            None,
        ),
        (None, None) => (None, None),
    };
Éloïs's avatar
Éloïs committed

Pascal Engélibert's avatar
Pascal Engélibert committed
    let client = Client::new().await.unwrap();
Éloïs's avatar
Éloïs committed

    if let Some(account_id) = &account_id {
Pascal Engélibert's avatar
Pascal Engélibert committed
        let account = client
            .storage()
            .fetch(&gdev::storage().system().account(account_id), None)
Pascal Engélibert's avatar
Pascal Engélibert committed
            .await?
            .expect("Cannot fetch account");
        logs::info!("Account free balance: {}", account.data.free);
    }
Éloïs's avatar
Éloïs committed

    match args.subcommand {
        Subcommand::CreateOneshot { balance, dest } => {
            commands::oneshot::create_oneshot_account(
                pair.expect("This subcommand needs a secret."),
                client,
                balance,
                dest,
            )
            .await?
        }
        Subcommand::ConsumeOneshot { dest, dest_oneshot } => {
            commands::oneshot::consume_oneshot_account(
                pair.expect("This subcommand needs a secret."),
                client,
                dest,
                dest_oneshot,
            )
            .await?
        }
        Subcommand::ConsumeOneshotWithRemaining {
            balance,
            dest,
            dest_oneshot,
            remaining_to,
            remaining_to_oneshot,
        } => {
            commands::oneshot::consume_oneshot_account_with_remaining(
                pair.expect("This subcommand needs a secret."),
                client,
                balance,
                dest,
                dest_oneshot,
                remaining_to,
                remaining_to_oneshot,
            )
            .await?
        Subcommand::Expire { blocks, sessions } => {
            commands::expire::monitor_expirations(client, blocks, sessions, &args).await?
        Subcommand::GenRevocDoc => {
            commands::revocation::gen_revoc_doc(
                &client,
                &pair.expect("This subcommand needs a secret."),
            )
            .await?
        Subcommand::OneshotBalance { account } => {
            commands::oneshot::oneshot_account_balance(client, account).await?
Éloïs's avatar
Éloïs committed
        Subcommand::Repart {
            target,
            actual_repart,
        } => {
            commands::net_test::repart(
                pair.expect("This subcommand needs a secret."),
                client,
                target,
                actual_repart,
            )
            .await?
Éloïs's avatar
Éloïs committed
        }
        Subcommand::SpamRoll { actual_repart } => {
            commands::net_test::spam_roll(
                pair.expect("This subcommand needs a secret."),
                client,
                actual_repart,
            )
            .await?
Éloïs's avatar
Éloïs committed
        }
Pascal Engélibert's avatar
Pascal Engélibert committed
        Subcommand::SudoSetKey { new_key } => {
            commands::sudo::set_key(
                pair.expect("This subcommand needs a secret."),
                client,
                new_key,
            )
            .await?
        Subcommand::Transfer {
            balance,
            dest,
            keep_alive,
        } => {
            commands::transfer::transfer(
                pair.expect("This subcommand needs a secret."),
                client,
                balance,
                dest,
                keep_alive,
            )
            .await?
Éloïs's avatar
Éloïs committed
    }

    Ok(())
}