Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds rewards calculation for sporks #365

Merged
merged 2 commits into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions contracts/epochs/FlowEpoch.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,6 @@ pub contract FlowEpoch {
pub fun resetEpoch(
currentEpochCounter: UInt64,
randomSource: String,
newPayout: UFix64?,
startView: UInt64,
stakingEndView: UInt64,
endView: UInt64,
Expand All @@ -451,23 +450,28 @@ pub contract FlowEpoch {
FlowEpoch.borrowDKGAdmin().forceEndDKG()
}

// Start a new Epoch, which increments the current epoch counter
FlowEpoch.startNewEpoch()

let currentBlock = getCurrentBlock()

// Create new Epoch metadata for the next epoch
// with the new values
let newEpochMetadata = EpochMetadata(
counter: FlowEpoch.currentEpochCounter,
counter: currentEpochCounter + 1,
seed: randomSource,
startView: startView,
endView: endView,
stakingEndView: stakingEndView,
totalRewards: FlowIDTableStaking.getEpochTokenPayout(),
// This will be overwritten in `calculateAndSetRewards` below
totalRewards: UFix64(0.0),
collectorClusters: collectorClusters,
clusterQCs: clusterQCs,
dkgKeys: dkgPubKeys)

FlowEpoch.saveEpochMetadata(newEpochMetadata)

// Calculate rewards for the current epoch
// and set the payout for the next epoch
self.calculateAndSetRewards()

// Start a new Epoch, which increments the current epoch counter
FlowEpoch.startNewEpoch()
}
}

Expand Down
6 changes: 3 additions & 3 deletions lib/go/contracts/internal/assets/assets.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions lib/go/templates/internal/assets/assets.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

135 changes: 110 additions & 25 deletions lib/go/test/flow_epoch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1178,12 +1178,11 @@ func TestEpochReset(t *testing.T) {
var endView uint64 = 200

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateResetEpochScript(env), idTableAddress)
_ = tx.AddArgument(cadence.NewUInt64(startEpochCounter + 1))
_ = tx.AddArgument(CadenceString("stillSoRandom"))
_ = tx.AddArgument(CadenceUFix64("1300000.0"))
_ = tx.AddArgument(cadence.NewUInt64(startView))
_ = tx.AddArgument(cadence.NewUInt64(stakingEndView))
_ = tx.AddArgument(cadence.NewUInt64(endView))
tx.AddArgument(cadence.NewUInt64(startEpochCounter + 1))
tx.AddArgument(CadenceString("stillSoRandom"))
tx.AddArgument(cadence.NewUInt64(startView))
tx.AddArgument(cadence.NewUInt64(stakingEndView))
tx.AddArgument(cadence.NewUInt64(endView))

signAndSubmit(
t, b, tx,
Expand All @@ -1200,12 +1199,11 @@ func TestEpochReset(t *testing.T) {
var endView uint64 = 200

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateResetEpochScript(env), idTableAddress)
_ = tx.AddArgument(cadence.NewUInt64(startEpochCounter))
_ = tx.AddArgument(CadenceString("stillSoRandom"))
_ = tx.AddArgument(CadenceUFix64("1300000.0"))
_ = tx.AddArgument(cadence.NewUInt64(startView))
_ = tx.AddArgument(cadence.NewUInt64(stakingEndView))
_ = tx.AddArgument(cadence.NewUInt64(endView))
tx.AddArgument(cadence.NewUInt64(startEpochCounter))
tx.AddArgument(CadenceString("stillSoRandom"))
tx.AddArgument(cadence.NewUInt64(startView))
tx.AddArgument(cadence.NewUInt64(stakingEndView))
tx.AddArgument(cadence.NewUInt64(endView))

signAndSubmit(
t, b, tx,
Expand All @@ -1222,12 +1220,11 @@ func TestEpochReset(t *testing.T) {
var endView uint64 = 200

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateResetEpochScript(env), idTableAddress)
_ = tx.AddArgument(cadence.NewUInt64(startEpochCounter))
_ = tx.AddArgument(CadenceString("stillSoRandom"))
_ = tx.AddArgument(CadenceUFix64("1300000.0"))
_ = tx.AddArgument(cadence.NewUInt64(startView))
_ = tx.AddArgument(cadence.NewUInt64(stakingEndView))
_ = tx.AddArgument(cadence.NewUInt64(endView))
tx.AddArgument(cadence.NewUInt64(startEpochCounter))
tx.AddArgument(CadenceString("stillSoRandom"))
tx.AddArgument(cadence.NewUInt64(startView))
tx.AddArgument(cadence.NewUInt64(stakingEndView))
tx.AddArgument(cadence.NewUInt64(endView))

signAndSubmit(
t, b, tx,
Expand All @@ -1244,12 +1241,11 @@ func TestEpochReset(t *testing.T) {
var endView uint64 = 160

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateResetEpochScript(env), idTableAddress)
_ = tx.AddArgument(cadence.NewUInt64(startEpochCounter))
_ = tx.AddArgument(CadenceString("stillSoRandom"))
_ = tx.AddArgument(CadenceUFix64("1300000.0"))
_ = tx.AddArgument(cadence.NewUInt64(startView))
_ = tx.AddArgument(cadence.NewUInt64(stakingEndView))
_ = tx.AddArgument(cadence.NewUInt64(endView))
tx.AddArgument(cadence.NewUInt64(startEpochCounter))
tx.AddArgument(CadenceString("stillSoRandom"))
tx.AddArgument(cadence.NewUInt64(startView))
tx.AddArgument(cadence.NewUInt64(stakingEndView))
tx.AddArgument(cadence.NewUInt64(endView))

signAndSubmit(
t, b, tx,
Expand All @@ -1265,7 +1261,7 @@ func TestEpochReset(t *testing.T) {
startView: startView,
endView: endView,
stakingEndView: stakingEndView,
totalRewards: "1250000.0",
totalRewards: "0.0",
rewardsBreakdownArray: 0,
rewardsPaid: false,
collectorClusters: nil,
Expand All @@ -1278,4 +1274,93 @@ func TestEpochReset(t *testing.T) {
result = executeScriptAndCheck(t, b, templates.GenerateGetQCEnabledScript(env), nil)
assert.Equal(t, cadence.NewBool(false), result)
})

result := executeScriptAndCheck(t, b, templates.GenerateGetFlowTotalSupplyScript(env), nil)
assertEqual(t, CadenceUFix64("7000000000.0"), result)

t.Run("Can reset the epoch during the staking auction with automatic rewards enabled", func(t *testing.T) {

tx := createTxWithTemplateAndAuthorizer(b, templates.GenerateEpochSetAutomaticRewardsScript(env), idTableAddress)

tx.AddArgument(cadence.NewBool(true))

signAndSubmit(
t, b, tx,
[]flow.Address{idTableAddress},
[]crypto.Signer{IDTableSigner},
false,
)

var startView uint64 = 100
var stakingEndView uint64 = 120
var endView uint64 = 160

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateResetEpochScript(env), idTableAddress)
tx.AddArgument(cadence.NewUInt64(startEpochCounter + 1))
tx.AddArgument(CadenceString("stillSoRandom"))
tx.AddArgument(cadence.NewUInt64(startView))
tx.AddArgument(cadence.NewUInt64(stakingEndView))
tx.AddArgument(cadence.NewUInt64(endView))

signAndSubmit(
t, b, tx,
[]flow.Address{idTableAddress},
[]crypto.Signer{IDTableSigner},
false,
)

// Verify the current epoch's metadata to make sure rewards were calculated
// properly after the reset and that they haven't been paid yet
verifyEpochMetadata(t, b, env,
EpochMetadata{
counter: startEpochCounter + 2,
seed: "stillSoRandom",
startView: startView,
endView: endView,
stakingEndView: stakingEndView,
// The calculation of the total rewards should have happened
// because automatic rewards are enabled
// (total supply + current payount amount - bonus tokens) * reward increase factor
// (7000000000 + 1250000 - 0) * 0.00093871 = 6,571,204.6775
totalRewards: "6572143.3875",
rewardsBreakdownArray: 0,
rewardsPaid: false,
collectorClusters: nil,
clusterQCs: nil,
dkgKeys: nil})

tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateEpochPayRewardsScript(env), idTableAddress)

signAndSubmit(
t, b, tx,
[]flow.Address{idTableAddress},
[]crypto.Signer{IDTableSigner},
false,
)

// Verifies that the rewards from the previous epoch does not include the new epoch's amount
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we spork, the rewards for the epoch pre-spork will be paid out when the resetEpoch transaction is submitted. Currently this is the next day, on Thursday. It would be ideal if this multisig could be moved to Wednesday, so there isn't a 1-day delay in reward payouts, once this is enabled. cc @vishalchangrani

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, it would be nice to reset on the same day as the spork

verifyEpochTotalRewardsPaid(t, b, idTableAddress,
EpochTotalRewardsPaid{
total: "1250000.00000000",
fromFees: "0.0",
minted: "1250000.00000000",
feesBurned: "0.035"})

result = executeScriptAndCheck(t, b, templates.GenerateGetRewardBalanceScript(env), [][]byte{jsoncdc.MustEncode(cadence.String(ids[0]))})
assertEqual(t, CadenceUFix64("249999.99300000"), result)

// Rewards have already been paid, so this should not do anything
tx = createTxWithTemplateAndAuthorizer(b, templates.GenerateEpochPayRewardsScript(env), idTableAddress)

signAndSubmit(
t, b, tx,
[]flow.Address{idTableAddress},
[]crypto.Signer{IDTableSigner},
false,
)

// The nodes rewards should not have increased
result = executeScriptAndCheck(t, b, templates.GenerateGetRewardBalanceScript(env), [][]byte{jsoncdc.MustEncode(cadence.String(ids[0]))})
assertEqual(t, CadenceUFix64("249999.99300000"), result)
})
}
2 changes: 0 additions & 2 deletions transactions/epoch/admin/reset_epoch.cdc
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import FlowIDTableStaking from 0xIDENTITYTABLEADDRESS

transaction(currentEpochCounter: UInt64,
randomSource: String,
newPayout: UFix64?,
startView: UInt64,
stakingEndView: UInt64,
endView: UInt64) {
Expand All @@ -26,7 +25,6 @@ transaction(currentEpochCounter: UInt64,

heartbeat.resetEpoch(currentEpochCounter: currentEpochCounter,
randomSource: randomSource,
newPayout: newPayout,
startView: startView,
stakingEndView: stakingEndView,
endView: endView,
Expand Down