From 9e1e9c873a1ed1fab93bda03acc6e0fd7b466dd4 Mon Sep 17 00:00:00 2001 From: twwu123 Date: Tue, 1 Oct 2024 20:24:08 +0800 Subject: [PATCH 1/5] add voting support --- packages/sidan-csl-rs/src/core/builder.rs | 19 ++ packages/sidan-csl-rs/src/core/core_csl.rs | 254 +++++++---------- .../sidan-csl-rs/src/core/tx_parser/mod.rs | 1 + packages/sidan-csl-rs/src/core/utils/mod.rs | 4 + .../sidan-csl-rs/src/core/utils/redeemer.rs | 30 ++ .../sidan-csl-rs/src/core/utils/script.rs | 59 +++- packages/sidan-csl-rs/src/core/utils/vote.rs | 39 +++ .../src/model/tx_builder_types/mod.rs | 2 + .../model/tx_builder_types/tx_builder_body.rs | 3 +- .../src/model/tx_builder_types/vote.rs | 57 ++++ packages/whisky/src/builder/mod.rs | 32 +++ packages/whisky/src/builder/vote.rs | 269 ++++++++++++++++++ packages/whisky/src/builder/withdrawal.rs | 5 +- packages/whisky/tests/integration_tests.rs | 37 ++- 14 files changed, 658 insertions(+), 153 deletions(-) create mode 100644 packages/sidan-csl-rs/src/core/utils/redeemer.rs create mode 100644 packages/sidan-csl-rs/src/core/utils/vote.rs create mode 100644 packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs create mode 100644 packages/whisky/src/builder/vote.rs diff --git a/packages/sidan-csl-rs/src/core/builder.rs b/packages/sidan-csl-rs/src/core/builder.rs index bd9672c..11b833f 100644 --- a/packages/sidan-csl-rs/src/core/builder.rs +++ b/packages/sidan-csl-rs/src/core/builder.rs @@ -40,6 +40,7 @@ pub fn serialize_tx_body( TxBuilderCore::add_all_withdrawals(&mut mesh_csl, mesh_tx_builder_body.withdrawals.clone())?; TxBuilderCore::add_all_mints(&mut mesh_csl, mesh_tx_builder_body.mints.clone())?; TxBuilderCore::add_all_certificates(&mut mesh_csl, mesh_tx_builder_body.certificates.clone())?; + TxBuilderCore::add_all_votes(&mut mesh_csl, mesh_tx_builder_body.votes.clone())?; TxBuilderCore::add_validity_range(&mut mesh_csl, mesh_tx_builder_body.validity_range.clone()); TxBuilderCore::add_all_required_signature( &mut mesh_csl, @@ -150,6 +151,7 @@ impl TxBuilderCore { change_address: "".to_string(), change_datum: None, certificates: vec![], + votes: vec![], metadata: vec![], validity_range: ValidityRange { invalid_before: None, @@ -344,6 +346,23 @@ impl TxBuilderCore { Ok(()) } + /// ## Internal method + /// + /// Add multiple votes to the TxBuilder instance + /// + /// ### Arguments + /// + /// * `mesh_csl` - The MeshCSL instance + /// * `votes` - A vector of votes + fn add_all_votes(mesh_csl: &mut MeshCSL, votes: Vec) -> Result<(), JsError> { + let mut vote_builder = csl::VotingBuilder::new(); + for (index, vote) in votes.into_iter().enumerate() { + mesh_csl.add_vote(&mut vote_builder, vote, index as u64)? + } + mesh_csl.tx_builder.set_voting_builder(&vote_builder); + Ok(()) + } + /// ## Internal method /// /// Add a validity range to the TxBuilder instance diff --git a/packages/sidan-csl-rs/src/core/core_csl.rs b/packages/sidan-csl-rs/src/core/core_csl.rs index 1aad003..09d4b2c 100644 --- a/packages/sidan-csl-rs/src/core/core_csl.rs +++ b/packages/sidan-csl-rs/src/core/core_csl.rs @@ -3,7 +3,11 @@ use cardano_serialization_lib::{JsError, MintWitness}; use super::{ constants::build_csl_cost_models, - utils::{build_tx_builder, sign_transaction, to_bignum, to_csl_cert, to_value}, + utils::{ + build_tx_builder, sign_transaction, to_bignum, to_csl_anchor, to_csl_cert, to_csl_redeemer, + to_csl_script_source, to_csl_simple_script_source, to_csl_vote_kind, to_csl_voter, + to_value, + }, }; #[derive(Clone, Debug)] @@ -68,9 +72,7 @@ impl MeshCSL { &to_value(&input.tx_in.amount.unwrap()), ); Ok(()) - } // Err(JsError::from_str( - // "Reference Native scripts not implemented", - // )), + } } } @@ -95,35 +97,7 @@ impl MeshCSL { } }; - let csl_script: csl::PlutusScriptSource = match script_source { - ScriptSource::ProvidedScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new(&csl::PlutusScript::from_hex_with_version( - &script.script_cbor, - &language_version, - )?) - } - ScriptSource::InlineScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new_ref_input( - &csl::ScriptHash::from_hex(&script.script_hash)?, - &csl::TransactionInput::new( - &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, - script.ref_tx_in.tx_index, - ), - &language_version, - script.script_size, - ) - } - }; + let csl_script: csl::PlutusScriptSource = to_csl_script_source(script_source)?; let csl_redeemer: csl::Redeemer = csl::Redeemer::new( &csl::RedeemerTag::new_spend(), @@ -263,35 +237,7 @@ impl MeshCSL { let script_source = withdrawal.script_source.unwrap(); let redeemer = withdrawal.redeemer.unwrap(); - let csl_script: csl::PlutusScriptSource = match script_source { - ScriptSource::ProvidedScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new(&csl::PlutusScript::from_hex_with_version( - &script.script_cbor, - &language_version, - )?) - } - ScriptSource::InlineScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new_ref_input( - &csl::ScriptHash::from_hex(&script.script_hash)?, - &csl::TransactionInput::new( - &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, - script.ref_tx_in.tx_index, - ), - &language_version, - script.script_size, - ) - } - }; + let csl_script: csl::PlutusScriptSource = to_csl_script_source(script_source)?; let csl_redeemer: csl::Redeemer = csl::Redeemer::new( &csl::RedeemerTag::new_spend(), @@ -368,35 +314,7 @@ impl MeshCSL { ), ); let script_source_info = script_mint.script_source.unwrap(); - let mint_script = match script_source_info { - ScriptSource::InlineScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new_ref_input( - &csl::ScriptHash::from_hex(script_mint.mint.policy_id.as_str())?, - &csl::TransactionInput::new( - &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, - script.ref_tx_in.tx_index, - ), - &language_version, - script.script_size, - ) - } - ScriptSource::ProvidedScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new(&csl::PlutusScript::from_hex_with_version( - script.script_cbor.as_str(), - &language_version, - )?) - } - }; + let mint_script = to_csl_script_source(script_source_info)?; mint_builder.add_asset( &csl::MintWitness::new_plutus_script(&mint_script, &mint_redeemer), &csl::AssetName::new(hex::decode(script_mint.mint.asset_name).unwrap())?, @@ -447,35 +365,7 @@ impl MeshCSL { } Certificate::ScriptCertificate(script_cert) => { let cert_script_source: csl::PlutusScriptSource = match script_cert.script_source { - Some(script_source) => match script_source { - ScriptSource::InlineScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new_ref_input( - &csl::ScriptHash::from_hex(&script.script_hash)?, - &csl::TransactionInput::new( - &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, - script.ref_tx_in.tx_index, - ), - &language_version, - script.script_size, - ) - } - ScriptSource::ProvidedScriptSource(script) => { - let language_version: csl::Language = match script.language_version { - LanguageVersion::V1 => csl::Language::new_plutus_v1(), - LanguageVersion::V2 => csl::Language::new_plutus_v2(), - LanguageVersion::V3 => csl::Language::new_plutus_v3(), - }; - csl::PlutusScriptSource::new(&csl::PlutusScript::from_hex_with_version( - script.script_cbor.as_str(), - &language_version, - )?) - } - }, + Some(script_source) => to_csl_script_source(script_source)?, None => { return Err(JsError::from_str( "Missing Plutus Script Source in Plutus Cert", @@ -483,15 +373,7 @@ impl MeshCSL { } }; let cert_redeemer = match script_cert.redeemer { - Some(redeemer) => csl::Redeemer::new( - &csl::RedeemerTag::new_cert(), - &to_bignum(index), - &csl::PlutusData::from_hex(&redeemer.data)?, - &csl::ExUnits::new( - &to_bignum(redeemer.ex_units.mem), - &to_bignum(redeemer.ex_units.steps), - ), - ), + Some(redeemer) => to_csl_redeemer(RedeemerTag::Cert, redeemer, index)?, None => return Err(JsError::from_str("Missing Redeemer in Plutus Cert")), }; let csl_plutus_witness: csl::PlutusWitness = @@ -505,24 +387,9 @@ impl MeshCSL { Certificate::SimpleScriptCertificate(simple_script_cert) => { let script_info = simple_script_cert.simple_script_source; let script_source: csl::NativeScriptSource = match script_info { - Some(script_source) => match script_source { - SimpleScriptSource::ProvidedSimpleScriptSource(script) => { - csl::NativeScriptSource::new(&csl::NativeScript::from_hex( - &script.script_cbor, - )?) - } - - SimpleScriptSource::InlineSimpleScriptSource(script) => { - csl::NativeScriptSource::new_ref_input( - &csl::ScriptHash::from_hex(&script.simple_script_hash)?, - &csl::TransactionInput::new( - &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, - script.ref_tx_in.tx_index, - ), - script.script_size, - ) - } - }, + Some(simple_script_source) => { + to_csl_simple_script_source(simple_script_source)? + } None => { return Err(JsError::from_str( "Missing Native Script Source in Native Cert", @@ -538,6 +405,99 @@ impl MeshCSL { Ok(()) } + pub fn add_vote( + &mut self, + vote_builder: &mut csl::VotingBuilder, + vote: Vote, + index: u64, + ) -> Result<(), JsError> { + match vote { + Vote::BasicVote(vote_type) => { + let voter = to_csl_voter(vote_type.voter)?; + let vote_kind = to_csl_vote_kind(vote_type.voting_procedure.vote_kind); + let voting_procedure = match vote_type.voting_procedure.anchor { + Some(anchor) => { + csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?) + } + None => csl::VotingProcedure::new(vote_kind), + }; + vote_builder.add( + &voter, + &csl::GovernanceActionId::new( + &csl::TransactionHash::from_hex(&vote_type.gov_action_id.tx_hash)?, + vote_type.gov_action_id.tx_index, + ), + &voting_procedure, + )? + } + Vote::ScriptVote(script_vote) => { + let voter = to_csl_voter(script_vote.vote.voter)?; + let vote_kind = to_csl_vote_kind(script_vote.vote.voting_procedure.vote_kind); + let voting_procedure = match script_vote.vote.voting_procedure.anchor { + Some(anchor) => { + csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?) + } + None => csl::VotingProcedure::new(vote_kind), + }; + let vote_script_source: csl::PlutusScriptSource = match script_vote.script_source { + Some(script_source) => to_csl_script_source(script_source)?, + None => { + return Err(JsError::from_str( + "Missing Plutus Script Source in Plutus Vote", + )) + } + }; + let vote_redeemer = match script_vote.redeemer { + Some(redeemer) => to_csl_redeemer(RedeemerTag::Vote, redeemer, index)?, + None => return Err(JsError::from_str("Missing Redeemer in Plutus Vote")), + }; + let csl_plutus_witness: csl::PlutusWitness = + csl::PlutusWitness::new_with_ref_without_datum( + &vote_script_source, + &vote_redeemer, + ); + vote_builder.add_with_plutus_witness( + &voter, + &csl::GovernanceActionId::new( + &csl::TransactionHash::from_hex(&script_vote.vote.gov_action_id.tx_hash)?, + script_vote.vote.gov_action_id.tx_index, + ), + &voting_procedure, + &csl_plutus_witness, + )? + } + Vote::SimpleScriptVote(simple_script_vote) => { + let voter = to_csl_voter(simple_script_vote.vote.voter)?; + let vote_kind = + to_csl_vote_kind(simple_script_vote.vote.voting_procedure.vote_kind); + let voting_procedure = match simple_script_vote.vote.voting_procedure.anchor { + Some(anchor) => { + csl::VotingProcedure::new_with_anchor(vote_kind, &to_csl_anchor(&anchor)?) + } + None => csl::VotingProcedure::new(vote_kind), + }; + let csl_simple_script_source = match simple_script_vote.simple_script_source { + Some(simple_script_source) => { + to_csl_simple_script_source(simple_script_source)? + } + None => return Err(JsError::from_str("Missing ")), + }; + vote_builder.add_with_native_script( + &voter, + &csl::GovernanceActionId::new( + &csl::TransactionHash::from_hex( + &simple_script_vote.vote.gov_action_id.tx_hash, + )?, + simple_script_vote.vote.gov_action_id.tx_index, + ), + &voting_procedure, + &csl_simple_script_source, + )? + } + }; + Ok(()) + } + pub fn add_invalid_before(&mut self, invalid_before: u64) { self.tx_builder .set_validity_start_interval_bignum(to_bignum(invalid_before)); diff --git a/packages/sidan-csl-rs/src/core/tx_parser/mod.rs b/packages/sidan-csl-rs/src/core/tx_parser/mod.rs index 8de1ec0..800a771 100644 --- a/packages/sidan-csl-rs/src/core/tx_parser/mod.rs +++ b/packages/sidan-csl-rs/src/core/tx_parser/mod.rs @@ -35,6 +35,7 @@ impl MeshTxParser { change_address: "".to_string(), change_datum: None, certificates: vec![], + votes: vec![], metadata: vec![], validity_range: ValidityRange { invalid_before: None, diff --git a/packages/sidan-csl-rs/src/core/utils/mod.rs b/packages/sidan-csl-rs/src/core/utils/mod.rs index 5cb9ad1..e3f24ed 100644 --- a/packages/sidan-csl-rs/src/core/utils/mod.rs +++ b/packages/sidan-csl-rs/src/core/utils/mod.rs @@ -1,17 +1,21 @@ mod address; mod aiken; mod certificates; +mod redeemer; mod script; mod staking; mod transaction; mod ungroup; mod value; +mod vote; pub use address::*; pub use aiken::*; pub use certificates::*; +pub use redeemer::*; pub use script::*; pub use staking::*; pub use transaction::*; pub use ungroup::*; pub use value::*; +pub use vote::*; diff --git a/packages/sidan-csl-rs/src/core/utils/redeemer.rs b/packages/sidan-csl-rs/src/core/utils/redeemer.rs new file mode 100644 index 0000000..af6e1ef --- /dev/null +++ b/packages/sidan-csl-rs/src/core/utils/redeemer.rs @@ -0,0 +1,30 @@ +use cardano_serialization_lib::JsError; +use model::{Redeemer, RedeemerTag}; + +use crate::*; + +use super::to_bignum; + +pub fn to_csl_redeemer( + redeemer_tag: RedeemerTag, + redeemer: Redeemer, + index: u64, +) -> Result { + let csl_redeemer_tag = match redeemer_tag { + RedeemerTag::Spend => csl::RedeemerTag::new_spend(), + RedeemerTag::Mint => csl::RedeemerTag::new_mint(), + RedeemerTag::Cert => csl::RedeemerTag::new_cert(), + RedeemerTag::Reward => csl::RedeemerTag::new_reward(), + RedeemerTag::Vote => csl::RedeemerTag::new_vote(), + RedeemerTag::Propose => csl::RedeemerTag::new_voting_proposal(), + }; + Ok(csl::Redeemer::new( + &csl_redeemer_tag, + &to_bignum(index), + &csl::PlutusData::from_hex(&redeemer.data)?, + &csl::ExUnits::new( + &to_bignum(redeemer.ex_units.mem), + &to_bignum(redeemer.ex_units.steps), + ), + )) +} diff --git a/packages/sidan-csl-rs/src/core/utils/script.rs b/packages/sidan-csl-rs/src/core/utils/script.rs index 9871521..c0e8323 100644 --- a/packages/sidan-csl-rs/src/core/utils/script.rs +++ b/packages/sidan-csl-rs/src/core/utils/script.rs @@ -1,5 +1,5 @@ use cardano_serialization_lib::JsError; -use model::LanguageVersion; +use model::{LanguageVersion, ScriptSource, SimpleScriptSource}; use crate::*; @@ -20,6 +20,63 @@ pub fn get_script_hash(script: &str, version: LanguageVersion) -> Result Result { + match script_source { + ScriptSource::InlineScriptSource(script) => { + let language_version: csl::Language = match script.language_version { + LanguageVersion::V1 => csl::Language::new_plutus_v1(), + LanguageVersion::V2 => csl::Language::new_plutus_v2(), + LanguageVersion::V3 => csl::Language::new_plutus_v3(), + }; + Ok(csl::PlutusScriptSource::new_ref_input( + &csl::ScriptHash::from_hex(&script.script_hash)?, + &csl::TransactionInput::new( + &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, + script.ref_tx_in.tx_index, + ), + &language_version, + script.script_size, + )) + } + ScriptSource::ProvidedScriptSource(script) => { + let language_version: csl::Language = match script.language_version { + LanguageVersion::V1 => csl::Language::new_plutus_v1(), + LanguageVersion::V2 => csl::Language::new_plutus_v2(), + LanguageVersion::V3 => csl::Language::new_plutus_v3(), + }; + Ok(csl::PlutusScriptSource::new( + &csl::PlutusScript::from_hex_with_version( + script.script_cbor.as_str(), + &language_version, + )?, + )) + } + } +} + +pub fn to_csl_simple_script_source( + simple_script_source: SimpleScriptSource, +) -> Result { + match simple_script_source { + SimpleScriptSource::ProvidedSimpleScriptSource(script) => Ok(csl::NativeScriptSource::new( + &csl::NativeScript::from_hex(&script.script_cbor)?, + )), + + SimpleScriptSource::InlineSimpleScriptSource(script) => { + Ok(csl::NativeScriptSource::new_ref_input( + &csl::ScriptHash::from_hex(&script.simple_script_hash)?, + &csl::TransactionInput::new( + &csl::TransactionHash::from_hex(&script.ref_tx_in.tx_hash)?, + script.ref_tx_in.tx_index, + ), + script.script_size, + )) + } + } +} + #[wasm_bindgen] pub fn get_v2_script_hash(script: &str) -> String { csl::PlutusScript::from_hex_with_version(script, &csl::Language::new_plutus_v2()) diff --git a/packages/sidan-csl-rs/src/core/utils/vote.rs b/packages/sidan-csl-rs/src/core/utils/vote.rs new file mode 100644 index 0000000..0122947 --- /dev/null +++ b/packages/sidan-csl-rs/src/core/utils/vote.rs @@ -0,0 +1,39 @@ +use cardano_serialization_lib::{self as csl, JsError}; + +use crate::model::{VoteKind, Voter}; + +pub fn to_csl_voter(voter: Voter) -> Result { + match voter { + Voter::ConstitutionalCommitteeHotAddress(reward_address) => { + Ok(csl::Voter::new_constitutional_committee_hot_credential( + &csl::RewardAddress::from_address(&csl::Address::from_bech32(&reward_address)?) + .unwrap() + .payment_cred(), + )) + } + Voter::DRepId(drep_id) => { + let drep = csl::DRep::from_bech32(&drep_id).unwrap(); + let drep_credential = if drep.to_script_hash().is_some() { + csl::Credential::from_scripthash(&drep.to_script_hash().unwrap()) + } else if drep.to_key_hash().is_some() { + csl::Credential::from_keyhash(&drep.to_key_hash().unwrap()) + } else { + return Err(JsError::from_str( + "Error occured when deserializing DrepId to either script hash or key hash", + )); + }; + Ok(csl::Voter::new_drep_credential(&drep_credential)) + } + Voter::StakingPoolKeyHash(key_hash) => Ok(csl::Voter::new_stake_pool_key_hash( + &csl::Ed25519KeyHash::from_hex(&key_hash)?, + )), + } +} + +pub fn to_csl_vote_kind(vote_kind: VoteKind) -> csl::VoteKind { + match vote_kind { + VoteKind::No => csl::VoteKind::No, + VoteKind::Yes => csl::VoteKind::Yes, + VoteKind::Abstain => csl::VoteKind::Abstain, + } +} diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs index d8a2a6c..0eee3d2 100644 --- a/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs @@ -10,6 +10,7 @@ mod tx_builder_body; mod tx_in; mod utxo; mod validity_range; +mod vote; mod withdrawal; pub use certificate::*; @@ -24,4 +25,5 @@ pub use tx_builder_body::*; pub use tx_in::*; pub use utxo::*; pub use validity_range::*; +pub use vote::*; pub use withdrawal::*; diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/tx_builder_body.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/tx_builder_body.rs index 3dcbba0..9eeaf6b 100644 --- a/packages/sidan-csl-rs/src/model/tx_builder_types/tx_builder_body.rs +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/tx_builder_body.rs @@ -2,7 +2,7 @@ use serde::{Deserialize, Serialize}; use super::{ Certificate, Datum, Metadata, MintItem, Network, Output, PubKeyTxIn, RefTxIn, TxIn, - ValidityRange, Withdrawal, + ValidityRange, Vote, Withdrawal, }; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -20,6 +20,7 @@ pub struct TxBuilderBody { pub metadata: Vec, pub validity_range: ValidityRange, pub certificates: Vec, + pub votes: Vec, pub signing_key: Vec, pub network: Option, } diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs new file mode 100644 index 0000000..a59cfb1 --- /dev/null +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs @@ -0,0 +1,57 @@ +use serde::{Deserialize, Serialize}; + +use super::{Anchor, Redeemer, RefTxIn, ScriptSource, SimpleScriptSource}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum Vote { + BasicVote(VoteType), + ScriptVote(ScriptVote), + SimpleScriptVote(SimpleScriptVote), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ScriptVote { + pub vote: VoteType, + pub redeemer: Option, + pub script_source: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct SimpleScriptVote { + pub vote: VoteType, + pub simple_script_source: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VoteType { + pub voter: Voter, + pub gov_action_id: RefTxIn, + pub voting_procedure: VotingProcedure, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum Voter { + ConstitutionalCommitteeHotAddress(String), + DRepId(String), + StakingPoolKeyHash(String), +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct VotingProcedure { + pub vote_kind: VoteKind, + pub anchor: Option, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum VoteKind { + No = 0, + Yes = 1, + Abstain = 2, +} diff --git a/packages/whisky/src/builder/mod.rs b/packages/whisky/src/builder/mod.rs index 1f998c0..d3b6b63 100644 --- a/packages/whisky/src/builder/mod.rs +++ b/packages/whisky/src/builder/mod.rs @@ -6,6 +6,7 @@ mod service; mod tx_eval; mod tx_in; mod tx_out; +mod vote; mod withdrawal; use std::collections::HashMap; @@ -25,12 +26,14 @@ pub struct TxBuilder { pub protocol_params: Option, pub tx_in_item: Option, pub withdrawal_item: Option, + pub vote_item: Option, pub mint_item: Option, pub collateral_item: Option, pub tx_output: Option, pub adding_script_input: Option, pub adding_plutus_mint: Option, pub adding_plutus_withdrawal: Option, + pub adding_plutus_vote: Option, pub fetcher: Option>, pub evaluator: Option>, pub submitter: Option>, @@ -65,12 +68,14 @@ impl TxBuilder { protocol_params: param.params.clone(), tx_in_item: None, withdrawal_item: None, + vote_item: None, mint_item: None, collateral_item: None, tx_output: None, adding_script_input: None, adding_plutus_mint: None, adding_plutus_withdrawal: None, + adding_plutus_vote: None, fetcher: param.fetcher, evaluator: match param.evaluator { Some(evaluator) => Some(evaluator), @@ -399,6 +404,30 @@ impl TxBuilder { self.withdrawal_item = None; } + /// ## Internal method + /// + /// Queue a vote in the TxBuilder instance + pub fn queue_vote(&mut self) { + let vote_item = self.vote_item.clone().unwrap(); + match vote_item { + Vote::ScriptVote(script_vote) => { + match (script_vote.redeemer, script_vote.script_source) { + (None, _) => panic!("Redeemer in script vote cannot be None"), + (_, None) => panic!("Script source in script vote cannot be None"), + _ => {} + } + } + Vote::SimpleScriptVote(simple_script_vote) => { + if simple_script_vote.simple_script_source.is_none() { + panic!("Script source is missing from native script vote") + } + } + Vote::BasicVote(_) => {} + } + self.core.mesh_tx_builder_body.votes.push(self.vote_item.clone().unwrap()); + self.vote_item = None; + } + /// ## Internal method /// /// Queue a mint in the TxBuilder instance @@ -451,6 +480,9 @@ impl TxBuilder { if self.withdrawal_item.is_some() { self.queue_withdrawal(); } + if self.vote_item.is_some() { + self.queue_vote(); + } if self.mint_item.is_some() { self.queue_mint(); } diff --git a/packages/whisky/src/builder/vote.rs b/packages/whisky/src/builder/vote.rs new file mode 100644 index 0000000..ed73e56 --- /dev/null +++ b/packages/whisky/src/builder/vote.rs @@ -0,0 +1,269 @@ +use sidan_csl_rs::model::*; + +use super::{TxBuilder, Vote, WRedeemer}; + +impl TxBuilder { + /// ## Transaction building method + /// + /// Indicate that the transaction is voting using a plutus staking script in the TxBuilder instance + /// + /// ### Arguments + /// + /// * `language_version` - The language version of the script + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn voting_plutus_script(&mut self, language_version: &LanguageVersion) -> &mut Self { + match language_version { + LanguageVersion::V1 => self.voting_plutus_script_v1(), + LanguageVersion::V2 => self.voting_plutus_script_v2(), + LanguageVersion::V3 => self.voting_plutus_script_v3(), + } + } + + /// ## Transaction building method + /// + /// Indicate that the transaction is voting using a plutus V1 staking script in the TxBuilder instance + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn voting_plutus_script_v1(&mut self) -> &mut Self { + self.adding_plutus_vote = Some(LanguageVersion::V1); + self + } + + /// ## Transaction building method + /// + /// Indicate that the transaction is voting using a plutus V2 staking script in the TxBuilder instance + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn voting_plutus_script_v2(&mut self) -> &mut Self { + self.adding_plutus_vote = Some(LanguageVersion::V2); + self + } + + /// ## Transaction building method + /// + /// Indicate that the transaction is voting using a plutus V3 staking script in the TxBuilder instance + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn voting_plutus_script_v3(&mut self) -> &mut Self { + self.adding_plutus_vote = Some(LanguageVersion::V3); + self + } + + /// ## Transaction building method + /// + /// Add a vote reference to the TxBuilder instance + /// + /// ### Arguments + /// + /// * `tx_hash` - The transaction hash + /// * `tx_index` - The transaction index + /// * `vote_script_hash` - The vote script hash + /// * `version` - The language version, if the language version is None, the script is assumed to be a Native Script + /// * `script_size` - Size of the script + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn vote_tx_in_reference( + &mut self, + tx_hash: &str, + tx_index: u32, + vote_script_hash: &str, + script_size: usize, + ) -> &mut Self { + let vote_item = self.vote_item.take(); + if vote_item.is_none() { + panic!("Undefined output") + } + let vote_item = vote_item.unwrap(); + match vote_item { + Vote::BasicVote(_) => { + panic!("Script reference cannot be defined for a pubkey vote") + } + Vote::SimpleScriptVote(mut simple_script_vote) => { + simple_script_vote.simple_script_source = Some( + SimpleScriptSource::InlineSimpleScriptSource(InlineSimpleScriptSource { + ref_tx_in: RefTxIn { + tx_hash: tx_hash.to_string(), + tx_index, + }, + simple_script_hash: vote_script_hash.to_string(), + script_size, + }), + ) + } + Vote::ScriptVote(mut script_vote) => { + script_vote.script_source = + Some(ScriptSource::InlineScriptSource(InlineScriptSource { + ref_tx_in: RefTxIn { + tx_hash: tx_hash.to_string(), + tx_index, + }, + script_hash: vote_script_hash.to_string(), + language_version: self + .adding_plutus_vote + .clone() + .expect("Plutus votes require a language version"), + script_size, + })); + self.vote_item = Some(Vote::ScriptVote(script_vote)); + } + } + self + } + + /// ## Transaction building method + /// + /// Add a vote in the TxBuilder instance + /// + /// ### Arguments + /// + /// * `voter` - The voter, can be a ConstitutionalCommittee, a DRep or a StakePool + /// * `gov_action_id` - The transaction hash and transaction id of the governance action + /// * `voting_precedure` - The voting kind (yes, no, abstain) with an optional anchor + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn vote( + &mut self, + voter: &Voter, + gov_action_id: &RefTxIn, + voting_procedure: &VotingProcedure, + ) -> &mut Self { + if self.vote_item.is_some() { + self.queue_vote(); + } + + match self.adding_plutus_vote { + Some(_) => { + let vote_item = Vote::ScriptVote(ScriptVote { + vote: VoteType { + voter: voter.clone(), + gov_action_id: gov_action_id.clone(), + voting_procedure: voting_procedure.clone(), + }, + redeemer: None, + script_source: None, + }); + self.vote_item = Some(vote_item); + } + None => { + let vote_item = Vote::BasicVote(VoteType { + voter: voter.clone(), + gov_action_id: gov_action_id.clone(), + voting_procedure: voting_procedure.clone(), + }); + self.vote_item = Some(vote_item); + } + } + self + } + + /// ## Transaction building method + /// + /// Add a vote script to the TxBuilder instance + /// + /// ### Arguments + /// + /// * `script_cbor` - The script in CBOR format + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn vote_script(&mut self, script_cbor: &str) -> &mut Self { + let vote_item = self.vote_item.take(); + if vote_item.is_none() { + panic!("Undefined vote") + } + let vote_item = vote_item.unwrap(); + match vote_item { + Vote::BasicVote(_) => { + panic!("Script reference cannot be defined for a pubkey vote") + } + Vote::SimpleScriptVote(mut simple_script_vote) => { + simple_script_vote.simple_script_source = Some( + SimpleScriptSource::ProvidedSimpleScriptSource(ProvidedSimpleScriptSource { + script_cbor: script_cbor.to_string(), + }), + ); + self.vote_item = Some(Vote::SimpleScriptVote(simple_script_vote)); + } + Vote::ScriptVote(mut script_vote) => { + script_vote.script_source = + Some(ScriptSource::ProvidedScriptSource(ProvidedScriptSource { + script_cbor: script_cbor.to_string(), + language_version: self + .adding_plutus_vote + .clone() + .expect("Plutus votes require a language version"), + })); + self.vote_item = Some(Vote::ScriptVote(script_vote)); + self.adding_plutus_vote = None; + } + } + self + } + + /// ## Transaction building method + /// + /// Set the transaction vote redeemer value in the TxBuilder instance + /// + /// ### Arguments + /// + /// * `redeemer` - The redeemer value + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn vote_redeemer_value(&mut self, redeemer: &WRedeemer) -> &mut Self { + let vote_item = self.vote_item.take(); + if vote_item.is_none() { + panic!("Undefined input") + } + let vote_item = vote_item.unwrap(); + match vote_item { + Vote::BasicVote(_) => { + panic!("Redeemer cannot be defined for a basic vote") + } + Vote::SimpleScriptVote(_) => { + panic!("Redeemer cannot be defined for a native script vote") + } + Vote::ScriptVote(mut script_vote) => match redeemer.data.to_cbor() { + Ok(raw_redeemer) => { + script_vote.redeemer = Some(Redeemer { + data: raw_redeemer, + ex_units: redeemer.clone().ex_units, + }); + self.vote_item = Some(Vote::ScriptVote(script_vote)); + } + Err(_) => panic!("Error converting redeemer to CBOR"), + }, + } + self + } + + /// ## Transaction building method + /// + /// Set the vote reference redeemer value in the TxBuilder instance + /// + /// ### Arguments + /// + /// * `redeemer` - The redeemer value + /// + /// ### Returns + /// + /// * `Self` - The TxBuilder instance + pub fn vote_reference_tx_in_redeemer_value(&mut self, redeemer: &WRedeemer) -> &mut Self { + self.vote_redeemer_value(redeemer) + } +} diff --git a/packages/whisky/src/builder/withdrawal.rs b/packages/whisky/src/builder/withdrawal.rs index e79a0e1..c3eb959 100644 --- a/packages/whisky/src/builder/withdrawal.rs +++ b/packages/whisky/src/builder/withdrawal.rs @@ -67,7 +67,6 @@ impl TxBuilder { /// * `tx_hash` - The transaction hash /// * `tx_index` - The transaction index /// * `withdrawal_script_hash` - The withdrawal script hash - /// * `version` - The language version, if the language version is None, the script is assumed to be a Native Script /// * `script_size` - Size of the script /// /// ### Returns @@ -166,7 +165,6 @@ impl TxBuilder { /// ### Arguments /// /// * `script_cbor` - The script in CBOR format - /// * `version` - The language version, if the language version is None, the script is assumed to be a Native Script /// /// ### Returns /// @@ -186,7 +184,8 @@ impl TxBuilder { ProvidedSimpleScriptSource { script_cbor: script_cbor.to_string(), }, - )) + )); + self.withdrawal_item = Some(Withdrawal::SimpleScriptWithdrawal(withdraw)); } Withdrawal::PlutusScriptWithdrawal(mut withdraw) => { withdraw.script_source = diff --git a/packages/whisky/tests/integration_tests.rs b/packages/whisky/tests/integration_tests.rs index 2693371..7be7b54 100644 --- a/packages/whisky/tests/integration_tests.rs +++ b/packages/whisky/tests/integration_tests.rs @@ -6,7 +6,7 @@ mod int_tests { }; use whisky::{ builder::{ TxBuilder, TxBuilderParam, WData::{self, JSON}, WRedeemer}, - core::utils::merge_vkey_witnesses_to_transaction, model::{Anchor, DRep}, + core::utils::merge_vkey_witnesses_to_transaction, model::{Anchor, DRep, RefTxIn, VoteKind, Voter, VotingProcedure}, }; #[test] @@ -551,4 +551,39 @@ mod int_tests { println!("{}", unsigned_tx); } + + #[test] + fn test_drep_vote() { + let mut mesh = TxBuilder::new(TxBuilderParam { + evaluator: None, + fetcher: None, + submitter: None, + params: None, + }); + + let unsigned_tx = mesh + .change_address("addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6") + .tx_in( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + &[Asset::new_from_str("lovelace", "9891607895")], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .vote(&Voter::DRepId("drep1j6257gz2swty9ut46lspyvujkt02pd82am2zq97p7p9pv2euzs7".to_string()), &RefTxIn { + tx_hash: "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85".to_string(), + tx_index: 2 + }, &VotingProcedure { + vote_kind: VoteKind::Abstain, + anchor: Some(Anchor { + anchor_url: "https://raw.githubusercontent.com/HinsonSIDAN/cardano-drep/main/HinsonSIDAN.jsonld".to_string(), + anchor_data_hash: "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060".to_string() + }) + }) + .complete_sync(None) + .unwrap() + .complete_signing() + .unwrap(); + + println!("{}", unsigned_tx); + } } From 04e664b2d062e91aff394f2ef53442fd08a8d8de Mon Sep 17 00:00:00 2001 From: twwu123 Date: Tue, 1 Oct 2024 20:26:03 +0800 Subject: [PATCH 2/5] bump version --- packages/Cargo.lock | 6 +++--- packages/Cargo.toml | 2 +- packages/sidan-csl-rs/Cargo.toml | 2 +- packages/whisky-examples/Cargo.toml | 4 ++-- packages/whisky/Cargo.toml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/Cargo.lock b/packages/Cargo.lock index 85eafb4..a53c41e 100644 --- a/packages/Cargo.lock +++ b/packages/Cargo.lock @@ -2644,7 +2644,7 @@ dependencies = [ [[package]] name = "sidan-csl-rs" -version = "0.8.5" +version = "0.8.6" dependencies = [ "cardano-serialization-lib", "cryptoxide", @@ -3258,7 +3258,7 @@ dependencies = [ [[package]] name = "whisky" -version = "0.8.5" +version = "0.8.6" dependencies = [ "async-trait", "cryptoxide", @@ -3283,7 +3283,7 @@ dependencies = [ [[package]] name = "whisky-examples" -version = "0.8.5" +version = "0.8.6" dependencies = [ "actix-cors", "actix-web", diff --git a/packages/Cargo.toml b/packages/Cargo.toml index f91f41a..c978ccb 100644 --- a/packages/Cargo.toml +++ b/packages/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -version = "0.8.5" +version = "0.8.6" resolver = "2" members = [ "sidan-csl-rs", diff --git a/packages/sidan-csl-rs/Cargo.toml b/packages/sidan-csl-rs/Cargo.toml index c8481e5..97dbb61 100644 --- a/packages/sidan-csl-rs/Cargo.toml +++ b/packages/sidan-csl-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sidan-csl-rs" -version = "0.8.5" +version = "0.8.6" edition = "2021" license = "Apache-2.0" description = "Wrapper around the cardano-serialization-lib for easier transaction building, heavily inspired by cardano-cli APIs" diff --git a/packages/whisky-examples/Cargo.toml b/packages/whisky-examples/Cargo.toml index f6b74db..cbb8e2b 100644 --- a/packages/whisky-examples/Cargo.toml +++ b/packages/whisky-examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whisky-examples" -version = "0.8.5" +version = "0.8.6" edition = "2021" license = "Apache-2.0" description = "The Cardano Rust SDK, inspired by MeshJS" @@ -13,4 +13,4 @@ path = "src/server.rs" actix-cors = "0.7.0" actix-web = "4.9.0" serde = "1.0.209" -whisky = { version = "=0.8.5", path = "../whisky" } +whisky = { version = "=0.8.6", path = "../whisky" } diff --git a/packages/whisky/Cargo.toml b/packages/whisky/Cargo.toml index e055da1..456470f 100644 --- a/packages/whisky/Cargo.toml +++ b/packages/whisky/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whisky" -version = "0.8.5" +version = "0.8.6" edition = "2021" license = "Apache-2.0" description = "The Cardano Rust SDK, inspired by MeshJS" @@ -24,7 +24,7 @@ pallas-codec = { version = "0.30.1", features = ["num-bigint"] } pallas-primitives = "0.30.1" pallas-traverse = "0.30.1" maestro-rust-sdk = "1.1.3" -sidan-csl-rs = { version = "=0.8.5", path = "../sidan-csl-rs" } +sidan-csl-rs = { version = "=0.8.6", path = "../sidan-csl-rs" } reqwest = "0.12.5" tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] } From 9a755d8f911e18559bb390b96146385304b6fece Mon Sep 17 00:00:00 2001 From: twwu123 Date: Mon, 7 Oct 2024 21:05:11 +0800 Subject: [PATCH 3/5] update CC voting types --- packages/sidan-csl-rs/src/core/utils/vote.rs | 21 ++++++++++++------- .../src/model/tx_builder_types/credential.rs | 8 +++++++ .../src/model/tx_builder_types/mod.rs | 2 ++ .../src/model/tx_builder_types/vote.rs | 4 ++-- 4 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 packages/sidan-csl-rs/src/model/tx_builder_types/credential.rs diff --git a/packages/sidan-csl-rs/src/core/utils/vote.rs b/packages/sidan-csl-rs/src/core/utils/vote.rs index 0122947..26f96fd 100644 --- a/packages/sidan-csl-rs/src/core/utils/vote.rs +++ b/packages/sidan-csl-rs/src/core/utils/vote.rs @@ -1,16 +1,21 @@ use cardano_serialization_lib::{self as csl, JsError}; -use crate::model::{VoteKind, Voter}; +use crate::model::{Credential, VoteKind, Voter}; pub fn to_csl_voter(voter: Voter) -> Result { match voter { - Voter::ConstitutionalCommitteeHotAddress(reward_address) => { - Ok(csl::Voter::new_constitutional_committee_hot_credential( - &csl::RewardAddress::from_address(&csl::Address::from_bech32(&reward_address)?) - .unwrap() - .payment_cred(), - )) - } + Voter::ConstitutionalCommitteeHotCred(cred) => match cred { + Credential::KeyHash(key_hash) => { + Ok(csl::Voter::new_constitutional_committee_hot_credential( + &csl::Credential::from_keyhash(&csl::Ed25519KeyHash::from_hex(&key_hash)?), + )) + } + Credential::ScriptHash(script_hash) => { + Ok(csl::Voter::new_constitutional_committee_hot_credential( + &csl::Credential::from_scripthash(&csl::ScriptHash::from_hex(&script_hash)?), + )) + } + }, Voter::DRepId(drep_id) => { let drep = csl::DRep::from_bech32(&drep_id).unwrap(); let drep_credential = if drep.to_script_hash().is_some() { diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/credential.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/credential.rs new file mode 100644 index 0000000..1ff62e6 --- /dev/null +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/credential.rs @@ -0,0 +1,8 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum Credential { + ScriptHash(String), + KeyHash(String), +} diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs index 0eee3d2..22c44b7 100644 --- a/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/mod.rs @@ -1,4 +1,5 @@ mod certificate; +mod credential; mod datum; mod metadata; mod mint; @@ -14,6 +15,7 @@ mod vote; mod withdrawal; pub use certificate::*; +pub use credential::*; pub use datum::*; pub use metadata::*; pub use mint::*; diff --git a/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs b/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs index a59cfb1..43cb025 100644 --- a/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs +++ b/packages/sidan-csl-rs/src/model/tx_builder_types/vote.rs @@ -1,6 +1,6 @@ use serde::{Deserialize, Serialize}; -use super::{Anchor, Redeemer, RefTxIn, ScriptSource, SimpleScriptSource}; +use super::{Anchor, Credential, Redeemer, RefTxIn, ScriptSource, SimpleScriptSource}; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] @@ -36,7 +36,7 @@ pub struct VoteType { #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] pub enum Voter { - ConstitutionalCommitteeHotAddress(String), + ConstitutionalCommitteeHotCred(Credential), DRepId(String), StakingPoolKeyHash(String), } From 8f63701cbafe1e56c8919a8c608ed10179cc84ef Mon Sep 17 00:00:00 2001 From: twwu123 Date: Mon, 7 Oct 2024 21:05:23 +0800 Subject: [PATCH 4/5] bump version --- packages/Cargo.lock | 6 +++--- packages/Cargo.toml | 2 +- packages/sidan-csl-rs/Cargo.toml | 2 +- packages/whisky-examples/Cargo.toml | 4 ++-- packages/whisky/Cargo.toml | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/Cargo.lock b/packages/Cargo.lock index a53c41e..a2a42ba 100644 --- a/packages/Cargo.lock +++ b/packages/Cargo.lock @@ -2644,7 +2644,7 @@ dependencies = [ [[package]] name = "sidan-csl-rs" -version = "0.8.6" +version = "0.8.7" dependencies = [ "cardano-serialization-lib", "cryptoxide", @@ -3258,7 +3258,7 @@ dependencies = [ [[package]] name = "whisky" -version = "0.8.6" +version = "0.8.7" dependencies = [ "async-trait", "cryptoxide", @@ -3283,7 +3283,7 @@ dependencies = [ [[package]] name = "whisky-examples" -version = "0.8.6" +version = "0.8.7" dependencies = [ "actix-cors", "actix-web", diff --git a/packages/Cargo.toml b/packages/Cargo.toml index c978ccb..5d4fe3a 100644 --- a/packages/Cargo.toml +++ b/packages/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -version = "0.8.6" +version = "0.8.7" resolver = "2" members = [ "sidan-csl-rs", diff --git a/packages/sidan-csl-rs/Cargo.toml b/packages/sidan-csl-rs/Cargo.toml index 97dbb61..af000e4 100644 --- a/packages/sidan-csl-rs/Cargo.toml +++ b/packages/sidan-csl-rs/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sidan-csl-rs" -version = "0.8.6" +version = "0.8.7" edition = "2021" license = "Apache-2.0" description = "Wrapper around the cardano-serialization-lib for easier transaction building, heavily inspired by cardano-cli APIs" diff --git a/packages/whisky-examples/Cargo.toml b/packages/whisky-examples/Cargo.toml index cbb8e2b..358d62c 100644 --- a/packages/whisky-examples/Cargo.toml +++ b/packages/whisky-examples/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whisky-examples" -version = "0.8.6" +version = "0.8.7" edition = "2021" license = "Apache-2.0" description = "The Cardano Rust SDK, inspired by MeshJS" @@ -13,4 +13,4 @@ path = "src/server.rs" actix-cors = "0.7.0" actix-web = "4.9.0" serde = "1.0.209" -whisky = { version = "=0.8.6", path = "../whisky" } +whisky = { version = "=0.8.7", path = "../whisky" } diff --git a/packages/whisky/Cargo.toml b/packages/whisky/Cargo.toml index 456470f..7fb4a83 100644 --- a/packages/whisky/Cargo.toml +++ b/packages/whisky/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "whisky" -version = "0.8.6" +version = "0.8.7" edition = "2021" license = "Apache-2.0" description = "The Cardano Rust SDK, inspired by MeshJS" @@ -24,7 +24,7 @@ pallas-codec = { version = "0.30.1", features = ["num-bigint"] } pallas-primitives = "0.30.1" pallas-traverse = "0.30.1" maestro-rust-sdk = "1.1.3" -sidan-csl-rs = { version = "=0.8.6", path = "../sidan-csl-rs" } +sidan-csl-rs = { version = "=0.8.7", path = "../sidan-csl-rs" } reqwest = "0.12.5" tokio = { version = "1.38.0", features = ["macros", "rt-multi-thread"] } From 98db61e8f1d43c20b77cc13ce9dbeb7a7bf14663 Mon Sep 17 00:00:00 2001 From: twwu123 Date: Mon, 7 Oct 2024 21:22:07 +0800 Subject: [PATCH 5/5] add minimal test for cc vote --- packages/whisky/tests/integration_tests.rs | 41 +++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/whisky/tests/integration_tests.rs b/packages/whisky/tests/integration_tests.rs index 7be7b54..6925e2a 100644 --- a/packages/whisky/tests/integration_tests.rs +++ b/packages/whisky/tests/integration_tests.rs @@ -6,7 +6,7 @@ mod int_tests { }; use whisky::{ builder::{ TxBuilder, TxBuilderParam, WData::{self, JSON}, WRedeemer}, - core::utils::merge_vkey_witnesses_to_transaction, model::{Anchor, DRep, RefTxIn, VoteKind, Voter, VotingProcedure}, + core::utils::merge_vkey_witnesses_to_transaction, model::{Anchor, Credential, DRep, RefTxIn, VoteKind, Voter, VotingProcedure}, }; #[test] @@ -523,6 +523,7 @@ mod int_tests { .unwrap(); println!("{}", unsigned_tx); + assert!(mesh.core.mesh_csl.tx_hex != *""); } #[test] @@ -550,6 +551,7 @@ mod int_tests { .unwrap(); println!("{}", unsigned_tx); + assert!(mesh.core.mesh_csl.tx_hex != *""); } #[test] @@ -585,5 +587,42 @@ mod int_tests { .unwrap(); println!("{}", unsigned_tx); + assert!(mesh.core.mesh_csl.tx_hex != *""); + } + + #[test] + fn test_cc_vote() { + let mut mesh = TxBuilder::new(TxBuilderParam { + evaluator: None, + fetcher: None, + submitter: None, + params: None, + }); + + let unsigned_tx = mesh + .change_address("addr_test1qpsmz8q2xj43wg597pnpp0ffnlvr8fpfydff0wcsyzqyrxguk5v6wzdvfjyy8q5ysrh8wdxg9h0u4ncse4cxhd7qhqjqk8pse6") + .tx_in( + "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85", + 3, + &[Asset::new_from_str("lovelace", "9891607895")], + "addr_test1vru4e2un2tq50q4rv6qzk7t8w34gjdtw3y2uzuqxzj0ldrqqactxh", + ) + .vote(&Voter::ConstitutionalCommitteeHotCred(Credential::KeyHash("e3a4c41d67592a1b8d87c62e5c5d73f7e8db836171945412d13f40f8".to_string())), &RefTxIn { + tx_hash: "2cb57168ee66b68bd04a0d595060b546edf30c04ae1031b883c9ac797967dd85".to_string(), + tx_index: 2 + }, &VotingProcedure { + vote_kind: VoteKind::Abstain, + anchor: Some(Anchor { + anchor_url: "https://raw.githubusercontent.com/HinsonSIDAN/cardano-drep/main/HinsonSIDAN.jsonld".to_string(), + anchor_data_hash: "2aef51273a566e529a2d5958d981d7f0b3c7224fc2853b6c4922e019657b5060".to_string() + }) + }) + .complete_sync(None) + .unwrap() + .complete_signing() + .unwrap(); + + println!("{}", unsigned_tx); + assert!(mesh.core.mesh_csl.tx_hex != *""); } }