From b637a77249cd7b25383c726e97e00a014649477e Mon Sep 17 00:00:00 2001 From: Shawn Tabrizi Date: Mon, 2 Dec 2019 17:55:54 +0100 Subject: [PATCH] Adding vesting logic to claims (#637) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding vesting logic to claims * Add genesis * Update runtime/src/claims.rs Co-Authored-By: Bastian Köcher * Bump spec * Update runtime/src/claims.rs --- polkadot/runtime/src/claims.rs | 61 +++++++++++++++++++++++++++--- polkadot/runtime/src/lib.rs | 2 +- polkadot/service/src/chain_spec.rs | 2 + 3 files changed, 58 insertions(+), 7 deletions(-) diff --git a/polkadot/runtime/src/claims.rs b/polkadot/runtime/src/claims.rs index 608295579e..2e40333717 100644 --- a/polkadot/runtime/src/claims.rs +++ b/polkadot/runtime/src/claims.rs @@ -20,7 +20,7 @@ use rstd::prelude::*; use sp_io::{hashing::keccak_256, crypto::secp256k1_ecdsa_recover}; use frame_support::{decl_event, decl_storage, decl_module}; use frame_support::weights::SimpleDispatchInfo; -use frame_support::traits::{Currency, Get}; +use frame_support::traits::{Currency, Get, VestingCurrency}; use system::{ensure_root, ensure_none}; use codec::{Encode, Decode}; #[cfg(feature = "std")] @@ -41,7 +41,8 @@ type BalanceOf = <::Currency as Currency<::Ac pub trait Trait: system::Trait { /// The overarching event type. type Event: From> + Into<::Event>; - type Currency: Currency; + type Currency: Currency + + VestingCurrency; type Prefix: Get<&'static [u8]>; } @@ -112,6 +113,11 @@ decl_storage! { Total get(total) build(|config: &GenesisConfig| { config.claims.iter().fold(Zero::zero(), |acc: BalanceOf, &(_, n)| acc + n) }): BalanceOf; + /// Vesting schedule for a claim. + /// First balance is the total amount that should be held for vesting. + /// Second balance is how much should be unlocked per block. + /// The block number is when the vesting should start. + Vesting get(vesting) config(): map EthereumAddress => Option<(BalanceOf, BalanceOf, T::BlockNumber)>; } add_extra_genesis { config(claims): Vec<(EthereumAddress, BalanceOf)>; @@ -135,9 +141,19 @@ decl_module! { let signer = Self::eth_recover(ðereum_signature, &data) .ok_or("Invalid Ethereum signature")?; - let balance_due = >::take(&signer) + let balance_due = >::get(&signer) .ok_or("Ethereum address has no claim")?; + // Check if this claim should have a vesting schedule. + if let Some(vs) = >::get(&signer) { + // If this fails, destination account already has a vesting schedule + // applied to it, and this claim should not be processed. + T::Currency::add_vesting_schedule(&dest, vs.0, vs.1, vs.2)?; + } + + >::remove(&signer); + >::remove(&signer); + >::mutate(|t| if *t < balance_due { panic!("Logic error: Pot less than the total of claims!") } else { @@ -152,11 +168,18 @@ decl_module! { /// Add a new claim, if you are root. #[weight = SimpleDispatchInfo::FreeOperational] - fn mint_claim(origin, who: EthereumAddress, value: BalanceOf) { + fn mint_claim(origin, + who: EthereumAddress, + value: BalanceOf, + vesting_schedule: Option<(BalanceOf, BalanceOf, T::BlockNumber)>, + ) { ensure_root(origin)?; >::mutate(|t| *t += value); >::insert(who, value); + if let Some(vs) = vesting_schedule { + >::insert(who, vs); + } } } } @@ -345,6 +368,7 @@ mod tests { balances::GenesisConfig::::default().assimilate_storage(&mut t).unwrap(); GenesisConfig::{ claims: vec![(eth(&alice()), 100)], + vesting: vec![(eth(&alice()), (50, 10, 1))], }.assimilate_storage(&mut t).unwrap(); t.into() } @@ -355,6 +379,7 @@ mod tests { assert_eq!(Claims::total(), 100); assert_eq!(Claims::claims(ð(&alice())), Some(100)); assert_eq!(Claims::claims(&EthereumAddress::default()), None); + assert_eq!(Claims::vesting(ð(&alice())), Some((50, 10, 1))); }); } @@ -373,21 +398,45 @@ mod tests { assert_eq!(Balances::free_balance(&42), 0); assert_ok!(Claims::claim(Origin::NONE, 42, sig(&alice(), &42u64.encode()))); assert_eq!(Balances::free_balance(&42), 100); + assert_eq!(Balances::vesting_balance(&42), 50); }); } #[test] fn add_claim_works() { new_test_ext().execute_with(|| { - assert_noop!(Claims::mint_claim(Origin::signed(42), eth(&bob()), 200), "RequireRootOrigin"); + assert_noop!( + Claims::mint_claim(Origin::signed(42), eth(&bob()), 200, None), + "RequireRootOrigin" + ); assert_eq!(Balances::free_balance(&42), 0); assert_noop!( Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())), "Ethereum address has no claim" ); - assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200)); + assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, None)); assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode()))); assert_eq!(Balances::free_balance(&69), 200); + assert_eq!(Balances::vesting_balance(&69), 0); + }); + } + + #[test] + fn add_claim_with_vesting_works() { + new_test_ext().execute_with(|| { + assert_noop!( + Claims::mint_claim(Origin::signed(42), eth(&bob()), 200, Some((50, 10, 1))), + "RequireRootOrigin" + ); + assert_eq!(Balances::free_balance(&42), 0); + assert_noop!( + Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode())), + "Ethereum address has no claim" + ); + assert_ok!(Claims::mint_claim(Origin::ROOT, eth(&bob()), 200, Some((50, 10, 1)))); + assert_ok!(Claims::claim(Origin::NONE, 69, sig(&bob(), &69u64.encode()))); + assert_eq!(Balances::free_balance(&69), 200); + assert_eq!(Balances::vesting_balance(&69), 50); }); } diff --git a/polkadot/runtime/src/lib.rs b/polkadot/runtime/src/lib.rs index 4b58486897..fd13d3fe94 100644 --- a/polkadot/runtime/src/lib.rs +++ b/polkadot/runtime/src/lib.rs @@ -97,7 +97,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("kusama"), impl_name: create_runtime_str!("parity-kusama"), authoring_version: 2, - spec_version: 1023, + spec_version: 1024, impl_version: 0, apis: RUNTIME_API_VERSIONS, }; diff --git a/polkadot/service/src/chain_spec.rs b/polkadot/service/src/chain_spec.rs index 592012cd0d..e60002bfed 100644 --- a/polkadot/service/src/chain_spec.rs +++ b/polkadot/service/src/chain_spec.rs @@ -199,6 +199,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { }), claims: Some(ClaimsConfig { claims: vec![], + vesting: vec![], }) } } @@ -338,6 +339,7 @@ pub fn testnet_genesis( }), claims: Some(ClaimsConfig { claims: vec![], + vesting: vec![], }) } }