Introduce vesting offsets (#3094)

* Introduce vesting offsets

Closes #3090

* Fix logic

* Bump impl verfsion

* Initial rewrite of vesting

* Test for liquidity with delayed vesting

* Bump Spec, Fix line width

* More line width fix

* Small nit to documentation
This commit is contained in:
Gavin Wood
2019-07-16 10:22:18 +09:00
committed by GitHub
parent f74c2676da
commit 1b5bafc8de
4 changed files with 160 additions and 63 deletions
+115 -42
View File
@@ -111,31 +111,37 @@ fn lock_value_extension_should_work() {
#[test]
fn lock_reasons_should_work() {
with_externalities(&mut ExtBuilder::default().existential_deposit(1).monied(true).transaction_fees(0, 1).build(), || {
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 1),
"account liquidity restrictions prevent withdrawal"
);
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert_ok!(<Balances as MakePayment<_>>::make_payment(&1, 1));
with_externalities(
&mut ExtBuilder::default()
.existential_deposit(1)
.monied(true).transaction_fees(0, 1)
.build(),
|| {
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Transfer.into());
assert_noop!(
<Balances as Currency<_>>::transfer(&1, &2, 1),
"account liquidity restrictions prevent withdrawal"
);
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert_ok!(<Balances as MakePayment<_>>::make_payment(&1, 1));
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1));
assert_noop!(
<Balances as ReservableCurrency<_>>::reserve(&1, 1),
"account liquidity restrictions prevent withdrawal"
);
assert_ok!(<Balances as MakePayment<_>>::make_payment(&1, 1));
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::Reserve.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1));
assert_noop!(
<Balances as ReservableCurrency<_>>::reserve(&1, 1),
"account liquidity restrictions prevent withdrawal"
);
assert_ok!(<Balances as MakePayment<_>>::make_payment(&1, 1));
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1));
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert_noop!(
<Balances as MakePayment<_>>::make_payment(&1, 1),
"account liquidity restrictions prevent withdrawal"
);
});
Balances::set_lock(ID_1, &1, 10, u64::max_value(), WithdrawReason::TransactionPayment.into());
assert_ok!(<Balances as Currency<_>>::transfer(&1, &2, 1));
assert_ok!(<Balances as ReservableCurrency<_>>::reserve(&1, 1));
assert_noop!(
<Balances as MakePayment<_>>::make_payment(&1, 1),
"account liquidity restrictions prevent withdrawal"
);
}
);
}
#[test]
@@ -204,8 +210,9 @@ fn default_indexing_on_new_accounts_should_not_work2() {
.monied(true)
.build(),
|| {
assert_eq!(Balances::is_dead_account(&5), true); // account 5 should not exist
// account 1 has 256 * 10 = 2560, account 5 is not exist, ext_deposit is 10, value is 9, not satisfies for ext_deposit
// ext_deposit is 10, value is 9, not satisfies for ext_deposit
assert_noop!(
Balances::transfer(Some(1).into(), 5, 9),
"value too low to create account"
@@ -235,16 +242,19 @@ fn reserved_balance_should_prevent_reclaim_count() {
assert_eq!(Balances::is_dead_account(&2), false);
assert_eq!(System::account_nonce(&2), 1);
assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69)); // account 4 tries to take index 1 for account 5.
// account 4 tries to take index 1 for account 5.
assert_ok!(Balances::transfer(Some(4).into(), 5, 256 * 1 + 0x69));
assert_eq!(Balances::total_balance(&5), 256 * 1 + 0x69);
assert_eq!(Balances::is_dead_account(&5), false);
assert!(Balances::slash(&2, 256 * 18 + 2).1.is_zero()); // account 2 gets slashed
assert_eq!(Balances::total_balance(&2), 0); // "reserve" account reduced to 255 (below ED) so account deleted
// "reserve" account reduced to 255 (below ED) so account deleted
assert_eq!(Balances::total_balance(&2), 0);
assert_eq!(System::account_nonce(&2), 0); // nonce zero
assert_eq!(Balances::is_dead_account(&2), true);
assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69)); // account 4 tries to take index 1 again for account 6.
// account 4 tries to take index 1 again for account 6.
assert_ok!(Balances::transfer(Some(4).into(), 6, 256 * 1 + 0x69));
assert_eq!(Balances::total_balance(&6), 256 * 1 + 0x69);
assert_eq!(Balances::is_dead_account(&6), false);
},
@@ -258,7 +268,7 @@ fn reward_should_work() {
assert_eq!(Balances::total_balance(&1), 10);
assert_ok!(Balances::deposit_into_existing(&1, 10).map(drop));
assert_eq!(Balances::total_balance(&1), 20);
assert_eq!(<TotalIssuance<Runtime>>::get(), 110);
assert_eq!(<TotalIssuance<Runtime>>::get(), 120);
});
}
@@ -294,7 +304,8 @@ fn dust_account_removal_should_work2() {
System::inc_account_nonce(&2);
assert_eq!(System::account_nonce(&2), 1);
assert_eq!(Balances::total_balance(&2), 2000);
assert_ok!(Balances::transfer(Some(2).into(), 5, 1851)); // index 1 (account 2) becomes zombie for 256*10 + 50(fee) < 256 * 10 (ext_deposit)
// index 1 (account 2) becomes zombie for 256*10 + 50(fee) < 256 * 10 (ext_deposit)
assert_ok!(Balances::transfer(Some(2).into(), 5, 1851));
assert_eq!(Balances::total_balance(&2), 0);
assert_eq!(Balances::total_balance(&5), 1851);
assert_eq!(System::account_nonce(&2), 0);
@@ -571,32 +582,52 @@ fn check_vesting_status() {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
let user2_free_balance = Balances::free_balance(&2);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user1_free_balance, 256 * 10); // Account 1 has free balance
assert_eq!(user2_free_balance, 256 * 20); // Account 2 has free balance
assert_eq!(user12_free_balance, 256 * 10); // Account 12 has free balance
let user1_vesting_schedule = VestingSchedule {
offset: 256 * 10,
per_block: 256,
locked: 256 * 5,
per_block: 128, // Vesting over 10 blocks
starting_block: 0,
};
let user2_vesting_schedule = VestingSchedule {
offset: 256 * 30,
per_block: 256,
locked: 256 * 20,
per_block: 256, // Vesting over 20 blocks
starting_block: 10,
};
let user12_vesting_schedule = VestingSchedule {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Balances::vesting(&1), Some(user1_vesting_schedule)); // Account 1 has a vesting schedule
assert_eq!(Balances::vesting(&2), Some(user2_vesting_schedule)); // Account 2 has a vesting schedule
assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule)); // Account 12 has a vesting schedule
assert_eq!(Balances::vesting_balance(&1), user1_free_balance - 256); // Account 1 has only 256 units vested at block 1
// Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1
assert_eq!(Balances::vesting_balance(&1), 128 * 9);
// Account 2 has their full balance locked
assert_eq!(Balances::vesting_balance(&2), user2_free_balance);
// Account 12 has only their illiquid funds locked
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(10);
assert_eq!(System::block_number(), 10);
assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 has fully vested by block 10
assert_eq!(Balances::vesting_balance(&2), user2_free_balance); // Account 2 has started vesting by block 10
// Account 1 has fully vested by block 10
assert_eq!(Balances::vesting_balance(&1), 0);
// Account 2 has started vesting by block 10
assert_eq!(Balances::vesting_balance(&2), user2_free_balance);
// Account 12 has started vesting by block 10
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
System::set_block_number(30);
assert_eq!(System::block_number(), 30);
assert_eq!(Balances::vesting_balance(&1), 0); // Account 1 is still fully vested, and not negative
assert_eq!(Balances::vesting_balance(&2), 0); // Account 2 has fully vested by block 30
assert_eq!(Balances::vesting_balance(&12), 0); // Account 2 has fully vested by block 30
}
);
@@ -614,9 +645,10 @@ fn unvested_balance_should_not_transfer() {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has only 10 units vested at block 1
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_noop!(
Balances::transfer(Some(1).into(), 2, 11),
Balances::transfer(Some(1).into(), 2, 56),
"vesting balance too high to send value"
); // Account 1 cannot send more than vested amount
}
@@ -635,8 +667,9 @@ fn vested_balance_should_transfer() {
assert_eq!(System::block_number(), 1);
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 100); // Account 1 has free balance
assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has only 10 units vested at block 1
assert_ok!(Balances::transfer(Some(1).into(), 2, 10));
// Account 1 has only 5 units vested at block 1 (plus 50 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_ok!(Balances::transfer(Some(1).into(), 2, 55));
}
);
}
@@ -652,11 +685,51 @@ fn extra_balance_should_transfer() {
|| {
assert_eq!(System::block_number(), 1);
assert_ok!(Balances::transfer(Some(3).into(), 1, 100));
assert_ok!(Balances::transfer(Some(3).into(), 2, 100));
let user1_free_balance = Balances::free_balance(&1);
assert_eq!(user1_free_balance, 200); // Account 1 has 100 more free balance than normal
assert_eq!(Balances::vesting_balance(&1), 90); // Account 1 has 90 units vested at block 1
assert_ok!(Balances::transfer(Some(1).into(), 2, 105)); // Account 1 can send extra units gained
let user2_free_balance = Balances::free_balance(&2);
assert_eq!(user2_free_balance, 300); // Account 2 has 100 more free balance than normal
// Account 1 has only 5 units vested at block 1 (plus 150 unvested)
assert_eq!(Balances::vesting_balance(&1), 45);
assert_ok!(Balances::transfer(Some(1).into(), 3, 155)); // Account 1 can send extra units gained
// Account 2 has no units vested at block 1, but gained 100
assert_eq!(Balances::vesting_balance(&2), 200);
assert_ok!(Balances::transfer(Some(2).into(), 3, 100)); // Account 2 can send extra units gained
}
);
}
#[test]
fn liquid_funds_should_transfer_with_delayed_vesting() {
with_externalities(
&mut ExtBuilder::default()
.existential_deposit(256)
.monied(true)
.vesting(true)
.build(),
|| {
assert_eq!(System::block_number(), 1);
let user12_free_balance = Balances::free_balance(&12);
assert_eq!(user12_free_balance, 2560); // Account 12 has free balance
// Account 12 has liquid funds
assert_eq!(Balances::vesting_balance(&12), user12_free_balance - 256 * 5);
// Account 12 has delayed vesting
let user12_vesting_schedule = VestingSchedule {
locked: 256 * 5,
per_block: 64, // Vesting over 20 blocks
starting_block: 10,
};
assert_eq!(Balances::vesting(&12), Some(user12_vesting_schedule));
// Account 12 can still send liquid funds
assert_ok!(Balances::transfer(Some(12).into(), 3, 256 * 5));
}
);
}