Search Apps Documentation Source Content File Folder Download Copy Actions Download 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}