Hypothesis-like property testing for Rust
Implementation of https://github.com/rust-lang/rfcs/pull/2173 in stable rust
Rewrite of Mozilla Labs Prospector Oneliner 2 with Addons SDK
Initial push of Framework + Model + input processors.
Centril/android-numberpicker 1
A backport of the Android 4.2 NumberPicker
small utility scripts, mostly git related.
Next gen rfcbot
Centril/android-project-template 0
template project for android.
Are we async yet?
Pull request review commentPolymathNetwork/Polymesh
MESH-1234: Allow GC to issue & revoke a CDD claim
decl_module! { } } + /// Assuming this is executed by the GC voting majority, adds a new cdd claim record.+ #[weight = 950_000_000]+ pub fn gc_add_cdd_claim(+ origin,+ target: IdentityId,+ expiry: Option<T::Moment>,+ ) -> DispatchResult {+ T::GCVotingMajorityOrigin::ensure_origin(origin)?;+ Self::base_add_cdd_claim(target, Claim::CustomerDueDiligence([0; 32].into()), GC_DID, expiry)
I've applied your suggestion; thanks for the tip!
comment created time in 4 hours
push eventPolymathNetwork/Polymesh
commit sha 5912d624144eecfbf125695146c21faea6305e70
mesh-1234: allow GC to issue CDD claim
push time in 4 hours
Pull request review commentPolymathNetwork/Polymesh
MESH-1281 (Pips expiry) & MESH-1266 (Test warnings)
pub struct PolymeshVotes<IdentityId, BlockNumber> { pub nays: Vec<IdentityId>, /// The hard end time of this vote. pub end: BlockNumber,+ /// The time **at** which the proposal is expired.+ pub expiry: Option<BlockNumber>, } +// Fool `decl_storage!` below into not strip the `Option` in the genesis config.+use Option as Maybe;
Converted to enum MaybeBlock { ... }
comment created time in 6 hours
push eventPolymathNetwork/Polymesh
commit sha fa72c14acb9bb8a634688b6e3642b0d25f2c63bb
Maybe -> enum MaybeBlock
push time in 6 hours
Pull request review commentPolymathNetwork/Polymesh
MESH-1281 (Pips expiry) & MESH-1266 (Test warnings)
decl_module! { let did = Context::current_identity_or::<Identity<T>>(&who)?; let voting = Self::voting(&proposal).ok_or(Error::<T, I>::NoSuchProposal)?;++ // Ensure proposal hasn't expired. If it has, prune the proposal and bail.+ let now = system::Module::<T>::block_number();+ Self::ensure_not_expired(&proposal, voting.expiry, now)?;+ // POLYMESH-NOTE- Change specific to Polymesh ensure!(T::MotionDuration::get() > Zero::zero(), Error::<T, I>::NotAllowed); ensure!(voting.index == index, Error::<T, I>::MismatchedVotingIndex);- ensure!(system::Module::<T>::block_number() >= voting.end, Error::<T, I>::TooEarly);+ ensure!(now >= voting.end, Error::<T, I>::TooEarly);
Renamed
comment created time in 8 hours
push eventPolymathNetwork/Polymesh
commit sha 0fb06bc4c4f3bf197a0f1a727c1070a83d679dd7
committee: TooEarly -> CloseBeforeVoteEnd
push time in 8 hours
push eventPolymathNetwork/Polymesh
commit sha 4812dff0465931ea016004ca8770cdf77f8f5906
MESH-1255/Staking: Pull in some substrate-rc6 changes (#613) * mesh-1255: copy-in staking/fuzzer * mesh-1255: copy-in staking/reward-curve * mesh-1255: un-copy 'reward-curve' crate * mesh-1255: copy-in staking/src Co-authored-by: Satyam Agrawal <[email protected]>
commit sha 8500cbb47915c42e7e2dbf7b92cb05b6e575fcf6
mesh-1255/transaction-payment: bring in some rc6 changes (#624) Co-authored-by: poly-auto-merge[bot] <65769705+poly-auto-merge[bot]@users.noreply.github.com>
commit sha 7b7ae562f269658d866f54aea5124097898e48ba
mesh-1255/balances: pull in substrate rc6 changes (#627) Co-authored-by: Satyam Agrawal <[email protected]>
commit sha 1d80a3c9391673bc90e27182024e2bf8c1682407
Mesh 1079/permission type (#489) * SigningItem renamed to SigningKey * fn name fix * fmt * signing_item.rs -> signing_key.rs * changed permissions to have a structure of 3 subsets * UT fixes * more UT fixes * schema and UT corrections * UT fixes * corrected initial permissions * undone making Debug std-only * review comments * typo fix and a few more test cases * fix for the fix * fmt and review comment * replaced LinkedKeyInfo with IdentityId in the map of primary keys * secondary key linkage * typo and format fixes * separate maps for storing account and identity key links * identifier name updates * fixed failing identity test * commented out a failing test * renamed account to identity map in JS * removed the identity secondary key mapping * removed the Option type from the key to identity map * removed LinkedKeyInfo schema definition * permissions pallet * ensure_permissions * calling ensure_permissions instead of ensure_signed * rewrote the permissions pallet without origin * calling ensure_call_permissions in every identity extrinsic * defined the call permission check in identity pallet * removed is_signer_authorized_with_permissions and has_permissions * fmt * fixed unit test and added permission check in testnet-v1 * PermissionChecker impl in unit tests * extrinsic check fix * debugging fee_details * minor test fix * removed debug code and corrected auth_id in fee_details test * using get_last_auth_id in multisig tests * applied get_next_auth_id where possible * fixed the frozen secondary keys issue * WIP on tests * implemented empty permissions by default * WIP on multisig tests * cleaned up permission checks in multisig * WIP on balances tests * asset and basic-sto extrinsic permissions * permission checks in pallets * added a utility function for a common permission check usecase * cleanup and using ensure_origin_call_permissions utility function * corrected Permissions after merge * redefined the subset type as a newtype for polkadot js compatibility * API permission types * lint and test fixes * added an API type for SecondaryKey * UT fixes * schema workarounds * generalised iterator parameter types * identity runtime upgrade * runtime upgrade * runtime upgrade fixups * use the trait type parameter name * removed unused variable * TODO about migrate_from * todo * named self * derived Migrate for Identity * migrate from Vec<Permission> to Permissions * review comments * schema update * schema fix * aggregating both primary and secondary identities in permission checks * portfolio permission check template * compute secondary keys during the call permission check * portfolio permissions are checked * test fix * test fix * restricted unknown CLI test errors to types only * fixing submodule removal * readded settlement pallet * removed duplicate module path * removed more duplicate module paths * fixed cargo errors * merge fixes * test import fixes * fixed asset test * batch call metadata WIP * set batched and relayed call metadata * set multisig and forwarded identity call metadata * removed old LinkedKeyInfo field access from CLI tests * updated secondary key creation in CLI tests * cleanup * CLI total permissions fix * fixed CLI test 4_permission_management * fixed settlement CLI tests Co-authored-by: Adam Dossa <[email protected]> Co-authored-by: Mudit Gupta <[email protected]>
commit sha 2efd6dbc58cdf1411ffaa60aa4ad1b28c8e67acb
Use vector in settlement extrinsics (#629) * use vector in extrinsics * fixed tests Co-authored-by: poly-auto-merge[bot] <65769705+poly-auto-merge[bot]@users.noreply.github.com>
commit sha 97ee18e0527fb53dc84bf5de4671d7b3d377612b
Update polymesh_schema.json
commit sha dd151534c247cb5d578b6a22af6c3e6e85b2e9bb
pips + committee: prepare storage wrt. expiry
commit sha e0b258e849bd050a16451ae967aac46df84b5221
drive-by: cleanup warnings in tests
commit sha ea9e5a6f0bc501027ced3f96a4cf5e50f183e700
pips: implement expiry scheduling
commit sha b81f53f247eba51f53bff49df6491dd02c6c2034
committee: implement expiry
commit sha 6cc66c3ce63eec0c734b51bcfd393e7c52fa14c9
cleanup more warnings
push time in 8 hours
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
decl_module! { ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio); let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset); + ensure!(tiers.len() > 0, Error::<T>::InvalidPriceTiers);+ ensure!(tiers.iter().all(|t| t.total > 0.into()), Error::<T>::InvalidPriceTiers);
ensure!(
tiers.len() > 0 && tiers.iter().all(|t| t.total > 0.into()),
Error::<T>::InvalidPriceTiers
);
comment created time in 9 hours
push eventPolymathNetwork/Polymesh
commit sha 133e130d4a66f6a06dd88244d17eb9fe03766379
Clarify note re. `Committee::vote_or_propose`. Co-authored-by: Satyam Agrawal <[email protected]>
push time in 3 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1281 (Pips expiry) & MESH-1266 (Test warnings)
impl<T: Trait<I>, I: Instance> Module<T, I> { /// Accepts or rejects the proposal if its threshold is satisfied. fn check_proposal_threshold(proposal: T::Hash) { if let Some(voting) = Self::voting(&proposal) {+ // Make sure we don't have an expired proposal at this point.+ if let Err(_) = Self::ensure_not_expired(+ &proposal,+ voting.expiry,+ system::Module::<T>::block_number(),+ ) {
Sure, but I don't think that makes anything clearer. Direct pattern matching both highlights the pattern as is more efficient to compile (no inlining necessary on LLVM's part).
comment created time in 3 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);
Seems like something we can & should implement? Open-coding this fold everytime seems suboptimal.
comment created time in 4 days
push eventPolymathNetwork/Polymesh
commit sha 2c02a3ed85814c5a10203fd7d92ddda25dfcf014
committee: implement expiry
push time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { <RevokeOffChainAuthorization<T>>::insert((signer, auth), true); Ok(()) }++ /// Add `Claim::InvestorUniqueness` claim for a given target identity.+ ///+ /// # <weight>+ /// Weight of the this extrinsic is depend on the computation that used to validate+ /// the proof of claim and that will be constant and not depend on the user inputs.+ /// # </weight>+ ///+ /// # Arguments+ /// * origin - Who provides the claim to the user, In this case user's account id as user provide+ /// this claim to itself.+ /// * target - IdentityId whom claim get assigned.+ /// * claim - `InvestorUniqueness` claim details.+ /// * proof - To validate the self attestation.+ /// * expiry - Expiry of claim.+ ///+ /// # Errors+ /// * `DidMustAlreadyExist` Target should already been a part of the ecosystem.+ /// * `ClaimVariantNotAllowed` When origin trying to pass claim variant other than `InvestorUniqueness`.+ /// * `ConfidentialScopeClaimNotAllowed` When issuer is different from target or CDD_ID is invalid for given user.+ /// * `InvalidScopeClaim1 When proof is invalid.+ #[weight = 7_500_000_000]+ pub fn add_investor_uniqueness_claim(origin, target: IdentityId, claim: Claim, proof: InvestorZKProofData, expiry: Option<T::Moment>) -> DispatchResult {+ // Validate whether the origin is signed or not. Also validate whether the given IdentityId (i.e target) has+ // already been in the system or not.+ let issuer = Self::ensure_signer_and_validate_claim_target(origin, target)?;++ // Validate proof and add claim only when the claim variant is `InvestorUniqueness` only+ // otherwise throw and error.+ match &claim {
If there's no else / _ branch then if let reduces 1 level of indentation and lets you omit the _ => ... arm, which improves readability, so I'd say always go for it.
The case for if let ... else is less clear. I usually try both to see which one rustfmt wants to format more nicely (e.g., will the 1 indent level make a difference in terms of keeping everything on one line?) according to my own subjective taste.
However, there's a good case for match and avoiding _ when its critical that you be notified of more variants by compile errors (often used in rustc to avoid surprises at runtime).
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { claim: Claim, expiry: Option<T::Moment>, ) -> DispatchResult {- let sender = ensure_signed(origin)?;- let issuer = Context::current_identity_or::<Self>(&sender)?;- ensure!(<DidRecords<T>>::contains_key(target), Error::<T>::DidMustAlreadyExist);+ // Validate whether the origin is signed or not. Also validate whether the given IdentityId (i.e target) has+ // already been in the system or not.
Doesn't particularly add value to repeat the doc comment on every use imo.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
impl<T: Trait> Module<T> { Self::unlink_key_from_did(&signer, did) } }++ /// Validate whether the origin is signed or not. Also validate whether the given IdentityId (i.e target) has+ /// already been in the system or not.+ fn ensure_signer_and_validate_claim_target(
fn ensure_signed_and_validate_claim_target(
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
impl<T: Trait> Module<T> { Self::unlink_key_from_did(&signer, did) } }++ /// Validate whether the origin is signed or not. Also validate whether the given IdentityId (i.e target) has+ /// already been in the system or not.
/// Ensure that the origin is signed and that the given `target` is already in the system.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
impl Claim { /// Claim type represent the claim without its data. /// /// # TODO-/// - Could we use `std::mem::Discriminat`?+/// - Could we use `std::mem::Discriminant`?
mem::Discriminant is not something you can match on, but PartialEq of two Claims is sufficient, then yes, you can.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
pub enum Claim { Exempted(#[migrate] Scope), /// User is Blocked Blocked(#[migrate] Scope),- /// Confidential Scope claim- InvestorZKProof(#[migrate] Scope, ScopeId, CddId, InvestorZKProofData),+ /// Confidential claim that will allow an investor to justify that it's identity can be+ /// a potential asset holder of given `scope`.+ ///+ /// This claim is mandatory to have for an investor. It will help issuer to apply compliance rules+ /// on the `ScopeId` instead of investor identityId as ScopeId is unique at investor entity level+ /// for a given scope (always be a Ticker).
/// All investors must have this claim, which will help the issuer apply compliance rules
/// on the `ScopeId` instead of the investor's `IdentityId`, as `ScopeId` is unique at the investor entity level
/// for a given scope (will always be a `Ticker`).
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { <RevokeOffChainAuthorization<T>>::insert((signer, auth), true); Ok(()) }++ /// Add `Claim::InvestorUniqueness` claim for a given target identity.+ ///+ /// # <weight>+ /// Weight of the this extrinsic is depend on the computation that used to validate+ /// the proof of claim and that will be constant and not depend on the user inputs.+ /// # </weight>+ ///+ /// # Arguments+ /// * origin - Who provides the claim to the user, In this case user's account id as user provide+ /// this claim to itself.+ /// * target - IdentityId whom claim get assigned.
/// * target - `IdentityId` to which the claim gets assigned.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { <RevokeOffChainAuthorization<T>>::insert((signer, auth), true); Ok(()) }++ /// Add `Claim::InvestorUniqueness` claim for a given target identity.+ ///+ /// # <weight>+ /// Weight of the this extrinsic is depend on the computation that used to validate+ /// the proof of claim and that will be constant and not depend on the user inputs.+ /// # </weight>+ ///+ /// # Arguments+ /// * origin - Who provides the claim to the user, In this case user's account id as user provide+ /// this claim to itself.+ /// * target - IdentityId whom claim get assigned.+ /// * claim - `InvestorUniqueness` claim details.+ /// * proof - To validate the self attestation.+ /// * expiry - Expiry of claim.+ ///+ /// # Errors+ /// * `DidMustAlreadyExist` Target should already been a part of the ecosystem.+ /// * `ClaimVariantNotAllowed` When origin trying to pass claim variant other than `InvestorUniqueness`.+ /// * `ConfidentialScopeClaimNotAllowed` When issuer is different from target or CDD_ID is invalid for given user.+ /// * `InvalidScopeClaim1 When proof is invalid.
/// * `InvalidScopeClaim` When proof is invalid.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { <RevokeOffChainAuthorization<T>>::insert((signer, auth), true); Ok(()) }++ /// Add `Claim::InvestorUniqueness` claim for a given target identity.+ ///+ /// # <weight>+ /// Weight of the this extrinsic is depend on the computation that used to validate+ /// the proof of claim and that will be constant and not depend on the user inputs.+ /// # </weight>+ ///+ /// # Arguments+ /// * origin - Who provides the claim to the user, In this case user's account id as user provide
/// * origin - Who provides the claim to the user? In this case, it's the user's account id as the user provides
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1277/ Add `add_investor_uniqueness_claim()` dispatchable
decl_module! { <RevokeOffChainAuthorization<T>>::insert((signer, auth), true); Ok(()) }++ /// Add `Claim::InvestorUniqueness` claim for a given target identity.+ ///+ /// # <weight>+ /// Weight of the this extrinsic is depend on the computation that used to validate+ /// the proof of claim and that will be constant and not depend on the user inputs.
/// Weight of the this extrinsic is depend on the computation used to validate
/// the proof of claim, which will be a constant independent of user inputs.
comment created time in 4 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);++ ensure!(offering_amount >= asset_balance, Error::<T>::InsufficientTokensRemaining);++ // Sort by price+ tiers.sort_by(|a, b| a.price.cmp(&b.price));++ // TODO: Take custodial ownership of $sell_amount of $offering_token from primary issuance agent?+ let fundraiser_id = Self::fundraiser_count(offering_asset) + 1;+ // TODO revise the defaults+ let fundraiser = Fundraiser {+ offering_portfolio,+ offering_asset,+ raising_asset,+ tiers: tiers.into_iter().map(Into::into).collect(),+ venue_id,+ start: start.unwrap_or(Timestamp::<T>::get()),+ end,+ frozen: false,+ };+ <FundraiserCount>::insert(offering_asset, fundraiser_id);+ <Fundraisers<T>>::insert(+ offering_asset,+ fundraiser_id,+ fundraiser+ );+ Self::deposit_event(+ RawEvent::FundraiserCreated(did, fundraiser)+ );+ Ok(())+ }++ /// Purchase tokens from an ongoing offering.+ #[weight = 2_000_000_000]+ pub fn invest(origin, portfolio: PortfolioId, offering_asset: Ticker, fundraiser_id: u64, offering_token_amount: T::Balance, max_price: T::Balance) -> DispatchResult {+ let sender = ensure_signed(origin.clone())?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;++ ensure!(<Fundraisers<T>>::contains_key(offering_asset, fundraiser_id), Error::<T>::FundraiserNotFound);+ let fundraiser = <Fundraisers<T>>::get(offering_asset, fundraiser_id);
Let's make the map an Option<_> too?
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);++ ensure!(offering_amount >= asset_balance, Error::<T>::InsufficientTokensRemaining);++ // Sort by price+ tiers.sort_by(|a, b| a.price.cmp(&b.price));++ // TODO: Take custodial ownership of $sell_amount of $offering_token from primary issuance agent?+ let fundraiser_id = Self::fundraiser_count(offering_asset) + 1;+ // TODO revise the defaults+ let fundraiser = Fundraiser {+ offering_portfolio,+ offering_asset,+ raising_asset,+ tiers: tiers.into_iter().map(Into::into).collect(),+ venue_id,+ start: start.unwrap_or(Timestamp::<T>::get()),+ end,+ frozen: false,+ };+ <FundraiserCount>::insert(offering_asset, fundraiser_id);+ <Fundraisers<T>>::insert(+ offering_asset,+ fundraiser_id,+ fundraiser+ );+ Self::deposit_event(+ RawEvent::FundraiserCreated(did, fundraiser)+ );+ Ok(())+ }++ /// Purchase tokens from an ongoing offering.
Let's elaborate here too?
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.
If we can elaborate in the documentation re. all the errors and conditions it would be good I think.
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);++ ensure!(offering_amount >= asset_balance, Error::<T>::InsufficientTokensRemaining);++ // Sort by price+ tiers.sort_by(|a, b| a.price.cmp(&b.price));++ // TODO: Take custodial ownership of $sell_amount of $offering_token from primary issuance agent?+ let fundraiser_id = Self::fundraiser_count(offering_asset) + 1;+ // TODO revise the defaults+ let fundraiser = Fundraiser {+ offering_portfolio,+ offering_asset,+ raising_asset,+ tiers: tiers.into_iter().map(Into::into).collect(),+ venue_id,+ start: start.unwrap_or(Timestamp::<T>::get()),+ end,+ frozen: false,+ };+ <FundraiserCount>::insert(offering_asset, fundraiser_id);
FundraiserCount::insert(offering_asset, fundraiser_id);
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);++ ensure!(offering_amount >= asset_balance, Error::<T>::InsufficientTokensRemaining);++ // Sort by price+ tiers.sort_by(|a, b| a.price.cmp(&b.price));
// (Stable) sort by price.
tiers.sort_by_key(|a| a.price);
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);
If we use Option<_> in the map we can make this code nicer too.
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {
Do you get coherence problems if you impl From instead?
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
decl_error! { decl_storage! { trait Store for Module<T: Trait> as StoCapped { /// Info about a venue. venue_id -> venue_details- VenueInfo get(fn venue_info): map hasher(twox_64_concat) u64 => Venue;+ pub VenueInfo get(fn venue_info): map hasher(twox_64_concat) u64 => Venue;
pub VenueInfo get(fn venue_info): map hasher(twox_64_concat) u64 => Option<Venue>;
Will generally make the other code nicer.
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);
let venue = VenueInfo::get(venue_id)
.filter(|v| v.creator == did && v.venue_type == VenueType::Sto)
.ok_or(Error::<T>::InvalidVenue)?;
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,
Let's document these?
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,+}++impl<Balance: From<u8>> Into<FundraiserTier<Balance>> for PriceTier<Balance> {+ fn into(self) -> FundraiserTier<Balance> {+ FundraiserTier {+ inner: self,+ remaining: Balance::from(0),+ }+ }+}++pub trait Trait:+ frame_system::Trait+ + CommonTrait+ + IdentityTrait+ + SettlementTrait+ + TimestampTrait+ + PortfolioTrait+{+ /// The overarching event type.+ type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;+}++decl_event!(+ pub enum Event<T>+ where+ Balance = <T as CommonTrait>::Balance,+ Moment = <T as TimestampTrait>::Moment,+ {+ /// A new fundraiser has been created+ /// (primary issuance agent, fundraiser)+ FundraiserCreated(IdentityId, Fundraiser<Balance, Moment>),+ /// An investor invested in the fundraiser+ /// (offering token, raise token, offering_token_amount, raise_token_amount, fundraiser_id)+ FundsRaised(IdentityId, Ticker, Ticker, Balance, Balance, u64),+ }+);++decl_error! {+ /// Errors for the Settlement module.+ pub enum Error for Module<T: Trait> {+ /// Sender does not have required permissions+ Unauthorized,+ /// An arithmetic operation overflowed+ Overflow,+ /// Not enough tokens left for sale+ InsufficientTokensRemaining,+ /// Fundraiser not found+ FundraiserNotFound,+ /// Fundraiser is frozen+ FundraiserFrozen,+ // Interacting with a fundraiser past the end `Moment`.+ FundraiserExpired,+ // Interacting with a fundraiser before the start `Moment`.+ FundraiserNotStated,+ // Using an invalid venue+ InvalidVenue,+ // Using an invalid portfolio+ InvalidPortfolio,+ }+}++decl_storage! {+ trait Store for Module<T: Trait> as StoCapped {+ /// All fundraisers that are currently running. (ticker, fundraiser_id) -> Fundraiser+ Fundraisers get(fn fundraisers): double_map hasher(blake2_128_concat) Ticker, hasher(twox_64_concat) u64 => Fundraiser<T::Balance, T::Moment>;+ /// Total fundraisers created for a token+ FundraiserCount get(fn fundraiser_count): map hasher(twox_64_concat) Ticker => u64;+ }+}++decl_module! {+ pub struct Module<T: Trait> for enum Call where origin: T::Origin {+ type Error = Error<T>;++ fn deposit_event() = default;++ /// Create a new offering. A fixed amount of pre-minted tokens are put up for sale at the specified tiered rate.+ #[weight = 800_000_000]+ pub fn create_fundraiser(+ origin,+ offering_portfolio: PortfolioId,+ offering_asset: Ticker,+ raising_asset: Ticker,+ tiers: Vec<PriceTier<T::Balance>>,+ venue_id: u64,+ start: Option<T::Moment>,+ end: Option<T::Moment>,+ ) -> DispatchResult {+ let sender = ensure_signed(origin)?;+ let did = Context::current_identity_or::<Identity<T>>(&sender)?;+ ensure!(T::Asset::primary_issuance_agent(&offering_asset) == did, Error::<T>::Unauthorized);++ ensure!(VenueInfo::contains_key(venue_id), Error::<T>::InvalidVenue);+ let venue = VenueInfo::get(venue_id);++ ensure!(venue.creator == did, Error::<T>::InvalidVenue);+ ensure!(venue.venue_type == VenueType::Sto, Error::<T>::InvalidVenue);++ ensure!(offering_portfolio.did == did, Error::<T>::InvalidPortfolio);+ ensure!(<PortfolioAssetBalances<T>>::contains_key(offering_portfolio, offering_asset), Error::<T>::InvalidPortfolio);+ let asset_balance = <PortfolioAssetBalances<T>>::get(offering_portfolio, offering_asset);++ let offering_amount: T::Balance = tiers+ .iter()+ .map(|t| t.amount)+ .fold(0.into(), |x, total| total + x);
.sum();
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
[WIP] MESH-1094/Implement a new PrimaryIssuance pallet which wraps up some of the STO functionality
+// Copyright (c) 2020 Polymath++//! # STO Module+//!+//! This is a proof of concept module. It is not meant to be used in the real world in its' current state.++#![cfg_attr(not(feature = "std"), no_std)]+#![recursion_limit = "256"]++use codec::{Decode, Encode};+use frame_support::{+ decl_error, decl_event, decl_module, decl_storage, dispatch::DispatchResult, ensure,+};+use frame_system::ensure_signed;+use pallet_identity as identity;+use pallet_portfolio::{self as portfolio, PortfolioAssetBalances, Trait as PortfolioTrait};+use pallet_settlement::{+ self as settlement, Leg, SettlementType, Trait as SettlementTrait, VenueInfo, VenueType,+};+use pallet_timestamp::{self as timestamp, Trait as TimestampTrait};+use polymesh_common_utilities::{+ constants::currency::*,+ traits::{asset::Trait as AssetTrait, identity::Trait as IdentityTrait, CommonTrait},+ Context,+};+use polymesh_primitives::{IdentityId, PortfolioId, Ticker};+use sp_runtime::traits::{CheckedAdd, CheckedMul, Saturating};+use sp_std::{collections::btree_set::BTreeSet, iter, prelude::*};++type Identity<T> = identity::Module<T>;+type Settlement<T> = settlement::Module<T>;+type Timestamp<T> = timestamp::Module<T>;++/// Details about the Fundraiser+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct Fundraiser<Balance, Moment> {+ /// Portfolio containing the asset being offered+ pub offering_portfolio: PortfolioId,+ /// Asset being offered+ pub offering_asset: Ticker,+ /// Asset to receive payment in+ pub raising_asset: Ticker,+ /// Tiers of the fundraiser.+ /// Each tier has a set amount of tokens available at a fixed price.+ /// The sum of the tiers is the total amount available in this fundraiser.+ pub tiers: Vec<FundraiserTier<Balance>>,+ /// Id of the venue to use for this fundraise+ pub venue_id: u64,+ /// Start of the fundraiser+ pub start: Moment,+ /// End of the fundraiser+ pub end: Option<Moment>,+ /// Fundraiser is frozen+ pub frozen: bool,+}++/// Single tier of a tiered pricing model+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct PriceTier<Balance> {+ amount: Balance,+ price: Balance,+}++/// Single price tier of a `Fundraiser`.+/// Similar to a `PriceTier` but with an extra field `remaining` for tracking the amount available in a tier.+#[cfg_attr(feature = "std", derive(Debug))]+#[derive(Encode, Decode, Default, Clone, PartialEq, Eq, PartialOrd, Ord)]+pub struct FundraiserTier<Balance> {+ inner: PriceTier<Balance>,+ remaining: Balance,
And these?
comment created time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 4812dff0465931ea016004ca8770cdf77f8f5906
MESH-1255/Staking: Pull in some substrate-rc6 changes (#613) * mesh-1255: copy-in staking/fuzzer * mesh-1255: copy-in staking/reward-curve * mesh-1255: un-copy 'reward-curve' crate * mesh-1255: copy-in staking/src Co-authored-by: Satyam Agrawal <[email protected]>
commit sha 73c1ad2611407b3d48fd47cafc3e193db122fea1
Merge branch 'develop' into mesh-1255-tx-pay
push time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Staking: Pull in some substrate-rc6 changes
pub mod weight { } } +pub trait WeightInfo {+ fn bond(u: u32) -> Weight;+ fn bond_extra(u: u32) -> Weight;+ fn unbond(u: u32) -> Weight;+ fn withdraw_unbonded_update(s: u32) -> Weight;+ fn withdraw_unbonded_kill(s: u32) -> Weight;+ fn validate(u: u32) -> Weight;+ fn nominate(n: u32) -> Weight;+ fn chill(u: u32) -> Weight;+ fn set_payee(u: u32) -> Weight;+ fn set_controller(u: u32) -> Weight;+ fn set_validator_count(c: u32) -> Weight;+ fn force_no_eras(i: u32) -> Weight;+ fn force_new_era(i: u32) -> Weight;+ fn force_new_era_always(i: u32) -> Weight;+ fn set_invulnerables(v: u32) -> Weight;+ fn force_unstake(s: u32) -> Weight;+ fn cancel_deferred_slash(s: u32) -> Weight;+ fn payout_stakers(n: u32) -> Weight;+ fn payout_stakers_alive_controller(n: u32) -> Weight;+ fn rebond(l: u32) -> Weight;+ fn set_history_depth(e: u32) -> Weight;+ fn reap_stash(s: u32) -> Weight;+ fn new_era(v: u32, n: u32) -> Weight;+ fn do_slash(l: u32) -> Weight;+ fn payout_all(v: u32, n: u32) -> Weight;+ fn submit_solution_initial(v: u32, n: u32, a: u32, w: u32) -> Weight;+ fn submit_solution_better(v: u32, n: u32, a: u32, w: u32) -> Weight;+ fn submit_solution_weaker(v: u32, n: u32) -> Weight;+}++impl WeightInfo for () {+ fn bond(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn bond_extra(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn unbond(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn withdraw_unbonded_update(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn withdraw_unbonded_kill(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn validate(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn nominate(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn chill(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_payee(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_controller(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_validator_count(_c: u32) -> Weight {+ 1_000_000_000+ }+ fn force_no_eras(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn force_new_era(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn force_new_era_always(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn set_invulnerables(_v: u32) -> Weight {+ 1_000_000_000+ }+ fn force_unstake(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn cancel_deferred_slash(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_stakers(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_stakers_alive_controller(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn rebond(_l: u32) -> Weight {+ 1_000_000_000+ }+ fn set_history_depth(_e: u32) -> Weight {+ 1_000_000_000+ }+ fn reap_stash(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn new_era(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+ fn do_slash(_l: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_all(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_initial(_v: u32, _n: u32, _a: u32, _w: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_better(_v: u32, _n: u32, _a: u32, _w: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_weaker(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+}+ pub trait Trait: frame_system::Trait + SendTransactionTypes<Call<Self>> + pallet_babe::Trait + IdentityTrait { /// The staking balance.- type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>- + BlockRewardsReserveCurrency<BalanceOf<Self>, NegativeImbalanceOf<Self>>;+ type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>;
Ah, I see; let's bring it up on the grooming/standup. :)
comment created time in 5 days
push eventPolymathNetwork/Polymesh
commit sha c8d38b8070f93f0524ea16e19a867132654f2aa6
mesh-1255: copy-in staking/src
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 078fe80a20ea0fb129aedc7fb186890567ac4a0d
Schema: fix `Vote`'s definition due to changes (#622)
commit sha 03a92abc24d1c06324581a43156e5260830719de
Mesh 1106/reserve currency ticker symbols on genesis (#598) * added country currencies json file * working on reserving currency tickers * made change to chain spec and asset module * added currency symbols to chain_spec and made minor changes * made changes to chain_spec and asset module * added FiatTickerReservation Systematic User * fixed linting issue * created function for currency symbol conversion in chain_spec and made minor changes * minor change * fixed linting issue * minor change * moved FiatCurrency Struct to chain_spec and optimized currency_codes function * minor changes and linting * aded POLY and POLYX to currency_symbols file * Empty commit to trigger build * rerun CI * minor changes * minor change Co-authored-by: Claus Strommer <[email protected]> Co-authored-by: poly-auto-merge[bot] <65769705+poly-auto-merge[bot]@users.noreply.github.com>
commit sha 85017a18cafc84863688521f2577b8c849c95ed5
AssetIdentifier::isin: remove allocation (#621) Co-authored-by: Adam Dossa <[email protected]>
commit sha 807d651f2fa689668c7d38f3ac501745e5e5814d
mesh-1255: copy-in staking/fuzzer
commit sha 56c3a0897a2df0ab6281c9ffe29ff9faf4f11b99
mesh-1255: copy-in staking/reward-curve
commit sha d0aaf31bfe3f254018076450fa503469639c2dd6
mesh-1255: un-copy 'reward-curve' crate
commit sha 20517f1f53775fcff205f19df183416a6c0b4c90
mesh-1255: copy-in staking/src
push time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Staking: Pull in some substrate-rc6 changes
pub mod weight { } } +pub trait WeightInfo {+ fn bond(u: u32) -> Weight;+ fn bond_extra(u: u32) -> Weight;+ fn unbond(u: u32) -> Weight;+ fn withdraw_unbonded_update(s: u32) -> Weight;+ fn withdraw_unbonded_kill(s: u32) -> Weight;+ fn validate(u: u32) -> Weight;+ fn nominate(n: u32) -> Weight;+ fn chill(u: u32) -> Weight;+ fn set_payee(u: u32) -> Weight;+ fn set_controller(u: u32) -> Weight;+ fn set_validator_count(c: u32) -> Weight;+ fn force_no_eras(i: u32) -> Weight;+ fn force_new_era(i: u32) -> Weight;+ fn force_new_era_always(i: u32) -> Weight;+ fn set_invulnerables(v: u32) -> Weight;+ fn force_unstake(s: u32) -> Weight;+ fn cancel_deferred_slash(s: u32) -> Weight;+ fn payout_stakers(n: u32) -> Weight;+ fn payout_stakers_alive_controller(n: u32) -> Weight;+ fn rebond(l: u32) -> Weight;+ fn set_history_depth(e: u32) -> Weight;+ fn reap_stash(s: u32) -> Weight;+ fn new_era(v: u32, n: u32) -> Weight;+ fn do_slash(l: u32) -> Weight;+ fn payout_all(v: u32, n: u32) -> Weight;+ fn submit_solution_initial(v: u32, n: u32, a: u32, w: u32) -> Weight;+ fn submit_solution_better(v: u32, n: u32, a: u32, w: u32) -> Weight;+ fn submit_solution_weaker(v: u32, n: u32) -> Weight;+}++impl WeightInfo for () {+ fn bond(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn bond_extra(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn unbond(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn withdraw_unbonded_update(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn withdraw_unbonded_kill(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn validate(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn nominate(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn chill(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_payee(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_controller(_u: u32) -> Weight {+ 1_000_000_000+ }+ fn set_validator_count(_c: u32) -> Weight {+ 1_000_000_000+ }+ fn force_no_eras(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn force_new_era(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn force_new_era_always(_i: u32) -> Weight {+ 1_000_000_000+ }+ fn set_invulnerables(_v: u32) -> Weight {+ 1_000_000_000+ }+ fn force_unstake(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn cancel_deferred_slash(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_stakers(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_stakers_alive_controller(_n: u32) -> Weight {+ 1_000_000_000+ }+ fn rebond(_l: u32) -> Weight {+ 1_000_000_000+ }+ fn set_history_depth(_e: u32) -> Weight {+ 1_000_000_000+ }+ fn reap_stash(_s: u32) -> Weight {+ 1_000_000_000+ }+ fn new_era(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+ fn do_slash(_l: u32) -> Weight {+ 1_000_000_000+ }+ fn payout_all(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_initial(_v: u32, _n: u32, _a: u32, _w: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_better(_v: u32, _n: u32, _a: u32, _w: u32) -> Weight {+ 1_000_000_000+ }+ fn submit_solution_weaker(_v: u32, _n: u32) -> Weight {+ 1_000_000_000+ }+}+ pub trait Trait: frame_system::Trait + SendTransactionTypes<Call<Self>> + pallet_babe::Trait + IdentityTrait { /// The staking balance.- type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>- + BlockRewardsReserveCurrency<BalanceOf<Self>, NegativeImbalanceOf<Self>>;+ type Currency: LockableCurrency<Self::AccountId, Moment = Self::BlockNumber>;
If things compile without the extra bound then it must be unused.
comment created time in 5 days
push eventPolymathNetwork/Polymesh
commit sha f68ec87b165f6207e789a098be9626517c6facde
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 5c2a33ad76c247a2b7ce4aa0926f251105d75789
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 666672266ccd5abca7e985109db098df60d87948
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha d0793e8bea2ad1df319cf0914f4332627b84b90b
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 1ee8617955517cc3ffdf22f56f65d3124c3a2884
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 4ca20d3e2441bbc1ba8be83356f9b18a5f4edb32
fixup
commit sha 08b09d4209c4e04e55721ce3d3c48c7f236c64a4
fixup
push time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Staking: Pull in some substrate-rc6 changes
decl_module! { ).expect( "An unsigned solution can only be submitted by validators; A validator should \ always produce correct solutions, else this block should not be imported, thus \- effectively depriving the validators from their authoring reward. Hence, this panic- is expected."+ effectively depriving the validators from their authoring reward. Hence, this panic
Odd; these didn't show up in VSCode :/
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Transaction Payment: Pull in some substrate-rc6 changes
where info: &DispatchInfoOf<T::Call>, len: usize, ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {- let fee = Module::<T>::compute_fee(len as u32, info, 0u32.into());+ let tip = self.0;+ let fee = Module::<T>::compute_fee(len as u32, info, tip); // Only mess with balances if fee is not zero. if fee.is_zero() { return Ok((fee, None)); } if let Some(payer_key) = T::CddHandler::get_valid_payer(call, &who)? {- let imbalance = T::Currency::withdraw(- &payer_key,- fee,- WithdrawReason::TransactionPayment.into(),- ExistenceRequirement::KeepAlive,- )- .map_err(|_| InvalidTransaction::Payment)?;+ let reason = if tip.is_zero() {+ WithdrawReason::TransactionPayment.into()+ } else {+ WithdrawReason::TransactionPayment | WithdrawReason::Tip
Yep, already fixed :)
comment created time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 21bc72820b17986d73130b4823beaa1056246f36
mesh-1255/transaction-payment: bring in some rc6 changes
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha c6a297341aa3c3e4e29b4f8d3d5d6196816379a9
fixup
push time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Transaction Payment: Pull in some substrate-rc6 changes
use sp_runtime::{ InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, },- FixedI128, FixedPointNumber, FixedPointOperand, Perquintill,+ FixedPointNumber, FixedPointOperand, FixedU128, Perquintill, }; use sp_std::prelude::*; /// Fee multiplier.-pub type Multiplier = FixedI128;+pub type Multiplier = FixedU128;
We decided it was not necessary on a meeting.
comment created time in 5 days
push eventPolymathNetwork/Polymesh
commit sha dc11a4b432ec91d29741a40eac0fb04d09100f86
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha ed87b2a8c07576b79aced6508e6634a1145e9a9f
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha 81b5bee08d1bdd525db000eb1b5c5f6797a252ae
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha be5530f13f52eb92489b81be6dbcd283c51a7354
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha ec43fbf3187e026ae800bb59a7677ddd789630fa
fixup
push time in 5 days
push eventPolymathNetwork/Polymesh
commit sha c9c0aa018d1c6bae89e86c66870eeb7658ecd511
fixup
push time in 5 days
Pull request review commentPolymathNetwork/Polymesh
Verify zk proof during claim addition
use crate::{- scalar_blake2_from_bytes, CddId, Claim, Context, IdentityId, InvestorZKProofData, Proposition,- Ticker,+ scalar_blake2_from_bytes, CddId, Claim, IdentityId, InvestorZKProofData, Scope, Ticker, }; use cryptography::claim_proofs::ProofPublicKey; use curve25519_dalek::{ristretto::CompressedRistretto, scalar::Scalar}; // ZKProofs claims // ========================================================= -/// Proposition that checks if any of its internal claims exists in context.+/// Data structure used to check if any of its internal claims exist in context. #[derive(Clone)] #[cfg_attr(feature = "std", derive(Debug))]-pub struct ValidProofOfInvestorProposition {- /// The Investor proof should be associated to this ticker.- pub ticker: Ticker,-}--impl Proposition for ValidProofOfInvestorProposition {- /// Evaluate proposition against `context`.- fn evaluate(&self, context: &Context) -> bool {- context- .claims- .iter()- .any(|claim| self.evaluate_claim(claim, context))- }-}+pub struct ValidProofOfInvestor; -impl ValidProofOfInvestorProposition {+impl ValidProofOfInvestor { /// Evaluates if the claim is a valid proof.- fn evaluate_claim(&self, claim: &Claim, context: &Context) -> bool {+ pub fn evaluate_claim(claim: &Claim, id: &IdentityId) -> bool { match claim {- Claim::InvestorZKProof(ref _ticker_scope, ref scope_id, ref cdd_id, ref proof) => {- let message = InvestorZKProofData::make_message(&context.id, &self.ticker);- Self::verify_proof(cdd_id, &context.id, scope_id, &self.ticker, proof, &message)+ Claim::InvestorZKProof(ref scope, scope_id, cdd_id, proof) => {+ if let Scope::Ticker(ticker) = scope {+ let message = InvestorZKProofData::make_message(id, ticker);+ return Self::verify_proof(cdd_id, id, scope_id, ticker, proof, &message);+ }+ false
Claim::InvestorZKProof(Scope::Ticker(ticker), scope_id, cdd_id, proof) => {
let message = InvestorZKProofData::make_message(id, ticker);
return Self::verify_proof(cdd_id, id, scope_id, ticker, proof, &message);
comment created time in 5 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Transaction Payment: Pull in some substrate-rc6 changes
where info: &DispatchInfoOf<T::Call>, len: usize, ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {- let fee = Module::<T>::compute_fee(len as u32, info, 0u32.into());+ let tip = self.0;
@satyamakgec So AIUI, we want to revert all the changes in this function?
comment created time in 6 days
pull request commentPolymathNetwork/Polymesh
[WIP] MESH-1255/im-online: Pull in some substrate-rc6 changes
The diff from https://github.com/paritytech/substrate/compare/v2.0.0-rc4...v2.0.0-rc6#diff-8fd54810abd2bd459e2decb6bffe9865 indicates that there were no useful/functional changes from rc4..rc6 in im-online, so I'll close this.
comment created time in 6 days
push eventPolymathNetwork/Polymesh
commit sha 6a0441ca2f8fbb6888af09825f0859eda878d664
fixup
push time in 6 days
push eventPolymathNetwork/Polymesh
commit sha 955b8280e167aa9bbd75f6cc22848a2654dda6ab
fixup
push time in 6 days
push eventPolymathNetwork/Polymesh
commit sha 82542b45f99e0bf9c2e9af9960c3870894bab9cf
fixup
push time in 6 days
Pull request review commentPolymathNetwork/Polymesh
MESH-1255/Transaction Payment: Pull in some substrate-rc6 changes
use sp_runtime::{ InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError, ValidTransaction, },- FixedI128, FixedPointNumber, FixedPointOperand, Perquintill,+ FixedPointNumber, FixedPointOperand, FixedU128, Perquintill, }; use sp_std::prelude::*; /// Fee multiplier.-pub type Multiplier = FixedI128;+pub type Multiplier = FixedU128;
This is used in the only storage item; should we write a migration?
comment created time in 6 days