forked from Geodefi/Portal-Eth
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAmplificationLib.sol
More file actions
143 lines (126 loc) · 4.84 KB
/
AmplificationLib.sol
File metadata and controls
143 lines (126 loc) · 4.84 KB
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
// SPDX-License-Identifier: BUSL-1.1
pragma solidity =0.8.20;
// internal - structs
import {LiquidityModuleStorage} from "../structs/storage.sol";
// internal - libraries
import {LiquidityModuleLib as LML} from "./LiquidityModuleLib.sol";
/**
* @title AL: Amplification Library
*
* @notice A helper library for Liquidity Module Library (LML) to calculate and ramp the A parameter of a given `LiquidityModuleLib.LiquidityModuleStorage` struct.
*
* @dev review: Liquidity Module for the StableSwap logic.
* @dev This library assumes the Swap struct is fully validated.
*
* @dev This is an internal library, requires NO deployment.
*
* @author Ice Bear & Crash Bandicoot
*/
library AmplificationLib {
/**
* @custom:section ** CONSTANTS **
*/
uint256 internal constant A_PRECISION = 100;
uint256 internal constant MAX_A = 1e6;
uint256 internal constant MAX_A_CHANGE = 2;
uint256 internal constant MIN_RAMP_TIME = 14 days;
/**
* @custom:section ** EVENTS **
*/
event RampA(uint256 oldA, uint256 newA, uint256 initialTime, uint256 futureTime);
event StopRampA(uint256 currentA, uint256 time);
/**
* @custom:section ** GETTER FUNCTIONS **
*
* @custom:visibility -> view-internal
*/
/**
* @notice Return A, the amplification coefficient * n * (n - 1)
* @dev See the StableSwap paper for details
* @param self Swap struct to read from
* @return A parameter
*/
function getA(LiquidityModuleStorage storage self) internal view returns (uint256) {
return _getAPrecise(self) / (A_PRECISION);
}
/**
* @notice Return A in its raw precision
* @dev See the StableSwap paper for details
* @param self Swap struct to read from
* @return A parameter in its raw precision form
*/
function getAPrecise(LiquidityModuleStorage storage self) internal view returns (uint256) {
return _getAPrecise(self);
}
/**
* @notice Return A in its raw precision
* @dev See the StableSwap paper for details
* @param self Swap struct to read from
* @return A parameter in its raw precision form
*/
function _getAPrecise(LiquidityModuleStorage storage self) internal view returns (uint256) {
uint256 t1 = self.futureATime; // time when ramp is finished
uint256 a1 = self.futureA; // final A value when ramp is finished
if (block.timestamp < t1) {
uint256 t0 = self.initialATime; // time when ramp is started
uint256 a0 = self.initialA; // initial A value when ramp is started
if (a1 > a0) {
// a0 + (a1 - a0) * (block.timestamp - t0) / (t1 - t0)
return a0 + ((a1 - a0) * (block.timestamp - t0)) / (t1 - t0);
} else {
// a0 - (a0 - a1) * (block.timestamp - t0) / (t1 - t0)
return a0 - ((a0 - a1) * (block.timestamp - t0)) / (t1 - t0);
}
} else {
return a1;
}
}
/**
* @custom:section ** SETTER FUNCTIONS **
*
* @custom:visibility -> internal
*/
/**
* @notice Start ramping up or down A parameter towards given futureA_ and futureTime_
* Checks if the change is too rapid, and commits the new A value only when it falls under
* the limit range.
* @param self Swap struct to update
* @param futureA_ the new A to ramp towards
* @param futureTime_ timestamp when the new A should be reached
*/
function rampA(
LiquidityModuleStorage storage self,
uint256 futureA_,
uint256 futureTime_
) internal {
require(block.timestamp >= self.initialATime + 1 days, "AL:Wait 1 day before starting ramp");
require(futureTime_ >= block.timestamp + MIN_RAMP_TIME, "AL:Insufficient ramp time");
require(futureA_ > 0 && futureA_ < MAX_A, "AL:futureA_ must be > 0 and < MAX_A");
uint256 initialAPrecise = _getAPrecise(self);
uint256 futureAPrecise = futureA_ * A_PRECISION;
if (futureAPrecise < initialAPrecise) {
require(futureAPrecise * MAX_A_CHANGE >= initialAPrecise, "AL:futureA_ is too small");
} else {
require(futureAPrecise <= initialAPrecise * MAX_A_CHANGE, "AL:futureA_ is too large");
}
self.initialA = initialAPrecise;
self.futureA = futureAPrecise;
self.initialATime = block.timestamp;
self.futureATime = futureTime_;
emit RampA(initialAPrecise, futureAPrecise, block.timestamp, futureTime_);
}
/**
* @notice Stops ramping A immediately. Once this function is called, rampA()
* cannot be called for another 24 hours
* @param self Swap struct to update
*/
function stopRampA(LiquidityModuleStorage storage self) internal {
require(self.futureATime > block.timestamp, "AL:Ramp is already stopped");
uint256 currentA = _getAPrecise(self);
self.initialA = currentA;
self.futureA = currentA;
self.initialATime = block.timestamp;
self.futureATime = block.timestamp;
emit StopRampA(currentA, block.timestamp);
}
}