/
hooks.go
169 lines (148 loc) · 5.28 KB
/
hooks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package keeper
import (
"fmt"
"github.com/armon/go-metrics"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/NibiruChain/nibiru/x/common/denoms"
epochstypes "github.com/NibiruChain/nibiru/x/epochs/types"
"github.com/NibiruChain/nibiru/x/inflation/types"
)
// Hooks implements module-specific calls ([epochstypes.EpochHooks]) that will
// occur at the end of every epoch. Hooks is meant for use with with
// `EpochsKeeper.SetHooks`. These functions run outside of the normal body of
// transactions.
type Hooks struct {
K Keeper
}
var _ epochstypes.EpochHooks = Hooks{}
// Hooks implements module-speecific calls that will occur in the ABCI
// BeginBlock logic.
func (k Keeper) Hooks() Hooks {
return Hooks{k}
}
// BeforeEpochStart is a hook that runs just prior to the start of a new epoch.
func (h Hooks) BeforeEpochStart(ctx sdk.Context, epochIdentifier string, epochNumber uint64) {
// Perform no operations; we don't need to do anything here
_, _, _ = ctx, epochIdentifier, epochNumber
}
// AfterEpochEnd is a hook that runs just prior to the first block whose
// timestamp is after the end of an epoch duration.
// AfterEpochEnd mints and allocates coins at the end of each epoch.
// If inflation is disabled as a module parameter, the state for
// "NumSkippedEpochs" increments.
func (h Hooks) AfterEpochEnd(ctx sdk.Context, epochIdentifier string, epochNumber uint64) {
if epochIdentifier != epochstypes.DayEpochID {
return
}
params := h.K.GetParams(ctx)
// Skip inflation if it is disabled and increment number of skipped epochs
if !params.InflationEnabled {
var prevSkippedEpochs uint64
if !params.HasInflationStarted {
// If the inflation never started, we use epochNumber as the number of skipped epochs
// to avoid missing periods when we upgrade a chain.
h.K.NumSkippedEpochs.Set(ctx, epochNumber)
prevSkippedEpochs = epochNumber
} else {
prevSkippedEpochs = h.K.NumSkippedEpochs.Next(ctx)
}
h.K.Logger(ctx).Debug(
"skipping inflation mint and allocation",
"height", ctx.BlockHeight(),
"epoch-id", epochIdentifier,
"epoch-number", epochNumber,
"skipped-epochs", prevSkippedEpochs,
)
return
}
// mint coins, update supply
period := h.K.CurrentPeriod.Peek(ctx)
epochsPerPeriod := h.K.GetEpochsPerPeriod(ctx)
epochMintProvision := types.CalculateEpochMintProvision(
params,
period,
)
if !epochMintProvision.IsPositive() {
h.K.Logger(ctx).Error(
"SKIPPING INFLATION: negative epoch mint provision",
"value", epochMintProvision.String(),
)
return
}
mintedCoin := sdk.Coin{
Denom: denoms.NIBI,
Amount: epochMintProvision.TruncateInt(),
}
staking, strategic, communityPool, err := h.K.MintAndAllocateInflation(ctx, mintedCoin, params)
if err != nil {
h.K.Logger(ctx).Error(
"SKIPPING INFLATION: failed to mint and allocate inflation",
"error", err,
)
return
}
// If period is passed, update the period. A period is
// passed if the current epoch number surpasses the epochsPerPeriod for the
// current period. Skipped epochs are subtracted to only account for epochs
// where inflation minted tokens.
//
// Examples:
// Given, epochNumber = 1, period = 0, epochPerPeriod = 30, skippedEpochs = 0
// => 1 - 30 * 0 - 0 < 30
// => nothing to do here
// Given, epochNumber = 70, period = 1, epochPerPeriod = 30, skippedEpochs = 10
// => 70 - 1 * 30 - 10 >= 30
// => a period has ended! we set a new period
// Given, epochNumber = 42099, period = 0, epochPerPeriod = 30, skippedEpochs = 42069
// => 42099 - 0 * 30 - 42069 >= 30
// => a period has ended! we set a new period
numSkippedEpochs := h.K.NumSkippedEpochs.Peek(ctx)
if int64(epochNumber)-
int64(epochsPerPeriod*period)-
int64(numSkippedEpochs) >= int64(epochsPerPeriod) {
periodBeforeIncrement := h.K.CurrentPeriod.Next(ctx)
h.K.Logger(ctx).Info(fmt.Sprintf("setting new period: %d", periodBeforeIncrement+1))
}
defer func() {
stakingAmt := staking.Amount
strategicAmt := strategic.Amount
cpAmt := communityPool.Amount
if mintedCoin.Amount.IsInt64() {
telemetry.IncrCounterWithLabels(
[]string{types.ModuleName, "allocate", "total"},
float32(mintedCoin.Amount.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", mintedCoin.Denom)},
)
}
if stakingAmt.IsInt64() {
telemetry.IncrCounterWithLabels(
[]string{types.ModuleName, "allocate", "staking", "total"},
float32(stakingAmt.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", mintedCoin.Denom)},
)
}
if strategicAmt.IsInt64() {
telemetry.IncrCounterWithLabels(
[]string{types.ModuleName, "allocate", "strategic", "total"},
float32(strategicAmt.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", mintedCoin.Denom)},
)
}
if cpAmt.IsInt64() {
telemetry.IncrCounterWithLabels(
[]string{types.ModuleName, "allocate", "community_pool", "total"},
float32(cpAmt.Int64()),
[]metrics.Label{telemetry.NewLabel("denom", mintedCoin.Denom)},
)
}
}()
ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypeInflation,
sdk.NewAttribute(types.AttributeEpochNumber, fmt.Sprintf("%d", epochNumber-numSkippedEpochs)),
sdk.NewAttribute(types.AttributeKeyEpochProvisions, epochMintProvision.String()),
sdk.NewAttribute(sdk.AttributeKeyAmount, mintedCoin.Amount.String()),
),
)
}