Skip to content

Commit 725b7b4

Browse files
committed
refactor: delegate series
1 parent 1df03e1 commit 725b7b4

File tree

6 files changed

+170
-195
lines changed

6 files changed

+170
-195
lines changed

contract/r/gnoswap/gov/staker/api_delegation.gno

+4-4
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func GetTotalVoteWeight() uint64 {
2121

2222
// GetTotalDelegated returns the total amount of xGNS delegated.
2323
func GetTotalDelegated() uint64 {
24-
return totalDelegated
24+
return state.TotalDelegated()
2525
}
2626

2727
// GetTotalLockedAmount returns the total amount of locked GNS.
@@ -31,7 +31,7 @@ func GetTotalLockedAmount() uint64 {
3131

3232
// GetTotalDelegatedFrom returns the total amount of xGNS delegated by given address.
3333
func GetTotalDelegatedFrom(from std.Address) uint64 {
34-
amount, exist := delegatorAmount.Get(from.String())
34+
amount, exist := state.DelegatorAmount().Get(from.String())
3535
if !exist {
3636
return 0
3737
}
@@ -40,7 +40,7 @@ func GetTotalDelegatedFrom(from std.Address) uint64 {
4040

4141
// GetTotalDelegatedTo returns the total amount of xGNS delegated to given address.
4242
func GetTotalDelegatedTo(to std.Address) uint64 {
43-
amount, exist := delegatedTo.Get(to.String())
43+
amount, exist := state.DelegatedTo().Get(to.String())
4444
if !exist {
4545
return 0
4646
}
@@ -49,7 +49,7 @@ func GetTotalDelegatedTo(to std.Address) uint64 {
4949

5050
// GetDelegationAmountFromTo returns the amount of xGNS delegated by given address to given address.
5151
func GetDelegationAmountFromTo(from, to std.Address) uint64 {
52-
toAmount, exist := delegatedFromTo.Get(from.String())
52+
toAmount, exist := state.DelegatedFromTo().Get(from.String())
5353
if !exist {
5454
return 0
5555
}

contract/r/gnoswap/gov/staker/delegate_undelegate.gno

+137-101
Original file line numberDiff line numberDiff line change
@@ -8,83 +8,131 @@ import (
88
"gno.land/p/demo/ufmt"
99
)
1010

11-
var (
12-
totalDelegated = uint64(0)
11+
// stakerState encapsulates all staking-related data.
12+
type stakerState struct {
13+
totalDelegated uint64
14+
delegatorAmount *avl.Tree // caller -> amount.
15+
delegatedFromTo *avl.Tree // caller -> (inner tree: to -> amount).
16+
delegatedTo *avl.Tree // to -> amount.
17+
delegationHistory *avl.Tree // caller -> []DelegationHistory.
18+
delegationSnapShotHistory *avl.Tree // to -> []DelegationSnapShotHistory.
19+
}
1320

14-
delegatorAmount = avl.NewTree() // caller => amount
15-
delegatedFromTo = avl.NewTree() // caller => to => amount
16-
delegatedTo = avl.NewTree() // to => amount
17-
)
18-
19-
func delegate(to std.Address, amount uint64) {
20-
caller := std.PrevRealm().Addr().String()
21-
toStr := to.String()
21+
func (s stakerState) TotalDelegated() uint64 { return s.totalDelegated }
22+
func (s stakerState) DelegatorAmount() *avl.Tree { return s.delegatorAmount }
23+
func (s stakerState) DelegatedFromTo() *avl.Tree { return s.delegatedFromTo }
24+
func (s stakerState) DelegatedTo() *avl.Tree { return s.delegatedTo }
25+
func (s stakerState) DelegationHistory() *avl.Tree { return s.delegationHistory }
26+
func (s stakerState) DelegationSnapShotHistory() *avl.Tree { return s.delegationSnapShotHistory }
27+
28+
// Global state instance.
29+
var state = newStakerState()
30+
31+
// newStakerState creates and returns a new StakerState.
32+
func newStakerState() *stakerState {
33+
return &stakerState{
34+
totalDelegated: 0,
35+
delegatorAmount: avl.NewTree(),
36+
delegatedFromTo: avl.NewTree(),
37+
delegatedTo: avl.NewTree(),
38+
delegationHistory: avl.NewTree(),
39+
delegationSnapShotHistory: avl.NewTree(),
40+
}
41+
}
2242

23-
// initialize the internal tree for callers to `delegatedFromTo`
24-
innerTree := getOrCreateInnerTree(delegatedFromTo, caller)
43+
// getOrCreateInnerTree returns the inner tree for the given caller,
44+
// creating it if it does not exist.
45+
func (s *stakerState) getOrCreateInnerTree(caller string) *avl.Tree {
46+
if inner, exists := s.delegatedFromTo.Get(caller); exists {
47+
return inner.(*avl.Tree)
48+
}
49+
innerTree := avl.NewTree()
50+
s.delegatedFromTo.Set(caller, innerTree)
51+
return innerTree
52+
}
53+
54+
// updateUint64 updates the value at key in the given tree by delta.
55+
// If add is true, it increments the value; otherwise, it decrements.
56+
func (s *stakerState) updateUint64(tree *avl.Tree, key string, delta uint64, add bool) {
57+
var current uint64 = 0
58+
if value, exists := tree.Get(key); exists {
59+
current = value.(uint64)
60+
}
61+
if add {
62+
current += delta
63+
} else {
64+
if current < delta {
65+
panic(ufmt.Sprintf("not enough value for key %s", key))
66+
}
67+
current -= delta
68+
}
69+
tree.Set(key, current)
70+
}
2571

26-
totalDelegated += amount
72+
// Delegate processes a delegation from the caller to the given address.
73+
func (s *stakerState) Delegate(to std.Address, amount uint64) {
74+
caller := std.PrevRealm().Addr().String()
75+
toStr := to.String()
2776

28-
// update delegator amount
29-
updateUint64InTree(delegatorAmount, caller, amount, true)
77+
innerTree := s.getOrCreateInnerTree(caller)
3078

31-
// update delegatedFromTo's inner tree
32-
updateUint64InTree(innerTree, toStr, amount, true)
79+
s.totalDelegated += amount
3380

34-
// update delegatedTo
35-
updateUint64InTree(delegatedTo, toStr, amount, true)
81+
s.updateUint64(s.delegatorAmount, caller, amount, true)
82+
s.updateUint64(innerTree, toStr, amount, true)
83+
s.updateUint64(s.delegatedTo, toStr, amount, true)
3684

3785
timeStamp := uint64(time.Now().Unix())
38-
// update delegation history
39-
delegation := DelegationHistory{
40-
to: to,
41-
amount: amount,
42-
timestamp: timeStamp,
43-
height: uint64(std.GetHeight()),
44-
add: true, // if true, delegation
45-
}
4686

47-
history := make([]DelegationHistory, 0)
48-
if value, exists := delegationHistory.Get(caller); exists {
87+
// Update delegation history.
88+
history := []DelegationHistory{}
89+
if value, exists := s.delegationHistory.Get(caller); exists {
4990
history = value.([]DelegationHistory)
5091
}
92+
delegation := newDelegationHistory(to, amount, timeStamp, uint64(std.GetHeight()), true)
5193
history = append(history, delegation)
52-
delegationHistory.Set(caller, history)
94+
s.delegationHistory.Set(caller, history)
5395

54-
// update delegation stat history
55-
updateAmount := uint64(0)
56-
snapShotHistory := make([]DelegationSnapShotHistory, 0)
57-
if value, exists := delegationSnapShotHistory.Get(toStr); exists {
96+
// Update snapshot history.
97+
updateAmount := amount
98+
snapShotHistory := []DelegationSnapShotHistory{}
99+
if value, exists := s.DelegationSnapShotHistory().Get(toStr); exists {
58100
snapShotHistory = value.([]DelegationSnapShotHistory)
59101
lastStat := snapShotHistory[len(snapShotHistory)-1]
60102
updateAmount = lastStat.amount + amount
61-
} else {
62-
updateAmount = amount
63103
}
104+
snapShot := newDelegationSnapShotHistory(to, updateAmount, uint64(std.GetHeight()), timeStamp)
105+
snapShotHistory = append(snapShotHistory, snapShot)
106+
s.delegationSnapShotHistory.Set(toStr, snapShotHistory)
107+
}
64108

65-
snapShotHistory = append(snapShotHistory, DelegationSnapShotHistory{
66-
to: to,
67-
amount: updateAmount,
68-
updatedBlock: uint64(std.GetHeight()),
69-
updatedAt: timeStamp,
70-
})
71-
delegationSnapShotHistory.Set(toStr, snapShotHistory)
109+
// getUint64OrPanic retrieves a uint64 value from the tree by key,
110+
// panicking with an error message if the key does not exist.
111+
func (s *stakerState) getUint64OrPanic(tree *avl.Tree, key, errMsg string) uint64 {
112+
if value, exists := tree.Get(key); exists {
113+
return value.(uint64)
114+
}
115+
panic(addDetailToError(
116+
errDataNotFound,
117+
ufmt.Sprintf("%s: %s", key, errMsg),
118+
))
72119
}
73120

74-
func undelegate(to std.Address, amount uint64) {
121+
// Undelegate processes an undelegation from the caller for the given address.
122+
func (s *stakerState) Undelegate(to std.Address, amount uint64) {
75123
caller := std.PrevRealm().Addr().String()
76124
toStr := to.String()
77125

78-
// check caller's delegatedFromTo
79-
innerTree, exists := delegatedFromTo.Get(caller)
126+
innerTreeValue, exists := s.DelegatedFromTo().Get(caller)
80127
if !exists {
81128
panic(addDetailToError(
82129
errNoDelegatedAmount,
83130
ufmt.Sprintf("caller(%s) has no delegated amount", caller),
84131
))
85132
}
86-
// check caller's delegatedFromTo's inner tree
87-
delegatedAmountValue, exists := innerTree.(*avl.Tree).Get(toStr)
133+
innerTree := innerTreeValue.(*avl.Tree)
134+
135+
delegatedAmountValue, exists := innerTree.Get(toStr)
88136
if !exists {
89137
panic(addDetailToError(
90138
errNoDelegatedTarget,
@@ -95,86 +143,74 @@ func undelegate(to std.Address, amount uint64) {
95143
if delegatedAmount < amount {
96144
panic(addDetailToError(
97145
errNotEnoughDelegated,
98-
ufmt.Sprintf("caller(%s) has only %d delegated amount(request: %d) to %s", caller, delegatedAmount, amount, to),
146+
ufmt.Sprintf("caller(%s) has only %d delegated amount (requested: %d) to %s", caller, delegatedAmount, amount, to),
99147
))
100148
}
101-
innerTree.(*avl.Tree).Set(toStr, delegatedAmount-amount)
102-
delegatedFromTo.Set(caller, innerTree)
149+
innerTree.Set(toStr, delegatedAmount-amount)
150+
s.DelegatedFromTo().Set(caller, innerTree)
103151

104-
// update total delegated amount
105-
totalDelegated -= amount
152+
s.totalDelegated -= amount
106153

107-
currentAmount := uint64(0)
108-
if value, exists := delegatorAmount.Get(caller); exists {
109-
currentAmount = value.(uint64)
110-
} else {
111-
panic(addDetailToError(
112-
errDataNotFound,
113-
ufmt.Sprintf("caller(%s) has no delegated amount", caller),
114-
))
115-
}
116-
if currentAmount < amount {
154+
currentDelegatorAmount := s.getUint64OrPanic(s.delegatorAmount, caller, "has no delegated amount")
155+
if currentDelegatorAmount < amount {
117156
panic(addDetailToError(
118157
errNotEnoughDelegated,
119-
ufmt.Sprintf("caller(%s) has only %d delegated amount(request: %d)", caller, currentAmount, amount),
158+
ufmt.Sprintf("caller(%s) has only %d delegated amount (requested: %d)", caller, currentDelegatorAmount, amount),
120159
))
121160
}
122-
delegatorAmount.Set(caller, currentAmount-amount)
161+
s.delegatorAmount.Set(caller, currentDelegatorAmount-amount)
123162

124-
currentToAmount := uint64(0)
125-
if value, exists := delegatedTo.Get(toStr); exists {
126-
currentToAmount = value.(uint64)
127-
} else {
128-
panic(addDetailToError(
129-
errDataNotFound,
130-
ufmt.Sprintf("to(%s) has no delegated amount", toStr),
131-
))
132-
}
133-
if currentToAmount < amount {
163+
currentDelegatedTo := s.getUint64OrPanic(s.delegatedTo, toStr, "target has no delegated amount")
164+
if currentDelegatedTo < amount {
134165
panic(addDetailToError(
135166
errNotEnoughDelegated,
136-
ufmt.Sprintf("to(%s) has only %d delegated amount(request: %d)", toStr, currentToAmount, amount),
167+
ufmt.Sprintf("to(%s) has only %d delegated amount (requested: %d)", toStr, currentDelegatedTo, amount),
137168
))
138169
}
139-
delegatedTo.Set(toStr, currentToAmount-amount)
140-
141-
// update delegation history
142-
delegation := DelegationHistory{
143-
to: to,
144-
amount: amount,
145-
timestamp: uint64(time.Now().Unix()),
146-
height: uint64(std.GetHeight()),
147-
add: false,
148-
}
149-
var history []DelegationHistory
150-
if value, exists := delegationHistory.Get(caller); exists {
170+
s.delegatedTo.Set(toStr, currentDelegatedTo-amount)
171+
172+
// Update delegation history.
173+
history := []DelegationHistory{}
174+
if value, exists := s.delegationHistory.Get(caller); exists {
151175
history = value.([]DelegationHistory)
152176
}
177+
delegation := newDelegationHistory(to, amount, uint64(time.Now().Unix()), uint64(std.GetHeight()), false)
153178
history = append(history, delegation)
154-
delegationHistory.Set(caller, history)
179+
s.delegationHistory.Set(caller, history)
155180

156-
// update delegation stat history
157-
statValue, exists := delegationSnapShotHistory.Get(toStr)
181+
// Update snapshot history.
182+
statValue, exists := s.DelegationSnapShotHistory().Get(toStr)
158183
if !exists {
159184
panic(addDetailToError(
160185
errDataNotFound,
161186
ufmt.Sprintf("caller(%s) has no delegation stat history", caller),
162187
))
163188
}
164-
165-
stat := statValue.([]DelegationSnapShotHistory)
189+
stats := statValue.([]DelegationSnapShotHistory)
166190
remainingAmount := amount
167-
for i := 0; i < len(stat); i++ {
168-
if stat[i].amount > 0 {
169-
if stat[i].amount < remainingAmount {
170-
remainingAmount -= stat[i].amount
171-
stat = append(stat[:i], stat[i+1:]...)
191+
for i := 0; i < len(stats); i++ {
192+
if stats[i].amount > 0 {
193+
if stats[i].amount < remainingAmount {
194+
remainingAmount -= stats[i].amount
195+
stats = append(stats[:i], stats[i+1:]...)
196+
i--
172197
} else {
173-
stat[i].amount -= remainingAmount
174-
stat[i].updatedAt = uint64(time.Now().Unix())
198+
stats[i].amount -= remainingAmount
199+
stats[i].updatedAt = uint64(time.Now().Unix())
200+
remainingAmount = 0
175201
break
176202
}
177203
}
178204
}
179-
delegationSnapShotHistory.Set(to.String(), stat)
205+
s.delegationSnapShotHistory.Set(toStr, stats)
206+
}
207+
208+
// delegate is the external API for delegation.
209+
func delegate(to std.Address, amount uint64) {
210+
state.Delegate(to, amount)
211+
}
212+
213+
// undelegate is the external API for undelegation.
214+
func undelegate(to std.Address, amount uint64) {
215+
state.Undelegate(to, amount)
180216
}

0 commit comments

Comments
 (0)