-
Notifications
You must be signed in to change notification settings - Fork 55
/
liquidfarm.go
133 lines (118 loc) · 4.08 KB
/
liquidfarm.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package types
import (
fmt "fmt"
"regexp"
"strconv"
"strings"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
farmingtypes "github.com/crescent-network/crescent/v5/x/farming/types"
)
const (
LiquidFarmReserveAccPrefix string = "LiquidFarmReserveAcc"
)
var (
liquidFarmCoinDenomRegexp = regexp.MustCompile(`^lf([1-9]\d*)$`)
)
// NewLiquidFarm returns a new LiquidFarm.
func NewLiquidFarm(poolId uint64, minFarmAmt, minBidAmount sdk.Int, feeRate sdk.Dec) LiquidFarm {
return LiquidFarm{
PoolId: poolId,
MinFarmAmount: minFarmAmt,
MinBidAmount: minBidAmount,
FeeRate: feeRate,
}
}
// Validate validates LiquidFarm.
func (l LiquidFarm) Validate() error {
if l.PoolId == 0 {
return fmt.Errorf("pool id must not be 0")
}
if l.MinBidAmount.IsNegative() {
return fmt.Errorf("minimum bid amount must be 0 or positive value: %s", l.MinBidAmount)
}
if l.MinFarmAmount.IsNegative() {
return fmt.Errorf("minimum farm amount must be 0 or positive value: %s", l.MinFarmAmount)
}
if l.FeeRate.IsNegative() {
return fmt.Errorf("fee rate must be 0 or positive value: %s", l.FeeRate)
}
return nil
}
// String returns a human-readable string representation of the LiquidFarm.
func (l LiquidFarm) String() string {
out, _ := l.MarshalYAML()
return out.(string)
}
// MarshalYAML returns the YAML representation of a LiquidFarm.
func (l LiquidFarm) MarshalYAML() (interface{}, error) {
bz, err := codec.MarshalYAML(codec.NewProtoCodec(codectypes.NewInterfaceRegistry()), &l)
if err != nil {
return nil, err
}
return string(bz), err
}
// LiquidFarmCoinDenom returns a unique liquid farming coin denom for a LiquidFarm.
func LiquidFarmCoinDenom(poolId uint64) string {
return fmt.Sprintf("lf%d", poolId)
}
// ParseLiquidFarmCoinDenom parses a LF coin denom and returns its pool id.
func ParseLiquidFarmCoinDenom(denom string) (poolId uint64, err error) {
chunks := liquidFarmCoinDenomRegexp.FindStringSubmatch(denom)
if len(chunks) == 0 {
return 0, fmt.Errorf("%s is not a liquid farm coin denom", denom)
}
poolId, err = strconv.ParseUint(chunks[1], 10, 64)
if err != nil {
return 0, fmt.Errorf("parse pool id: %w", err)
}
return poolId, nil
}
// LiquidFarmReserveAddress returns the reserve address for a liquid farm with the given pool id.
func LiquidFarmReserveAddress(poolId uint64) sdk.AccAddress {
return farmingtypes.DeriveAddress(
ReserveAddressType,
ModuleName,
strings.Join([]string{LiquidFarmReserveAccPrefix, strconv.FormatUint(poolId, 10)}, ModuleAddressNameSplitter),
)
}
// CalculateLiquidFarmAmount calculates minting liquid farm amount.
// MintingAmt = LFCoinTotalSupply / LPCoinTotalAmount * LPCoinFarmingAmount
func CalculateLiquidFarmAmount(
lfCoinTotalSupplyAmt sdk.Int,
lpCoinTotalFarmingAmt sdk.Int,
newFarmingAmt sdk.Int,
) sdk.Int {
if lfCoinTotalSupplyAmt.IsZero() { // initial minting
return newFarmingAmt
}
return lfCoinTotalSupplyAmt.Mul(newFarmingAmt).Quo(lpCoinTotalFarmingAmt)
}
// CalculateLiquidUnfarmAmount calculates unfarming amount.
// UnfarmingAmount = LPCoinTotalAmount - CompoundingRewards / LFCoinTotalSupply * LFCoinUnfarmingAmount
func CalculateLiquidUnfarmAmount(
lfCoinTotalSupplyAmt sdk.Int,
lpCoinTotalFarmingAmt sdk.Int,
unfarmingAmt sdk.Int,
compoundingRewards sdk.Int,
) sdk.Int {
if lfCoinTotalSupplyAmt.Equal(unfarmingAmt) { // last one to unfarm
return lpCoinTotalFarmingAmt
}
totalFarmingAmt := lpCoinTotalFarmingAmt.Sub(compoundingRewards)
return totalFarmingAmt.Mul(unfarmingAmt).Quo(lfCoinTotalSupplyAmt)
}
// DeductFees deducts rewards by the fee rate.
func DeductFees(rewards sdk.Coins, feeRate sdk.Dec) (deducted sdk.Coins, fees sdk.Coins) {
deducted = make(sdk.Coins, len(rewards))
for i, reward := range rewards {
multiplier := sdk.OneDec().Sub(feeRate) // 1 - feeRate
deducted[i] = sdk.NewCoin(reward.Denom, reward.Amount.ToDec().Mul(multiplier).TruncateInt()) // RewardAmt * Multiplier
}
fees = rewards.Sub(deducted)
if fees.IsZero() {
fees = sdk.Coins{}
}
return deducted, fees
}