Skip to content

Commit 3da3857

Browse files
MESH-2262 - Add initiate_corporate_action_and_ballot (#1797)
* Add initiate_corporate_action_and_ballot * Update chain metadata. --------- Co-authored-by: Robert G. Jakabosky <rjakabosky+neopallium@neoawareness.com>
1 parent 90087f5 commit 3da3857

File tree

5 files changed

+117
-45
lines changed

5 files changed

+117
-45
lines changed
1.01 KB
Binary file not shown.
1.01 KB
Binary file not shown.
1.01 KB
Binary file not shown.

pallets/corporate-actions/src/ballot/mod.rs

Lines changed: 60 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ pub struct BallotMeta {
160160
}
161161

162162
impl BallotMeta {
163-
fn saturating_num_choices(&self) -> u32 {
163+
pub(crate) fn saturating_num_choices(&self) -> u32 {
164164
self.motions
165165
.iter()
166166
.fold(0, |a, m| a.saturating_add(m.choices.len() as u32))
@@ -399,37 +399,14 @@ pub mod pallet {
399399
meta: BallotMeta,
400400
rcv: bool,
401401
) -> DispatchResult {
402-
// Ensure origin is a permissioned agent, that `ca_id` exists, that its a notice, and the date invariant.
403-
let agent = <ExternalAgents<T>>::ensure_perms(origin, ca_id.asset_id)?;
404-
let ca = <CA<T>>::ensure_ca_exists(ca_id)?;
405-
ensure!(
406-
matches!(ca.kind, CAKind::IssuerNotice),
407-
Error::<T>::CANotNotice
408-
);
409-
Self::ensure_range_invariant(&ca, range)?;
410-
411-
// Ensure CA doesn't have a ballot yet.
412-
ensure!(
413-
!TimeRanges::<T>::contains_key(ca_id),
414-
Error::<T>::AlreadyExists
415-
);
416-
417-
// Compute number-of-choices-in-motion cache.
418-
let choices = Self::derive_motion_num_choices(&meta.motions)?;
419-
Self::ensure_meta_lengths_limited(&meta)?;
402+
// Ensure that the caller is a permissioned agent
403+
let caller_did = ExternalAgents::<T>::ensure_perms(origin, ca_id.asset_id)?;
420404

421-
// Charge protocol fee.
422-
T::ProtocolFee::charge_fee(ProtocolOp::CorporateBallotAttachBallot)?;
405+
let motion_choices = Self::validate_ballot_creation_rules(ca_id, range, &meta)?;
423406

424-
// Commit to storage.
425-
MotionNumChoices::<T>::insert(ca_id, choices);
426-
TimeRanges::<T>::insert(ca_id, range);
427-
Metas::<T>::insert(ca_id, meta.clone());
428-
RCV::<T>::insert(ca_id, rcv);
407+
Self::unverified_create_ballot(caller_did, ca_id, motion_choices, range, meta, rcv)?;
429408

430-
// Emit event.
431-
Self::deposit_event(Event::Created(agent, ca_id, range, meta, rcv));
432-
Ok(().into())
409+
Ok(())
433410
}
434411

435412
/// Cast `votes` in the ballot attached to the CA identified by `ca_id`.
@@ -719,6 +696,60 @@ pub mod pallet {
719696
}
720697

721698
impl<T: Config> Pallet<T> {
699+
/// Returns the number-of-choices-in-motion if all rules for creating a ballot are satisfied. Otherwise, an error.
700+
pub(crate) fn validate_ballot_creation_rules(
701+
ca_id: CAId,
702+
ballot_time_range: BallotTimeRange,
703+
ballot_meta: &BallotMeta,
704+
) -> Result<Vec<u16>, DispatchError> {
705+
let corporate_action = CA::<T>::ensure_ca_exists(ca_id)?;
706+
707+
ensure!(
708+
corporate_action.kind == CAKind::IssuerNotice,
709+
Error::<T>::CANotNotice
710+
);
711+
712+
Self::ensure_range_invariant(&corporate_action, ballot_time_range)?;
713+
714+
// Ensure CA doesn't have a ballot yet
715+
ensure!(
716+
!TimeRanges::<T>::contains_key(ca_id),
717+
Error::<T>::AlreadyExists
718+
);
719+
720+
let motion_choices = Self::derive_motion_num_choices(&ballot_meta.motions)?;
721+
Self::ensure_meta_lengths_limited(ballot_meta)?;
722+
723+
Ok(motion_choices)
724+
}
725+
726+
/// Charges the protocol fee and creates a ballot.
727+
pub(crate) fn unverified_create_ballot(
728+
caller_id: IdentityId,
729+
ca_id: CAId,
730+
motion_choices: Vec<u16>,
731+
ballot_time_range: BallotTimeRange,
732+
ballot_meta: BallotMeta,
733+
rcv: bool,
734+
) -> DispatchResult {
735+
T::ProtocolFee::charge_fee(ProtocolOp::CorporateBallotAttachBallot)?;
736+
737+
MotionNumChoices::<T>::insert(ca_id, motion_choices);
738+
TimeRanges::<T>::insert(ca_id, ballot_time_range);
739+
Metas::<T>::insert(ca_id, ballot_meta.clone());
740+
RCV::<T>::insert(ca_id, rcv);
741+
742+
Self::deposit_event(Event::Created(
743+
caller_id,
744+
ca_id,
745+
ballot_time_range,
746+
ballot_meta,
747+
rcv,
748+
));
749+
750+
Ok(())
751+
}
752+
722753
/// Ensure the ballot hasn't started and remove it.
723754
pub(crate) fn remove_ballot_base(
724755
agent: EventDid,

pallets/corporate-actions/src/lib.rs

Lines changed: 57 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,30 +91,28 @@ pub mod benchmarking;
9191
pub mod ballot;
9292
pub mod distribution;
9393

94-
use ballot::TimeRanges;
9594
use codec::{Decode, Encode, MaxEncodedLen};
96-
use distribution::{Distributions, WeightInfo as DistWeightInfoTrait};
97-
use frame_support::{
98-
dispatch::{DispatchError, DispatchResult},
99-
ensure,
100-
traits::Get,
101-
weights::Weight,
102-
};
95+
use frame_support::dispatch::{DispatchError, DispatchResult};
96+
use frame_support::ensure;
97+
use frame_support::traits::Get;
98+
use frame_support::weights::Weight;
10399
use frame_system::ensure_root;
100+
use scale_info::TypeInfo;
101+
use sp_arithmetic::Permill;
102+
use sp_std::prelude::*;
103+
104104
use pallet_asset::checkpoint::{SchedulePoints, Timestamps};
105105
use pallet_asset::{checkpoint, BalanceOf};
106106
use pallet_base::try_next_post;
107107
use pallet_identity::{Config as IdentityConfig, PermissionedCallOriginData};
108108
use polymesh_common_utilities::checkpoint::ScheduleId;
109-
use polymesh_primitives::asset::AssetId;
110-
use polymesh_primitives::{
111-
asset::CheckpointId, impl_checked_inc, storage_migration_ver, Balance, DocumentId, EventDid,
112-
IdentityId, Moment, PortfolioNumber, GC_DID,
113-
};
109+
use polymesh_primitives::asset::{AssetId, CheckpointId};
110+
use polymesh_primitives::{impl_checked_inc, storage_migration_ver, Balance, DocumentId};
111+
use polymesh_primitives::{EventDid, IdentityId, Moment, PortfolioNumber, GC_DID};
114112
use polymesh_primitives_derive::VecU8StrongTyped;
115-
use scale_info::TypeInfo;
116-
use sp_arithmetic::Permill;
117-
use sp_std::prelude::*;
113+
114+
use ballot::{BallotMeta, BallotTimeRange, TimeRanges, WeightInfo as BallotWeightInfo};
115+
use distribution::{Distributions, WeightInfo as DistWeightInfoTrait};
118116

119117
storage_migration_ver!(1);
120118

@@ -913,6 +911,49 @@ pub mod pallet {
913911

914912
Ok(())
915913
}
914+
915+
#[pallet::weight(initiate_corporate_action_weight::<T>(&ca_args.targets, &ca_args.withholding_tax)
916+
.saturating_add(<T as Config>::BallotWeightInfo::attach_ballot(ballot_meta.saturating_num_choices())))]
917+
#[pallet::call_index(9)]
918+
pub fn initiate_corporate_action_and_ballot(
919+
origin: OriginFor<T>,
920+
ca_args: InitiateCorporateActionArgs,
921+
ballot_time_range: BallotTimeRange,
922+
ballot_meta: BallotMeta,
923+
rcv: bool,
924+
) -> DispatchResult {
925+
// Ensure that the caller is a permissioned agent
926+
let caller_did = ExternalAgents::<T>::ensure_perms(origin, ca_args.asset_id)?;
927+
928+
let ca_id = Self::unsafe_initiate_corporate_action(
929+
caller_did,
930+
ca_args.asset_id,
931+
ca_args.kind,
932+
ca_args.decl_date,
933+
ca_args.record_date,
934+
ca_args.details,
935+
ca_args.targets,
936+
ca_args.default_withholding_tax,
937+
ca_args.withholding_tax,
938+
)?;
939+
940+
let motion_choices = ballot::Pallet::<T>::validate_ballot_creation_rules(
941+
ca_id,
942+
ballot_time_range,
943+
&ballot_meta,
944+
)?;
945+
946+
ballot::Pallet::<T>::unverified_create_ballot(
947+
caller_did,
948+
ca_id,
949+
motion_choices,
950+
ballot_time_range,
951+
ballot_meta,
952+
rcv,
953+
)?;
954+
955+
Ok(())
956+
}
916957
}
917958

918959
#[pallet::event]

0 commit comments

Comments
 (0)