diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 3b19903d9a..2b8c9502a8 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -3066,6 +3066,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "sr-io 0.1.0", diff --git a/substrate/node-template/runtime/wasm/Cargo.lock b/substrate/node-template/runtime/wasm/Cargo.lock index fb0369e036..2e168f226f 100644 --- a/substrate/node-template/runtime/wasm/Cargo.lock +++ b/substrate/node-template/runtime/wasm/Cargo.lock @@ -1146,6 +1146,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.85 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", diff --git a/substrate/node-template/src/chain_spec.rs b/substrate/node-template/src/chain_spec.rs index 0580314cbf..6b1370b102 100644 --- a/substrate/node-template/src/chain_spec.rs +++ b/substrate/node-template/src/chain_spec.rs @@ -96,6 +96,7 @@ fn testnet_genesis(initial_authorities: Vec, endowed_account transfer_fee: 0, creation_fee: 0, balances: endowed_accounts.iter().map(|&k|(k, (1 << 60))).collect(), + vesting: vec![], }), sudo: Some(SudoConfig { key: root_key, diff --git a/substrate/node/cli/src/chain_spec.rs b/substrate/node/cli/src/chain_spec.rs index 6429d4923d..878ffb2b10 100644 --- a/substrate/node/cli/src/chain_spec.rs +++ b/substrate/node/cli/src/chain_spec.rs @@ -69,6 +69,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { existential_deposit: 1 * DOLLARS, transfer_fee: 1 * CENTS, creation_fee: 1 * CENTS, + vesting: vec![], }), indices: Some(IndicesConfig { ids: endowed_accounts.clone(), @@ -197,6 +198,7 @@ pub fn testnet_genesis( transfer_fee: 0, creation_fee: 0, balances: endowed_accounts.iter().map(|&k| (k.into(), (1 << 60))).collect(), + vesting: vec![], }), session: Some(SessionConfig { validators: initial_authorities.iter().cloned().map(Into::into).collect(), diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index d6701266d8..901955b59d 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -269,6 +269,7 @@ mod tests { existential_deposit: 0, transfer_fee: 0, creation_fee: 0, + vesting: vec![], }), session: Some(SessionConfig { session_length: 2, diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index 4328ac7f3a..a75d90e83c 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -65,8 +65,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 25, - impl_version: 25, + spec_version: 26, + impl_version: 26, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index 764523e3d4..91ec5f1cf4 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -1160,6 +1160,7 @@ version = "0.1.0" dependencies = [ "hex-literal 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "parity-codec 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-codec-derive 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.81 (registry+https://github.com/rust-lang/crates.io-index)", "sr-primitives 0.1.0", diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 0e77e95a5a..ba214caed2 100644 Binary files a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/substrate/srml/balances/Cargo.toml b/substrate/srml/balances/Cargo.toml index be8ed7e07e..06f4be7026 100644 --- a/substrate/srml/balances/Cargo.toml +++ b/substrate/srml/balances/Cargo.toml @@ -9,6 +9,7 @@ hex-literal = "0.1.0" serde = { version = "1.0", default-features = false } safe-mix = { version = "1.0", default-features = false} parity-codec = { version = "3.0", default-features = false } +parity-codec-derive = { version = "3.0", default-features = false } substrate-keyring = { path = "../../core/keyring", optional = true } rstd = { package = "sr-std", path = "../../core/sr-std", default-features = false } primitives = { package = "sr-primitives", path = "../../core/sr-primitives", default-features = false } @@ -26,6 +27,7 @@ std = [ "safe-mix/std", "substrate-keyring", "parity-codec/std", + "parity-codec-derive/std", "rstd/std", "srml-support/std", "primitives/std", diff --git a/substrate/srml/balances/src/lib.rs b/substrate/srml/balances/src/lib.rs index 9aab3dacc9..e2edf5e3e4 100644 --- a/substrate/srml/balances/src/lib.rs +++ b/substrate/srml/balances/src/lib.rs @@ -27,7 +27,8 @@ use rstd::prelude::*; use rstd::{cmp, result}; use parity_codec::Codec; -use srml_support::{StorageValue, StorageMap, Parameter, decl_module, decl_event, decl_storage}; +use parity_codec_derive::{Encode, Decode}; +use srml_support::{StorageValue, StorageMap, Parameter, decl_event, decl_storage, decl_module}; use srml_support::traits::{UpdateBalanceOutcome, Currency, EnsureAccountLiquid, OnFreeBalanceZero}; use srml_support::dispatch::Result; use primitives::traits::{Zero, SimpleArithmetic, MakePayment, @@ -57,34 +58,6 @@ pub trait Trait: system::Trait { type Event: From> + Into<::Event>; } -decl_module! { - pub struct Module for enum Call where origin: T::Origin { - fn deposit_event() = default; - - /// Transfer some liquid free balance to another staker. - pub fn transfer( - origin, - dest: ::Source, - #[compact] value: T::Balance - ) { - let transactor = ensure_signed(origin)?; - let dest = T::Lookup::lookup(dest)?; - Self::make_transfer(&transactor, &dest, value)?; - } - - /// Set the balances of a given account. - fn set_balance( - who: ::Source, - #[compact] free: T::Balance, - #[compact] reserved: T::Balance - ) { - let who = T::Lookup::lookup(who)?; - Self::set_free_balance(&who, free); - Self::set_reserved_balance(&who, reserved); - } - } -} - decl_event!( pub enum Event where ::AccountId, @@ -99,6 +72,27 @@ decl_event!( } ); +/// Struct to encode the vesting schedule of an individual account. +#[derive(Encode, Decode, Copy, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "std", derive(Debug))] +pub struct VestingSchedule { + /// Locked amount at genesis. + pub offset: Balance, + /// Amount that gets unlocked every block from genesis. + pub per_block: Balance, +} + +impl> VestingSchedule { + /// Amount locked at block `n`. + pub fn locked_at>(&self, n: BlockNumber) -> Balance { + if let Some(x) = Balance::sa(n.as_()).checked_mul(&self.per_block) { + self.offset.max(x) - x + } else { + Zero::zero() + } + } +} + decl_storage! { trait Store for Module as Balances { /// The total amount of stake on the system. @@ -112,6 +106,28 @@ decl_storage! { /// The fee required to create an account. At least as big as ReclaimRebate. pub CreationFee get(creation_fee) config(): T::Balance; + /// Information regarding the vesting of a given account. + pub Vesting get(vesting) build(|config: &GenesisConfig| { + config.vesting.iter().filter_map(|&(ref who, begin, length)| { + let begin: u64 = begin.as_(); + let length: u64 = length.as_(); + let begin: T::Balance = As::sa(begin); + let length: T::Balance = As::sa(length); + + config.balances.iter() + .find(|&&(ref w, _)| w == who) + .map(|&(_, balance)| { + // <= begin it should be >= balance + // >= begin+length it should be <= 0 + + let per_block = balance / length; + let offset = begin * per_block + balance; + + (who.clone(), VestingSchedule { offset, per_block }) + }) + }).collect::>() + }): map T::AccountId => Option>; + /// The 'free' balance of a given account. /// /// This is the only balance that matters in terms of most operations on tokens. It is @@ -149,11 +165,50 @@ decl_storage! { } add_extra_genesis { config(balances): Vec<(T::AccountId, T::Balance)>; + config(vesting): Vec<(T::AccountId, T::BlockNumber, T::BlockNumber)>; // begin, length + } +} + +decl_module! { + pub struct Module for enum Call where origin: T::Origin { + fn deposit_event() = default; + + /// Transfer some liquid free balance to another staker. + pub fn transfer( + origin, + dest: ::Source, + #[compact] value: T::Balance + ) { + let transactor = ensure_signed(origin)?; + let dest = T::Lookup::lookup(dest)?; + Self::make_transfer(&transactor, &dest, value)?; + } + + /// Set the balances of a given account. + fn set_balance( + who: ::Source, + #[compact] free: T::Balance, + #[compact] reserved: T::Balance + ) { + let who = T::Lookup::lookup(who)?; + Self::set_free_balance(&who, free); + Self::set_reserved_balance(&who, reserved); + } } } // For funding methods, see Currency trait impl Module { + + /// Get the amount that is currently being vested and cannot be transfered out of this account. + pub fn vesting_balance(who: &T::AccountId) -> T::Balance { + if let Some(v) = Self::vesting(who) { + Self::free_balance(who).min(v.locked_at(>::block_number())) + } else { + Zero::zero() + } + } + /// Set the free balance of an account to some new value. /// /// Will enforce ExistentialDeposit law, anulling the account as needed. @@ -260,9 +315,11 @@ impl Module { None => return Err("got overflow after adding a fee to value"), }; + let vesting_balance = Self::vesting_balance(transactor); let new_from_balance = match from_balance.checked_sub(&liability) { - Some(b) => b, None => return Err("balance too low to send value"), + Some(b) if b < vesting_balance => return Err("vesting balance too high to send value"), + Some(b) => b, }; if would_create && value < Self::existential_deposit() { return Err("value too low to create account"); diff --git a/substrate/srml/balances/src/mock.rs b/substrate/srml/balances/src/mock.rs index da3d30c034..03d2acf862 100644 --- a/substrate/srml/balances/src/mock.rs +++ b/substrate/srml/balances/src/mock.rs @@ -105,6 +105,7 @@ impl ExtBuilder { existential_deposit: self.existential_deposit, transfer_fee: self.transfer_fee, creation_fee: self.creation_fee, + vesting: vec![], }.build_storage().unwrap().0); t.into() } diff --git a/substrate/srml/contract/src/tests.rs b/substrate/srml/contract/src/tests.rs index 8931e37d8b..80efd3785d 100644 --- a/substrate/srml/contract/src/tests.rs +++ b/substrate/srml/contract/src/tests.rs @@ -170,6 +170,7 @@ impl ExtBuilder { existential_deposit: self.existential_deposit, transfer_fee: self.transfer_fee, creation_fee: self.creation_fee, + vesting: vec![], } .build_storage() .unwrap() diff --git a/substrate/srml/council/src/lib.rs b/substrate/srml/council/src/lib.rs index 03e6caef8c..5439336ef9 100644 --- a/substrate/srml/council/src/lib.rs +++ b/substrate/srml/council/src/lib.rs @@ -123,6 +123,7 @@ mod tests { existential_deposit: 0, transfer_fee: 0, creation_fee: 0, + vesting: vec![], }.build_storage().unwrap().0); t.extend(democracy::GenesisConfig::{ launch_period: 1, diff --git a/substrate/srml/democracy/src/lib.rs b/substrate/srml/democracy/src/lib.rs index 15323bbcaa..a246e98146 100644 --- a/substrate/srml/democracy/src/lib.rs +++ b/substrate/srml/democracy/src/lib.rs @@ -501,6 +501,7 @@ mod tests { existential_deposit: 0, transfer_fee: 0, creation_fee: 0, + vesting: vec![], }.build_storage().unwrap().0); t.extend(GenesisConfig::{ launch_period: 1, diff --git a/substrate/srml/executive/src/lib.rs b/substrate/srml/executive/src/lib.rs index 70318a65f4..c4e59dbbbd 100644 --- a/substrate/srml/executive/src/lib.rs +++ b/substrate/srml/executive/src/lib.rs @@ -355,6 +355,7 @@ mod tests { existential_deposit: 0, transfer_fee: 0, creation_fee: 0, + vesting: vec![], }.build_storage().unwrap().0); let xt = primitives::testing::TestXt(Some(1), 0, Call::transfer(2, 69)); let mut t = runtime_io::TestExternalities::::new(t); diff --git a/substrate/srml/staking/src/mock.rs b/substrate/srml/staking/src/mock.rs index ccf27ac432..09d63d2701 100644 --- a/substrate/srml/staking/src/mock.rs +++ b/substrate/srml/staking/src/mock.rs @@ -108,6 +108,7 @@ pub fn new_test_ext( existential_deposit: ext_deposit, transfer_fee: 0, creation_fee: 0, + vesting: vec![], }.build_storage().unwrap().0); t.extend(GenesisConfig::{ sessions_per_era, diff --git a/substrate/srml/treasury/src/lib.rs b/substrate/srml/treasury/src/lib.rs index f93c2324e4..a4fd741bb3 100644 --- a/substrate/srml/treasury/src/lib.rs +++ b/substrate/srml/treasury/src/lib.rs @@ -308,6 +308,7 @@ mod tests { transfer_fee: 0, creation_fee: 0, existential_deposit: 0, + vesting: vec![], }.build_storage().unwrap().0); t.extend(GenesisConfig::{ proposal_bond: Permill::from_percent(5),