@@ -857,6 +857,8 @@ impl StakeAmount {
857
857
}
858
858
}
859
859
860
+ // TODO: remove subperiod argument since it's pointless. If BEP is > 0, then it's build&earn, otherwise it's voting or build&earn but it doesn't matter.
861
+
860
862
/// Unstake the specified `amount` for the specified `subperiod`.
861
863
///
862
864
/// In case subperiod is `Voting`, the amount is subtracted from the voting subperiod.
@@ -977,6 +979,8 @@ impl EraInfo {
977
979
/// Keeps track of amount staked in the 'voting subperiod', as well as 'build&earn subperiod'.
978
980
#[ derive( Encode , Decode , MaxEncodedLen , Copy , Clone , Debug , PartialEq , Eq , TypeInfo , Default ) ]
979
981
pub struct SingularStakingInfo {
982
+ /// Amount staked before, if anything.
983
+ previous_staked : StakeAmount ,
980
984
/// Staked amount
981
985
staked : StakeAmount ,
982
986
/// Indicates whether a staker is a loyal staker or not.
@@ -992,11 +996,10 @@ impl SingularStakingInfo {
992
996
/// `subperiod` - subperiod during which this entry is created.
993
997
pub fn new ( period : PeriodNumber , subperiod : Subperiod ) -> Self {
994
998
Self {
999
+ previous_staked : Default :: default ( ) ,
995
1000
staked : StakeAmount {
996
- voting : Balance :: zero ( ) ,
997
- build_and_earn : Balance :: zero ( ) ,
998
- era : 0 ,
999
1001
period,
1002
+ ..Default :: default ( )
1000
1003
} ,
1001
1004
// Loyalty staking is only possible if stake is first made during the voting subperiod.
1002
1005
loyal_staker : subperiod == Subperiod :: Voting ,
@@ -1005,11 +1008,17 @@ impl SingularStakingInfo {
1005
1008
1006
1009
/// Stake the specified amount on the contract, for the specified subperiod.
1007
1010
pub fn stake ( & mut self , amount : Balance , current_era : EraNumber , subperiod : Subperiod ) {
1008
- self . staked . add ( amount, subperiod) ;
1011
+ // Keep the previous stake amount for future reference
1012
+ self . previous_staked = self . staked ;
1013
+ self . previous_staked . era = current_era;
1014
+
1009
1015
// Stake is only valid from the next era so we keep it consistent here
1016
+ self . staked . add ( amount, subperiod) ;
1010
1017
self . staked . era = current_era. saturating_add ( 1 ) ;
1011
1018
}
1012
1019
1020
+ // TODO: add better docs below and in the function!
1021
+
1013
1022
/// Unstakes some of the specified amount from the contract.
1014
1023
///
1015
1024
/// In case the `amount` being unstaked is larger than the amount staked in the `Voting` subperiod,
@@ -1021,10 +1030,18 @@ impl SingularStakingInfo {
1021
1030
amount : Balance ,
1022
1031
current_era : EraNumber ,
1023
1032
subperiod : Subperiod ,
1024
- ) -> ( Balance , Balance ) {
1033
+ ) -> ( EraNumber , Balance ) {
1034
+ // Keep the previous stake amounts for final calculation
1025
1035
let snapshot = self . staked ;
1026
1036
1037
+ let stake_delta = self
1038
+ . staked
1039
+ . total ( )
1040
+ . saturating_sub ( self . previous_staked . total ( ) ) ;
1041
+
1042
+ // Modify inner fields
1027
1043
self . staked . subtract ( amount, subperiod) ;
1044
+ let unstaked_amount = snapshot. total ( ) . saturating_sub ( self . staked . total ( ) ) ;
1028
1045
// Keep the latest era for which the entry is valid
1029
1046
self . staked . era = self . staked . era . max ( current_era) ;
1030
1047
@@ -1034,13 +1051,23 @@ impl SingularStakingInfo {
1034
1051
Subperiod :: BuildAndEarn => self . staked . voting == snapshot. voting ,
1035
1052
} ;
1036
1053
1037
- // Amount that was unstaked
1038
- (
1039
- snapshot. voting . saturating_sub ( self . staked . voting ) ,
1040
- snapshot
1041
- . build_and_earn
1042
- . saturating_sub ( self . staked . build_and_earn ) ,
1043
- )
1054
+ // Move over the snapshot to the previous snapshot field and make sure
1055
+ // to update era in case something was staked before.
1056
+ if stake_delta. is_zero ( ) {
1057
+ self . previous_staked = Default :: default ( ) ;
1058
+ } else {
1059
+ self . previous_staked = snapshot;
1060
+ self . previous_staked . era = self . staked . era . saturating_sub ( 1 ) ;
1061
+ }
1062
+
1063
+ if stake_delta. is_zero ( ) {
1064
+ ( 0 , 0 )
1065
+ } else {
1066
+ (
1067
+ self . staked . era . saturating_sub ( 1 ) ,
1068
+ unstaked_amount. saturating_sub ( stake_delta) ,
1069
+ )
1070
+ }
1044
1071
}
1045
1072
1046
1073
/// Total staked on the contract by the user. Both subperiod stakes are included.
@@ -1199,11 +1226,49 @@ impl ContractStakeAmount {
1199
1226
}
1200
1227
1201
1228
/// Unstake the specified `Voting` and `Build&Earn` subperiod amounts from the contract, for the specified `subperiod` and `era`.
1202
- pub fn unstake (
1229
+ pub fn unstake ( & mut self , amount : Balance , period_info : PeriodInfo , current_era : EraNumber ) {
1230
+ // First align entries - we only need to keep track of the current era, and the next one
1231
+ match self . staked_future {
1232
+ // Future entry exists, but it covers current or older era.
1233
+ Some ( stake_amount)
1234
+ if stake_amount. era <= current_era && stake_amount. period == period_info. number =>
1235
+ {
1236
+ self . staked = stake_amount;
1237
+ self . staked . era = current_era;
1238
+ self . staked_future = None ;
1239
+ }
1240
+ _ => ( ) ,
1241
+ }
1242
+
1243
+ // Current entry is from the right period, but older era. Shift it to the current era.
1244
+ if self . staked . era < current_era && self . staked . period == period_info. number {
1245
+ self . staked . era = current_era;
1246
+ }
1247
+
1248
+ // Subtract both amounts
1249
+ self . staked . subtract ( amount, period_info. subperiod ) ;
1250
+ if let Some ( stake_amount) = self . staked_future . as_mut ( ) {
1251
+ stake_amount. subtract ( amount, period_info. subperiod ) ;
1252
+ }
1253
+
1254
+ // Convenience cleanup
1255
+ if self . staked . is_empty ( ) {
1256
+ self . staked = Default :: default ( ) ;
1257
+ }
1258
+ if let Some ( stake_amount) = self . staked_future {
1259
+ if stake_amount. is_empty ( ) {
1260
+ self . staked_future = None ;
1261
+ }
1262
+ }
1263
+ }
1264
+
1265
+ // TODO
1266
+ pub fn new_unstake (
1203
1267
& mut self ,
1204
1268
amount : Balance ,
1205
1269
period_info : PeriodInfo ,
1206
1270
current_era : EraNumber ,
1271
+ additional_unstake_info : ( EraNumber , Balance ) ,
1207
1272
) {
1208
1273
// First align entries - we only need to keep track of the current era, and the next one
1209
1274
match self . staked_future {
@@ -1224,9 +1289,15 @@ impl ContractStakeAmount {
1224
1289
}
1225
1290
1226
1291
// Subtract both amounts
1227
- self . staked . subtract ( amount, period_info. subperiod ) ;
1228
1292
if let Some ( stake_amount) = self . staked_future . as_mut ( ) {
1229
1293
stake_amount. subtract ( amount, period_info. subperiod ) ;
1294
+
1295
+ let ( old_era, old_amount) = additional_unstake_info;
1296
+ if self . staked . era == old_era {
1297
+ self . staked . subtract ( old_amount, period_info. subperiod ) ;
1298
+ }
1299
+ } else {
1300
+ self . staked . subtract ( amount, period_info. subperiod ) ;
1230
1301
}
1231
1302
1232
1303
// Convenience cleanup
0 commit comments