@oldzeppelin/contract 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.docker/Dockerfile +17 -0
- package/.dockerignore +7 -0
- package/.env.sample +24 -0
- package/.gitlab-ci.yml +51 -0
- package/.gitmodules +15 -0
- package/.prettierrc +10 -0
- package/.solcover.js +4 -0
- package/.vscode/settings.json +23 -0
- package/LICENSE.MD +51 -0
- package/README.md +135 -0
- package/contracts/arbitrum/contracts/controllers/UniswapV2ControllerArbitrum.sol +37 -0
- package/contracts/arbitrum/contracts/controllers/UniswapV3ControllerArbitrum.sol +46 -0
- package/contracts/arbitrum/contracts/oracle/PriceOracleArbitrum.sol +51 -0
- package/contracts/main/contracts/controllers/Controller.sol +61 -0
- package/contracts/main/contracts/controllers/IController.sol +81 -0
- package/contracts/main/contracts/controllers/OneInchV5Controller.sol +332 -0
- package/contracts/main/contracts/controllers/UnoswapV2Controller.sol +789 -0
- package/contracts/main/contracts/controllers/UnoswapV3Controller.sol +1018 -0
- package/contracts/main/contracts/core/CoreWhitelist.sol +192 -0
- package/contracts/main/contracts/core/ICoreWhitelist.sol +92 -0
- package/contracts/main/contracts/core/IUFarmCore.sol +95 -0
- package/contracts/main/contracts/core/UFarmCore.sol +402 -0
- package/contracts/main/contracts/fund/FundFactory.sol +59 -0
- package/contracts/main/contracts/fund/IUFarmFund.sol +68 -0
- package/contracts/main/contracts/fund/UFarmFund.sol +504 -0
- package/contracts/main/contracts/oracle/ChainlinkedOracle.sol +71 -0
- package/contracts/main/contracts/oracle/IChainlinkAggregator.sol +18 -0
- package/contracts/main/contracts/oracle/IPriceOracle.sol +55 -0
- package/contracts/main/contracts/oracle/PriceOracle.sol +20 -0
- package/contracts/main/contracts/oracle/PriceOracleCore.sol +212 -0
- package/contracts/main/contracts/oracle/WstETHOracle.sol +64 -0
- package/contracts/main/contracts/permissions/Permissions.sol +54 -0
- package/contracts/main/contracts/permissions/UFarmPermissionsModel.sol +136 -0
- package/contracts/main/contracts/pool/IPoolAdmin.sol +57 -0
- package/contracts/main/contracts/pool/IUFarmPool.sol +304 -0
- package/contracts/main/contracts/pool/PerformanceFeeLib.sol +81 -0
- package/contracts/main/contracts/pool/PoolAdmin.sol +437 -0
- package/contracts/main/contracts/pool/PoolFactory.sol +74 -0
- package/contracts/main/contracts/pool/PoolWhitelist.sol +70 -0
- package/contracts/main/contracts/pool/UFarmPool.sol +959 -0
- package/contracts/main/shared/AssetController.sol +194 -0
- package/contracts/main/shared/ECDSARecover.sol +91 -0
- package/contracts/main/shared/NZGuard.sol +99 -0
- package/contracts/main/shared/SafeOPS.sol +128 -0
- package/contracts/main/shared/UFarmCoreLink.sol +83 -0
- package/contracts/main/shared/UFarmErrors.sol +16 -0
- package/contracts/main/shared/UFarmMathLib.sol +80 -0
- package/contracts/main/shared/UFarmOwnableUUPS.sol +59 -0
- package/contracts/main/shared/UFarmOwnableUUPSBeacon.sol +34 -0
- package/contracts/test/Block.sol +15 -0
- package/contracts/test/InchSwapTestProxy.sol +292 -0
- package/contracts/test/MockPoolAdmin.sol +8 -0
- package/contracts/test/MockUFarmPool.sol +8 -0
- package/contracts/test/MockV3wstETHstETHAgg.sol +128 -0
- package/contracts/test/MockedWETH9.sol +72 -0
- package/contracts/test/OneInchToUFarmTestEnv.sol +466 -0
- package/contracts/test/StableCoin.sol +25 -0
- package/contracts/test/UFarmMockSequencerUptimeFeed.sol +44 -0
- package/contracts/test/UFarmMockV3Aggregator.sol +145 -0
- package/contracts/test/UUPSBlock.sol +19 -0
- package/contracts/test/ufarmLocal/MulticallV3.sol +220 -0
- package/contracts/test/ufarmLocal/controllers/UniswapV2ControllerUFarm.sol +27 -0
- package/contracts/test/ufarmLocal/controllers/UniswapV3ControllerUFarm.sol +43 -0
- package/deploy/100_test_env_setup.ts +483 -0
- package/deploy/20_deploy_uniV2.ts +48 -0
- package/deploy/21_create_pairs_uniV2.ts +149 -0
- package/deploy/22_deploy_mocked_aggregators.ts +123 -0
- package/deploy/22_deploy_wsteth_oracle.ts +65 -0
- package/deploy/23_deploy_uniV3.ts +80 -0
- package/deploy/24_create_pairs_uniV3.ts +140 -0
- package/deploy/25_deploy_oneInch.ts +38 -0
- package/deploy/2_deploy_multicall.ts +34 -0
- package/deploy/30_deploy_price_oracle.ts +33 -0
- package/deploy/3_deploy_lido.ts +114 -0
- package/deploy/40_deploy_pool_beacon.ts +19 -0
- package/deploy/41_deploy_poolAdmin_beacon.ts +19 -0
- package/deploy/42_deploy_ufarmcore.ts +29 -0
- package/deploy/43_deploy_fund_beacon.ts +19 -0
- package/deploy/4_deploy_tokens.ts +76 -0
- package/deploy/50_deploy_poolFactory.ts +35 -0
- package/deploy/51_deploy_fundFactory.ts +29 -0
- package/deploy/60_init_contracts.ts +101 -0
- package/deploy/61_whitelist_tokens.ts +18 -0
- package/deploy/70_deploy_uniV2Controller.ts +70 -0
- package/deploy/71_deploy_uniV3Controller.ts +67 -0
- package/deploy/72_deploy_oneInchController.ts +25 -0
- package/deploy/79_whitelist_controllers.ts +125 -0
- package/deploy/ufarm/arbitrum/1_prepare_env.ts +82 -0
- package/deploy/ufarm/arbitrum/2_deploy_ufarm.ts +178 -0
- package/deploy/ufarm/arbitrum-sepolia/1000_prepare_arb_sepolia_env.ts +308 -0
- package/deploy-config.json +112 -0
- package/deploy-data/oracles.csv +32 -0
- package/deploy-data/protocols.csv +10 -0
- package/deploy-data/tokens.csv +32 -0
- package/docker-compose.yml +67 -0
- package/hardhat.config.ts +449 -0
- package/index.js +93 -0
- package/package.json +82 -0
- package/scripts/_deploy_helpers.ts +992 -0
- package/scripts/_deploy_network_options.ts +49 -0
- package/scripts/activatePool.ts +51 -0
- package/scripts/createPool.ts +62 -0
- package/scripts/deploy_1inch_proxy.ts +98 -0
- package/scripts/pool-data.ts +420 -0
- package/scripts/post-deploy.sh +24 -0
- package/scripts/setUniV2Rate.ts +252 -0
- package/scripts/swapOneInchV5.ts +94 -0
- package/scripts/swapUniswapV2.ts +65 -0
- package/scripts/swapUniswapV3.ts +71 -0
- package/scripts/test.ts +61 -0
- package/scripts/typings-copy-artifacts.ts +83 -0
- package/tasks/boostPool.ts +39 -0
- package/tasks/createFund.ts +44 -0
- package/tasks/deboostPool.ts +48 -0
- package/tasks/grantUFarmPermissions.ts +57 -0
- package/tasks/index.ts +7 -0
- package/tasks/mintUSDT.ts +62 -0
- package/test/Periphery.test.ts +640 -0
- package/test/PriceOracle.test.ts +82 -0
- package/test/TestCases.MD +109 -0
- package/test/UFarmCore.test.ts +331 -0
- package/test/UFarmFund.test.ts +406 -0
- package/test/UFarmPool.test.ts +4736 -0
- package/test/_fixtures.ts +783 -0
- package/test/_helpers.ts +2195 -0
- package/test/_oneInchTestData.ts +632 -0
- package/tsconfig.json +12 -0
@@ -0,0 +1,437 @@
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
2
|
+
|
3
|
+
pragma solidity ^0.8.0;
|
4
|
+
|
5
|
+
/// INTERFACES
|
6
|
+
import {IUFarmCore} from '../core/IUFarmCore.sol';
|
7
|
+
import {IUFarmFund} from '../fund/IUFarmFund.sol';
|
8
|
+
import {IUFarmPool} from './IUFarmPool.sol';
|
9
|
+
import {IPoolAdmin} from './IPoolAdmin.sol';
|
10
|
+
|
11
|
+
/// CONTRACTS
|
12
|
+
import {ECDSARecover} from '../../shared/ECDSARecover.sol';
|
13
|
+
import {NZGuard} from '../../shared/NZGuard.sol';
|
14
|
+
import {Permissions} from '../permissions/Permissions.sol';
|
15
|
+
import {PoolWhitelist} from './PoolWhitelist.sol';
|
16
|
+
import {ReentrancyGuardUpgradeable as ReentrancyGuard} from '@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol';
|
17
|
+
import {UFarmErrors} from '../../shared/UFarmErrors.sol';
|
18
|
+
import {UFarmPermissionsModel} from '../permissions/UFarmPermissionsModel.sol';
|
19
|
+
import {UFarmOwnableUUPSBeacon} from '../../shared/UFarmOwnableUUPSBeacon.sol';
|
20
|
+
|
21
|
+
/// LIBRARIES
|
22
|
+
import {AssetLib} from '../../shared/AssetController.sol';
|
23
|
+
import {PerformanceFeeLib} from './PerformanceFeeLib.sol';
|
24
|
+
import {SafeOPS} from '../../shared/SafeOPS.sol';
|
25
|
+
|
26
|
+
/**
|
27
|
+
* @title PoolAdmin contract
|
28
|
+
* @author https://ufarm.digital/
|
29
|
+
* @notice Contract that implements admin functionality for UFarm pools
|
30
|
+
*/
|
31
|
+
contract PoolAdmin is IPoolAdmin, UFarmPermissionsModel, UFarmOwnableUUPSBeacon, NZGuard {
|
32
|
+
uint256 private constant ONE = 1e18;
|
33
|
+
uint256 private constant TEN_PERCENTS = 1e17;
|
34
|
+
uint256 private constant YEAR = 365 days;
|
35
|
+
|
36
|
+
uint256 public constant MAX_PERFORMANCE_FEE = PerformanceFeeLib.ONE_HUNDRED_PERCENT / 2; // 50%
|
37
|
+
uint256 public constant MAX_LOCKUP_PERIOD = 100 days;
|
38
|
+
|
39
|
+
/// @notice Pool configuration
|
40
|
+
PoolConfig public poolConfig;
|
41
|
+
|
42
|
+
address public ufarmCore;
|
43
|
+
address public ufarmFund;
|
44
|
+
address public ufarmPool;
|
45
|
+
|
46
|
+
/**
|
47
|
+
* @notice Emitted when the pool commission is changed
|
48
|
+
* @param managementCommission - management commission
|
49
|
+
* @param performanceCommission - performance commission
|
50
|
+
*/
|
51
|
+
event CommissionChanged(uint256 managementCommission, uint256 performanceCommission);
|
52
|
+
|
53
|
+
/**
|
54
|
+
* @notice Emitted when the investment range is changed
|
55
|
+
* @param minInvestment - new minimum investment boundary
|
56
|
+
* @param maxInvestment - new maximum investment boundary
|
57
|
+
*/
|
58
|
+
event InvestmentRangeChanged(uint256 minInvestment, uint256 maxInvestment);
|
59
|
+
|
60
|
+
/**
|
61
|
+
* @notice Emitted when the withdrawal lockup period is changed
|
62
|
+
* @param withdrawalLockupPeriod - new withdrawal lockup period
|
63
|
+
*/
|
64
|
+
event LockupPeriodChanged(uint256 withdrawalLockupPeriod);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* @notice Reverts if `_newStatus` can't be set as a new status
|
68
|
+
*/
|
69
|
+
error WrongNewPoolStatus(IUFarmPool.PoolStatus _currentStatus, IUFarmPool.PoolStatus _newStatus);
|
70
|
+
|
71
|
+
/**
|
72
|
+
* @notice Reverts if caller is not a fund member
|
73
|
+
*/
|
74
|
+
modifier onlyFundMember() {
|
75
|
+
_isCallerFundMember();
|
76
|
+
_;
|
77
|
+
}
|
78
|
+
|
79
|
+
/**
|
80
|
+
* @notice Reverts if the UFarm platform is paused
|
81
|
+
*/
|
82
|
+
modifier ufarmIsNotPaused() {
|
83
|
+
_ufarmIsNotPaused();
|
84
|
+
_;
|
85
|
+
}
|
86
|
+
|
87
|
+
/**
|
88
|
+
* @notice Reverts if the Fund is not active
|
89
|
+
*/
|
90
|
+
modifier onlyActiveFund() {
|
91
|
+
_checkActiveFund();
|
92
|
+
_;
|
93
|
+
}
|
94
|
+
|
95
|
+
modifier onlyStatus(IUFarmPool.PoolStatus _onlyStatus) {
|
96
|
+
_statusIs(_onlyStatus);
|
97
|
+
_;
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* @notice Initializes the PoolAdmin contract
|
102
|
+
* @param _settings - initial pool settings
|
103
|
+
* @param _poolAddr - address of the pool
|
104
|
+
*/
|
105
|
+
function __init_PoolAdmin(
|
106
|
+
IUFarmPool.CreationSettingsWithLinks memory _settings,
|
107
|
+
address _poolAddr
|
108
|
+
) external checkDelegateCall initializer {
|
109
|
+
// Set permissions
|
110
|
+
{
|
111
|
+
uint256 staffCount = _settings.params.staff.length;
|
112
|
+
IUFarmPool.Staff memory staff;
|
113
|
+
for (uint256 i; i < staffCount; ++i) {
|
114
|
+
staff = _settings.params.staff[i];
|
115
|
+
_nonZeroAddress(staff.addr);
|
116
|
+
_updatePermissions(staff.addr, staff.permissionsMask);
|
117
|
+
}
|
118
|
+
}
|
119
|
+
|
120
|
+
// Set addresses
|
121
|
+
(ufarmFund, ufarmCore, ufarmPool) = (_settings.ufarmFund, _settings.ufarmCore, _poolAddr);
|
122
|
+
|
123
|
+
// Set pool config
|
124
|
+
{
|
125
|
+
_valueInRange(_settings.params.managementCommission, 0, TEN_PERCENTS);
|
126
|
+
_checkLockupPeriod(_settings.params.withdrawalLockupPeriod);
|
127
|
+
_checkInvestmentBorders(_settings.params.minInvestment, _settings.params.maxInvestment);
|
128
|
+
|
129
|
+
poolConfig = PoolConfig({
|
130
|
+
managementCommission: _settings.params.managementCommission,
|
131
|
+
withdrawalLockupPeriod: _settings.params.withdrawalLockupPeriod,
|
132
|
+
packedPerformanceFee: packPerformanceCommission(
|
133
|
+
unpackPerformanceCommission(_settings.params.packedPerformanceCommission)
|
134
|
+
),
|
135
|
+
minInvestment: _settings.params.minInvestment,
|
136
|
+
maxInvestment: _settings.params.maxInvestment
|
137
|
+
});
|
138
|
+
}
|
139
|
+
}
|
140
|
+
|
141
|
+
function getConfig() external view override returns (PoolConfig memory) {
|
142
|
+
return poolConfig;
|
143
|
+
}
|
144
|
+
|
145
|
+
function changePoolStatus(IUFarmPool.PoolStatus _newStatus) external override onlyFundMember {
|
146
|
+
_checkActiveFund();
|
147
|
+
|
148
|
+
checkPoolOrFundPermission(
|
149
|
+
msg.sender,
|
150
|
+
Permissions.Pool.PoolStatusControl,
|
151
|
+
Permissions.Fund.PoolStatusControl
|
152
|
+
);
|
153
|
+
IUFarmPool.PoolStatus currentPoolState = IUFarmPool(ufarmPool).status();
|
154
|
+
|
155
|
+
// New status can't be the same as the current one
|
156
|
+
if (currentPoolState == _newStatus) revert UFarmErrors.ActionAlreadyDone();
|
157
|
+
|
158
|
+
// Terminated is the final state, it can't be changed
|
159
|
+
if (currentPoolState == IUFarmPool.PoolStatus.Terminated)
|
160
|
+
revert WrongNewPoolStatus(currentPoolState, _newStatus);
|
161
|
+
|
162
|
+
// Active is the initial status transition
|
163
|
+
if (_newStatus < IUFarmPool.PoolStatus.Active)
|
164
|
+
revert WrongNewPoolStatus(currentPoolState, _newStatus);
|
165
|
+
|
166
|
+
// Active status can be changed from Created
|
167
|
+
if (_newStatus == IUFarmPool.PoolStatus.Active) {
|
168
|
+
if (currentPoolState != IUFarmPool.PoolStatus.Created) {
|
169
|
+
revert WrongNewPoolStatus(currentPoolState, _newStatus);
|
170
|
+
}
|
171
|
+
(uint256 _totalCost, uint256 minimumFundDeposit) = (
|
172
|
+
IUFarmPool(ufarmPool).getTotalCost(),
|
173
|
+
IUFarmCore(ufarmCore).minimumFundDeposit()
|
174
|
+
);
|
175
|
+
if (_totalCost < minimumFundDeposit) {
|
176
|
+
revert IUFarmPool.InsufficientDepositAmount(_totalCost, minimumFundDeposit);
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
// Deactivating status can be changed from Active
|
181
|
+
if (
|
182
|
+
_newStatus == IUFarmPool.PoolStatus.Deactivating &&
|
183
|
+
currentPoolState != IUFarmPool.PoolStatus.Active
|
184
|
+
) revert WrongNewPoolStatus(currentPoolState, _newStatus);
|
185
|
+
|
186
|
+
// Set lockup period to 0 if pool is Terminated
|
187
|
+
if (_newStatus == IUFarmPool.PoolStatus.Terminated) {
|
188
|
+
_setLockupPeriod(0);
|
189
|
+
}
|
190
|
+
|
191
|
+
// Terminated status can be changed from Created, Active or Deactivating
|
192
|
+
IUFarmPool(ufarmPool).changeStatus(_newStatus);
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* @notice Updates Pool permissions for the given account
|
197
|
+
* @param _account - address of the account to update permissions
|
198
|
+
* @param _permissions - new permissions mask
|
199
|
+
*/
|
200
|
+
function updatePermissions(
|
201
|
+
address _account,
|
202
|
+
uint256 _permissions
|
203
|
+
) external ufarmIsNotPaused onlyFundMember {
|
204
|
+
// if user is pool member and fund member, then he can update permissions
|
205
|
+
checkPoolOrFundPermission(
|
206
|
+
msg.sender,
|
207
|
+
Permissions.Pool.UpdatePoolPermissions,
|
208
|
+
Permissions.Fund.UpdatePoolPermissions
|
209
|
+
);
|
210
|
+
_updatePermissions(_account, _permissions);
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* @notice Changes the pool commission
|
215
|
+
* @dev Reverts if the new commission is the same as the old one
|
216
|
+
* @param _managementCommission - new management commission
|
217
|
+
* @param _packedPerformanceFee - new performance commission
|
218
|
+
*/
|
219
|
+
function setCommissions(
|
220
|
+
uint256 _managementCommission,
|
221
|
+
uint256 _packedPerformanceFee
|
222
|
+
)
|
223
|
+
external
|
224
|
+
ufarmIsNotPaused
|
225
|
+
onlyFundMember
|
226
|
+
onlyActiveFund
|
227
|
+
onlyStatus(IUFarmPool.PoolStatus.Created)
|
228
|
+
valueInRange(_managementCommission, 0, TEN_PERCENTS)
|
229
|
+
{
|
230
|
+
checkPoolOrFundPermission(
|
231
|
+
msg.sender,
|
232
|
+
Permissions.Pool.UpdatePoolFees,
|
233
|
+
Permissions.Fund.UpdatePoolFees
|
234
|
+
);
|
235
|
+
|
236
|
+
bool managementCommissionChanged = _managementCommission != poolConfig.managementCommission;
|
237
|
+
bool performanceCommissionStepsChanged = _packedPerformanceFee !=
|
238
|
+
poolConfig.packedPerformanceFee;
|
239
|
+
|
240
|
+
if (!managementCommissionChanged && !performanceCommissionStepsChanged)
|
241
|
+
revert UFarmErrors.ActionAlreadyDone();
|
242
|
+
|
243
|
+
if (performanceCommissionStepsChanged) {
|
244
|
+
poolConfig.packedPerformanceFee = packPerformanceCommission(
|
245
|
+
unpackPerformanceCommission(_packedPerformanceFee)
|
246
|
+
);
|
247
|
+
}
|
248
|
+
if (managementCommissionChanged) {
|
249
|
+
poolConfig.managementCommission = _managementCommission;
|
250
|
+
}
|
251
|
+
|
252
|
+
emit CommissionChanged(_managementCommission, _packedPerformanceFee);
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* @notice Changes the withdrawal lockup period
|
257
|
+
* @dev Reverts if the new withdrawal lockup period is the same as the old one
|
258
|
+
* @param _withdrawalLockupPeriod - new withdrawal lockup period
|
259
|
+
*/
|
260
|
+
function setLockupPeriod(
|
261
|
+
uint128 _withdrawalLockupPeriod
|
262
|
+
) external onlyFundMember onlyActiveFund onlyStatus(IUFarmPool.PoolStatus.Created) {
|
263
|
+
checkPoolOrFundPermission(
|
264
|
+
msg.sender,
|
265
|
+
Permissions.Pool.UpdateLockupPeriods,
|
266
|
+
Permissions.Fund.UpdateLockupPeriods
|
267
|
+
);
|
268
|
+
|
269
|
+
if (_withdrawalLockupPeriod == poolConfig.withdrawalLockupPeriod)
|
270
|
+
revert UFarmErrors.ActionAlreadyDone();
|
271
|
+
_checkLockupPeriod(_withdrawalLockupPeriod);
|
272
|
+
|
273
|
+
_setLockupPeriod(_withdrawalLockupPeriod);
|
274
|
+
}
|
275
|
+
|
276
|
+
/**
|
277
|
+
* @notice Changes the investment range
|
278
|
+
* @dev Reverts if the new investment range is the same as the old one
|
279
|
+
* @param _minInvestment - new minimum investment boundary
|
280
|
+
* @param _maxInvestment - new maximum investment boundary
|
281
|
+
*/
|
282
|
+
function setInvestmentRange(
|
283
|
+
uint256 _minInvestment,
|
284
|
+
uint256 _maxInvestment
|
285
|
+
) external onlyFundMember onlyActiveFund {
|
286
|
+
IUFarmPool.PoolStatus currentState = IUFarmPool(ufarmPool).status();
|
287
|
+
if (currentState > IUFarmPool.PoolStatus.Active) {
|
288
|
+
revert IUFarmPool.InvalidPoolStatus(IUFarmPool.PoolStatus.Active, currentState);
|
289
|
+
}
|
290
|
+
checkPoolOrFundPermission(
|
291
|
+
msg.sender,
|
292
|
+
Permissions.Pool.UpdatePoolTopUpAmount,
|
293
|
+
Permissions.Fund.UpdatePoolTopUpAmount
|
294
|
+
);
|
295
|
+
|
296
|
+
if (
|
297
|
+
(_minInvestment == poolConfig.minInvestment) && (_maxInvestment == poolConfig.maxInvestment)
|
298
|
+
) revert UFarmErrors.ActionAlreadyDone();
|
299
|
+
|
300
|
+
_setInvestmentRange(_minInvestment, _maxInvestment);
|
301
|
+
}
|
302
|
+
|
303
|
+
/**
|
304
|
+
* @notice Encodes PerformanceCommissionSteps into a single uint256 value with validation
|
305
|
+
* @param steps - PerformanceCommissionSteps array
|
306
|
+
* @return packedPerformanceFee - encoded PerformanceCommissionSteps
|
307
|
+
*/
|
308
|
+
function packPerformanceCommission(
|
309
|
+
IUFarmPool.PerformanceCommissionStep[] memory steps
|
310
|
+
) public pure returns (uint256 packedPerformanceFee) {
|
311
|
+
uint256 stepsCount = steps.length;
|
312
|
+
if (stepsCount > 8) revert PerformanceFeeLib.InvalidPerformanceCommissionStepsCount();
|
313
|
+
|
314
|
+
uint16 previousStep;
|
315
|
+
IUFarmPool.PerformanceCommissionStep memory thisStep;
|
316
|
+
for (uint256 i; i < stepsCount; ++i) {
|
317
|
+
thisStep = steps[i];
|
318
|
+
if (thisStep.step > previousStep || i == 0) {
|
319
|
+
_valueInRange(thisStep.commission, 0, MAX_PERFORMANCE_FEE);
|
320
|
+
previousStep = thisStep.step;
|
321
|
+
} else {
|
322
|
+
revert PerformanceFeeLib.InvalidPerformanceCommissionStep(
|
323
|
+
thisStep.step,
|
324
|
+
thisStep.commission
|
325
|
+
);
|
326
|
+
}
|
327
|
+
|
328
|
+
packedPerformanceFee |= uint256(thisStep.step) << (i * 32); // Shift 'step' by 32 bits
|
329
|
+
packedPerformanceFee |= uint256(thisStep.commission) << (i * 32 + 16); // Shift 'commission' by 16 bits
|
330
|
+
}
|
331
|
+
return packedPerformanceFee;
|
332
|
+
}
|
333
|
+
|
334
|
+
/**
|
335
|
+
* @notice Decodes PerformanceCommissionSteps from a single uint256 value
|
336
|
+
* @param packedPerformanceFee - encoded PerformanceCommissionSteps
|
337
|
+
* @return steps - PerformanceCommissionSteps array
|
338
|
+
*/
|
339
|
+
function unpackPerformanceCommission(
|
340
|
+
uint256 packedPerformanceFee
|
341
|
+
) public pure returns (IUFarmPool.PerformanceCommissionStep[] memory steps) {
|
342
|
+
uint8 filledLength = PerformanceFeeLib._getPerformanceCommissionStepsCount(
|
343
|
+
packedPerformanceFee
|
344
|
+
);
|
345
|
+
steps = new IUFarmPool.PerformanceCommissionStep[](filledLength);
|
346
|
+
for (uint8 i; i < filledLength; ++i) {
|
347
|
+
steps[i] = PerformanceFeeLib._getPerformanceCommissionStep(packedPerformanceFee, i);
|
348
|
+
}
|
349
|
+
}
|
350
|
+
|
351
|
+
/**
|
352
|
+
* @inheritdoc IPoolAdmin
|
353
|
+
*/
|
354
|
+
function isAbleToManageFunds(address manager) public view override returns (bool) {
|
355
|
+
_checkActiveFund();
|
356
|
+
|
357
|
+
bool poolFinanceManager = _hasPermissionMask(
|
358
|
+
manager,
|
359
|
+
_twoPermissionsToMask(uint8(Permissions.Pool.Member), uint8(Permissions.Pool.ManagePoolFunds))
|
360
|
+
);
|
361
|
+
if (!poolFinanceManager) {
|
362
|
+
bool allPoolsManager = UFarmPermissionsModel(ufarmFund).hasPermission(
|
363
|
+
manager,
|
364
|
+
uint8(Permissions.Fund.ManagePoolFunds)
|
365
|
+
);
|
366
|
+
if (!allPoolsManager) revert UFarmErrors.NonAuthorized();
|
367
|
+
}
|
368
|
+
return true;
|
369
|
+
}
|
370
|
+
|
371
|
+
/**
|
372
|
+
* @notice Reverts if the caller doesn't have pool permission or fund permission
|
373
|
+
* @param _account - address of the account to check permissions
|
374
|
+
* @param _poolPermission - permission in the pool
|
375
|
+
* @param _fundPermission - permission in the fund
|
376
|
+
*/
|
377
|
+
function checkPoolOrFundPermission(
|
378
|
+
address _account,
|
379
|
+
Permissions.Pool _poolPermission,
|
380
|
+
Permissions.Fund _fundPermission
|
381
|
+
) public view {
|
382
|
+
if (
|
383
|
+
!_hasPermissionMask(
|
384
|
+
_account,
|
385
|
+
_twoPermissionsToMask(uint8(Permissions.Pool.Member), uint8(_poolPermission))
|
386
|
+
) && !UFarmPermissionsModel(ufarmFund).hasPermission(_account, uint8(_fundPermission))
|
387
|
+
) revert UFarmErrors.NonAuthorized();
|
388
|
+
}
|
389
|
+
|
390
|
+
function _setLockupPeriod(uint128 _withdrawalLockupPeriod) private {
|
391
|
+
poolConfig.withdrawalLockupPeriod = _withdrawalLockupPeriod;
|
392
|
+
emit LockupPeriodChanged(_withdrawalLockupPeriod);
|
393
|
+
}
|
394
|
+
|
395
|
+
function _checkActiveFund() private view {
|
396
|
+
IUFarmFund.FundStatus fundStatus = IUFarmFund(ufarmFund).status();
|
397
|
+
if (fundStatus != IUFarmFund.FundStatus.Active) {
|
398
|
+
revert IUFarmFund.WrongFundStatus(IUFarmFund.FundStatus.Active, fundStatus);
|
399
|
+
}
|
400
|
+
}
|
401
|
+
|
402
|
+
function _setInvestmentRange(uint256 _minInvestment, uint256 _maxInvestment) private {
|
403
|
+
_checkInvestmentBorders(_minInvestment, _maxInvestment);
|
404
|
+
(poolConfig.minInvestment, poolConfig.maxInvestment) = (_minInvestment, _maxInvestment);
|
405
|
+
emit InvestmentRangeChanged(_minInvestment, _maxInvestment);
|
406
|
+
}
|
407
|
+
|
408
|
+
function _ufarmIsNotPaused() private view {
|
409
|
+
if (IUFarmCore(ufarmCore).isPaused()) revert UFarmErrors.UFarmIsPaused();
|
410
|
+
}
|
411
|
+
|
412
|
+
function _isCallerFundMember() private view {
|
413
|
+
if (
|
414
|
+
!UFarmPermissionsModel(address(ufarmFund)).hasPermission(
|
415
|
+
msg.sender,
|
416
|
+
uint8(Permissions.Fund.Member)
|
417
|
+
)
|
418
|
+
) revert UFarmErrors.NonAuthorized();
|
419
|
+
}
|
420
|
+
|
421
|
+
function _statusIs(IUFarmPool.PoolStatus _requiredStatus) private view {
|
422
|
+
IUFarmPool.PoolStatus currentState = IUFarmPool(ufarmPool).status();
|
423
|
+
if (currentState != _requiredStatus)
|
424
|
+
revert IUFarmPool.InvalidPoolStatus(_requiredStatus, currentState);
|
425
|
+
}
|
426
|
+
|
427
|
+
function _checkInvestmentBorders(uint256 minInvestment, uint256 maxInvestment) private pure {
|
428
|
+
if (minInvestment > maxInvestment) revert ValueNotInRange(minInvestment, 0, maxInvestment);
|
429
|
+
}
|
430
|
+
|
431
|
+
function _checkLockupPeriod(uint256 _lockupPeriod) private pure {
|
432
|
+
if (_lockupPeriod > MAX_LOCKUP_PERIOD)
|
433
|
+
revert ValueNotInRange(_lockupPeriod, 0, MAX_LOCKUP_PERIOD);
|
434
|
+
}
|
435
|
+
|
436
|
+
uint256[50] private __gap;
|
437
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
2
|
+
|
3
|
+
pragma solidity ^0.8.0;
|
4
|
+
|
5
|
+
/// INTERFACES
|
6
|
+
import {IUFarmCore} from '../core/IUFarmCore.sol';
|
7
|
+
import {IUFarmPool} from '../pool/IUFarmPool.sol';
|
8
|
+
import {IPoolAdmin} from '../pool/IPoolAdmin.sol';
|
9
|
+
|
10
|
+
/// CONTRACTS
|
11
|
+
import {UFarmCoreLink} from '../../shared/UFarmCoreLink.sol';
|
12
|
+
|
13
|
+
/// LIBRARIES
|
14
|
+
import {SafeOPS} from '../../shared/SafeOPS.sol';
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @title IPoolFactory interface
|
18
|
+
* @author https://ufarm.digital/
|
19
|
+
* @notice Interface for the PoolFactory contract, that creates new pools
|
20
|
+
*/
|
21
|
+
interface IPoolFactory {
|
22
|
+
/**
|
23
|
+
* @notice Creates a new pool
|
24
|
+
* @param _settings - settings for the pool
|
25
|
+
* @param salt - salt for the pool
|
26
|
+
* @return pool - address of the created pool
|
27
|
+
*/
|
28
|
+
function createPool(
|
29
|
+
IUFarmPool.CreationSettingsWithLinks calldata _settings,
|
30
|
+
bytes32 salt
|
31
|
+
) external returns (address pool, address poolAdmin);
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @title PoolFactory contract
|
36
|
+
* @author https://ufarm.digital/
|
37
|
+
* @notice Deployer of new pools for UFarm Funds. Creates new beacon proxies from the UUPS upgradeable proxy.
|
38
|
+
* @notice All proxies are linked to the one implementation contract.
|
39
|
+
*/
|
40
|
+
contract PoolFactory is IPoolFactory, UFarmCoreLink {
|
41
|
+
// Beacon is UUPS upgradeable proxy address, implementation can be upgraded if needed
|
42
|
+
address public immutable poolImplementationBeacon;
|
43
|
+
address public immutable poolAdminImplBeacon;
|
44
|
+
|
45
|
+
/**
|
46
|
+
* @dev Reverts if caller is not a fund
|
47
|
+
*/
|
48
|
+
error CallerIsNotFund();
|
49
|
+
|
50
|
+
constructor(address _ufarmCore, address _poolImpl, address _poolAdminImplBeacon) {
|
51
|
+
__init__UFarmCoreLink(_ufarmCore);
|
52
|
+
poolImplementationBeacon = _poolImpl;
|
53
|
+
poolAdminImplBeacon = _poolAdminImplBeacon;
|
54
|
+
}
|
55
|
+
|
56
|
+
/// @inheritdoc IPoolFactory
|
57
|
+
function createPool(
|
58
|
+
IUFarmPool.CreationSettingsWithLinks calldata _settings,
|
59
|
+
bytes32 _salt
|
60
|
+
) public onlyLinked returns (address pool, address poolAdmin) {
|
61
|
+
if (!IUFarmCore(ufarmCore()).isFund(msg.sender)) revert CallerIsNotFund();
|
62
|
+
|
63
|
+
poolAdmin = SafeOPS._safeBeaconCreate2Deploy(poolAdminImplBeacon, _salt, hex'');
|
64
|
+
pool = SafeOPS._safeBeaconCreate2Deploy(poolImplementationBeacon, _salt, hex'');
|
65
|
+
|
66
|
+
IPoolAdmin(poolAdmin).__init_PoolAdmin(_settings, pool);
|
67
|
+
IUFarmPool(pool).__init_UFarmPool(_settings, poolAdmin);
|
68
|
+
}
|
69
|
+
|
70
|
+
function getPoolBySalt(bytes32 _salt) public view returns (address pool, address poolAdmin) {
|
71
|
+
poolAdmin = SafeOPS.computeBeaconProxyAddress(poolAdminImplBeacon, _salt, hex'');
|
72
|
+
pool = SafeOPS.computeBeaconProxyAddress(poolImplementationBeacon, _salt, hex'');
|
73
|
+
}
|
74
|
+
}
|
@@ -0,0 +1,70 @@
|
|
1
|
+
// SPDX-License-Identifier: BUSL-1.1
|
2
|
+
|
3
|
+
pragma solidity ^0.8.0;
|
4
|
+
|
5
|
+
import {ICoreWhitelist} from '../core/CoreWhitelist.sol';
|
6
|
+
|
7
|
+
interface IPoolWhitelist {
|
8
|
+
error TokenIsNotAllowed(address token);
|
9
|
+
|
10
|
+
function isTokenAllowed(address token) external view returns (bool);
|
11
|
+
|
12
|
+
function isProtocolAllowed(bytes32 protocol) external view returns (bool);
|
13
|
+
}
|
14
|
+
|
15
|
+
/**
|
16
|
+
* @title PoolWhitelist contract
|
17
|
+
* @author https://ufarm.digital/
|
18
|
+
* @notice Contract that implements whitelist for tokens and protocols
|
19
|
+
*/
|
20
|
+
abstract contract PoolWhitelist is IPoolWhitelist {
|
21
|
+
function ufarmCore() public view virtual returns (address);
|
22
|
+
|
23
|
+
error ProtocolNotAllowed(bytes32 protocol);
|
24
|
+
|
25
|
+
/**
|
26
|
+
* @notice Reverts if protocol is not whitelisted here or in parent whitelist
|
27
|
+
* @param _protocol - protocol to check
|
28
|
+
*/
|
29
|
+
modifier protocolAllowed(bytes32 _protocol) {
|
30
|
+
_checkProtocolAllowance(_protocol);
|
31
|
+
_;
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* @notice Checks if protocol is allowed to be used in the pool
|
36
|
+
* @param protocol - protocol to check
|
37
|
+
* @return true if protocol is allowed, false otherwise
|
38
|
+
*/
|
39
|
+
function isProtocolAllowed(bytes32 protocol) external view override returns (bool) {
|
40
|
+
return _isProtocolAllowed(protocol);
|
41
|
+
}
|
42
|
+
|
43
|
+
/**
|
44
|
+
* @notice Checks if protocol is allowed to be used in the pool, revert if not
|
45
|
+
* @param _protocol - protocol to check
|
46
|
+
*/
|
47
|
+
function _checkProtocolAllowance(bytes32 _protocol) internal view {
|
48
|
+
if (!_isProtocolAllowed(_protocol)) revert ProtocolNotAllowed(_protocol);
|
49
|
+
}
|
50
|
+
|
51
|
+
/**
|
52
|
+
* @notice Checks if protocol is allowed on the platform
|
53
|
+
* @param _protocol - protocol to check
|
54
|
+
* @return true if protocol is allowed, false otherwise
|
55
|
+
*/
|
56
|
+
function _isProtocolAllowed(bytes32 _protocol) internal view returns (bool) {
|
57
|
+
return ICoreWhitelist(ufarmCore()).isProtocolWhitelisted(_protocol);
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* @notice Checks if token is allowed to be used in the pool
|
62
|
+
* @param token - token to check
|
63
|
+
* @return true if token is allowed, false otherwise
|
64
|
+
*/
|
65
|
+
function isTokenAllowed(address token) public view virtual returns (bool) {
|
66
|
+
return ICoreWhitelist(ufarmCore()).isTokenWhitelisted(token);
|
67
|
+
}
|
68
|
+
|
69
|
+
uint256[50] private __gap;
|
70
|
+
}
|