@@ -3,6 +3,7 @@ import FlowToken from 0xFLOWTOKENADDRESS
3
3
import FlowIDTableStaking from 0xFLOWIDTABLESTAKINGADDRESS
4
4
import FlowClusterQC from 0xQCADDRESS
5
5
import FlowDKG from 0xDKGADDRESS
6
+ import FlowFees from 0xFLOWFEESADDRESS
6
7
7
8
// The top-level smart contract managing the lifecycle of epochs. In Flow,
8
9
// epochs are the smallest unit of time where the identity table (the set of
@@ -212,8 +213,8 @@ pub contract FlowEpoch {
212
213
/// The number of collector clusters in each epoch
213
214
pub (set) var numCollectorClusters : UInt16
214
215
215
- /// Tracks the annualized percentage of FLOW total supply that is minted as rewards at the end of an epoch
216
- /// Calculation for a single epoch would be (totalSupply * FLOWsupplyIncreasePercentage) / 52
216
+ /// Tracks the rate at which the rewards payout increases every epoch
217
+ /// This value is multiplied by the FLOW total supply to get the next payout
217
218
pub (set) var FLOWsupplyIncreasePercentage : UFix64
218
219
219
220
init (numViewsInEpoch : UInt64 , numViewsInStakingAuction : UInt64 , numViewsInDKGPhase : UInt64 , numCollectorClusters : UInt16 , FLOWsupplyIncreasePercentage : UFix64 ) {
@@ -331,6 +332,12 @@ pub contract FlowEpoch {
331
332
332
333
FlowEpoch.configurableMetadata.FLOWsupplyIncreasePercentage = newPercentage
333
334
}
335
+
336
+ // Enable or disable automatic rewards calculations and payments
337
+ pub fun updateAutomaticRewardsEnabled (_ enabled : Bool ) {
338
+ FlowEpoch.account.load< Bool> (from : / storage/ flowAutomaticRewardsEnabled)
339
+ FlowEpoch.account.save (enabled, to : / storage/ flowAutomaticRewardsEnabled)
340
+ }
334
341
}
335
342
336
343
/// Resource that is controlled by the protocol and is used
@@ -357,8 +364,11 @@ pub contract FlowEpoch {
357
364
let currentBlock = getCurrentBlock ()
358
365
let currentEpochMetadata = FlowEpoch.getEpochMetadata (FlowEpoch.currentEpochCounter)!
359
366
if currentBlock.view > = currentEpochMetadata.endView {
360
- self .calculateAndSetRewards (nil )
367
+ self .calculateAndSetRewards ()
361
368
self .endEpoch ()
369
+ if FlowEpoch.automaticRewardsEnabled () {
370
+ self .payRewards ()
371
+ }
362
372
}
363
373
default :
364
374
return
@@ -399,8 +409,8 @@ pub contract FlowEpoch {
399
409
400
410
/// Needs to be called before the epoch is over
401
411
/// Calculates rewards for the current epoch and stores them in epoch metadata
402
- pub fun calculateAndSetRewards (_ newPayout : UFix64 ? ) {
403
- FlowEpoch.calculateAndSetRewards (newPayout )
412
+ pub fun calculateAndSetRewards () {
413
+ FlowEpoch.calculateAndSetRewards ()
404
414
}
405
415
406
416
pub fun payRewards () {
@@ -438,8 +448,6 @@ pub contract FlowEpoch {
438
448
FlowEpoch.borrowDKGAdmin ().forceEndDKG ()
439
449
}
440
450
441
- FlowEpoch.calculateAndSetRewards (newPayout)
442
-
443
451
// Start a new Epoch, which increments the current epoch counter
444
452
FlowEpoch.startNewEpoch ()
445
453
@@ -462,21 +470,37 @@ pub contract FlowEpoch {
462
470
463
471
/// Calculates a new token payout for the current epoch
464
472
/// and sets the new payout for the next epoch
465
- access (account) fun calculateAndSetRewards (_ newPayout : UFix64 ? ) {
473
+ access (account) fun calculateAndSetRewards () {
466
474
467
- let rewardsBreakdown = self .borrowStakingAdmin ().calculateRewards ()
475
+ let stakingAdmin = self .borrowStakingAdmin ()
476
+
477
+ // Calculate rewards for the current epoch that is about to end
478
+ // and save that reward breakdown in the epoch metadata for the current epoch
479
+ let rewardsBreakdown = stakingAdmin.calculateRewards ()
468
480
let currentMetadata = self .getEpochMetadata (self .currentEpochCounter)!
469
481
currentMetadata.setRewardAmounts (rewardsBreakdown)
470
482
self .saveEpochMetadata (currentMetadata)
471
483
472
- // Calculate the new epoch's payout
473
- // disabled until we enable automated rewards calculations
474
- // let newPayout = FlowToken.totalSupply * (FlowEpoch.configurableMetadata.FLOWsupplyIncreasePercentage / 52.0)
484
+ if FlowEpoch.automaticRewardsEnabled () {
485
+ // Calculate the total supply of FLOW after the current epoch's payout
486
+ // the calculation includes the tokens that haven't been minted for the current epoch yet
487
+ let currentPayout = FlowIDTableStaking.getEpochTokenPayout ()
488
+ let feeAmount = FlowFees.getFeeBalance ()
489
+ var flowTotalSupplyAfterPayout = 0 .0
490
+ if feeAmount > = currentPayout {
491
+ flowTotalSupplyAfterPayout = FlowToken.totalSupply
492
+ } else {
493
+ flowTotalSupplyAfterPayout = FlowToken.totalSupply + (currentPayout - feeAmount)
494
+ }
495
+
496
+ // Calculate the payout for the next epoch
497
+ let proposedPayout = flowTotalSupplyAfterPayout * FlowEpoch.configurableMetadata.FLOWsupplyIncreasePercentage
475
498
476
- if let payout = newPayout {
477
- self .borrowStakingAdmin ().setEpochTokenPayout (payout)
478
- let proposedMetadata = self .getEpochMetadata (self .proposedEpochCounter ())!
479
- proposedMetadata.setTotalRewards (payout)
499
+ // Set the new payout in the staking contract and proposed Epoch Metadata
500
+ self .borrowStakingAdmin ().setEpochTokenPayout (proposedPayout)
501
+ let proposedMetadata = self .getEpochMetadata (self .proposedEpochCounter ())
502
+ ?? panic (" Cannot set rewards for the next epoch becuase it hasn't been proposed yet" )
503
+ proposedMetadata.setTotalRewards (proposedPayout)
480
504
self .saveEpochMetadata (proposedMetadata)
481
505
}
482
506
}
@@ -767,6 +791,10 @@ pub contract FlowEpoch {
767
791
return self .currentEpochCounter + 1 as UInt64
768
792
}
769
793
794
+ pub fun automaticRewardsEnabled (): Bool {
795
+ return self .account.copy< Bool> (from : / storage/ flowAutomaticRewardsEnabled) ?? false
796
+ }
797
+
770
798
init (currentEpochCounter : UInt64 ,
771
799
numViewsInEpoch : UInt64 ,
772
800
numViewsInStakingAuction : UInt64 ,
0 commit comments