mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-30 14:17:56 +00:00
Introduce add_memo for Crowdloans (#2728)
* Add memo, but don't use it yet * add_memo * add weights * Update lib.rs * Update crowdloan.rs * add event
This commit is contained in:
@@ -101,6 +101,7 @@ pub trait WeightInfo {
|
||||
fn withdraw() -> Weight;
|
||||
fn dissolve(k: u32, ) -> Weight;
|
||||
fn edit() -> Weight;
|
||||
fn add_memo() -> Weight;
|
||||
fn on_initialize(n: u32, ) -> Weight;
|
||||
}
|
||||
|
||||
@@ -111,6 +112,7 @@ impl WeightInfo for TestWeightInfo {
|
||||
fn withdraw() -> Weight { 0 }
|
||||
fn dissolve(_k: u32, ) -> Weight { 0 }
|
||||
fn edit() -> Weight { 0 }
|
||||
fn add_memo() -> Weight { 0 }
|
||||
fn on_initialize(_n: u32, ) -> Weight { 0 }
|
||||
}
|
||||
|
||||
@@ -148,6 +150,9 @@ pub trait Config: frame_system::Config {
|
||||
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;
|
||||
}
|
||||
@@ -242,6 +247,8 @@ decl_event! {
|
||||
HandleBidResult(ParaId, DispatchResult),
|
||||
/// The configuration to a crowdloan has been edited. [fund_index]
|
||||
Edited(ParaId),
|
||||
/// A memo has been updated. [who, fund_index, memo]
|
||||
MemoUpdated(AccountId, ParaId, Vec<u8>),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,6 +294,8 @@ decl_error! {
|
||||
NotReadyToDissolve,
|
||||
/// Invalid signature.
|
||||
InvalidSignature,
|
||||
/// The provided memo is too large.
|
||||
MemoTooLarge,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,7 +366,7 @@ decl_module! {
|
||||
pub fn contribute(origin,
|
||||
#[compact] index: ParaId,
|
||||
#[compact] value: BalanceOf<T>,
|
||||
signature: Option<MultiSignature>
|
||||
signature: Option<MultiSignature>,
|
||||
) {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
@@ -370,7 +379,7 @@ decl_module! {
|
||||
let now = <frame_system::Pallet<T>>::block_number();
|
||||
ensure!(now < fund.end, Error::<T>::ContributionPeriodOver);
|
||||
|
||||
let old_balance = Self::contribution_get(fund.trie_index, &who);
|
||||
let (old_balance, memo) = Self::contribution_get(fund.trie_index, &who);
|
||||
|
||||
if let Some(ref verifier) = fund.verifier {
|
||||
let signature = signature.ok_or(Error::<T>::InvalidSignature)?;
|
||||
@@ -382,7 +391,7 @@ decl_module! {
|
||||
CurrencyOf::<T>::transfer(&who, &Self::fund_account_id(index), value, AllowDeath)?;
|
||||
|
||||
let balance = old_balance.saturating_add(value);
|
||||
Self::contribution_put(fund.trie_index, &who, &balance);
|
||||
Self::contribution_put(fund.trie_index, &who, &balance, &memo);
|
||||
|
||||
if T::Auctioneer::is_ending(now).is_some() {
|
||||
match fund.last_contribution {
|
||||
@@ -443,7 +452,7 @@ decl_module! {
|
||||
let fund_account = Self::fund_account_id(index);
|
||||
Self::ensure_crowdloan_ended(now, &fund_account, &fund)?;
|
||||
|
||||
let balance = Self::contribution_get(fund.trie_index, &who);
|
||||
let (balance, _) = Self::contribution_get(fund.trie_index, &who);
|
||||
ensure!(balance > Zero::zero(), Error::<T>::NoContributions);
|
||||
|
||||
CurrencyOf::<T>::transfer(&fund_account, &who, balance, AllowDeath)?;
|
||||
@@ -531,6 +540,23 @@ decl_module! {
|
||||
Self::deposit_event(RawEvent::Edited(index));
|
||||
}
|
||||
|
||||
/// Add an optional memo to an existing crowdloan contribution.
|
||||
///
|
||||
/// Origin must be Signed, and the user must have contributed to the crowdloan.
|
||||
#[weight = T::WeightInfo::add_memo()]
|
||||
pub fn add_memo(origin, index: ParaId, memo: Vec<u8>) {
|
||||
let who = ensure_signed(origin)?;
|
||||
|
||||
ensure!(memo.len() <= T::MaxMemoLength::get().into(), Error::<T>::MemoTooLarge);
|
||||
let fund = Self::funds(index).ok_or(Error::<T>::InvalidParaId)?;
|
||||
|
||||
let (balance, _) = Self::contribution_get(fund.trie_index, &who);
|
||||
ensure!(balance > Zero::zero(), Error::<T>::NoContributions);
|
||||
|
||||
Self::contribution_put(fund.trie_index, &who, &balance, &memo);
|
||||
Self::deposit_event(RawEvent::MemoUpdated(who, index, memo));
|
||||
}
|
||||
|
||||
fn on_initialize(n: T::BlockNumber) -> frame_support::weights::Weight {
|
||||
if let Some(n) = T::Auctioneer::is_ending(n) {
|
||||
if n.is_zero() {
|
||||
@@ -576,12 +602,12 @@ impl<T: Config> Module<T> {
|
||||
child::ChildInfo::new_default(T::Hashing::hash(&buf[..]).as_ref())
|
||||
}
|
||||
|
||||
pub fn contribution_put(index: TrieIndex, who: &T::AccountId, balance: &BalanceOf<T>) {
|
||||
who.using_encoded(|b| child::put(&Self::id_from_index(index), b, balance));
|
||||
pub fn contribution_put(index: TrieIndex, who: &T::AccountId, balance: &BalanceOf<T>, memo: &[u8]) {
|
||||
who.using_encoded(|b| child::put(&Self::id_from_index(index), b, &(balance, memo)));
|
||||
}
|
||||
|
||||
pub fn contribution_get(index: TrieIndex, who: &T::AccountId) -> BalanceOf<T> {
|
||||
who.using_encoded(|b| child::get_or_default::<BalanceOf<T>>(
|
||||
pub fn contribution_get(index: TrieIndex, who: &T::AccountId) -> (BalanceOf<T>, Vec<u8>) {
|
||||
who.using_encoded(|b| child::get_or_default::<(BalanceOf<T>, Vec<u8>)>(
|
||||
&Self::id_from_index(index),
|
||||
b,
|
||||
))
|
||||
@@ -806,6 +832,7 @@ mod tests {
|
||||
pub const RetirementPeriod: u64 = 5;
|
||||
pub const CrowdloanModuleId: ModuleId = ModuleId(*b"py/cfund");
|
||||
pub const RemoveKeysLimit: u32 = 10;
|
||||
pub const MaxMemoLength: u8 = 32;
|
||||
}
|
||||
|
||||
impl Config for Test {
|
||||
@@ -818,6 +845,7 @@ mod tests {
|
||||
type RemoveKeysLimit = RemoveKeysLimit;
|
||||
type Registrar = TestRegistrar<Test>;
|
||||
type Auctioneer = TestAuctioneer;
|
||||
type MaxMemoLength = MaxMemoLength;
|
||||
type WeightInfo = crate::crowdloan::TestWeightInfo;
|
||||
}
|
||||
|
||||
@@ -865,7 +893,7 @@ mod tests {
|
||||
assert_eq!(Crowdloan::funds(ParaId::from(0)), None);
|
||||
let empty: Vec<ParaId> = Vec::new();
|
||||
assert_eq!(Crowdloan::new_raise(), empty);
|
||||
assert_eq!(Crowdloan::contribution_get(0u32, &1), 0);
|
||||
assert_eq!(Crowdloan::contribution_get(0u32, &1).0, 0);
|
||||
assert_eq!(Crowdloan::endings_count(), 0);
|
||||
|
||||
assert_ok!(TestAuctioneer::new_auction(5, 0));
|
||||
@@ -976,14 +1004,14 @@ mod tests {
|
||||
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, None));
|
||||
|
||||
// No contributions yet
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1), 0);
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 0);
|
||||
|
||||
// User 1 contributes to their own crowdloan
|
||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), para, 49, None));
|
||||
// User 1 has spent some funds to do this, transfer fees **are** taken
|
||||
assert_eq!(Balances::free_balance(1), 950);
|
||||
// Contributions are stored in the trie
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1), 49);
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 49);
|
||||
// Contributions appear in free balance of crowdloan
|
||||
assert_eq!(Balances::free_balance(Crowdloan::fund_account_id(para)), 49);
|
||||
// Crowdloan is added to NewRaise
|
||||
@@ -1006,7 +1034,7 @@ mod tests {
|
||||
assert_ok!(Crowdloan::create(Origin::signed(1), para, 1000, 1, 4, 9, Some(pubkey.clone())));
|
||||
|
||||
// No contributions yet
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1), 0);
|
||||
assert_eq!(Crowdloan::contribution_get(u32::from(para), &1).0, 0);
|
||||
|
||||
// Missing signature
|
||||
assert_noop!(Crowdloan::contribute(Origin::signed(1), para, 49, None), Error::<Test>::InvalidSignature);
|
||||
@@ -1351,6 +1379,34 @@ mod tests {
|
||||
assert!(old_crowdloan.last_slot != new_crowdloan.last_slot);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_memo_works() {
|
||||
new_test_ext().execute_with(|| {
|
||||
let para_1 = new_para();
|
||||
|
||||
assert_ok!(Crowdloan::create(Origin::signed(1), para_1, 1000, 1, 1, 9, None));
|
||||
// Cant add a memo before you have contributed.
|
||||
assert_noop!(
|
||||
Crowdloan::add_memo(Origin::signed(1), para_1, b"hello, world".to_vec()),
|
||||
Error::<Test>::NoContributions,
|
||||
);
|
||||
// Make a contribution. Initially no memo.
|
||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), para_1, 100, None));
|
||||
assert_eq!(Crowdloan::contribution_get(0u32, &1), (100, vec![]));
|
||||
// Can't place a memo that is too large.
|
||||
assert_noop!(
|
||||
Crowdloan::add_memo(Origin::signed(1), para_1, vec![123; 123]),
|
||||
Error::<Test>::MemoTooLarge,
|
||||
);
|
||||
// Adding a memo to an existing contribution works
|
||||
assert_ok!(Crowdloan::add_memo(Origin::signed(1), para_1, b"hello, world".to_vec()));
|
||||
assert_eq!(Crowdloan::contribution_get(0u32, &1), (100, b"hello, world".to_vec()));
|
||||
// Can contribute again and data persists
|
||||
assert_ok!(Crowdloan::contribute(Origin::signed(1), para_1, 100, None));
|
||||
assert_eq!(Crowdloan::contribution_get(0u32, &1), (200, b"hello, world".to_vec()));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "runtime-benchmarks")]
|
||||
@@ -1520,6 +1576,20 @@ mod benchmarking {
|
||||
assert_last_event::<T>(RawEvent::Edited(para_id).into())
|
||||
}
|
||||
|
||||
add_memo {
|
||||
let fund_index = create_fund::<T>(1, 100u32.into());
|
||||
let caller: T::AccountId = whitelisted_caller();
|
||||
contribute_fund::<T>(&caller, fund_index);
|
||||
let worst_memo = vec![42; T::MaxMemoLength::get().into()];
|
||||
}: _(RawOrigin::Signed(caller.clone()), fund_index, worst_memo.clone())
|
||||
verify {
|
||||
let fund = Funds::<T>::get(fund_index).expect("fund was created...");
|
||||
assert_eq!(
|
||||
Crowdloan::<T>::contribution_get(fund.trie_index, &caller),
|
||||
(T::MinContribution::get(), worst_memo),
|
||||
);
|
||||
}
|
||||
|
||||
// Worst case scenario: N funds are all in the `NewRaise` list, we are
|
||||
// in the beginning of the ending period, and each fund outbids the next
|
||||
// over the same slot.
|
||||
|
||||
@@ -216,7 +216,7 @@ parameter_types! {
|
||||
pub const MinContribution: Balance = 1;
|
||||
pub const RetirementPeriod: BlockNumber = 10;
|
||||
pub const RemoveKeysLimit: u32 = 100;
|
||||
|
||||
pub const MaxMemoLength: u8 = 32;
|
||||
}
|
||||
|
||||
impl crowdloan::Config for Test {
|
||||
@@ -229,6 +229,7 @@ impl crowdloan::Config for Test {
|
||||
type RemoveKeysLimit = RemoveKeysLimit;
|
||||
type Registrar = Registrar;
|
||||
type Auctioneer = Auctions;
|
||||
type MaxMemoLength = MaxMemoLength;
|
||||
type WeightInfo = crate::crowdloan::TestWeightInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -660,6 +660,8 @@ parameter_types! {
|
||||
pub const MinContribution: Balance = 1 * DOLLARS;
|
||||
pub const RetirementPeriod: BlockNumber = 6 * HOURS;
|
||||
pub const RemoveKeysLimit: u32 = 500;
|
||||
// Allow 32 bytes for an additional memo to a crowdloan.
|
||||
pub const MaxMemoLength: u8 = 32;
|
||||
}
|
||||
|
||||
impl crowdloan::Config for Runtime {
|
||||
@@ -672,6 +674,7 @@ impl crowdloan::Config for Runtime {
|
||||
type RemoveKeysLimit = RemoveKeysLimit;
|
||||
type Registrar = Registrar;
|
||||
type Auctioneer = Auctions;
|
||||
type MaxMemoLength = MaxMemoLength;
|
||||
type WeightInfo = crowdloan::TestWeightInfo;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user