emission_state.gno
5.20 Kb · 168 lines
1package gns
2
3import (
4 "chain/runtime"
5 "time"
6
7 gnsmath "gno.land/p/gnoswap/gnsmath"
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// getHalvingYearAccumulatedAmount returns the accumulated emission amount for the specified halving year.
104func (e *EmissionState) getHalvingYearAccumulatedAmount(year int64) int64 {
105 return e.halvingData.getAccumAmount(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// addHalvingYearAccumulatedAmount adds to the accumulated emission amount for the specified halving year.
114// Returns error if year is invalid (0 or outside 1-12 range).
115func (e *EmissionState) addHalvingYearAccumulatedAmount(year int64, amount int64) error {
116 if year == 0 {
117 return makeErrorWithDetails(errInvalidYear, ufmt.Sprintf("year: %d", year))
118 }
119
120 accumulatedAmount := e.halvingData.getAccumAmount(year)
121 accumulatedAmount = gnsmath.SafeAddInt64(accumulatedAmount, amount)
122
123 return e.halvingData.setAccumAmount(year, accumulatedAmount)
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
139func (e *EmissionState) Clone() *EmissionState {
140 return &EmissionState{
141 createdHeight: e.createdHeight,
142 startTimestamp: e.startTimestamp,
143 endTimestamp: e.endTimestamp,
144 halvingData: e.halvingData.Clone(),
145 }
146}
147
148// NewEmissionState creates a new EmissionState with specified start height and timestamp.
149// Calculates emission end time based on 12-year schedule and initializes halving data.
150func NewEmissionState(createdHeight int64, startTimestamp int64) *EmissionState {
151 emissionEndTime := gnsmath.SafeAddInt64(startTimestamp, SECONDS_IN_YEAR*HALVING_END_YEAR-1)
152
153 return &EmissionState{
154 createdHeight: createdHeight,
155 startTimestamp: startTimestamp,
156 endTimestamp: emissionEndTime,
157 halvingData: NewHalvingData(startTimestamp),
158 }
159}
160
161// getEmissionState returns the singleton emission state instance.
162func getEmissionState() *EmissionState {
163 if emissionState == nil {
164 emissionState = NewEmissionState(runtime.ChainHeight(), time.Now().Unix())
165 }
166
167 return emissionState
168}