@@ -84,6 +84,7 @@ pub struct VestingInfo<Balance, BlockNumber> {
8484 /// Amount that gets unlocked every block after `starting_block`.
8585 pub per_block : Balance ,
8686 /// Starting block for unlocking(vesting).
87+ /// It's relative position to the pallet vesting starting block.
8788 pub starting_block : BlockNumber ,
8889}
8990
@@ -207,6 +208,12 @@ pub mod pallet {
207208 ExistingVestingSchedule ,
208209 /// Amount being transferred is too low to create a vesting schedule.
209210 AmountLow ,
211+ /// change to the same per_block param
212+ SamePerBlock ,
213+ /// VestingStartAt storage is not set
214+ VestingStartAtNotSet ,
215+ /// Wrong amount
216+ WrongLockedAmount ,
210217 }
211218
212219 #[ pallet:: hooks]
@@ -397,6 +404,48 @@ pub mod pallet {
397404
398405 Ok ( ( ) )
399406 }
407+
408+ #[ pallet:: weight( 0 ) ]
409+ pub fn set_vesting_per_block (
410+ origin : OriginFor < T > ,
411+ target : <T :: Lookup as StaticLookup >:: Source ,
412+ per_block : BalanceOf < T > ,
413+ ) -> DispatchResult {
414+ ensure_root ( origin) ?;
415+ let target = T :: Lookup :: lookup ( target) ?;
416+
417+ Self :: update_lock ( target. clone ( ) ) ?;
418+ let vesting = Self :: vesting ( & target) . ok_or ( Error :: < T > :: NotVesting ) ?;
419+
420+ ensure ! ( vesting. per_block != per_block, Error :: <T >:: SamePerBlock ) ;
421+
422+ let absolute_start =
423+ VestingStartAt :: < T > :: get ( ) . ok_or ( Error :: < T > :: VestingStartAtNotSet ) ?;
424+ let now = <frame_system:: Pallet < T > >:: block_number ( ) ;
425+
426+ let old_start_at = absolute_start. saturating_add ( vesting. starting_block ) ;
427+ let remained_vesting =
428+ vesting. locked_at :: < T :: BlockNumberToBalance > ( now, Some ( old_start_at) ) ;
429+
430+ ensure ! ( remained_vesting <= vesting. locked, Error :: <T >:: WrongLockedAmount ) ;
431+
432+ let mut new_start_offset = vesting. starting_block ;
433+ if now > old_start_at {
434+ new_start_offset = now - absolute_start;
435+ }
436+
437+ Vesting :: < T > :: mutate_exists ( & target, |info| {
438+ if let Some ( ref mut vesting_info) = info {
439+ vesting_info. locked = remained_vesting;
440+ vesting_info. per_block = per_block;
441+ vesting_info. starting_block = new_start_offset;
442+ }
443+ } ) ;
444+
445+ Self :: update_lock ( target) ?;
446+
447+ Ok ( ( ) )
448+ }
400449 }
401450}
402451
@@ -946,4 +995,119 @@ mod tests {
946995 assert_eq ! ( user4_free_balance, 256 * 40 ) ;
947996 } ) ;
948997 }
998+
999+ #[ test]
1000+ fn set_vesting_per_block_should_work ( ) {
1001+ ExtBuilder :: default ( ) . existential_deposit ( 256 ) . build ( ) . execute_with ( || {
1002+ assert_ok ! ( Vesting :: init_vesting_start_at( Origin :: root( ) , 1 ) ) ;
1003+
1004+ let user1_free_balance = Balances :: free_balance ( & 1 ) ;
1005+ assert_eq ! ( user1_free_balance, 256 * 10 ) ; // Account 1 has free balance
1006+ let user1_vesting_schedule = VestingInfo {
1007+ locked : 256 * 5 ,
1008+ per_block : 128 , // Vesting over 10 blocks
1009+ starting_block : 0 ,
1010+ } ;
1011+
1012+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( user1_vesting_schedule) ) ; // Account 1 has a vesting schedule
1013+
1014+ // Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1
1015+ assert_eq ! ( Vesting :: vesting_balance( & 1 ) , Some ( 256 * 5 ) ) ;
1016+
1017+ System :: set_block_number ( 6 ) ;
1018+ assert_eq ! ( System :: block_number( ) , 6 ) ;
1019+
1020+ // Account 1 has vested by half at the end of block 5
1021+ assert_eq ! ( Vesting :: vesting_balance( & 1 ) , Some ( 128 * 5 ) ) ;
1022+
1023+ // Change the per_block of account 1 to 256
1024+ assert_ok ! ( Vesting :: set_vesting_per_block( Origin :: root( ) , 1 , 256 ) ) ;
1025+
1026+ System :: set_block_number ( 7 ) ;
1027+ assert_eq ! ( System :: block_number( ) , 7 ) ;
1028+
1029+ let change1_user1_vesting_schedule = VestingInfo {
1030+ locked : 256 * 5 - 128 * 5 ,
1031+ per_block : 256 , // Vesting over 10 blocks
1032+ starting_block : 5 ,
1033+ } ;
1034+
1035+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( change1_user1_vesting_schedule) ) ; // Account 1 has a vesting schedule
1036+ assert_eq ! ( Vesting :: vesting_balance( & 1 ) , Some ( 256 * 5 - 128 * 5 - 256 ) ) ;
1037+
1038+ assert_eq ! (
1039+ Vesting :: set_vesting_per_block( RawOrigin :: Root . into( ) , 1 , 256 ) ,
1040+ Err ( DispatchError :: Module { index: 2 , error: 3 , message: Some ( "SamePerBlock" ) } )
1041+ ) ;
1042+
1043+ assert_ok ! ( Vesting :: set_vesting_per_block( Origin :: root( ) , 1 , 10 ) ) ;
1044+
1045+ System :: set_block_number ( 8 ) ;
1046+ assert_eq ! ( System :: block_number( ) , 8 ) ;
1047+
1048+ let change2_user1_vesting_schedule = VestingInfo {
1049+ locked : 256 * 5 - 128 * 5 - 256 ,
1050+ per_block : 10 , // Vesting over 10 blocks
1051+ starting_block : 6 ,
1052+ } ;
1053+
1054+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( change2_user1_vesting_schedule) ) ;
1055+ assert_eq ! ( Vesting :: vesting_balance( & 1 ) , Some ( 256 * 5 - 128 * 5 - 256 - 10 ) ) ;
1056+
1057+ System :: set_block_number ( 46 ) ;
1058+ assert_eq ! ( System :: block_number( ) , 46 ) ;
1059+
1060+ assert_eq ! (
1061+ Vesting :: set_vesting_per_block( Origin :: root( ) , 1 , 20 ) ,
1062+ Err ( DispatchError :: Module { index: 2 , error: 0 , message: Some ( "NotVesting" ) } )
1063+ ) ;
1064+ } ) ;
1065+ }
1066+
1067+ #[ test]
1068+ fn set_vesting_per_block_before_and_after_original_start_block_should_work ( ) {
1069+ ExtBuilder :: default ( ) . existential_deposit ( 256 ) . build ( ) . execute_with ( || {
1070+ assert_ok ! ( Vesting :: init_vesting_start_at( Origin :: root( ) , 10 ) ) ;
1071+
1072+ let user1_free_balance = Balances :: free_balance ( & 1 ) ;
1073+ assert_eq ! ( user1_free_balance, 256 * 10 ) ; // Account 1 has free balance
1074+ let user1_vesting_schedule = VestingInfo {
1075+ locked : 256 * 5 ,
1076+ per_block : 128 , // Vesting over 10 blocks
1077+ starting_block : 0 ,
1078+ } ;
1079+
1080+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( user1_vesting_schedule) ) ; // Account 1 has a vesting schedule
1081+
1082+ // Account 1 has only 128 units vested from their illiquid 256 * 5 units at block 1
1083+ assert_eq ! ( Vesting :: vesting_balance( & 1 ) , Some ( 256 * 5 ) ) ;
1084+
1085+ System :: set_block_number ( 6 ) ;
1086+ assert_eq ! ( System :: block_number( ) , 6 ) ;
1087+
1088+ // Change the per_block of account 1 to 256
1089+ assert_ok ! ( Vesting :: set_vesting_per_block( Origin :: root( ) , 1 , 256 ) ) ;
1090+
1091+ let user2_vesting_schedule = VestingInfo {
1092+ locked : 256 * 5 ,
1093+ per_block : 256 , // Vesting over 10 blocks
1094+ starting_block : 0 ,
1095+ } ;
1096+
1097+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( user2_vesting_schedule) ) ; // Account 1 has a vesting schedule
1098+
1099+ System :: set_block_number ( 12 ) ;
1100+ assert_eq ! ( System :: block_number( ) , 12 ) ;
1101+
1102+ assert_ok ! ( Vesting :: set_vesting_per_block( Origin :: root( ) , 1 , 128 ) ) ;
1103+
1104+ let user3_vesting_schedule = VestingInfo {
1105+ locked : 256 * 5 - 256 * 2 ,
1106+ per_block : 128 , // Vesting over 10 blocks
1107+ starting_block : 2 ,
1108+ } ;
1109+
1110+ assert_eq ! ( Vesting :: vesting( & 1 ) , Some ( user3_vesting_schedule) ) ; // Account 1 has a vesting schedule
1111+ } ) ;
1112+ }
9491113}
0 commit comments