Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

delegation.gno

5.56 Kb · 189 lines
  1package staker
  2
  3import (
  4	"errors"
  5
  6	gnsmath "gno.land/p/gnoswap/gnsmath/v1"
  7
  8	"gno.land/r/gnoswap/gov/staker"
  9)
 10
 11const errCollectAmountExceedsCollectable = "amount to collect is greater than collectable amount"
 12
 13type DelegationResolver struct {
 14	delegation *staker.Delegation
 15}
 16
 17// NewDelegationResolver wraps a delegation in a resolver for derived amounts and withdrawals.
 18//
 19// Parameters:
 20//   - delegation: delegation state to resolve
 21//
 22// Returns:
 23//   - *DelegationResolver: resolver backed by delegation
 24func NewDelegationResolver(delegation *staker.Delegation) *DelegationResolver {
 25	return &DelegationResolver{delegation}
 26}
 27
 28// Get returns the underlying delegation state.
 29//
 30// Returns:
 31//   - *staker.Delegation: wrapped delegation instance
 32func (r *DelegationResolver) Get() *staker.Delegation {
 33	return r.delegation
 34}
 35
 36// DelegatedAmount returns total delegated amount minus amount already undelegated.
 37//
 38// Returns:
 39//   - int64: amount still delegated
 40func (r *DelegationResolver) DelegatedAmount() int64 {
 41	return gnsmath.SafeSubInt64(r.delegation.TotalDelegatedAmount(), r.delegation.UnDelegatedAmount())
 42}
 43
 44// LockedAmount returns total delegated amount minus amount already collected.
 45//
 46// Returns:
 47//   - int64: amount still locked in the delegation
 48func (r *DelegationResolver) LockedAmount() int64 {
 49	return gnsmath.SafeSubInt64(r.delegation.TotalDelegatedAmount(), r.delegation.CollectedAmount())
 50}
 51
 52// IsEmpty reports whether no locked delegation amount remains.
 53//
 54// Returns:
 55//   - bool: true when LockedAmount is zero, otherwise false
 56func (r *DelegationResolver) IsEmpty() bool {
 57	return r.LockedAmount() == 0
 58}
 59
 60// CollectableAmount calculates the total amount that can be collected at the given time.
 61//
 62// Parameters:
 63//   - currentTime: current Unix timestamp used to evaluate each withdrawal's lockup
 64//
 65// Returns:
 66//   - total: sum of all withdrawal amounts currently available for collection
 67func (r *DelegationResolver) CollectableAmount(currentTime int64) (total int64) {
 68	for _, withdraw := range r.delegation.Withdraws() {
 69		total = gnsmath.SafeAddInt64(total, NewDelegationWithdrawResolver(&withdraw).CollectableAmount(currentTime))
 70	}
 71
 72	return total
 73}
 74
 75// UnDelegate processes an undelegation with a time-based lockup period.
 76//
 77// Parameters:
 78//   - amount: amount to undelegate and place into a withdrawal
 79//   - currentHeight: block height at which the undelegation is recorded
 80//   - currentTimestamp: Unix timestamp at which the undelegation is recorded
 81//   - unDelegationLockupPeriod: lockup duration in seconds before the withdrawal is collectible
 82func (r *DelegationResolver) UnDelegate(
 83	amount, currentHeight, currentTimestamp, unDelegationLockupPeriod int64,
 84) {
 85	r.delegation.SetUnDelegateAmount(gnsmath.SafeAddInt64(r.delegation.UnDelegatedAmount(), amount))
 86
 87	withdraw := NewDelegationWithdraw(
 88		r.delegation.ID(),
 89		amount,
 90		currentHeight,
 91		currentTimestamp,
 92		unDelegationLockupPeriod,
 93	)
 94	r.delegation.AddWithdraw(withdraw)
 95}
 96
 97// UnDelegateWithoutLockup processes an immediate undelegation without lockup.
 98//
 99// Parameters:
100//   - amount: amount to undelegate and mark as collected immediately
101//   - currentHeight: current block height context; retained for API symmetry and unused by this immediate path
102//   - currentTime: current Unix timestamp context; retained for API symmetry and unused by this immediate path
103func (r *DelegationResolver) UnDelegateWithoutLockup(
104	amount, currentHeight, currentTime int64,
105) {
106	r.delegation.SetUnDelegateAmount(gnsmath.SafeAddInt64(r.delegation.UnDelegatedAmount(), amount))
107	r.delegation.SetCollectedAmount(gnsmath.SafeAddInt64(r.delegation.CollectedAmount(), amount))
108}
109
110// processCollection handles the actual collection logic
111func (r *DelegationResolver) processCollection(currentTime int64) (int64, error) {
112	collectedAmount := int64(0)
113	withdraws := r.delegation.Withdraws()
114
115	for i := range withdraws {
116		resolver := NewDelegationWithdrawResolver(&withdraws[i])
117
118		collectableAmount := resolver.CollectableAmount(currentTime)
119		if collectableAmount <= 0 {
120			continue
121		}
122
123		err := resolver.Collect(collectableAmount, currentTime)
124		if err != nil {
125			return 0, err
126		}
127
128		updatedAmount, err := addToCollectedAmount(r.delegation.CollectedAmount(), collectableAmount)
129		if err != nil {
130			return 0, err
131		}
132
133		r.delegation.SetCollectedAmount(updatedAmount)
134		collectedAmount = gnsmath.SafeAddInt64(collectedAmount, collectableAmount)
135	}
136
137	// Skip filtering if nothing was collected
138	if collectedAmount == 0 {
139		return collectedAmount, nil
140	}
141
142	currentIndex := 0
143
144	for i := range withdraws {
145		if !withdraws[i].IsCollected() {
146			r.delegation.SetWithdraw(currentIndex, withdraws[i])
147			currentIndex++
148		}
149	}
150
151	r.delegation.SetWithdraws(withdraws[:currentIndex])
152
153	return collectedAmount, nil
154}
155
156func addToCollectedAmount(collectedAmount, amount int64) (int64, error) {
157	if amount < 0 {
158		return 0, errors.New(errAmountMustBeNonNegative)
159	}
160	return gnsmath.SafeAddInt64(collectedAmount, amount), nil
161}
162
163// NewDelegation creates a new delegation.
164// This is a convenience wrapper around staker.NewDelegation.
165//
166// Parameters:
167//   - id: delegation ID
168//   - delegateFrom: delegator's address
169//   - delegateTo: delegatee's address
170//   - delegateAmount: amount to delegate
171//   - createdHeight: creation block height
172//   - createdAt: creation timestamp
173//
174// Returns:
175//   - *staker.Delegation: new delegation instance
176func NewDelegation(
177	id int64,
178	delegateFrom, delegateTo address,
179	delegateAmount, createdHeight, createdAt int64,
180) *staker.Delegation {
181	return staker.NewDelegation(
182		id,
183		delegateFrom,
184		delegateTo,
185		delegateAmount,
186		createdHeight,
187		createdAt,
188	)
189}