-
Notifications
You must be signed in to change notification settings - Fork 0
/
emission.go
153 lines (126 loc) · 4.78 KB
/
emission.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
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/elysium-station/blackfury/x/ve/types"
)
type Emitter struct {
keeper Keeper
}
func NewEmitter(keeper Keeper) Emitter {
return Emitter{keeper: keeper}
}
func (e Emitter) AddTotalEmission(ctx sdk.Context, emission sdk.Int) {
if !emission.IsPositive() {
panic("emission must be nonzero")
}
total := e.keeper.GetTotalEmission(ctx)
e.keeper.SetTotalEmission(ctx, total.Add(emission))
// for geometric sequence of weeks of every 4 years,
// a * (1 - r^n) / (1 - r) = <total emission>
emissionInitial := emission.ToDec().Mul(sdk.OneDec().Sub(types.EmissionRatio)).Quo(sdk.OneDec().Sub(types.EmissionRatio.Power(types.MaxLockTimeWeeks))).TruncateInt()
emissionLast := e.keeper.GetEmissionAtLastPeriod(ctx)
e.keeper.SetEmissionAtLastPeriod(ctx, emissionLast.Add(emissionInitial))
}
func (e Emitter) CirculationSupply(ctx sdk.Context) sdk.Int {
totalSupply := e.keeper.bankKeeper.GetSupply(ctx, e.keeper.LockDenom(ctx)).Amount
// actually voting power is degenerative locked amount by ve
veLocked := e.keeper.GetTotalVotingPower(ctx, 0, ctx.BlockHeight())
return totalSupply.Sub(veLocked)
}
func (e Emitter) CirculationRate(ctx sdk.Context) sdk.Dec {
totalSupply := e.keeper.bankKeeper.GetSupply(ctx, e.keeper.LockDenom(ctx)).Amount
return e.CirculationSupply(ctx).ToDec().QuoInt(totalSupply)
}
func (e Emitter) Emission(ctx sdk.Context) sdk.Int {
emissionLast := e.keeper.GetEmissionAtLastPeriod(ctx)
emission := emissionLast.ToDec().Mul(types.EmissionRatio)
circulationRate := e.CirculationRate(ctx)
if circulationRate.LT(types.MinEmissionCirculating) {
circulationRate = types.MinEmissionCirculating
}
return emission.Mul(circulationRate).TruncateInt()
}
func (e Emitter) EmissionCompensation(ctx sdk.Context, emission sdk.Int) sdk.Int {
return emission.ToDec().Mul(sdk.OneDec().Sub(e.CirculationRate(ctx))).TruncateInt()
}
// Emit emits coin rewards of every period, on the basis of predefined emission policy.
// The part of compensation for ve holders will be sent into the distribution pool.
// The remaining will be deposited as rewards by the voter module.
func (e Emitter) Emit(ctx sdk.Context) sdk.Int {
timestamp := types.RegulatedUnixTimeFromNow(ctx, 0)
timeLast := e.keeper.GetEmissionLastTimestamp(ctx)
// only allow one emission per period
if timestamp-timeLast < types.RegulatedPeriod {
return sdk.ZeroInt()
}
// TODO: add initialization
if true {
return sdk.ZeroInt()
}
emission := e.Emission(ctx)
// mint emission amount
emissionAmt := sdk.NewCoin(e.keeper.LockDenom(ctx), emission)
err := e.keeper.bankKeeper.MintCoins(ctx, types.EmissionPoolName, sdk.NewCoins(emissionAmt))
if err != nil {
panic(err)
}
e.keeper.SetEmissionLastTimestamp(ctx, timestamp)
e.keeper.SetEmissionAtLastPeriod(ctx, emission)
// calculate compensation for ve holders due to inflation loss
compensation := e.EmissionCompensation(ctx, emission)
compensationAmt := sdk.NewCoin(e.keeper.LockDenom(ctx), compensation)
// send compensation into distribution pool
err = e.keeper.bankKeeper.SendCoinsFromModuleToModule(ctx, types.EmissionPoolName, types.DistributionPoolName, sdk.NewCoins(compensationAmt))
if err != nil {
panic(err)
}
NewDistributor(e.keeper).DistributePerPeriod(ctx)
e.keeper.RegulateCheckpoint(ctx)
emission = emission.Sub(compensation)
return emission
}
func (k Keeper) AddTotalEmission(ctx sdk.Context, emission sdk.Int) {
NewEmitter(k).AddTotalEmission(ctx, emission)
}
func (k Keeper) SetTotalEmission(ctx sdk.Context, total sdk.Int) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&sdk.IntProto{Int: total})
store.Set(types.TotalEmissionKey(), bz)
}
func (k Keeper) GetTotalEmission(ctx sdk.Context) sdk.Int {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.TotalEmissionKey())
if bz == nil {
return sdk.ZeroInt()
}
var total sdk.IntProto
k.cdc.MustUnmarshal(bz, &total)
return total.Int
}
func (k Keeper) SetEmissionAtLastPeriod(ctx sdk.Context, emission sdk.Int) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshal(&sdk.IntProto{Int: emission})
store.Set(types.EmissionAtLastPeriodKey(), bz)
}
func (k Keeper) GetEmissionAtLastPeriod(ctx sdk.Context) sdk.Int {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.EmissionAtLastPeriodKey())
if bz == nil {
return sdk.ZeroInt()
}
var emission sdk.IntProto
k.cdc.MustUnmarshal(bz, &emission)
return emission.Int
}
func (k Keeper) SetEmissionLastTimestamp(ctx sdk.Context, timestamp uint64) {
store := ctx.KVStore(k.storeKey)
store.Set(types.EmissionLastTimestampKey(), sdk.Uint64ToBigEndian(timestamp))
}
func (k Keeper) GetEmissionLastTimestamp(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.EmissionLastTimestampKey())
if bz == nil {
return 0
}
return sdk.BigEndianToUint64(bz)
}