Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .metadata/polymesh_dev/7002000.meta
Binary file not shown.
Binary file modified .metadata/polymesh_mainnet/7002000.meta
Binary file not shown.
Binary file modified .metadata/polymesh_testnet/7002000.meta
Binary file not shown.
89 changes: 60 additions & 29 deletions pallets/corporate-actions/src/ballot/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ pub struct BallotMeta {
}

impl BallotMeta {
fn saturating_num_choices(&self) -> u32 {
pub(crate) fn saturating_num_choices(&self) -> u32 {
self.motions
.iter()
.fold(0, |a, m| a.saturating_add(m.choices.len() as u32))
Expand Down Expand Up @@ -399,37 +399,14 @@ pub mod pallet {
meta: BallotMeta,
rcv: bool,
) -> DispatchResult {
// Ensure origin is a permissioned agent, that `ca_id` exists, that its a notice, and the date invariant.
let agent = <ExternalAgents<T>>::ensure_perms(origin, ca_id.asset_id)?;
let ca = <CA<T>>::ensure_ca_exists(ca_id)?;
ensure!(
matches!(ca.kind, CAKind::IssuerNotice),
Error::<T>::CANotNotice
);
Self::ensure_range_invariant(&ca, range)?;

// Ensure CA doesn't have a ballot yet.
ensure!(
!TimeRanges::<T>::contains_key(ca_id),
Error::<T>::AlreadyExists
);

// Compute number-of-choices-in-motion cache.
let choices = Self::derive_motion_num_choices(&meta.motions)?;
Self::ensure_meta_lengths_limited(&meta)?;
// Ensure that the caller is a permissioned agent
let caller_did = ExternalAgents::<T>::ensure_perms(origin, ca_id.asset_id)?;

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

// Commit to storage.
MotionNumChoices::<T>::insert(ca_id, choices);
TimeRanges::<T>::insert(ca_id, range);
Metas::<T>::insert(ca_id, meta.clone());
RCV::<T>::insert(ca_id, rcv);
Self::unverified_create_ballot(caller_did, ca_id, motion_choices, range, meta, rcv)?;

// Emit event.
Self::deposit_event(Event::Created(agent, ca_id, range, meta, rcv));
Ok(().into())
Ok(())
}

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

impl<T: Config> Pallet<T> {
/// Returns the number-of-choices-in-motion if all rules for creating a ballot are satisfied. Otherwise, an error.
pub(crate) fn validate_ballot_creation_rules(
ca_id: CAId,
ballot_time_range: BallotTimeRange,
ballot_meta: &BallotMeta,
) -> Result<Vec<u16>, DispatchError> {
let corporate_action = CA::<T>::ensure_ca_exists(ca_id)?;

ensure!(
corporate_action.kind == CAKind::IssuerNotice,
Error::<T>::CANotNotice
);

Self::ensure_range_invariant(&corporate_action, ballot_time_range)?;

// Ensure CA doesn't have a ballot yet
ensure!(
!TimeRanges::<T>::contains_key(ca_id),
Error::<T>::AlreadyExists
);

let motion_choices = Self::derive_motion_num_choices(&ballot_meta.motions)?;
Self::ensure_meta_lengths_limited(ballot_meta)?;

Ok(motion_choices)
}

/// Charges the protocol fee and creates a ballot.
pub(crate) fn unverified_create_ballot(
caller_id: IdentityId,
ca_id: CAId,
motion_choices: Vec<u16>,
ballot_time_range: BallotTimeRange,
ballot_meta: BallotMeta,
rcv: bool,
) -> DispatchResult {
T::ProtocolFee::charge_fee(ProtocolOp::CorporateBallotAttachBallot)?;

MotionNumChoices::<T>::insert(ca_id, motion_choices);
TimeRanges::<T>::insert(ca_id, ballot_time_range);
Metas::<T>::insert(ca_id, ballot_meta.clone());
RCV::<T>::insert(ca_id, rcv);

Self::deposit_event(Event::Created(
caller_id,
ca_id,
ballot_time_range,
ballot_meta,
rcv,
));

Ok(())
}

/// Ensure the ballot hasn't started and remove it.
pub(crate) fn remove_ballot_base(
agent: EventDid,
Expand Down
73 changes: 57 additions & 16 deletions pallets/corporate-actions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,30 +91,28 @@ pub mod benchmarking;
pub mod ballot;
pub mod distribution;

use ballot::TimeRanges;
use codec::{Decode, Encode, MaxEncodedLen};
use distribution::{Distributions, WeightInfo as DistWeightInfoTrait};
use frame_support::{
dispatch::{DispatchError, DispatchResult},
ensure,
traits::Get,
weights::Weight,
};
use frame_support::dispatch::{DispatchError, DispatchResult};
use frame_support::ensure;
use frame_support::traits::Get;
use frame_support::weights::Weight;
use frame_system::ensure_root;
use scale_info::TypeInfo;
use sp_arithmetic::Permill;
use sp_std::prelude::*;

use pallet_asset::checkpoint::{SchedulePoints, Timestamps};
use pallet_asset::{checkpoint, BalanceOf};
use pallet_base::try_next_post;
use pallet_identity::{Config as IdentityConfig, PermissionedCallOriginData};
use polymesh_common_utilities::checkpoint::ScheduleId;
use polymesh_primitives::asset::AssetId;
use polymesh_primitives::{
asset::CheckpointId, impl_checked_inc, storage_migration_ver, Balance, DocumentId, EventDid,
IdentityId, Moment, PortfolioNumber, GC_DID,
};
use polymesh_primitives::asset::{AssetId, CheckpointId};
use polymesh_primitives::{impl_checked_inc, storage_migration_ver, Balance, DocumentId};
use polymesh_primitives::{EventDid, IdentityId, Moment, PortfolioNumber, GC_DID};
use polymesh_primitives_derive::VecU8StrongTyped;
use scale_info::TypeInfo;
use sp_arithmetic::Permill;
use sp_std::prelude::*;

use ballot::{BallotMeta, BallotTimeRange, TimeRanges, WeightInfo as BallotWeightInfo};
use distribution::{Distributions, WeightInfo as DistWeightInfoTrait};

storage_migration_ver!(1);

Expand Down Expand Up @@ -913,6 +911,49 @@ pub mod pallet {

Ok(())
}

#[pallet::weight(initiate_corporate_action_weight::<T>(&ca_args.targets, &ca_args.withholding_tax)
.saturating_add(<T as Config>::BallotWeightInfo::attach_ballot(ballot_meta.saturating_num_choices())))]
#[pallet::call_index(9)]
pub fn initiate_corporate_action_and_ballot(
origin: OriginFor<T>,
ca_args: InitiateCorporateActionArgs,
ballot_time_range: BallotTimeRange,
ballot_meta: BallotMeta,
rcv: bool,
) -> DispatchResult {
// Ensure that the caller is a permissioned agent
let caller_did = ExternalAgents::<T>::ensure_perms(origin, ca_args.asset_id)?;

let ca_id = Self::unsafe_initiate_corporate_action(
caller_did,
ca_args.asset_id,
ca_args.kind,
ca_args.decl_date,
ca_args.record_date,
ca_args.details,
ca_args.targets,
ca_args.default_withholding_tax,
ca_args.withholding_tax,
)?;

let motion_choices = ballot::Pallet::<T>::validate_ballot_creation_rules(
ca_id,
ballot_time_range,
&ballot_meta,
)?;

ballot::Pallet::<T>::unverified_create_ballot(
caller_did,
ca_id,
motion_choices,
ballot_time_range,
ballot_meta,
rcv,
)?;

Ok(())
}
}

#[pallet::event]
Expand Down