partner_chains_smart_contracts_commands/
lib.rs1use ogmios_client::jsonrpsee::{OgmiosClients, client_for_url};
27use partner_chains_cardano_offchain::{
28 await_tx::FixedDelayRetries,
29 cardano_keys::{CardanoKeyFileContent, CardanoPaymentSigningKey},
30 multisig::MultiSigSmartContractResult,
31};
32use serde::Serialize;
33use sidechain_domain::*;
34use std::time::Duration;
35
36pub mod assemble_tx;
37pub mod d_parameter;
38pub mod get_scripts;
39pub mod governance;
40pub mod governed_map;
41pub mod permissioned_candidates;
42pub mod register;
43pub mod reserve;
44pub mod sign_tx;
45
46#[derive(Clone, Debug, clap::Subcommand)]
47#[allow(clippy::large_enum_variant)]
48pub enum SmartContractsCmd {
50 GetScripts(get_scripts::GetScripts),
52 UpsertDParameter(d_parameter::UpsertDParameterCmd),
54 UpsertPermissionedCandidates(permissioned_candidates::UpsertPermissionedCandidatesCmd),
56 Register(register::RegisterCmd),
58 Deregister(register::DeregisterCmd),
60 #[command(subcommand)]
61 Reserve(reserve::ReserveCmd),
63 #[command(subcommand)]
64 Governance(governance::GovernanceCmd),
66 AssembleAndSubmitTx(assemble_tx::AssembleAndSubmitCmd),
68 SignTx(sign_tx::SignTxCmd),
70 #[command(subcommand)]
71 GovernedMap(governed_map::GovernedMapCmd),
73}
74
75#[derive(Clone, Debug, clap::Parser)]
76#[command(author, version, about, long_about = None)]
77pub struct CommonArguments {
79 #[arg(default_value = "ws://localhost:1337", long, short = 'O', env)]
80 ogmios_url: String,
82 #[arg(default_value = "180", long, env)]
83 ogmios_requests_timeout_seconds: u64,
85 #[arg(default_value = "5", long)]
86 retry_delay_seconds: u64,
89 #[arg(default_value = "59", long)]
90 retry_count: usize,
93}
94
95impl CommonArguments {
96 pub async fn get_ogmios_client(&self) -> crate::CmdResult<OgmiosClients> {
98 Ok(client_for_url(
99 &self.ogmios_url,
100 Duration::from_secs(self.ogmios_requests_timeout_seconds),
101 )
102 .await
103 .map_err(|e| format!("Failed to connect to Ogmios at {} with: {}", &self.ogmios_url, e))?)
104 }
105
106 pub fn retries(&self) -> FixedDelayRetries {
108 FixedDelayRetries::new(Duration::from_secs(self.retry_delay_seconds), self.retry_count)
109 }
110}
111
112type CmdResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;
114type SubCmdResult = Result<serde_json::Value, Box<dyn std::error::Error + Send + Sync>>;
116
117impl SmartContractsCmd {
118 pub async fn execute(self) -> CmdResult<()> {
120 let result: serde_json::Value = match self {
121 Self::Governance(cmd) => cmd.execute().await,
122 Self::GetScripts(cmd) => cmd.execute().await,
123 Self::UpsertDParameter(cmd) => cmd.execute().await,
124 Self::UpsertPermissionedCandidates(cmd) => cmd.execute().await,
125 Self::Register(cmd) => cmd.execute().await,
126 Self::Deregister(cmd) => cmd.execute().await,
127 Self::Reserve(cmd) => cmd.execute().await,
128 Self::AssembleAndSubmitTx(cmd) => cmd.execute().await,
129 Self::SignTx(cmd) => cmd.execute().await,
130 Self::GovernedMap(cmd) => cmd.execute().await,
131 }?;
132 println!("{}", result);
133 Ok(())
134 }
135
136 pub fn execute_blocking(self) -> CmdResult<()> {
138 tokio::runtime::Runtime::new()?.block_on(self.execute())
139 }
140}
141
142pub(crate) fn transaction_submitted_json(tx_hash: McTxHash) -> serde_json::Value {
145 serde_json::json!(MultiSigSmartContractResult::TransactionSubmitted(tx_hash))
146}
147
148pub(crate) fn option_to_json<T: Serialize>(value_opt: Option<T>) -> serde_json::Value {
150 match value_opt {
151 Some(value) => serde_json::json!(value),
152 None => serde_json::json!({}),
153 }
154}
155
156#[derive(Clone, Debug, clap::Parser)]
157pub(crate) struct PaymentFilePath {
158 #[arg(long, short = 'k')]
159 payment_key_file: String,
161}
162
163impl PaymentFilePath {
164 pub(crate) fn read_key(&self) -> CmdResult<CardanoPaymentSigningKey> {
166 let key_file = CardanoKeyFileContent::parse_file(&self.payment_key_file)?;
167 Ok(CardanoPaymentSigningKey::try_from(key_file)?)
168 }
169}
170
171#[derive(Clone, Debug, clap::Parser)]
172pub(crate) struct GenesisUtxo {
173 #[arg(long, short = 'c')]
174 genesis_utxo: UtxoId,
176}
177
178impl From<GenesisUtxo> for UtxoId {
179 fn from(value: GenesisUtxo) -> Self {
180 value.genesis_utxo
181 }
182}
183
184pub(crate) fn parse_partnerchain_public_keys(
186 partner_chain_public_keys: &str,
187) -> CmdResult<PermissionedCandidateData> {
188 let partner_chain_public_keys = partner_chain_public_keys.replace("0x", "");
189 if let [sidechain_pub_key, aura_pub_key, grandpa_pub_key] =
190 partner_chain_public_keys.split(":").collect::<Vec<_>>()[..]
191 {
192 Ok(PermissionedCandidateData {
193 sidechain_public_key: SidechainPublicKey(hex::decode(sidechain_pub_key)?),
194 aura_public_key: AuraPublicKey(hex::decode(aura_pub_key)?),
195 grandpa_public_key: GrandpaPublicKey(hex::decode(grandpa_pub_key)?),
196 })
197 } else {
198 Err("Failed to parse partner chain public keys.".into())
199 }
200}
201
202#[cfg(test)]
203mod test {
204 use crate::parse_partnerchain_public_keys;
205 use hex_literal::hex;
206 use sidechain_domain::{
207 AuraPublicKey, GrandpaPublicKey, PermissionedCandidateData, SidechainPublicKey,
208 };
209
210 #[test]
211 fn parse_partnerchain_public_keys_with_0x_prefix() {
212 let input = "039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180:e85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73:cdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
213 assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
214 }
215
216 #[test]
217 fn parse_partnerchain_public_keys_without_0x_prefix() {
218 let input = "0x039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180:0xe85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73:0xcdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55";
219 assert_eq!(parse_partnerchain_public_keys(input).unwrap(), expected_public_keys())
220 }
221
222 fn expected_public_keys() -> PermissionedCandidateData {
223 PermissionedCandidateData {
224 sidechain_public_key: SidechainPublicKey(
225 hex!("039799ff93d184146deacaa455dade51b13ed16f23cdad11d1ad6af20103391180").to_vec(),
226 ),
227 aura_public_key: AuraPublicKey(
228 hex!("e85534c93315d60f808568d1dce5cb9e8ba6ed0b204209c5cc8f3bec56c10b73").to_vec(),
229 ),
230 grandpa_public_key: GrandpaPublicKey(
231 hex!("cdf3e5b33f53c8b541bbaea383225c45654f24de38c585725f3cff25b2802f55").to_vec(),
232 ),
233 }
234 }
235}