emission_state.gno
5.52 Kb · 178 lines
1package gns
2
3import (
4 "chain/runtime"
5 "time"
6
7 gnsmath "gno.land/p/gnoswap/gnsmath/v1"
8 ufmt "gno.land/p/nt/ufmt/v0"
9)
10
11var emissionState *EmissionState
12
13func init() {
14 emissionState = NewEmissionState(0, 0)
15}
16
17// EmissionState manages emission state and halving data.
18// Tracks emission timing, status, and halving year information for 12-year schedule.
19type EmissionState struct {
20 createdHeight int64
21 startTimestamp int64
22 endTimestamp int64
23 halvingData *HalvingData
24}
25
26// isInitialized returns true if emission state has been initialized with valid height and timestamp.
27func (e *EmissionState) isInitialized() bool {
28 return e.createdHeight != 0 && e.startTimestamp != 0
29}
30
31// isActive returns true if emission is currently active at the given timestamp.
32// Returns false if not initialized or timestamp is outside emission period.
33func (e *EmissionState) isActive(timestamp int64) bool {
34 if !e.isInitialized() {
35 return false
36 }
37
38 if e.startTimestamp > timestamp {
39 return false
40 }
41
42 if e.endTimestamp < timestamp {
43 return false
44 }
45
46 return true
47}
48
49// isEnded returns true if emission has ended at the given timestamp.
50func (e *EmissionState) isEnded(timestamp int64) bool {
51 return e.endTimestamp < timestamp
52}
53
54// getCurrentYear returns the halving year (1-12) for the given timestamp, or 0 if outside emission period.
55func (e *EmissionState) getCurrentYear(timestamp int64) int64 {
56 if timestamp < e.startTimestamp {
57 return 0
58 }
59
60 if timestamp > e.endTimestamp {
61 return 0
62 }
63
64 year := (timestamp - e.startTimestamp) / SECONDS_IN_YEAR
65 return year + 1
66}
67
68// getCreatedHeight returns the blockchain height when emission started.
69func (e *EmissionState) getCreatedHeight() int64 {
70 return e.createdHeight
71}
72
73// getStartTimestamp returns the timestamp when emission started.
74func (e *EmissionState) getStartTimestamp() int64 {
75 return e.startTimestamp
76}
77
78// getEndTimestamp returns the timestamp when emission ends.
79func (e *EmissionState) getEndTimestamp() int64 {
80 return e.endTimestamp
81}
82
83// getHalvingData returns the halving data containing emission schedule details.
84func (e *EmissionState) getHalvingData() *HalvingData {
85 return e.halvingData
86}
87
88// getHalvingYearStartTimestamp returns the start timestamp for the specified halving year.
89func (e *EmissionState) getHalvingYearStartTimestamp(year int64) int64 {
90 return e.halvingData.getStartTimestamp(year)
91}
92
93// getHalvingYearEndTimestamp returns the end timestamp for the specified halving year.
94func (e *EmissionState) getHalvingYearEndTimestamp(year int64) int64 {
95 return e.halvingData.getEndTimestamp(year)
96}
97
98// getHalvingYearAmountPerSecond returns the emission rate per second for the specified halving year.
99func (e *EmissionState) getHalvingYearAmountPerSecond(year int64) int64 {
100 return e.halvingData.getAmountPerSecond(year)
101}
102
103// getHalvingYearMintedAmount returns the minted emission amount for the specified halving year.
104func (e *EmissionState) getHalvingYearMintedAmount(year int64) int64 {
105 return e.halvingData.getMintedAmount(year)
106}
107
108// getHalvingYearLeftAmount returns the remaining emission amount for the specified halving year.
109func (e *EmissionState) getHalvingYearLeftAmount(year int64) int64 {
110 return e.halvingData.getLeftAmount(year)
111}
112
113// addHalvingYearMintedAmount adds to the minted emission amount for the specified halving year.
114// Returns error if year is invalid (0 or outside 1-12 range).
115func (e *EmissionState) addHalvingYearMintedAmount(year int64, amount int64) error {
116 if year == 0 {
117 return makeErrorWithDetails(errInvalidYear, ufmt.Sprintf("year: %d", year))
118 }
119
120 mintedAmount := e.halvingData.getMintedAmount(year)
121 mintedAmount = gnsmath.SafeAddInt64(mintedAmount, amount)
122
123 return e.halvingData.setMintedAmount(year, mintedAmount)
124}
125
126// subHalvingYearLeftAmount subtracts from the remaining emission amount for the specified halving year.
127// Returns error if year is invalid (0 or outside 1-12 range).
128func (e *EmissionState) subHalvingYearLeftAmount(year int64, amount int64) error {
129 if year == 0 {
130 return makeErrorWithDetails(errInvalidYear, ufmt.Sprintf("year: %d", year))
131 }
132
133 leftAmount := e.halvingData.getLeftAmount(year)
134 leftAmount = gnsmath.SafeSubInt64(leftAmount, amount)
135
136 return e.halvingData.setLeftAmount(year, leftAmount)
137}
138
139// Clone returns a deep copy of the emission state, including independent halving data.
140//
141// Returns:
142// - clone: independent EmissionState copy with the same schedule values.
143func (e *EmissionState) Clone() *EmissionState {
144 return &EmissionState{
145 createdHeight: e.createdHeight,
146 startTimestamp: e.startTimestamp,
147 endTimestamp: e.endTimestamp,
148 halvingData: e.halvingData.Clone(),
149 }
150}
151
152// NewEmissionState creates an emission state and its 12-year halving schedule.
153//
154// Parameters:
155// - createdHeight: blockchain height recorded as the schedule's creation height.
156// - startTimestamp: Unix timestamp at which the first halving year begins.
157//
158// Returns:
159// - state: newly allocated emission state with an end timestamp and initialized halving data.
160func NewEmissionState(createdHeight int64, startTimestamp int64) *EmissionState {
161 emissionEndTime := gnsmath.SafeAddInt64(startTimestamp, SECONDS_IN_YEAR*HALVING_END_YEAR-1)
162
163 return &EmissionState{
164 createdHeight: createdHeight,
165 startTimestamp: startTimestamp,
166 endTimestamp: emissionEndTime,
167 halvingData: NewHalvingData(startTimestamp),
168 }
169}
170
171// getEmissionState returns the singleton emission state instance.
172func getEmissionState() *EmissionState {
173 if emissionState == nil {
174 emissionState = NewEmissionState(runtime.ChainHeight(), time.Now().Unix())
175 }
176
177 return emissionState
178}