Newer
Older
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//!
//! The point of this module is to allow parachain projects to offer the ability to help fund a
//! deposit for the parachain. When the crowdloan has ended, the funds are returned.
//! Each fund has a child-trie which stores all contributors account IDs together with the amount
//! they contributed; the root of this can then be used by the parachain to allow contributors to
//! prove that they made some particular contribution to the project (e.g. to be rewarded through
//! some token or badge). The trie is retained for later (efficient) redistribution back to the
//! contributors.
//!
//! Contributions must be of at least `MinContribution` (to account for the resources taken in
//! tracking contributions), and may never tally greater than the fund's `cap`, set and fixed at the
//! time of creation. The `create` call may be used to create a new fund. In order to do this, then
//! a deposit must be paid of the amount `SubmissionDeposit`. Substantial resources are taken on
//! the main trie in tracking a fund and this accounts for that.
//!
//! Funds may be set up during an auction period; their closing time is fixed at creation (as a
//! block number) and if the fund is not successful by the closing time, then it can be dissolved.
//! Funds may span multiple auctions, and even auctions that sell differing periods. However, for a
//! fund to be active in bidding for an auction, it *must* have had *at least one bid* since the end
//! of the last auction. Until a fund takes a further bid following the end of an auction, then it
//! will be inactive.
//!
//! Contributors will get a refund of their contributions from completed funds before the crowdloan
//! can be dissolved.
//! Funds may accept contributions at any point before their success or end. When a parachain
//! slot auction enters its ending period, then parachains will each place a bid; the bid will be
//! raised once per block if the parachain had additional funds contributed since the last bid.
//!
//! Successful funds remain tracked (in the `Funds` storage item and the associated child trie) as long as
//! the parachain remains active. Users can withdraw their funds once the slot is completed and funds are
//! returned to the crowdloan account.
decl_module, decl_storage, decl_event, decl_error, ensure, Identity,
storage::{child, ChildTriePrefixIterator},
Currency, ReservableCurrency, Get, ExistenceRequirement::AllowDeath
pallet_prelude::{Weight, DispatchResultWithPostInfo},
use frame_system::{ensure_signed, ensure_root};
ModuleId, DispatchResult, RuntimeDebug, MultiSignature, MultiSigner,
AccountIdConversion, Hash, Saturating, Zero, One, CheckedAdd, Verify, IdentifyAccount,
use crate::traits::{Registrar, Auctioneer};
use crate::slot_range::SlotRange;
use parity_scale_codec::{Encode, Decode};
use primitives::v1::Id as ParaId;
type CurrencyOf<T> = <<T as Config>::Auctioneer as Auctioneer>::Currency;
type LeasePeriodOf<T> = <<T as Config>::Auctioneer as Auctioneer>::LeasePeriod;
type BalanceOf<T> = <CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::Balance;
type NegativeImbalanceOf<T> = <CurrencyOf<T> as Currency<<T as frame_system::Config>::AccountId>>::NegativeImbalance;
type TrieIndex = u32;
pub trait WeightInfo {
fn create() -> Weight;
fn contribute() -> Weight;
fn withdraw() -> Weight;
fn refund(k: u32, ) -> Weight;
fn dissolve() -> Weight;
fn edit() -> Weight;
fn on_initialize(n: u32, ) -> Weight;
}
pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
fn create() -> Weight { 0 }
fn contribute() -> Weight { 0 }
fn withdraw() -> Weight { 0 }
fn refund(_k: u32, ) -> Weight { 0 }
fn dissolve() -> Weight { 0 }
fn edit() -> Weight { 0 }
fn add_memo() -> Weight { 0 }
fn on_initialize(_n: u32, ) -> Weight { 0 }
}
pub trait Config: frame_system::Config {
type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;
/// ModuleID for the crowdloan module. An appropriate value could be ```ModuleId(*b"py/cfund")```
/// The amount to be held on deposit by the depositor of a crowdloan.
type SubmissionDeposit: Get<BalanceOf<Self>>;
/// The minimum amount that may be contributed into a crowdloan. Should almost certainly be at
/// least ExistentialDeposit.
type MinContribution: Get<BalanceOf<Self>>;
/// Max number of storage keys to remove per extrinsic call.
type RemoveKeysLimit: Get<u32>;
/// The parachain registrar type. We jus use this to ensure that only the manager of a para is able to
/// start a crowdloan for its slot.
type Registrar: Registrar<AccountId=Self::AccountId>;
/// The type representing the auctioning system.
type Auctioneer: Auctioneer<
AccountId=Self::AccountId,
BlockNumber=Self::BlockNumber,
LeasePeriod=Self::BlockNumber,
>;
/// The maximum length for the memo attached to a crowdloan contribution.
type MaxMemoLength: Get<u8>;
/// Weight Information for the Extrinsics in the Pallet
type WeightInfo: WeightInfo;
}
#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq, RuntimeDebug)]
pub enum LastContribution<BlockNumber> {
Never,
/// Information on a funding effort for a pre-existing parachain. We assume that the parachain ID
/// is known as it's used for the key of the storage item for which this is the value (`Funds`).
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
#[codec(dumb_trait_bound)]
pub struct FundInfo<AccountId, Balance, BlockNumber, LeasePeriod> {
/// The owning account who placed the deposit.
/// An optional verifier. If exists, contributions must be signed by verifier.
verifier: Option<MultiSigner>,
/// The amount of deposit placed.
deposit: Balance,
/// The total amount raised.
raised: Balance,
/// Block number after which the funding must have succeeded. If not successful at this number
/// then everyone may withdraw their funds.
end: BlockNumber,
/// A hard-cap on the amount that may be contributed.
cap: Balance,
/// The most recent block that this had a contribution. Determines if we make a bid or not.
/// If this is `Never`, this fund has never received a contribution.
/// If this is `PreEnding(n)`, this fund received a contribution sometime in auction
/// number `n` before the ending period.
/// If this is `Ending(n)`, this fund received a contribution during the current ending period,
/// where `n` is how far into the ending period the contribution was made.
last_contribution: LastContribution<BlockNumber>,
/// First lease period in range to bid on; it's actually a LeasePeriod, but that's the same type
/// as BlockNumber.
first_period: LeasePeriod,
/// Last lease period in range to bid on; it's actually a LeasePeriod, but that's the same type
/// as BlockNumber.
last_period: LeasePeriod,
/// Index used for the child trie of this fund
trie_index: TrieIndex,
trait Store for Module<T: Config> as Crowdloan {
map hasher(twox_64_concat) ParaId
=> Option<FundInfo<T::AccountId, BalanceOf<T>, T::BlockNumber, LeasePeriodOf<T>>>;
/// The funds that have had additional contributions during the last block. This is used
/// in order to determine which funds should submit new or updated bids.
NewRaise get(fn new_raise): Vec<ParaId>;
/// The number of auctions that have entered into their ending period so far.
EndingsCount get(fn endings_count): u32;
/// Tracker for the next available trie index
NextTrieIndex get(fn next_trie_index): u32;
Loading full blame...