diff --git a/bridges/relays/bin-substrate/src/cli/derive_account.rs b/bridges/relays/bin-substrate/src/cli/derive_account.rs
new file mode 100644
index 0000000000..cd40fb5891
--- /dev/null
+++ b/bridges/relays/bin-substrate/src/cli/derive_account.rs
@@ -0,0 +1,135 @@
+// Copyright 2019-2021 Parity Technologies (UK) Ltd.
+// This file is part of Parity Bridges Common.
+
+// Parity Bridges Common is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Bridges Common is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Bridges Common. If not, see .
+
+use crate::cli::AccountId;
+use relay_substrate_client::Chain;
+use structopt::{clap::arg_enum, StructOpt};
+
+/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
+///
+/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call
+/// that has been sent over the bridge.
+/// This account can also be used to receive target-chain funds (or other form of ownership),
+/// since messages sent over the bridge will be able to spend these.
+#[derive(StructOpt)]
+pub struct DeriveAccount {
+ /// A bridge instance to initalize.
+ #[structopt(possible_values = &DeriveAccountBridge::variants(), case_insensitive = true)]
+ bridge: DeriveAccountBridge,
+ /// Source-chain address to derive Target-chain address from.
+ account: AccountId,
+}
+
+arg_enum! {
+ #[derive(Debug)]
+ /// Bridge to derive account for.
+ pub enum DeriveAccountBridge {
+ MillauToRialto,
+ RialtoToMillau,
+ }
+}
+
+macro_rules! select_bridge {
+ ($bridge: expr, $generic: tt) => {
+ match $bridge {
+ DeriveAccountBridge::MillauToRialto => {
+ type Source = relay_millau_client::Millau;
+ type Target = relay_rialto_client::Rialto;
+
+ #[allow(unused_imports)] // the import is not used in `run`
+ use bp_millau::derive_account_from_rialto_id as derive_account;
+
+ $generic
+ }
+ DeriveAccountBridge::RialtoToMillau => {
+ type Source = relay_rialto_client::Rialto;
+ type Target = relay_millau_client::Millau;
+
+ #[allow(unused_imports)] // the import is not used in `run`.
+ use bp_rialto::derive_account_from_millau_id as derive_account;
+
+ $generic
+ }
+ }
+ };
+}
+
+impl DeriveAccount {
+ /// Parse CLI arguments and derive account.
+ ///
+ /// Returns both the Source account in correct SS58 format and the derived account.
+ fn derive_account(&self) -> (AccountId, AccountId) {
+ select_bridge!(self.bridge, {
+ let mut account = self.account.clone();
+ account.enforce_chain::();
+ let acc = bp_runtime::SourceAccount::Account(account.raw_id());
+ let id = derive_account(acc);
+ let derived_account = AccountId::from_raw::(id);
+ (account, derived_account)
+ })
+ }
+
+ /// Run the command.
+ pub async fn run(self) -> anyhow::Result<()> {
+ select_bridge!(self.bridge, {
+ let (account, derived_account) = self.derive_account();
+ println!("Source address:\n{} ({})", account, Source::NAME);
+ println!(
+ "->Corresponding (derived) address:\n{} ({})",
+ derived_account,
+ Target::NAME,
+ );
+
+ Ok(())
+ })
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ fn derive_account_cli(bridge: &str, account: &str) -> (AccountId, AccountId) {
+ DeriveAccount::from_iter(vec!["derive-account", bridge, account]).derive_account()
+ }
+
+ #[test]
+ fn should_derive_accounts_correctly() {
+ // given
+ let rialto = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU";
+ let millau = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9";
+
+ // when
+ let (rialto_parsed, rialto_derived) = derive_account_cli("RialtoToMillau", rialto);
+ let (millau_parsed, millau_derived) = derive_account_cli("MillauToRialto", millau);
+ let (millau2_parsed, millau2_derived) = derive_account_cli("MillauToRialto", rialto);
+
+ // then
+ assert_eq!(format!("{}", rialto_parsed), rialto);
+ assert_eq!(format!("{}", millau_parsed), millau);
+ assert_eq!(format!("{}", millau2_parsed), millau);
+
+ assert_eq!(
+ format!("{}", rialto_derived),
+ "73gLnUwrAdH4vMjbXCiNEpgyz1PLk9JxCaY4cKzvfSZT73KE"
+ );
+ assert_eq!(
+ format!("{}", millau_derived),
+ "5rpTJqGv1BPAYy2sXzkPpc3Wx1ZpQtgfuBsrDpNV4HsXAmbi"
+ );
+ assert_eq!(millau_derived, millau2_derived);
+ }
+}
diff --git a/bridges/relays/bin-substrate/src/cli/mod.rs b/bridges/relays/bin-substrate/src/cli/mod.rs
index 5419f82637..3bcc1bf584 100644
--- a/bridges/relays/bin-substrate/src/cli/mod.rs
+++ b/bridges/relays/bin-substrate/src/cli/mod.rs
@@ -25,6 +25,7 @@ use frame_support::weights::Weight;
use sp_runtime::app_crypto::Ss58Codec;
use structopt::{clap::arg_enum, StructOpt};
+mod derive_account;
mod init_bridge;
mod relay_headers;
mod relay_messages;
@@ -71,7 +72,7 @@ pub enum Command {
/// Estimate Delivery and Dispatch Fee required for message submission to messages pallet.
EstimateFee(EstimateFee),
/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
- DeriveAccount(DeriveAccount),
+ DeriveAccount(derive_account::DeriveAccount),
}
impl Command {
@@ -159,28 +160,6 @@ impl EstimateFee {
}
}
-/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
-///
-/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call
-/// that has been sent over the bridge.
-/// This account can also be used to receive target-chain funds (or other form of ownership),
-/// since messages sent over the bridge will be able to spend these.
-#[derive(StructOpt)]
-pub enum DeriveAccount {
- #[structopt(flatten)]
- RialtoMillau(rialto_millau::DeriveAccount),
-}
-
-impl DeriveAccount {
- /// Run the command.
- pub async fn run(self) -> anyhow::Result<()> {
- match self {
- Self::RialtoMillau(arg) => arg.run().await?,
- }
- Ok(())
- }
-}
-
arg_enum! {
#[derive(Debug)]
/// The origin to use when dispatching the message on the target chain.
@@ -213,7 +192,7 @@ impl Balance {
}
/// Generic account id with custom parser.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AccountId {
account: sp_runtime::AccountId32,
ss58_format: sp_core::crypto::Ss58AddressFormat,
diff --git a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs
index 3d314cc71b..2f11156537 100644
--- a/bridges/relays/bin-substrate/src/rialto_millau/cli.rs
+++ b/bridges/relays/bin-substrate/src/rialto_millau/cli.rs
@@ -176,30 +176,6 @@ impl EstimateFee {
}
}
-/// Given a source chain `AccountId`, derive the corresponding `AccountId` for the target chain.
-///
-/// The (derived) target chain `AccountId` is going to be used as dispatch origin of the call
-/// that has been sent over the bridge.
-/// This account can also be used to receive target-chain funds (or other form of ownership),
-/// since messages sent over the bridge will be able to spend these.
-///
-/// TODO [#855] Move to separate module.
-#[derive(StructOpt)]
-pub enum DeriveAccount {
- /// Given Rialto AccountId, display corresponding Millau AccountId.
- RialtoToMillau { account: AccountId },
- /// Given Millau AccountId, display corresponding Rialto AccountId.
- MillauToRialto { account: AccountId },
-}
-
-impl DeriveAccount {
- /// Run the command.
- pub async fn run(self) -> anyhow::Result<()> {
- super::run_derive_account(self).await.map_err(format_err)?;
- Ok(())
- }
-}
-
fn format_err(err: String) -> anyhow::Error {
anyhow::anyhow!(err)
}
diff --git a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs
index 5446e382a7..bcc7821e20 100644
--- a/bridges/relays/bin-substrate/src/rialto_millau/mod.rs
+++ b/bridges/relays/bin-substrate/src/rialto_millau/mod.rs
@@ -29,7 +29,7 @@ pub type MillauClient = relay_substrate_client::Client;
pub type RialtoClient = relay_substrate_client::Client;
use crate::cli::{
- AccountId, CliChain, ExplicitOrMaximal, HexBytes, Origins, SourceConnectionParams, SourceSigningParams,
+ CliChain, ExplicitOrMaximal, HexBytes, Origins, SourceConnectionParams, SourceSigningParams,
TargetConnectionParams, TargetSigningParams,
};
use codec::{Decode, Encode};
@@ -337,43 +337,6 @@ async fn run_estimate_fee(cmd: cli::EstimateFee) -> Result<(), String> {
Ok(())
}
-async fn run_derive_account(cmd: cli::DeriveAccount) -> Result<(), String> {
- match cmd {
- cli::DeriveAccount::RialtoToMillau { mut account } => {
- type Source = Rialto;
- type Target = Millau;
-
- account.enforce_chain::();
- let acc = bp_runtime::SourceAccount::Account(account.raw_id());
- let id = bp_millau::derive_account_from_rialto_id(acc);
- let derived_account = AccountId::from_raw::(id);
- println!("Source address:\n{} ({})", account, Source::NAME);
- println!(
- "->Corresponding (derived) address:\n{} ({})",
- derived_account,
- Target::NAME,
- );
- }
- cli::DeriveAccount::MillauToRialto { mut account } => {
- type Source = Millau;
- type Target = Rialto;
-
- account.enforce_chain::();
- let acc = bp_runtime::SourceAccount::Account(account.raw_id());
- let id = bp_rialto::derive_account_from_millau_id(acc);
- let derived_account = AccountId::from_raw::(id);
- println!("Source address:\n{} ({})", account, Source::NAME);
- println!(
- "->Corresponding (derived) address:\n{} ({})",
- derived_account,
- Target::NAME,
- );
- }
- }
-
- Ok(())
-}
-
async fn estimate_message_delivery_and_dispatch_fee(
client: &relay_substrate_client::Client,
estimate_fee_method: &str,
@@ -864,25 +827,4 @@ mod tests {
extra_bytes_in_transaction,
);
}
-
- #[test]
- fn should_reformat_addresses() {
- // given
- let mut rialto1: AccountId = "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU".parse().unwrap();
- let mut millau1: AccountId = "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9".parse().unwrap();
-
- // when
- rialto1.enforce_chain::();
- millau1.enforce_chain::();
-
- // then
- assert_eq!(
- &format!("{}", rialto1),
- "752paRyW1EGfq9YLTSSqcSJ5hqnBDidBmaftGhBo8fy6ypW9"
- );
- assert_eq!(
- &format!("{}", millau1),
- "5sauUXUfPjmwxSgmb3tZ5d6yx24eZX4wWJ2JtVUBaQqFbvEU"
- );
- }
}