-
Notifications
You must be signed in to change notification settings - Fork 83
/
LibStakingFormulas.sol
180 lines (166 loc) · 6.05 KB
/
LibStakingFormulas.sol
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;
import {StakingShare} from "../../../src/dollar/core/StakingShare.sol";
import "abdk/ABDKMathQuad.sol";
import "./Constants.sol";
/// @notice Library for staking formulas
library LibStakingFormulas {
using ABDKMathQuad for uint256;
using ABDKMathQuad for bytes16;
/**
* @notice Formula to calculate the corrected amount to withdraw based on the proportion of
* LP deposited against actual LP tokens in the staking contract
* @notice `corrected_amount = amount * (stakingLpBalance / totalLpDeposited)`
* @notice If there is more or the same amount of LP than deposited then do nothing
* @param _totalLpDeposited Total amount of LP deposited by users
* @param _stakingLpBalance Actual staking contract LP tokens balance minus LP rewards
* @param _amount Amount of LP tokens
* @return Amount of LP tokens to redeem
*/
function correctedAmountToWithdraw(
uint256 _totalLpDeposited,
uint256 _stakingLpBalance,
uint256 _amount
) internal pure returns (uint256) {
if (_stakingLpBalance < _totalLpDeposited && _stakingLpBalance > 0) {
// if there is less LP token inside the staking contract that what have been deposited
// we have to reduce proportionally the lp amount to withdraw
return
_amount
.fromUInt()
.mul(_stakingLpBalance.fromUInt())
.div(_totalLpDeposited.fromUInt())
.toUInt();
}
return _amount;
}
/**
* @notice Formula of governance rights corresponding to a staking shares LP amount
* @notice Used on removing liquidity from staking
* @notice `shares = (stake.shares * _amount) / stake.lpAmount`
* @param _stake Stake info of staking share
* @param _shareInfo Array of share amounts
* @param _amount Amount of LP tokens
* @return _uLP Amount of shares
*/
function sharesForLP(
StakingShare.Stake memory _stake,
uint256[2] memory _shareInfo,
uint256 _amount
) internal pure returns (uint256 _uLP) {
bytes16 a = _shareInfo[0].fromUInt(); // shares amount
bytes16 v = _amount.fromUInt();
bytes16 t = _stake.lpAmount.fromUInt();
_uLP = a.mul(v).div(t).toUInt();
}
/**
* @notice Formula may add a decreasing rewards if locking end is near when removing liquidity
* @notice `rewards = _amount`
* @param _amount Amount of LP tokens
* @return Amount of LP rewards
*/
function lpRewardsRemoveLiquidityNormalization(
StakingShare.Stake memory /* _stake */,
uint256[2] memory /* _shareInfo */,
uint256 _amount
) internal pure returns (uint256) {
return _amount;
}
/**
* @notice Formula may add a decreasing rewards if locking end is near when adding liquidity
* @notice `rewards = _amount`
* @param _amount Amount of LP tokens
* @return Amount of LP rewards
*/
function lpRewardsAddLiquidityNormalization(
StakingShare.Stake memory /* _stake */,
uint256[2] memory /* _shareInfo */,
uint256 _amount
) internal pure returns (uint256) {
return _amount;
}
/**
* @notice Formula duration multiply
* @notice `_shares = (1 + _multiplier * _weeks^3/2) * _uLP`
* @notice `D32 = D^3/2`
* @notice `S = m * D32 * A + A`
* @param _uLP Amount of LP tokens
* @param _weeks Minimum duration of staking period
* @param _multiplier Staking discount multiplier = 0.0001
* @return _shares Amount of shares
*/
function durationMultiply(
uint256 _uLP,
uint256 _weeks,
uint256 _multiplier
) internal pure returns (uint256 _shares) {
bytes16 unit = uint256(1 ether).fromUInt();
bytes16 d = _weeks.fromUInt();
bytes16 d32 = (d.mul(d).mul(d)).sqrt();
bytes16 a = _uLP.fromUInt();
_shares = _multiplier
.fromUInt()
.mul(d32)
.mul(a)
.div(unit)
.add(a)
.toUInt();
}
/**
* @notice Formula staking price
* @notice
* ```
* IF _totalStakingShares = 0
* priceBOND = TARGET_PRICE
* ELSE
* priceBOND = totalLP / totalShares * TARGET_PRICE
* R = T == 0 ? 1 : LP / S
* P = R * T
* ```
* @param _totalULP Total LP tokens
* @param _totalStakingShares Total staking shares
* @param _targetPrice Target Ubiquity Dollar price
* @return _stakingPrice Staking share price
*/
function bondPrice(
uint256 _totalULP,
uint256 _totalStakingShares,
uint256 _targetPrice
) internal pure returns (uint256 _stakingPrice) {
bytes16 lp = _totalULP.fromUInt();
bytes16 s = _totalStakingShares.fromUInt();
bytes16 r = _totalStakingShares == 0
? uint256(1).fromUInt()
: lp.div(s);
bytes16 t = _targetPrice.fromUInt();
_stakingPrice = r.mul(t).toUInt();
}
/**
* @notice Formula Governance token multiply
* @notice
* ```
* new_multiplier = multiplier * (1.05 / (1 + abs(1 - price)))
* nM = M * C / A
* A = (1 + abs(1 - P)))
* 5 >= multiplier >= 0.2
* ```
* @param _multiplier Initial Governance token min multiplier
* @param _price Current share price
* @return _newMultiplier New Governance token min multiplier
*/
function governanceMultiply(
uint256 _multiplier,
uint256 _price
) internal pure returns (uint256 _newMultiplier) {
bytes16 m = _multiplier.fromUInt();
bytes16 p = _price.fromUInt();
bytes16 c = uint256(105 * 1e16).fromUInt(); // 1.05
bytes16 u = uint256(1e18).fromUInt(); // 1
bytes16 a = u.add(u.sub(p).abs()); // 1 + abs( 1 - P )
_newMultiplier = m.mul(c).div(a).toUInt(); // nM = M * C / A
// 5 >= multiplier >= 0.2
if (_newMultiplier > 5e18 || _newMultiplier < 2e17) {
_newMultiplier = _multiplier;
}
}
}