diff --git a/Cargo.lock b/Cargo.lock
index 03c85511a..6e584c624 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -753,6 +753,18 @@ dependencies = [
"syn_derive",
]
+[[package]]
+name = "bounded-collections"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca548b6163b872067dc5eb82fd130c56881435e30367d2073594a3d9744120dd"
+dependencies = [
+ "log",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+]
+
[[package]]
name = "bounded-collections"
version = "0.2.0"
@@ -881,11 +893,10 @@ dependencies = [
"semver",
"serde",
"serde_json",
- "sp-core",
- "sp-weights",
+ "sp-core 30.0.0",
+ "sp-weights 29.0.0",
"substrate-build-script-utils",
"subxt",
- "subxt-signer",
"tempfile",
"tokio",
"tracing",
@@ -1176,7 +1187,6 @@ dependencies = [
"anyhow",
"assert_cmd",
"blake2",
- "clap",
"colored",
"contract-build",
"contract-metadata",
@@ -1196,9 +1206,9 @@ dependencies = [
"scale-info",
"serde",
"serde_json",
- "sp-core",
- "sp-runtime",
- "sp-weights",
+ "sp-core 30.0.0",
+ "sp-runtime 33.0.0",
+ "sp-weights 29.0.0",
"subxt",
"subxt-signer",
"tempfile",
@@ -1244,7 +1254,7 @@ dependencies = [
"scale-info",
"serde",
"serde_json",
- "sp-core",
+ "sp-core 30.0.0",
"sp-keyring",
"strsim 0.11.0",
"thiserror",
@@ -4936,6 +4946,20 @@ dependencies = [
"sha-1",
]
+[[package]]
+name = "sp-application-crypto"
+version = "30.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e4fe7a9b7fa9da76272b201e2fb3c7900d97d32a46b66af9a04dad457f73c71"
+dependencies = [
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "sp-core 28.0.0",
+ "sp-io 30.0.0",
+ "sp-std",
+]
+
[[package]]
name = "sp-application-crypto"
version = "32.0.0"
@@ -4945,9 +4969,24 @@ dependencies = [
"parity-scale-codec",
"scale-info",
"serde",
- "sp-core",
- "sp-io",
+ "sp-core 30.0.0",
+ "sp-io 32.0.0",
+ "sp-std",
+]
+
+[[package]]
+name = "sp-arithmetic"
+version = "23.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f42721f072b421f292a072e8f52a3b3c0fbc27428f0c9fe24067bc47046bad63"
+dependencies = [
+ "integer-sqrt",
+ "num-traits",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
"sp-std",
+ "static_assertions",
]
[[package]]
@@ -4965,6 +5004,52 @@ dependencies = [
"static_assertions",
]
+[[package]]
+name = "sp-core"
+version = "28.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f230cb12575455070da0fc174815958423a0b9a641d5e304a9457113c7cb4007"
+dependencies = [
+ "array-bytes",
+ "bip39",
+ "bitflags 1.3.2",
+ "blake2",
+ "bounded-collections 0.1.9",
+ "bs58",
+ "dyn-clonable",
+ "ed25519-zebra 3.1.0",
+ "futures",
+ "hash-db",
+ "hash256-std-hasher",
+ "impl-serde",
+ "itertools 0.10.5",
+ "libsecp256k1",
+ "log",
+ "merlin",
+ "parity-scale-codec",
+ "parking_lot",
+ "paste",
+ "primitive-types",
+ "rand",
+ "scale-info",
+ "schnorrkel",
+ "secp256k1",
+ "secrecy",
+ "serde",
+ "sp-core-hashing",
+ "sp-debug-derive",
+ "sp-externalities 0.25.0",
+ "sp-runtime-interface 24.0.0",
+ "sp-std",
+ "sp-storage 19.0.0",
+ "ss58-registry",
+ "substrate-bip39",
+ "thiserror",
+ "tracing",
+ "w3f-bls",
+ "zeroize",
+]
+
[[package]]
name = "sp-core"
version = "30.0.0"
@@ -4975,7 +5060,7 @@ dependencies = [
"bip39",
"bitflags 1.3.2",
"blake2",
- "bounded-collections",
+ "bounded-collections 0.2.0",
"bs58",
"dyn-clonable",
"ed25519-zebra 3.1.0",
@@ -4999,10 +5084,10 @@ dependencies = [
"serde",
"sp-crypto-hashing",
"sp-debug-derive",
- "sp-externalities",
- "sp-runtime-interface",
+ "sp-externalities 0.27.0",
+ "sp-runtime-interface 26.0.0",
"sp-std",
- "sp-storage",
+ "sp-storage 20.0.0",
"ss58-registry",
"substrate-bip39",
"thiserror",
@@ -5050,6 +5135,18 @@ dependencies = [
"syn 2.0.52",
]
+[[package]]
+name = "sp-externalities"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "63867ec85950ced90d4ab1bba902a47db1b1efdf2829f653945669b2bb470a9c"
+dependencies = [
+ "environmental",
+ "parity-scale-codec",
+ "sp-std",
+ "sp-storage 19.0.0",
+]
+
[[package]]
name = "sp-externalities"
version = "0.27.0"
@@ -5059,7 +5156,32 @@ dependencies = [
"environmental",
"parity-scale-codec",
"sp-std",
- "sp-storage",
+ "sp-storage 20.0.0",
+]
+
+[[package]]
+name = "sp-io"
+version = "30.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c55f26d89feedaf0faf81688b6e1e1e81329cd8b4c6a4fd6c5b97ed9dd068b8a"
+dependencies = [
+ "bytes",
+ "ed25519-dalek",
+ "libsecp256k1",
+ "log",
+ "parity-scale-codec",
+ "rustversion",
+ "secp256k1",
+ "sp-core 28.0.0",
+ "sp-externalities 0.25.0",
+ "sp-keystore 0.34.0",
+ "sp-runtime-interface 24.0.0",
+ "sp-state-machine 0.35.0",
+ "sp-std",
+ "sp-tracing",
+ "sp-trie 29.0.0",
+ "tracing",
+ "tracing-core",
]
[[package]]
@@ -5075,15 +5197,15 @@ dependencies = [
"parity-scale-codec",
"rustversion",
"secp256k1",
- "sp-core",
+ "sp-core 30.0.0",
"sp-crypto-hashing",
- "sp-externalities",
- "sp-keystore",
- "sp-runtime-interface",
- "sp-state-machine",
+ "sp-externalities 0.27.0",
+ "sp-keystore 0.36.0",
+ "sp-runtime-interface 26.0.0",
+ "sp-state-machine 0.37.0",
"sp-std",
"sp-tracing",
- "sp-trie",
+ "sp-trie 31.0.0",
"tracing",
"tracing-core",
]
@@ -5094,11 +5216,24 @@ version = "33.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f9c74648e593b45309dfddf34f4edfd0a91816d1d97dd5e0bd93c46e7cdb0d6"
dependencies = [
- "sp-core",
- "sp-runtime",
+ "sp-core 30.0.0",
+ "sp-runtime 33.0.0",
"strum 0.24.1",
]
+[[package]]
+name = "sp-keystore"
+version = "0.34.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96806a28a62ed9ddecd0b28857b1344d029390f7c5c42a2ff9199cbf5638635c"
+dependencies = [
+ "parity-scale-codec",
+ "parking_lot",
+ "sp-core 28.0.0",
+ "sp-externalities 0.25.0",
+ "thiserror",
+]
+
[[package]]
name = "sp-keystore"
version = "0.36.0"
@@ -5107,8 +5242,8 @@ checksum = "bd4bf9e5fa486416c92c2bb497b7ce2c43eac80cbdc407ffe2d34b365694ac29"
dependencies = [
"parity-scale-codec",
"parking_lot",
- "sp-core",
- "sp-externalities",
+ "sp-core 30.0.0",
+ "sp-externalities 0.27.0",
]
[[package]]
@@ -5122,6 +5257,31 @@ dependencies = [
"regex",
]
+[[package]]
+name = "sp-runtime"
+version = "31.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3bb49a4475d390198dfd3d41bef4564ab569fbaf1b5e38ae69b35fc01199d91"
+dependencies = [
+ "docify",
+ "either",
+ "hash256-std-hasher",
+ "impl-trait-for-tuples",
+ "log",
+ "parity-scale-codec",
+ "paste",
+ "rand",
+ "scale-info",
+ "serde",
+ "simple-mermaid",
+ "sp-application-crypto 30.0.0",
+ "sp-arithmetic 23.0.0",
+ "sp-core 28.0.0",
+ "sp-io 30.0.0",
+ "sp-std",
+ "sp-weights 27.0.0",
+]
+
[[package]]
name = "sp-runtime"
version = "33.0.0"
@@ -5139,12 +5299,31 @@ dependencies = [
"scale-info",
"serde",
"simple-mermaid",
- "sp-application-crypto",
- "sp-arithmetic",
- "sp-core",
- "sp-io",
+ "sp-application-crypto 32.0.0",
+ "sp-arithmetic 25.0.0",
+ "sp-core 30.0.0",
+ "sp-io 32.0.0",
"sp-std",
- "sp-weights",
+ "sp-weights 29.0.0",
+]
+
+[[package]]
+name = "sp-runtime-interface"
+version = "24.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f66b66d8cec3d785fa6289336c1d9cbd4305d5d84f7134378c4d79ed7983e6fb"
+dependencies = [
+ "bytes",
+ "impl-trait-for-tuples",
+ "parity-scale-codec",
+ "primitive-types",
+ "sp-externalities 0.25.0",
+ "sp-runtime-interface-proc-macro 17.0.0",
+ "sp-std",
+ "sp-storage 19.0.0",
+ "sp-tracing",
+ "sp-wasm-interface",
+ "static_assertions",
]
[[package]]
@@ -5158,15 +5337,29 @@ dependencies = [
"parity-scale-codec",
"polkavm-derive 0.8.0",
"primitive-types",
- "sp-externalities",
- "sp-runtime-interface-proc-macro",
+ "sp-externalities 0.27.0",
+ "sp-runtime-interface-proc-macro 18.0.0",
"sp-std",
- "sp-storage",
+ "sp-storage 20.0.0",
"sp-tracing",
"sp-wasm-interface",
"static_assertions",
]
+[[package]]
+name = "sp-runtime-interface-proc-macro"
+version = "17.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cfaf6e85b2ec12a4b99cd6d8d57d083e30c94b7f1b0d8f93547121495aae6f0c"
+dependencies = [
+ "Inflector",
+ "expander",
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.52",
+]
+
[[package]]
name = "sp-runtime-interface-proc-macro"
version = "18.0.0"
@@ -5181,6 +5374,28 @@ dependencies = [
"syn 2.0.52",
]
+[[package]]
+name = "sp-state-machine"
+version = "0.35.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "718c779ad1d6fcc0be64c7ce030b33fa44b5c8914b3a1319ef63bb5f27fb98df"
+dependencies = [
+ "hash-db",
+ "log",
+ "parity-scale-codec",
+ "parking_lot",
+ "rand",
+ "smallvec",
+ "sp-core 28.0.0",
+ "sp-externalities 0.25.0",
+ "sp-panic-handler",
+ "sp-std",
+ "sp-trie 29.0.0",
+ "thiserror",
+ "tracing",
+ "trie-db",
+]
+
[[package]]
name = "sp-state-machine"
version = "0.37.0"
@@ -5193,11 +5408,11 @@ dependencies = [
"parking_lot",
"rand",
"smallvec",
- "sp-core",
- "sp-externalities",
+ "sp-core 30.0.0",
+ "sp-externalities 0.27.0",
"sp-panic-handler",
"sp-std",
- "sp-trie",
+ "sp-trie 31.0.0",
"thiserror",
"tracing",
"trie-db",
@@ -5209,6 +5424,20 @@ version = "14.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12f8ee986414b0a9ad741776762f4083cd3a5128449b982a3919c4df36874834"
+[[package]]
+name = "sp-storage"
+version = "19.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fb92d7b24033a8a856d6e20dd980b653cbd7af7ec471cc988b1b7c1d2e3a32b"
+dependencies = [
+ "impl-serde",
+ "parity-scale-codec",
+ "ref-cast",
+ "serde",
+ "sp-debug-derive",
+ "sp-std",
+]
+
[[package]]
name = "sp-storage"
version = "20.0.0"
@@ -5236,6 +5465,31 @@ dependencies = [
"tracing-subscriber 0.2.25",
]
+[[package]]
+name = "sp-trie"
+version = "29.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e4d24d84a0beb44a71dcac1b41980e1edf7fb722c7f3046710136a283cd479b"
+dependencies = [
+ "ahash 0.8.11",
+ "hash-db",
+ "lazy_static",
+ "memory-db",
+ "nohash-hasher",
+ "parity-scale-codec",
+ "parking_lot",
+ "rand",
+ "scale-info",
+ "schnellru",
+ "sp-core 28.0.0",
+ "sp-externalities 0.25.0",
+ "sp-std",
+ "thiserror",
+ "tracing",
+ "trie-db",
+ "trie-root",
+]
+
[[package]]
name = "sp-trie"
version = "31.0.0"
@@ -5252,8 +5506,8 @@ dependencies = [
"rand",
"scale-info",
"schnellru",
- "sp-core",
- "sp-externalities",
+ "sp-core 30.0.0",
+ "sp-externalities 0.27.0",
"sp-std",
"thiserror",
"tracing",
@@ -5275,18 +5529,34 @@ dependencies = [
"wasmtime",
]
+[[package]]
+name = "sp-weights"
+version = "27.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e874bdf9dd3fd3242f5b7867a4eaedd545b02f29041a46d222a9d9d5caaaa5c"
+dependencies = [
+ "bounded-collections 0.1.9",
+ "parity-scale-codec",
+ "scale-info",
+ "serde",
+ "smallvec",
+ "sp-arithmetic 23.0.0",
+ "sp-debug-derive",
+ "sp-std",
+]
+
[[package]]
name = "sp-weights"
version = "29.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ab8a9c7a1b64fa7dba38622ad1de26f0b2e595727c0e42c7b109ecb8e7120688"
dependencies = [
- "bounded-collections",
+ "bounded-collections 0.2.0",
"parity-scale-codec",
"scale-info",
"serde",
"smallvec",
- "sp-arithmetic",
+ "sp-arithmetic 25.0.0",
"sp-debug-derive",
"sp-std",
]
@@ -5460,7 +5730,9 @@ dependencies = [
"scale-value",
"serde",
"serde_json",
+ "sp-core 28.0.0",
"sp-core-hashing",
+ "sp-runtime 31.0.1",
"subxt-lightclient",
"subxt-macro",
"subxt-metadata",
diff --git a/crates/cargo-contract/Cargo.toml b/crates/cargo-contract/Cargo.toml
index 85c6a967f..668936caa 100644
--- a/crates/cargo-contract/Cargo.toml
+++ b/crates/cargo-contract/Cargo.toml
@@ -43,11 +43,10 @@ comfy-table = "7.1.0"
# dependencies for extrinsics (deploying and calling a contract)
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
-subxt = "0.34.0"
+subxt = { version = "0.34.0", features = ["substrate-compat"] }
sp-core = "30.0.0"
sp-weights = "29.0.0"
hex = "0.4.3"
-subxt-signer = { version = "0.34.0", features = ["subxt", "sr25519"] }
[build-dependencies]
anyhow = "1.0.81"
diff --git a/crates/cargo-contract/src/cmd/call.rs b/crates/cargo-contract/src/cmd/call.rs
index fc1b94e1d..a0939bff3 100644
--- a/crates/cargo-contract/src/cmd/call.rs
+++ b/crates/cargo-contract/src/cmd/call.rs
@@ -14,20 +14,29 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
-use crate::ErrorVariant;
+use crate::{
+ call_with_config,
+ ErrorVariant,
+};
use contract_build::util::DEFAULT_KEY_COL_WIDTH;
-use ink_env::{
- DefaultEnvironment,
- Environment,
+use ink_env::Environment;
+use serde::Serialize;
+use std::{
+ fmt::{
+ Debug,
+ Display,
+ },
+ str::FromStr,
};
-use std::fmt::Debug;
use super::{
- create_signer,
+ config::SignerConfig,
display_contract_exec_result,
display_contract_exec_result_debug,
display_dry_run_result_warning,
+ parse_account,
+ parse_balance,
print_dry_running_status,
print_gas_required_success,
prompt_confirm_tx,
@@ -42,7 +51,6 @@ use anyhow::{
use contract_build::name_value_println;
use contract_extrinsics::{
pallet_contracts_primitives::StorageDeposit,
- BalanceVariant,
CallCommandBuilder,
CallExec,
DisplayEvents,
@@ -52,16 +60,20 @@ use contract_extrinsics::{
use contract_transcode::Value;
use sp_weights::Weight;
use subxt::{
+ config::ExtrinsicParams,
+ ext::{
+ scale_decode::IntoVisitor,
+ scale_encode::EncodeAsType,
+ },
Config,
- PolkadotConfig as DefaultConfig,
};
-use subxt_signer::sr25519::Keypair;
+
#[derive(Debug, clap::Args)]
#[clap(name = "call", about = "Call a contract")]
pub struct CallCommand {
/// The address of the the contract to call.
#[clap(name = "contract", long, env = "CONTRACT")]
- contract: ::AccountId,
+ contract: String,
/// The name of the contract message to call.
#[clap(long, short)]
message: String,
@@ -82,10 +94,13 @@ pub struct CallCommand {
proof_size: Option,
/// The value to be transferred as part of the call.
#[clap(name = "value", long, default_value = "0")]
- value: BalanceVariant<::Balance>,
+ value: String,
/// Export the call output in JSON format.
#[clap(long, conflicts_with = "verbose")]
output_json: bool,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
impl CallCommand {
@@ -95,31 +110,50 @@ impl CallCommand {
}
pub async fn handle(&self) -> Result<(), ErrorVariant> {
- let token_metadata =
- TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ call_with_config!(self, run, self.config.as_str())
+ }
- let signer = create_signer(&self.extrinsic_cli_opts.suri)?;
+ async fn run>(
+ &self,
+ ) -> Result<(), ErrorVariant>
+ where
+ ::AccountId: IntoVisitor + FromStr + EncodeAsType,
+ <::AccountId as FromStr>::Err: Display,
+ C::Balance: From + Display + Default + FromStr + Serialize + Debug,
+ >::OtherParams: Default,
+ {
+ let contract = parse_account(&self.contract)
+ .map_err(|e| anyhow::anyhow!("Failed to parse contract option: {}", e))?;
+ let signer = C::Signer::from_str(&self.extrinsic_cli_opts.suri)
+ .map_err(|_| anyhow::anyhow!("Failed to parse suri option"))?;
+ let token_metadata =
+ TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ let storage_deposit_limit = self
+ .extrinsic_cli_opts
+ .storage_deposit_limit
+ .clone()
+ .map(|b| parse_balance(&b, &token_metadata))
+ .transpose()
+ .map_err(|e| {
+ anyhow::anyhow!("Failed to parse storage_deposit_limit option: {}", e)
+ })?;
+ let value = parse_balance(&self.value, &token_metadata)
+ .map_err(|e| anyhow::anyhow!("Failed to parse value option: {}", e))?;
let extrinsic_opts = ExtrinsicOptsBuilder::new(signer)
.file(self.extrinsic_cli_opts.file.clone())
.manifest_path(self.extrinsic_cli_opts.manifest_path.clone())
.url(self.extrinsic_cli_opts.url.clone())
- .storage_deposit_limit(
- self.extrinsic_cli_opts
- .storage_deposit_limit
- .clone()
- .map(|bv| bv.denominate_balance(&token_metadata))
- .transpose()?,
- )
+ .storage_deposit_limit(storage_deposit_limit)
.verbosity(self.extrinsic_cli_opts.verbosity()?)
.done();
- let call_exec =
- CallCommandBuilder::new(self.contract.clone(), &self.message, extrinsic_opts)
- .args(self.args.clone())
- .gas_limit(self.gas_limit)
- .proof_size(self.proof_size)
- .value(self.value.denominate_balance(&token_metadata)?)
- .done()
- .await?;
+
+ let call_exec = CallCommandBuilder::new(contract, &self.message, extrinsic_opts)
+ .args(self.args.clone())
+ .gas_limit(self.gas_limit)
+ .proof_size(self.proof_size)
+ .value(value)
+ .done()
+ .await?;
let metadata = call_exec.client().metadata();
if !self.extrinsic_cli_opts.execute {
@@ -147,7 +181,7 @@ impl CallCommand {
println!("{}", dry_run_result.to_json()?);
} else {
dry_run_result.print();
- display_contract_exec_result_debug::<_, DEFAULT_KEY_COL_WIDTH>(
+ display_contract_exec_result_debug::<_, DEFAULT_KEY_COL_WIDTH, _>(
&result,
)?;
display_dry_run_result_warning("message");
@@ -159,7 +193,7 @@ impl CallCommand {
return Err(object)
} else {
name_value_println!("Result", object, MAX_KEY_COL_WIDTH);
- display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(&result)?;
+ display_contract_exec_result::<_, MAX_KEY_COL_WIDTH, _>(&result)?;
}
}
}
@@ -190,15 +224,13 @@ impl CallCommand {
})?;
}
let events = call_exec.call(Some(gas_limit)).await?;
- let display_events = DisplayEvents::from_events::<
- DefaultConfig,
- DefaultEnvironment,
- >(&events, None, &metadata)?;
+ let display_events =
+ DisplayEvents::from_events::(&events, None, &metadata)?;
let output = if self.output_json() {
display_events.to_json()?
} else {
- display_events.display_events::(
+ display_events.display_events::(
self.extrinsic_cli_opts.verbosity().unwrap(),
&token_metadata,
)?
@@ -210,11 +242,17 @@ impl CallCommand {
}
/// A helper function to estimate the gas required for a contract call.
-async fn pre_submit_dry_run_gas_estimate_call(
- call_exec: &CallExec,
+async fn pre_submit_dry_run_gas_estimate_call(
+ call_exec: &CallExec,
output_json: bool,
skip_dry_run: bool,
-) -> Result {
+) -> Result
+where
+ Signer: subxt::tx::Signer + Clone,
+ ::AccountId: IntoVisitor + EncodeAsType,
+ C::Balance: Debug,
+ >::OtherParams: Default,
+{
if skip_dry_run {
return match (call_exec.gas_limit(), call_exec.proof_size()) {
(Some(ref_time), Some(proof_size)) => Ok(Weight::from_parts(ref_time, proof_size)),
@@ -250,7 +288,7 @@ async fn pre_submit_dry_run_gas_estimate_call(
Err(anyhow!("{}", serde_json::to_string_pretty(&object)?))
} else {
name_value_println!("Result", object, MAX_KEY_COL_WIDTH);
- display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(&call_result)?;
+ display_contract_exec_result::<_, MAX_KEY_COL_WIDTH, _>(&call_result)?;
Err(anyhow!("Pre-submission dry-run failed. Use --skip-dry-run to skip this step."))
}
@@ -260,17 +298,17 @@ async fn pre_submit_dry_run_gas_estimate_call(
/// Result of the contract call
#[derive(serde::Serialize)]
-pub struct CallDryRunResult {
+pub struct CallDryRunResult {
/// Was the operation reverted
pub reverted: bool,
pub data: Value,
pub gas_consumed: Weight,
pub gas_required: Weight,
/// Storage deposit after the operation
- pub storage_deposit: StorageDeposit<::Balance>,
+ pub storage_deposit: StorageDeposit,
}
-impl CallDryRunResult {
+impl CallDryRunResult {
/// Returns a result in json format
pub fn to_json(&self) -> Result {
Ok(serde_json::to_string_pretty(self)?)
diff --git a/crates/cargo-contract/src/cmd/config.rs b/crates/cargo-contract/src/cmd/config.rs
new file mode 100644
index 000000000..57e02a97f
--- /dev/null
+++ b/crates/cargo-contract/src/cmd/config.rs
@@ -0,0 +1,250 @@
+// Copyright (C) Parity Technologies (UK) Ltd.
+// This file is part of cargo-contract.
+//
+// cargo-contract 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.
+//
+// cargo-contract 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 cargo-contract. If not, see .
+
+use ink_env::{
+ DefaultEnvironment,
+ Environment,
+};
+use std::{
+ fmt::Debug,
+ str::FromStr,
+};
+use subxt::{
+ config::{
+ PolkadotExtrinsicParams,
+ SubstrateExtrinsicParams,
+ },
+ ext::{
+ sp_core,
+ sp_core::Pair,
+ },
+ tx::{
+ PairSigner,
+ Signer as SignerT,
+ },
+ Config,
+ PolkadotConfig,
+ SubstrateConfig,
+};
+
+/// Configuration for signer
+pub trait SignerConfig {
+ type Signer: SignerT + FromStr + Clone;
+}
+
+/// A runtime configuration for the ecdsa test chain.
+/// This thing is not meant to be instantiated; it is just a collection of types.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Ecdsachain {}
+
+impl Config for Ecdsachain {
+ type Hash = ::Hash;
+ type AccountId = ::AccountId;
+ type Address = ::Address;
+ type Signature = ::Signature;
+ type Hasher = ::Hasher;
+ type Header = ::Header;
+ type ExtrinsicParams = SubstrateExtrinsicParams;
+ type AssetId = ::AssetId;
+}
+
+impl Environment for Ecdsachain {
+ const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS;
+ type AccountId = ::AccountId;
+ type Balance = ::Balance;
+ type Hash = ::Hash;
+ type Timestamp = ::Timestamp;
+ type BlockNumber = ::BlockNumber;
+ type ChainExtension = ::ChainExtension;
+}
+
+impl SignerConfig for Ecdsachain
+where
+ ::Signature: From,
+{
+ type Signer = SignerEcdsa;
+}
+
+/// A runtime configuration for the Substrate based chain.
+/// This thing is not meant to be instantiated; it is just a collection of types.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Substrate {}
+
+impl Config for Substrate {
+ type Hash = ::Hash;
+ type AccountId = ::AccountId;
+ type Address = ::Address;
+ type Signature = ::Signature;
+ type Hasher = ::Hasher;
+ type Header = ::Header;
+ type ExtrinsicParams = SubstrateExtrinsicParams;
+ type AssetId = ::AssetId;
+}
+
+impl Environment for Substrate {
+ const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS;
+ type AccountId = ::AccountId;
+ type Balance = ::Balance;
+ type Hash = ::Hash;
+ type Timestamp = ::Timestamp;
+ type BlockNumber = ::BlockNumber;
+ type ChainExtension = ::ChainExtension;
+}
+
+impl SignerConfig for Substrate {
+ type Signer = SignerSR25519;
+}
+
+/// A runtime configuration for the Polkadot based chain.
+/// This thing is not meant to be instantiated; it is just a collection of types.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Polkadot {}
+
+impl Config for Polkadot {
+ type Hash = ::Hash;
+ type AccountId = ::AccountId;
+ type Address = ::Address;
+ type Signature = ::Signature;
+ type Hasher = ::Hasher;
+ type Header = ::Header;
+ type ExtrinsicParams = PolkadotExtrinsicParams;
+ type AssetId = ::AssetId;
+}
+
+impl Environment for Polkadot {
+ const MAX_EVENT_TOPICS: usize = ::MAX_EVENT_TOPICS;
+ type AccountId = ::AccountId;
+ type Balance = ::Balance;
+ type Hash = ::Hash;
+ type Timestamp = ::Timestamp;
+ type BlockNumber = ::BlockNumber;
+ type ChainExtension = ::ChainExtension;
+}
+
+impl SignerConfig for Polkadot {
+ type Signer = SignerSR25519;
+}
+
+/// Struct representing the implementation of the sr25519 signer
+#[derive(Clone)]
+pub struct SignerSR25519(pub PairSigner);
+
+impl FromStr for SignerSR25519
+where
+ ::AccountId: From,
+{
+ type Err = anyhow::Error;
+
+ /// Attempts to parse the Signer suri string
+ fn from_str(input: &str) -> Result, Self::Err> {
+ let keypair = sp_core::sr25519::Pair::from_string(input, None)?;
+ let signer = PairSigner::::new(keypair);
+ Ok(Self(signer))
+ }
+}
+
+impl SignerT for SignerSR25519
+where
+ ::Signature: From,
+{
+ fn account_id(&self) -> ::AccountId {
+ self.0.account_id().clone()
+ }
+
+ fn address(&self) -> C::Address {
+ self.0.address()
+ }
+
+ fn sign(&self, signer_payload: &[u8]) -> C::Signature {
+ self.0.sign(signer_payload)
+ }
+}
+
+/// Struct representing the implementation of the ecdsa signer
+#[derive(Clone)]
+pub struct SignerEcdsa(pub PairSigner);
+
+impl FromStr for SignerEcdsa
+where
+ // Requirements of the `PairSigner where:
+ // T::AccountId: From`
+ ::AccountId: From,
+{
+ type Err = anyhow::Error;
+
+ /// Attempts to parse the Signer suri string
+ fn from_str(input: &str) -> Result, Self::Err> {
+ let keypair = sp_core::ecdsa::Pair::from_string(input, None)?;
+ let signer = PairSigner::::new(keypair);
+ Ok(Self(signer))
+ }
+}
+
+impl SignerT for SignerEcdsa
+where
+ ::Signature: From,
+{
+ fn account_id(&self) -> ::AccountId {
+ self.0.account_id().clone()
+ }
+
+ fn address(&self) -> C::Address {
+ self.0.address()
+ }
+
+ fn sign(&self, signer_payload: &[u8]) -> C::Signature {
+ self.0.sign(signer_payload)
+ }
+}
+
+#[macro_export]
+macro_rules! call_with_config_internal {
+ ($obj:tt ,$function:tt, $config_name:expr, $($config:ty),*) => {
+ match $config_name {
+ $(
+ stringify!($config) => $obj.$function::<$config>().await,
+ )*
+ _ => {
+
+ let configs = vec![$(stringify!($config)),*].iter()
+ .map(|s| s.trim_start_matches("crate::cmd::config::"))
+ .collect::>()
+ .join(", ");
+ Err(ErrorVariant::Generic(
+ contract_extrinsics::GenericError::from_message(
+ format!("Chain configuration not found, Allowed configurations: {configs}")
+ )))
+ },
+ }
+ };
+}
+
+/// Macro that allows calling the command member function with chain configuration
+#[macro_export]
+macro_rules! call_with_config {
+ ($obj:tt, $function:ident, $config_name:expr) => {{
+ let config_name = format!("crate::cmd::config::{}", $config_name);
+ $crate::call_with_config_internal!(
+ $obj,
+ $function,
+ config_name.as_str(),
+ // All available chain configs need to be specified here
+ $crate::cmd::config::Polkadot,
+ $crate::cmd::config::Substrate,
+ $crate::cmd::config::Ecdsachain
+ )
+ }};
+}
diff --git a/crates/cargo-contract/src/cmd/info.rs b/crates/cargo-contract/src/cmd/info.rs
index e9e19f49b..73a9573ec 100644
--- a/crates/cargo-contract/src/cmd/info.rs
+++ b/crates/cargo-contract/src/cmd/info.rs
@@ -14,10 +14,12 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
+use crate::call_with_config;
+
use super::{
basic_display_format_extended_contract_info,
display_all_contracts,
- DefaultConfig,
+ parse_account,
};
use anyhow::Result;
use contract_analyze::determine_language;
@@ -30,19 +32,25 @@ use contract_extrinsics::{
ErrorVariant,
TrieId,
};
-use ink_env::{
- DefaultEnvironment,
- Environment,
-};
+use ink_env::Environment;
+use serde::Serialize;
use std::{
- fmt::Debug,
+ fmt::{
+ Debug,
+ Display,
+ },
io::Write,
+ str::FromStr,
};
use subxt::{
backend::{
legacy::LegacyRpcMethods,
rpc::RpcClient,
},
+ ext::{
+ codec::Decode,
+ scale_decode::IntoVisitor,
+ },
Config,
OnlineClient,
};
@@ -57,7 +65,7 @@ pub struct InfoCommand {
env = "CONTRACT",
required_unless_present = "all"
)]
- contract: Option<::AccountId>,
+ contract: Option,
/// Websockets url of a substrate node.
#[clap(
name = "url",
@@ -75,14 +83,28 @@ pub struct InfoCommand {
/// Display all contracts addresses
#[clap(name = "all", long)]
all: bool,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
impl InfoCommand {
- pub async fn run(&self) -> Result<(), ErrorVariant> {
+ pub async fn handle(&self) -> Result<(), ErrorVariant> {
+ call_with_config!(self, run, self.config.as_str())
+ }
+
+ pub async fn run(&self) -> Result<(), ErrorVariant>
+ where
+ ::AccountId:
+ Serialize + Display + IntoVisitor + Decode + AsRef<[u8]> + FromStr,
+ ::Hash: IntoVisitor + Display,
+ ::Balance: Serialize + Debug + IntoVisitor,
+ <::AccountId as FromStr>::Err:
+ Into> + Display,
+ {
let rpc_cli = RpcClient::from_url(url_to_string(&self.url)).await?;
- let client =
- OnlineClient::::from_rpc_client(rpc_cli.clone()).await?;
- let rpc = LegacyRpcMethods::::new(rpc_cli.clone());
+ let client = OnlineClient::::from_rpc_client(rpc_cli.clone()).await?;
+ let rpc = LegacyRpcMethods::::new(rpc_cli.clone());
// All flag applied
if self.all {
@@ -103,12 +125,12 @@ impl InfoCommand {
let contract = self
.contract
.as_ref()
- .expect("Contract argument was not provided");
+ .map(|c| parse_account(c))
+ .transpose()?
+ .expect("Contract argument shall be present");
- let info_to_json = fetch_contract_info::(
- contract, &rpc, &client,
- )
- .await?;
+ let info_to_json =
+ fetch_contract_info::(&contract, &rpc, &client).await?;
let wasm_code =
fetch_wasm_code(&client, &rpc, info_to_json.code_hash()).await?;
@@ -128,16 +150,16 @@ impl InfoCommand {
println!(
"{}",
serde_json::to_string_pretty(&ExtendedContractInfo::<
- ::Hash,
- ::Balance,
+ ::Hash,
+ C::Balance,
>::new(
info_to_json, &wasm_code
))?
)
} else {
basic_display_format_extended_contract_info(&ExtendedContractInfo::<
- ::Hash,
- ::Balance,
+ ::Hash,
+ C::Balance,
>::new(
info_to_json, &wasm_code
))
diff --git a/crates/cargo-contract/src/cmd/instantiate.rs b/crates/cargo-contract/src/cmd/instantiate.rs
index 58de3da4b..0f4d7c96b 100644
--- a/crates/cargo-contract/src/cmd/instantiate.rs
+++ b/crates/cargo-contract/src/cmd/instantiate.rs
@@ -15,10 +15,11 @@
// along with cargo-contract. If not, see .
use super::{
- create_signer,
+ config::SignerConfig,
display_contract_exec_result,
display_contract_exec_result_debug,
display_dry_run_result_warning,
+ parse_balance,
print_dry_running_status,
print_gas_required_success,
prompt_confirm_tx,
@@ -27,6 +28,7 @@ use super::{
};
use crate::{
anyhow,
+ call_with_config,
ErrorVariant,
InstantiateExec,
Weight,
@@ -41,7 +43,6 @@ use contract_build::{
Verbosity,
};
use contract_extrinsics::{
- BalanceVariant,
Code,
DisplayEvents,
ExtrinsicOptsBuilder,
@@ -50,14 +51,25 @@ use contract_extrinsics::{
InstantiateExecResult,
TokenMetadata,
};
-use ink_env::{
- DefaultEnvironment,
- Environment,
-};
+use ink_env::Environment;
+use serde::Serialize;
use sp_core::Bytes;
-use std::fmt::Debug;
-use subxt::PolkadotConfig as DefaultConfig;
-use subxt_signer::sr25519::Keypair;
+use std::{
+ fmt::{
+ Debug,
+ Display,
+ },
+ str::FromStr,
+};
+use subxt::{
+ config::ExtrinsicParams,
+ ext::{
+ codec::Decode,
+ scale_decode::IntoVisitor,
+ scale_encode::EncodeAsType,
+ },
+ Config,
+};
#[derive(Debug, clap::Args)]
pub struct InstantiateCommand {
@@ -71,7 +83,7 @@ pub struct InstantiateCommand {
extrinsic_cli_opts: CLIExtrinsicOpts,
/// Transfers an initial balance to the instantiated contract
#[clap(name = "value", long, default_value = "0")]
- value: BalanceVariant<::Balance>,
+ value: String,
/// Maximum amount of gas to be used for this command.
/// If not specified will perform a dry-run to estimate the gas consumed for the
/// instantiation.
@@ -88,6 +100,9 @@ pub struct InstantiateCommand {
/// Export the instantiate output in JSON format.
#[clap(long, conflicts_with = "verbose")]
output_json: bool,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
/// Parse hex encoded bytes.
@@ -103,35 +118,52 @@ impl InstantiateCommand {
}
pub async fn handle(&self) -> Result<(), ErrorVariant> {
- let token_metadata =
- TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ call_with_config!(self, run, self.config.as_str())
+ }
- let signer = create_signer(&self.extrinsic_cli_opts.suri)?;
+ async fn run>(
+ &self,
+ ) -> Result<(), ErrorVariant>
+ where
+ >::Signer: subxt::tx::Signer + Clone + FromStr,
+ ::AccountId: IntoVisitor + FromStr + EncodeAsType + Decode + Display,
+ <::AccountId as FromStr>::Err: Display,
+ C::Balance: From + Display + Default + FromStr + Serialize + Debug,
+ >::OtherParams: Default,
+ ::Hash: From<[u8; 32]> + IntoVisitor + EncodeAsType,
+ {
+ let signer = C::Signer::from_str(&self.extrinsic_cli_opts.suri)
+ .map_err(|_| anyhow::anyhow!("Failed to parse suri option"))?;
+ let token_metadata =
+ TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ let storage_deposit_limit = self
+ .extrinsic_cli_opts
+ .storage_deposit_limit
+ .clone()
+ .map(|b| parse_balance(&b, &token_metadata))
+ .transpose()
+ .map_err(|e| {
+ anyhow::anyhow!("Failed to parse storage_deposit_limit option: {}", e)
+ })?;
+ let value = parse_balance(&self.value, &token_metadata)
+ .map_err(|e| anyhow::anyhow!("Failed to parse value option: {}", e))?;
let extrinsic_opts = ExtrinsicOptsBuilder::new(signer)
.file(self.extrinsic_cli_opts.file.clone())
.manifest_path(self.extrinsic_cli_opts.manifest_path.clone())
.url(self.extrinsic_cli_opts.url.clone())
- .storage_deposit_limit(
- self.extrinsic_cli_opts
- .storage_deposit_limit
- .clone()
- .map(|bv| bv.denominate_balance(&token_metadata))
- .transpose()?,
- )
+ .storage_deposit_limit(storage_deposit_limit)
.done();
- let instantiate_exec: InstantiateExec<
- DefaultConfig,
- DefaultEnvironment,
- Keypair,
- > = InstantiateCommandBuilder::new(extrinsic_opts)
- .constructor(self.constructor.clone())
- .args(self.args.clone())
- .value(self.value.denominate_balance(&token_metadata)?)
- .gas_limit(self.gas_limit)
- .proof_size(self.proof_size)
- .salt(self.salt.clone())
- .done()
- .await?;
+
+ let instantiate_exec: InstantiateExec =
+ InstantiateCommandBuilder::new(extrinsic_opts)
+ .constructor(self.constructor.clone())
+ .args(self.args.clone())
+ .value(value)
+ .gas_limit(self.gas_limit)
+ .proof_size(self.proof_size)
+ .salt(self.salt.clone())
+ .done()
+ .await?;
if !self.extrinsic_cli_opts.execute {
let result = instantiate_exec.instantiate_dry_run().await?;
@@ -141,7 +173,7 @@ impl InstantiateCommand {
println!("{}", dry_run_result.to_json()?);
} else {
print_instantiate_dry_run_result(&dry_run_result);
- display_contract_exec_result_debug::<_, DEFAULT_KEY_COL_WIDTH>(
+ display_contract_exec_result_debug::<_, DEFAULT_KEY_COL_WIDTH, _>(
&result,
)?;
display_dry_run_result_warning("instantiate");
@@ -153,7 +185,7 @@ impl InstantiateCommand {
return Err(object)
} else {
name_value_println!("Result", object, MAX_KEY_COL_WIDTH);
- display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(&result)?;
+ display_contract_exec_result::<_, MAX_KEY_COL_WIDTH, _>(&result)?;
}
Err(object)
}
@@ -196,11 +228,20 @@ impl InstantiateCommand {
}
/// A helper function to estimate the gas required for a contract instantiation.
-async fn pre_submit_dry_run_gas_estimate_instantiate(
- instantiate_exec: &InstantiateExec,
+async fn pre_submit_dry_run_gas_estimate_instantiate<
+ C: Config + Environment + SignerConfig,
+>(
+ instantiate_exec: &InstantiateExec,
output_json: bool,
skip_dry_run: bool,
-) -> Result {
+) -> Result
+where
+ C::Signer: subxt::tx::Signer + Clone,
+ ::AccountId: IntoVisitor + Display + Decode,
+ ::Hash: IntoVisitor + EncodeAsType,
+ C::Balance: Serialize + Debug,
+ >::OtherParams: Default,
+{
if skip_dry_run {
return match (instantiate_exec.args().gas_limit(), instantiate_exec.args().proof_size()) {
(Some(ref_time), Some(proof_size)) => Ok(Weight::from_parts(ref_time, proof_size)),
@@ -240,7 +281,7 @@ async fn pre_submit_dry_run_gas_estimate_instantiate(
Err(anyhow!("{}", serde_json::to_string_pretty(&object)?))
} else {
name_value_println!("Result", object, MAX_KEY_COL_WIDTH);
- display_contract_exec_result::<_, MAX_KEY_COL_WIDTH>(
+ display_contract_exec_result::<_, MAX_KEY_COL_WIDTH, _>(
&instantiate_result,
)?;
@@ -252,14 +293,20 @@ async fn pre_submit_dry_run_gas_estimate_instantiate(
/// Displays the results of contract instantiation, including contract address,
/// events, and optional code hash.
-pub async fn display_result(
- instantiate_exec: &InstantiateExec,
- instantiate_exec_result: InstantiateExecResult,
+pub async fn display_result>(
+ instantiate_exec: &InstantiateExec,
+ instantiate_exec_result: InstantiateExecResult,
token_metadata: &TokenMetadata,
output_json: bool,
verbosity: Verbosity,
-) -> Result<(), ErrorVariant> {
- let events = DisplayEvents::from_events::(
+) -> Result<(), ErrorVariant>
+where
+ ::AccountId: IntoVisitor + EncodeAsType + Display + Decode,
+ ::Hash: IntoVisitor + EncodeAsType,
+ C::Balance: Serialize + From + Display,
+ >::OtherParams: Default,
+{
+ let events = DisplayEvents::from_events::(
&instantiate_exec_result.events,
Some(instantiate_exec.transcoder()),
&instantiate_exec.client().metadata(),
@@ -275,10 +322,7 @@ pub async fn display_result(
};
println!("{}", display_instantiate_result.to_json()?)
} else {
- println!(
- "{}",
- events.display_events::(verbosity, token_metadata)?
- );
+ println!("{}", events.display_events::(verbosity, token_metadata)?);
if let Some(code_hash) = instantiate_exec_result.code_hash {
name_value_println!("Code hash", format!("{code_hash:?}"));
}
@@ -287,10 +331,16 @@ pub async fn display_result(
Ok(())
}
-pub fn print_default_instantiate_preview(
- instantiate_exec: &InstantiateExec,
+pub fn print_default_instantiate_preview>(
+ instantiate_exec: &InstantiateExec,
gas_limit: Weight,
-) {
+) where
+ C::Signer: subxt::tx::Signer + Clone,
+ ::AccountId: IntoVisitor + EncodeAsType + Display + Decode,
+ ::Hash: IntoVisitor + EncodeAsType,
+ C::Balance: Serialize,
+ >::OtherParams: Default,
+{
name_value_println!(
"Constructor",
instantiate_exec.args().constructor(),
@@ -323,8 +373,8 @@ impl InstantiateResult {
}
}
-pub fn print_instantiate_dry_run_result(
- result: &InstantiateDryRunResult<::Balance>,
+pub fn print_instantiate_dry_run_result(
+ result: &InstantiateDryRunResult,
) {
name_value_println!(
"Result",
diff --git a/crates/cargo-contract/src/cmd/mod.rs b/crates/cargo-contract/src/cmd/mod.rs
index f0fb9f125..b38c6a6e4 100644
--- a/crates/cargo-contract/src/cmd/mod.rs
+++ b/crates/cargo-contract/src/cmd/mod.rs
@@ -14,6 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
+mod config;
+
pub mod build;
pub mod call;
pub mod decode;
@@ -70,23 +72,19 @@ pub(crate) use contract_extrinsics::ErrorVariant;
use contract_extrinsics::{
pallet_contracts_primitives::ContractResult,
BalanceVariant,
+ TokenMetadata,
};
-use core::fmt;
-use ink_env::{
- DefaultEnvironment,
- Environment,
-};
-use std::io::{
- self,
- Write,
-};
-pub use subxt::{
- Config,
- PolkadotConfig as DefaultConfig,
-};
-use subxt_signer::{
- sr25519::Keypair,
- SecretUri,
+
+use std::{
+ fmt::{
+ Debug,
+ Display,
+ },
+ io::{
+ self,
+ Write,
+ },
+ str::FromStr,
};
/// Arguments required for creating and sending an extrinsic to a substrate node.
@@ -122,8 +120,7 @@ pub struct CLIExtrinsicOpts {
/// The maximum amount of balance that can be charged from the caller to pay for the
/// storage. consumed.
#[clap(long)]
- storage_deposit_limit:
- Option::Balance>>,
+ storage_deposit_limit: Option,
/// Before submitting a transaction, do not dry-run it via RPC first.
#[clap(long)]
skip_dry_run: bool,
@@ -143,9 +140,12 @@ const STORAGE_DEPOSIT_KEY: &str = "Storage Total Deposit";
pub const MAX_KEY_COL_WIDTH: usize = STORAGE_DEPOSIT_KEY.len() + 1;
/// Print to stdout the fields of the result of a `instantiate` or `call` dry-run via RPC.
-pub fn display_contract_exec_result(
- result: &ContractResult::Balance, ()>,
-) -> Result<()> {
+pub fn display_contract_exec_result(
+ result: &ContractResult,
+) -> Result<()>
+where
+ Balance: Debug,
+{
let mut debug_message_lines = std::str::from_utf8(&result.debug_message)
.context("Error decoding UTF8 debug message bytes")?
.lines();
@@ -168,8 +168,8 @@ pub fn display_contract_exec_result(
Ok(())
}
-pub fn display_contract_exec_result_debug(
- result: &ContractResult::Balance, ()>,
+pub fn display_contract_exec_result_debug(
+ result: &ContractResult,
) -> Result<()> {
let mut debug_message_lines = std::str::from_utf8(&result.debug_message)
.context("Error decoding UTF8 debug message bytes")?
@@ -235,10 +235,11 @@ pub fn print_gas_required_success(gas: Weight) {
}
/// Display contract information in a formatted way
-pub fn basic_display_format_extended_contract_info(
- info: &ExtendedContractInfo::Balance>,
+pub fn basic_display_format_extended_contract_info(
+ info: &ExtendedContractInfo,
) where
- Hash: fmt::Debug,
+ Hash: Debug,
+ Balance: Debug,
{
name_value_println!("TrieId", info.trie_id, MAX_KEY_COL_WIDTH);
name_value_println!(
@@ -269,21 +270,37 @@ pub fn basic_display_format_extended_contract_info(
}
/// Display all contracts addresses in a formatted way
-pub fn display_all_contracts(contracts: &[::AccountId]) {
- contracts
- .iter()
- .for_each(|e: &::AccountId| println!("{}", e))
+pub fn display_all_contracts(contracts: &[AccountId])
+where
+ AccountId: Display,
+{
+ contracts.iter().for_each(|e: &AccountId| println!("{}", e))
}
-/// Create a Signer from a secret URI.
-pub fn create_signer(suri: &str) -> Result {
- let uri = ::from_str(suri)?;
- let keypair = Keypair::from_uri(&uri)?;
- Ok(keypair)
+/// Parse a balance from string format
+pub fn parse_balance + Clone>(
+ balance: &str,
+ token_metadata: &TokenMetadata,
+) -> Result {
+ BalanceVariant::from_str(balance)
+ .map_err(|e| anyhow!("Balance parsing failed: {e}"))
+ .and_then(|bv| bv.denominate_balance(token_metadata))
+}
+
+/// Parse a account from string format
+pub fn parse_account(account: &str) -> Result
+where
+ ::Err: Display,
+{
+ AccountId::from_str(account)
+ .map_err(|e| anyhow::anyhow!("Account address parsing failed: {e}"))
}
/// Parse a hex encoded 32 byte hash. Returns error if not exactly 32 bytes.
-pub fn parse_code_hash(input: &str) -> Result<::Hash> {
+pub fn parse_code_hash(input: &str) -> Result
+where
+ Hash: From<[u8; 32]>,
+{
let bytes = contract_build::util::decode_hex(input)?;
if bytes.len() != 32 {
anyhow::bail!("Code hash should be 32 bytes in length")
@@ -295,17 +312,22 @@ pub fn parse_code_hash(input: &str) -> Result<::Hash> {
#[cfg(test)]
mod tests {
+ use subxt::{
+ Config,
+ SubstrateConfig,
+ };
+
use super::*;
#[test]
fn parse_code_hash_works() {
// with 0x prefix
- assert!(parse_code_hash(
+ assert!(parse_code_hash::<::Hash>(
"0xd43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
)
.is_ok());
// without 0x prefix
- assert!(parse_code_hash(
+ assert!(parse_code_hash::<::Hash>(
"d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
)
.is_ok())
@@ -314,7 +336,7 @@ mod tests {
#[test]
fn parse_incorrect_len_code_hash_fails() {
// with len not equal to 32
- assert!(parse_code_hash(
+ assert!(parse_code_hash::<::Hash>(
"d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da2"
)
.is_err())
@@ -323,7 +345,7 @@ mod tests {
#[test]
fn parse_bad_format_code_hash_fails() {
// with bad format
- assert!(parse_code_hash(
+ assert!(parse_code_hash::<::Hash>(
"x43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d"
)
.is_err())
diff --git a/crates/cargo-contract/src/cmd/remove.rs b/crates/cargo-contract/src/cmd/remove.rs
index ad7c7e8d1..ef619b124 100644
--- a/crates/cargo-contract/src/cmd/remove.rs
+++ b/crates/cargo-contract/src/cmd/remove.rs
@@ -14,11 +14,21 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
-use crate::ErrorVariant;
-use std::fmt::Debug;
+use crate::{
+ call_with_config,
+ ErrorVariant,
+};
+use std::{
+ fmt::{
+ Debug,
+ Display,
+ },
+ str::FromStr,
+};
use super::{
- create_signer,
+ config::SignerConfig,
+ parse_balance,
parse_code_hash,
CLIExtrinsicOpts,
};
@@ -31,24 +41,31 @@ use contract_extrinsics::{
RemoveExec,
TokenMetadata,
};
-use ink_env::DefaultEnvironment;
+use ink_env::Environment;
+use serde::Serialize;
use subxt::{
+ config::ExtrinsicParams,
+ ext::{
+ scale_decode::IntoVisitor,
+ scale_encode::EncodeAsType,
+ },
Config,
- PolkadotConfig as DefaultConfig,
};
-use subxt_signer::sr25519::Keypair;
#[derive(Debug, clap::Args)]
#[clap(name = "remove", about = "Remove a contract's code")]
pub struct RemoveCommand {
/// The hash of the smart contract code already uploaded to the chain.
- #[clap(long, value_parser = parse_code_hash)]
- code_hash: Option<::Hash>,
+ #[clap(long)]
+ code_hash: Option,
#[clap(flatten)]
extrinsic_cli_opts: CLIExtrinsicOpts,
/// Export the call output as JSON.
#[clap(long, conflicts_with = "verbose")]
output_json: bool,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
impl RemoveCommand {
@@ -58,44 +75,67 @@ impl RemoveCommand {
}
pub async fn handle(&self) -> Result<(), ErrorVariant> {
- let token_metadata =
- TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ call_with_config!(self, run, self.config.as_str())
+ }
- let signer: Keypair = create_signer(&self.extrinsic_cli_opts.suri)?;
+ async fn run>(
+ &self,
+ ) -> Result<(), ErrorVariant>
+ where
+ ::AccountId: IntoVisitor + FromStr + EncodeAsType,
+ <::AccountId as FromStr>::Err: Display,
+ C::Balance:
+ Into + From + Display + Default + FromStr + Serialize + Debug,
+ >::OtherParams: Default,
+ ::Hash: IntoVisitor + EncodeAsType + From<[u8; 32]>,
+ {
+ let signer = C::Signer::from_str(&self.extrinsic_cli_opts.suri)
+ .map_err(|_| anyhow::anyhow!("Failed to parse suri option"))?;
+ let token_metadata =
+ TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ let storage_deposit_limit = self
+ .extrinsic_cli_opts
+ .storage_deposit_limit
+ .clone()
+ .map(|b| parse_balance(&b, &token_metadata))
+ .transpose()
+ .map_err(|e| {
+ anyhow::anyhow!("Failed to parse storage_deposit_limit option: {}", e)
+ })?;
+ let code_hash = self
+ .code_hash
+ .clone()
+ .map(|h| parse_code_hash(&h))
+ .transpose()
+ .map_err(|e| anyhow::anyhow!("Failed to parse code_hash option: {}", e))?;
let extrinsic_opts = ExtrinsicOptsBuilder::new(signer)
.file(self.extrinsic_cli_opts.file.clone())
.manifest_path(self.extrinsic_cli_opts.manifest_path.clone())
.url(self.extrinsic_cli_opts.url.clone())
- .storage_deposit_limit(
- self.extrinsic_cli_opts
- .storage_deposit_limit
- .clone()
- .map(|bv| bv.denominate_balance(&token_metadata))
- .transpose()?,
- )
+ .storage_deposit_limit(storage_deposit_limit)
.done();
- let remove_exec: RemoveExec =
- RemoveCommandBuilder::new(extrinsic_opts)
- .code_hash(self.code_hash)
- .done()
- .await?;
+
+ let remove_exec: RemoveExec = RemoveCommandBuilder::new(extrinsic_opts)
+ .code_hash(code_hash)
+ .done()
+ .await?;
let remove_result = remove_exec.remove_code().await?;
- let display_events =
- DisplayEvents::from_events::(
- &remove_result.events,
- Some(remove_exec.transcoder()),
- &remove_exec.client().metadata(),
- )?;
+ let display_events = DisplayEvents::from_events::(
+ &remove_result.events,
+ Some(remove_exec.transcoder()),
+ &remove_exec.client().metadata(),
+ )?;
+
let output_events = if self.output_json() {
display_events.to_json()?
} else {
- display_events.display_events::(
+ display_events.display_events::(
self.extrinsic_cli_opts.verbosity().unwrap(),
&token_metadata,
)?
};
if let Some(code_removed) = remove_result.code_removed {
- let remove_result: ::Hash = code_removed.code_hash;
+ let remove_result: ::Hash = code_removed.code_hash;
if self.output_json() {
// Create a JSON object with the events and the removed code hash.
diff --git a/crates/cargo-contract/src/cmd/storage.rs b/crates/cargo-contract/src/cmd/storage.rs
index 73d198f7a..73806a87f 100644
--- a/crates/cargo-contract/src/cmd/storage.rs
+++ b/crates/cargo-contract/src/cmd/storage.rs
@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
-use super::DefaultConfig;
use anyhow::Result;
use colored::Colorize;
use comfy_table::{
@@ -28,16 +27,28 @@ use contract_extrinsics::{
ContractStorageRpc,
ErrorVariant,
};
-use ink_env::DefaultEnvironment;
-use std::path::PathBuf;
-use subxt::Config;
+use ink_env::Environment;
+use serde::Serialize;
+use std::{
+ fmt::Display,
+ path::PathBuf,
+ str::FromStr,
+};
+use subxt::{
+ ext::scale_decode::IntoVisitor,
+ Config,
+};
+
+use crate::call_with_config;
+
+use super::parse_account;
#[derive(Debug, clap::Args)]
#[clap(name = "storage", about = "Inspect contract storage")]
pub struct StorageCommand {
/// The address of the contract to inspect storage of.
#[clap(name = "contract", long, env = "CONTRACT")]
- contract: ::AccountId,
+ contract: String,
/// Fetch the "raw" storage keys and values for the contract.
#[clap(long)]
raw: bool,
@@ -59,18 +70,32 @@ pub struct StorageCommand {
default_value = "ws://localhost:9944"
)]
url: url::Url,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
impl StorageCommand {
- pub async fn run(&self) -> Result<(), ErrorVariant> {
- let rpc = ContractStorageRpc::::new(&self.url).await?;
- let storage_layout =
- ContractStorage::::new(rpc);
+ pub async fn handle(&self) -> Result<(), ErrorVariant> {
+ call_with_config!(self, run, self.config.as_str())
+ }
+
+ pub async fn run(&self) -> Result<(), ErrorVariant>
+ where
+ ::AccountId: Display + IntoVisitor + AsRef<[u8]> + FromStr,
+ <::AccountId as FromStr>::Err:
+ Into> + Display,
+ C::Balance: Serialize + IntoVisitor,
+ ::Hash: IntoVisitor,
+ {
+ let rpc = ContractStorageRpc::::new(&self.url).await?;
+ let storage_layout = ContractStorage::::new(rpc);
+ let contract = parse_account(&self.contract)
+ .map_err(|e| anyhow::anyhow!("Failed to parse contract option: {}", e))?;
if self.raw {
- let storage_data = storage_layout
- .load_contract_storage_data(&self.contract)
- .await?;
+ let storage_data =
+ storage_layout.load_contract_storage_data(&contract).await?;
println!(
"{json}",
json = serde_json::to_string_pretty(&storage_data)?
@@ -87,7 +112,7 @@ impl StorageCommand {
Ok(contract_artifacts) => {
let transcoder = contract_artifacts.contract_transcoder()?;
let contract_storage = storage_layout
- .load_contract_storage_with_layout(&self.contract, &transcoder)
+ .load_contract_storage_with_layout(&contract, &transcoder)
.await?;
if self.output_json {
println!(
@@ -104,14 +129,12 @@ impl StorageCommand {
"{} Displaying raw storage: no valid contract metadata artifacts found",
"Info:".cyan().bold(),
);
- let storage_data = storage_layout
- .load_contract_storage_data(&self.contract)
- .await?;
+ let storage_data =
+ storage_layout.load_contract_storage_data(&contract).await?;
println!(
"{json}",
json = serde_json::to_string_pretty(&storage_data)?
);
- return Ok(())
}
}
diff --git a/crates/cargo-contract/src/cmd/upload.rs b/crates/cargo-contract/src/cmd/upload.rs
index 9fdd40762..b047e7925 100644
--- a/crates/cargo-contract/src/cmd/upload.rs
+++ b/crates/cargo-contract/src/cmd/upload.rs
@@ -14,12 +14,22 @@
// You should have received a copy of the GNU General Public License
// along with cargo-contract. If not, see .
-use crate::ErrorVariant;
-use std::fmt::Debug;
+use crate::{
+ call_with_config,
+ ErrorVariant,
+};
+use std::{
+ fmt::{
+ Debug,
+ Display,
+ },
+ str::FromStr,
+};
use super::{
- create_signer,
+ config::SignerConfig,
display_dry_run_result_warning,
+ parse_balance,
CLIExtrinsicOpts,
};
use anyhow::Result;
@@ -31,15 +41,16 @@ use contract_extrinsics::{
UploadCommandBuilder,
UploadExec,
};
-use ink_env::{
- DefaultEnvironment,
- Environment,
-};
+use ink_env::Environment;
+use serde::Serialize;
use subxt::{
+ config::ExtrinsicParams,
+ ext::{
+ scale_decode::IntoVisitor,
+ scale_encode::EncodeAsType,
+ },
Config,
- PolkadotConfig as DefaultConfig,
};
-use subxt_signer::sr25519::Keypair;
#[derive(Debug, clap::Args)]
#[clap(name = "upload", about = "Upload a contract's code")]
@@ -49,6 +60,9 @@ pub struct UploadCommand {
/// Export the call output in JSON format.
#[clap(long, conflicts_with = "verbose")]
output_json: bool,
+ /// The chain config to be used as part of the call.
+ #[clap(name = "config", long, default_value = "Polkadot")]
+ config: String,
}
impl UploadCommand {
@@ -58,25 +72,42 @@ impl UploadCommand {
}
pub async fn handle(&self) -> Result<(), ErrorVariant> {
- let token_metadata =
- TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ call_with_config!(self, run, self.config.as_str())
+ }
- let signer = create_signer(&self.extrinsic_cli_opts.suri)?;
+ async fn run>(
+ &self,
+ ) -> Result<(), ErrorVariant>
+ where
+ ::AccountId: IntoVisitor + FromStr + EncodeAsType,
+ <::AccountId as FromStr>::Err: Display,
+ C::Balance:
+ Into + From + Display + Default + FromStr + Serialize + Debug,
+ >::OtherParams: Default,
+ ::Hash: IntoVisitor + EncodeAsType + From<[u8; 32]>,
+ {
+ let signer = C::Signer::from_str(&self.extrinsic_cli_opts.suri)
+ .map_err(|_| anyhow::anyhow!("Failed to parse suri option"))?;
+ let token_metadata =
+ TokenMetadata::query::(&self.extrinsic_cli_opts.url).await?;
+ let storage_deposit_limit = self
+ .extrinsic_cli_opts
+ .storage_deposit_limit
+ .clone()
+ .map(|b| parse_balance(&b, &token_metadata))
+ .transpose()
+ .map_err(|e| {
+ anyhow::anyhow!("Failed to parse storage_deposit_limit option: {}", e)
+ })?;
let extrinsic_opts = ExtrinsicOptsBuilder::new(signer)
.file(self.extrinsic_cli_opts.file.clone())
.manifest_path(self.extrinsic_cli_opts.manifest_path.clone())
.url(self.extrinsic_cli_opts.url.clone())
- .storage_deposit_limit(
- self.extrinsic_cli_opts
- .storage_deposit_limit
- .clone()
- .map(|bv| bv.denominate_balance(&token_metadata))
- .transpose()?,
- )
+ .storage_deposit_limit(storage_deposit_limit)
.done();
- let upload_exec: UploadExec =
- UploadCommandBuilder::new(extrinsic_opts).done().await?;
+ let upload_exec: UploadExec =
+ UploadCommandBuilder::new(extrinsic_opts).done().await?;
let code_hash = upload_exec.code().code_hash();
let metadata = upload_exec.client().metadata();
@@ -106,20 +137,21 @@ impl UploadCommand {
}
} else {
let upload_result = upload_exec.upload_code().await?;
- let display_events = DisplayEvents::from_events::<
- DefaultConfig,
- DefaultEnvironment,
- >(&upload_result.events, None, &metadata)?;
+ let display_events = DisplayEvents::from_events::(
+ &upload_result.events,
+ None,
+ &metadata,
+ )?;
let output_events = if self.output_json() {
display_events.to_json()?
} else {
- display_events.display_events::(
+ display_events.display_events::(
self.extrinsic_cli_opts.verbosity()?,
&token_metadata,
)?
};
if let Some(code_stored) = upload_result.code_stored {
- let code_hash: ::Hash = code_stored.code_hash;
+ let code_hash: