Skip to content

Commit 79918a9

Browse files
committed
GSW-1845 refactor: separate math logic from mint()
1 parent f7f0233 commit 79918a9

File tree

5 files changed

+305
-211
lines changed

5 files changed

+305
-211
lines changed

_deploy/r/gnoswap/gns/gns.gno

Lines changed: 121 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,78 @@ import (
1616
"gno.land/r/gnoswap/v1/consts"
1717
)
1818

19-
const MAXIMUM_SUPPLY = uint64(1_000_000_000_000_000) // 1B
19+
const (
20+
MAXIMUM_SUPPLY = uint64(1_000_000_000_000_000)
21+
INITIAL_MINT_AMOUNT = uint64(100_000_000_000_000)
22+
MAX_EMISSION_AMOUNT = MAXIMUM_SUPPLY - INITIAL_MINT_AMOUNT
23+
)
24+
25+
var (
26+
lastMintedHeight = std.GetHeight()
27+
)
2028

2129
var (
22-
lastMintedHeight int64
23-
amountToEmission uint64
30+
leftEmissionAmount = MAX_EMISSION_AMOUNT
2431
)
2532

2633
var (
2734
Token, privateLedger = grc20.NewToken("Gnoswap", "GNS", 6)
2835
UserTeller = Token.CallerTeller()
29-
owner = ownable.NewWithAddress("g17290cwvmrapvp869xfnhhawa8sm9edpufzat7d") // ADMIN
36+
owner = ownable.NewWithAddress(consts.ADMIN)
3037
)
3138

3239
func init() {
33-
privateLedger.Mint(owner.Owner(), 100_000_000_000_000) // 100_000_000 GNS ≈ 0.1B
40+
privateLedger.Mint(owner.Owner(), INITIAL_MINT_AMOUNT)
3441
getter := func() *grc20.Token { return Token }
3542
grc20reg.Register(getter, "")
43+
}
3644

37-
amountToEmission = MAXIMUM_SUPPLY - uint64(100_000_000_000_000)
45+
// MintedEmissionAmount returns the amount of GNS that has been minted by the emission contract.
46+
// It does not include initial minted amount.
47+
func MintedEmissionAmount() uint64 {
48+
return TotalSupply() - INITIAL_MINT_AMOUNT
49+
}
3850

39-
lastMintedHeight = std.GetHeight()
51+
func Mint(address pusers.AddressOrName) uint64 {
52+
common.IsHalted()
53+
54+
caller := std.PrevRealm().Addr()
55+
if err := common.EmissionOnly(caller); err != nil {
56+
panic(err)
57+
}
58+
59+
lastMintedHeight := GetLastMintedHeight()
60+
currentHeight := std.GetHeight()
61+
62+
// skip minting process if gns for current block is already minted
63+
if skipIfSameHeight(lastMintedHeight, currentHeight) {
64+
return 0
65+
}
66+
67+
// calculate gns amount to mint, and the mint to the target address
68+
amountToMint := calculateAmountToMint(lastMintedHeight+1, currentHeight)
69+
err := privateLedger.Mint(users.Resolve(address), amountToMint)
70+
if err != nil {
71+
panic(err.Error())
72+
}
73+
74+
// update
75+
setLastMintedHeight(currentHeight)
76+
setLeftEmissionAmount(leftEmissionAmount - amountToMint)
77+
78+
return amountToMint
4079
}
4180

42-
func GetAmountToEmission() uint64 { return amountToEmission }
81+
func Burn(from pusers.AddressOrName, amount uint64) {
82+
owner.AssertCallerIsOwner()
83+
fromAddr := users.Resolve(from)
84+
checkErr(privateLedger.Burn(fromAddr, amount))
85+
}
4386

4487
func TotalSupply() uint64 {
4588
return UserTeller.TotalSupply()
4689
}
4790

48-
func TotalMinted() uint64 {
49-
return UserTeller.TotalSupply() - uint64(100_000_000_000_000)
50-
}
51-
5291
func BalanceOf(owner pusers.AddressOrName) uint64 {
5392
ownerAddr := users.Resolve(owner)
5493
return UserTeller.BalanceOf(ownerAddr)
@@ -93,93 +132,94 @@ func Render(path string) string {
93132
}
94133
}
95134

96-
// Mint mints GNS to the address.
97-
// Only emission contract can call Mint.
98-
func Mint(address pusers.AddressOrName) uint64 {
99-
common.IsHalted()
100-
101-
caller := std.PrevRealm().Addr()
102-
if caller != consts.EMISSION_ADDR {
103-
panic(addDetailToError(
104-
errNoPermission,
105-
ufmt.Sprintf("only emission contract(%s) can call Mint, called from %s", consts.EMISSION_ADDR, caller.String()),
106-
))
135+
func checkErr(err error) {
136+
if err != nil {
137+
panic(err.Error())
107138
}
139+
}
108140

109-
// if not yet initialized, mint 0 amount
110-
if initialized == false {
111-
return 0
112-
}
141+
// calculateAmountToMint calculates the amount of gns to mint
142+
// It calculates the amount of gns to mint for each halving year for block range.
143+
// It also handles the left emission amount if the current block range includes halving year end block.
144+
func calculateAmountToMint(fromHeight, toHeight int64) uint64 {
145+
fromYear := GetHalvingYearByHeight(fromHeight)
146+
toYear := GetHalvingYearByHeight(toHeight)
113147

114-
// calculate gns emission amount for every block, and send by single call
115-
// for this case, we assume that inside of block range gnoswap state hasn't changed.
116-
nowHeight := std.GetHeight()
117-
amountToMint := uint64(0)
148+
totalAmountToMint := uint64(0)
118149

119-
if lastMintedHeight >= nowHeight {
120-
return 0
121-
}
150+
for i := fromYear; i <= toYear; i++ {
151+
yearEndHeight := GetHalvingYearBlock(i)
152+
mintUntilHeight := yearEndHeight
122153

123-
// If from, to block is at same halving year, no need iterate
124-
fromYear := GetHalvingYearByHeight(lastMintedHeight + 1)
125-
toYear := GetHalvingYearByHeight(nowHeight)
126-
127-
if fromYear == toYear {
128-
numBlock := uint64(nowHeight - lastMintedHeight)
129-
singleBlockAmount := GetAmountByHeight(nowHeight)
130-
totalBlockAmount := singleBlockAmount * numBlock
131-
132-
amountToMint += totalBlockAmount
133-
amountToMint = checkAndHandleIfLastBlockOfHalvingYear(nowHeight, amountToMint)
134-
135-
halvingYearMintAmount[fromYear] += totalBlockAmount
136-
} else {
137-
for i := lastMintedHeight + 1; i <= nowHeight; i++ {
138-
amount := GetAmountByHeight(i)
139-
amount = checkAndHandleIfLastBlockOfHalvingYear(i, amount)
140-
year := GetHalvingYearByHeight(i)
141-
halvingYearMintAmount[year] += amount
142-
amountToMint += amount
154+
if toHeight < mintUntilHeight {
155+
mintUntilHeight = toHeight
143156
}
144-
}
145157

146-
err := privateLedger.Mint(users.Resolve(address), amountToMint)
147-
if err != nil {
148-
panic(err.Error())
149-
}
158+
// how many blocks to calculate
159+
numBlock := uint64(mintUntilHeight-fromHeight) + 1
150160

151-
lastMintedHeight = nowHeight
161+
// amount of gns to mint for each block for current year
162+
singleBlockAmount := GetAmountByHeight(yearEndHeight)
152163

153-
return amountToMint
154-
}
164+
// amount of gns to mint for current year
165+
yearAmountToMint := singleBlockAmount * numBlock
155166

156-
func Burn(from pusers.AddressOrName, amount uint64) {
157-
owner.AssertCallerIsOwner()
158-
fromAddr := users.Resolve(from)
159-
checkErr(privateLedger.Burn(fromAddr, amount))
167+
// if last block of halving year, handle left emission amount
168+
if isLastBlockOfHalvingYear(mintUntilHeight) {
169+
yearAmountToMint += handleLeftEmissionAmount(i, yearAmountToMint)
170+
totalAmountToMint += yearAmountToMint
171+
} else {
172+
totalAmountToMint += yearAmountToMint
173+
}
174+
SetHalvingYearMintAmount(i, GetHalvingYearMintAmount(i)+yearAmountToMint)
175+
176+
// update fromHeight for next year (if necessary)
177+
fromHeight = mintUntilHeight + 1
178+
}
179+
180+
return totalAmountToMint
160181
}
161182

162-
func checkAndHandleIfLastBlockOfHalvingYear(height int64, amount uint64) uint64 {
183+
// isLastBlockOfHalvingYear returns true if the current block is the last block of a halving year.
184+
func isLastBlockOfHalvingYear(height int64) bool {
163185
year := GetHalvingYearByHeight(height)
164-
lastBlock := halvingYearBlock[year]
165-
if height == lastBlock {
166-
leftForThisYear := halvingYearAmount[year] - halvingYearMintAmount[year]
167-
amount = leftForThisYear
168-
return amount
169-
}
186+
lastBlock := GetHalvingYearBlock(year)
170187

171-
return amount
188+
return height == lastBlock
172189
}
173190

174-
func checkErr(err error) {
175-
if err != nil {
176-
panic(err.Error())
177-
}
191+
// handleLeftEmissionAmount handles the left emission amount for a halving year.
192+
// It calculates the left emission amount by subtracting the halving year mint amount from the halving year amount.
193+
func handleLeftEmissionAmount(year int64, amount uint64) uint64 {
194+
return GetHalvingYearAmount(year) - GetHalvingYearMintAmount(year) - amount
195+
}
196+
197+
func setLeftEmissionAmount(amount uint64) {
198+
leftEmissionAmount = amount
199+
}
200+
201+
func isInitialized() bool {
202+
return initialized
178203
}
179204

180-
// TODO:
181-
// 1. when emission contract mint gns reward, last executed height should be get from gns contract.
182-
// mint function of gns contract and mintGns function of emission contract should be synchronized.
183205
func GetLastMintedHeight() int64 {
184206
return lastMintedHeight
185207
}
208+
209+
func setLastMintedHeight(height int64) {
210+
lastMintedHeight = height
211+
}
212+
213+
func GetLeftEmissionAmount() uint64 {
214+
return leftEmissionAmount
215+
}
216+
217+
// skipIfSameHeight returns true if the current block height is the same as the last minted height.
218+
// This prevents multiple gns minting inside the same block.
219+
func skipIfSameHeight(lastMintedHeight, currentHeight int64) bool {
220+
if lastMintedHeight == currentHeight {
221+
return true
222+
}
223+
224+
return false
225+
}

0 commit comments

Comments
 (0)