@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.
Files changed (127) hide show
  1. package/.docker/Dockerfile +17 -0
  2. package/.dockerignore +7 -0
  3. package/.env.sample +24 -0
  4. package/.gitlab-ci.yml +51 -0
  5. package/.gitmodules +15 -0
  6. package/.prettierrc +10 -0
  7. package/.solcover.js +4 -0
  8. package/.vscode/settings.json +23 -0
  9. package/LICENSE.MD +51 -0
  10. package/README.md +135 -0
  11. package/contracts/arbitrum/contracts/controllers/UniswapV2ControllerArbitrum.sol +37 -0
  12. package/contracts/arbitrum/contracts/controllers/UniswapV3ControllerArbitrum.sol +46 -0
  13. package/contracts/arbitrum/contracts/oracle/PriceOracleArbitrum.sol +51 -0
  14. package/contracts/main/contracts/controllers/Controller.sol +61 -0
  15. package/contracts/main/contracts/controllers/IController.sol +81 -0
  16. package/contracts/main/contracts/controllers/OneInchV5Controller.sol +332 -0
  17. package/contracts/main/contracts/controllers/UnoswapV2Controller.sol +789 -0
  18. package/contracts/main/contracts/controllers/UnoswapV3Controller.sol +1018 -0
  19. package/contracts/main/contracts/core/CoreWhitelist.sol +192 -0
  20. package/contracts/main/contracts/core/ICoreWhitelist.sol +92 -0
  21. package/contracts/main/contracts/core/IUFarmCore.sol +95 -0
  22. package/contracts/main/contracts/core/UFarmCore.sol +402 -0
  23. package/contracts/main/contracts/fund/FundFactory.sol +59 -0
  24. package/contracts/main/contracts/fund/IUFarmFund.sol +68 -0
  25. package/contracts/main/contracts/fund/UFarmFund.sol +504 -0
  26. package/contracts/main/contracts/oracle/ChainlinkedOracle.sol +71 -0
  27. package/contracts/main/contracts/oracle/IChainlinkAggregator.sol +18 -0
  28. package/contracts/main/contracts/oracle/IPriceOracle.sol +55 -0
  29. package/contracts/main/contracts/oracle/PriceOracle.sol +20 -0
  30. package/contracts/main/contracts/oracle/PriceOracleCore.sol +212 -0
  31. package/contracts/main/contracts/oracle/WstETHOracle.sol +64 -0
  32. package/contracts/main/contracts/permissions/Permissions.sol +54 -0
  33. package/contracts/main/contracts/permissions/UFarmPermissionsModel.sol +136 -0
  34. package/contracts/main/contracts/pool/IPoolAdmin.sol +57 -0
  35. package/contracts/main/contracts/pool/IUFarmPool.sol +304 -0
  36. package/contracts/main/contracts/pool/PerformanceFeeLib.sol +81 -0
  37. package/contracts/main/contracts/pool/PoolAdmin.sol +437 -0
  38. package/contracts/main/contracts/pool/PoolFactory.sol +74 -0
  39. package/contracts/main/contracts/pool/PoolWhitelist.sol +70 -0
  40. package/contracts/main/contracts/pool/UFarmPool.sol +959 -0
  41. package/contracts/main/shared/AssetController.sol +194 -0
  42. package/contracts/main/shared/ECDSARecover.sol +91 -0
  43. package/contracts/main/shared/NZGuard.sol +99 -0
  44. package/contracts/main/shared/SafeOPS.sol +128 -0
  45. package/contracts/main/shared/UFarmCoreLink.sol +83 -0
  46. package/contracts/main/shared/UFarmErrors.sol +16 -0
  47. package/contracts/main/shared/UFarmMathLib.sol +80 -0
  48. package/contracts/main/shared/UFarmOwnableUUPS.sol +59 -0
  49. package/contracts/main/shared/UFarmOwnableUUPSBeacon.sol +34 -0
  50. package/contracts/test/Block.sol +15 -0
  51. package/contracts/test/InchSwapTestProxy.sol +292 -0
  52. package/contracts/test/MockPoolAdmin.sol +8 -0
  53. package/contracts/test/MockUFarmPool.sol +8 -0
  54. package/contracts/test/MockV3wstETHstETHAgg.sol +128 -0
  55. package/contracts/test/MockedWETH9.sol +72 -0
  56. package/contracts/test/OneInchToUFarmTestEnv.sol +466 -0
  57. package/contracts/test/StableCoin.sol +25 -0
  58. package/contracts/test/UFarmMockSequencerUptimeFeed.sol +44 -0
  59. package/contracts/test/UFarmMockV3Aggregator.sol +145 -0
  60. package/contracts/test/UUPSBlock.sol +19 -0
  61. package/contracts/test/ufarmLocal/MulticallV3.sol +220 -0
  62. package/contracts/test/ufarmLocal/controllers/UniswapV2ControllerUFarm.sol +27 -0
  63. package/contracts/test/ufarmLocal/controllers/UniswapV3ControllerUFarm.sol +43 -0
  64. package/deploy/100_test_env_setup.ts +483 -0
  65. package/deploy/20_deploy_uniV2.ts +48 -0
  66. package/deploy/21_create_pairs_uniV2.ts +149 -0
  67. package/deploy/22_deploy_mocked_aggregators.ts +123 -0
  68. package/deploy/22_deploy_wsteth_oracle.ts +65 -0
  69. package/deploy/23_deploy_uniV3.ts +80 -0
  70. package/deploy/24_create_pairs_uniV3.ts +140 -0
  71. package/deploy/25_deploy_oneInch.ts +38 -0
  72. package/deploy/2_deploy_multicall.ts +34 -0
  73. package/deploy/30_deploy_price_oracle.ts +33 -0
  74. package/deploy/3_deploy_lido.ts +114 -0
  75. package/deploy/40_deploy_pool_beacon.ts +19 -0
  76. package/deploy/41_deploy_poolAdmin_beacon.ts +19 -0
  77. package/deploy/42_deploy_ufarmcore.ts +29 -0
  78. package/deploy/43_deploy_fund_beacon.ts +19 -0
  79. package/deploy/4_deploy_tokens.ts +76 -0
  80. package/deploy/50_deploy_poolFactory.ts +35 -0
  81. package/deploy/51_deploy_fundFactory.ts +29 -0
  82. package/deploy/60_init_contracts.ts +101 -0
  83. package/deploy/61_whitelist_tokens.ts +18 -0
  84. package/deploy/70_deploy_uniV2Controller.ts +70 -0
  85. package/deploy/71_deploy_uniV3Controller.ts +67 -0
  86. package/deploy/72_deploy_oneInchController.ts +25 -0
  87. package/deploy/79_whitelist_controllers.ts +125 -0
  88. package/deploy/ufarm/arbitrum/1_prepare_env.ts +82 -0
  89. package/deploy/ufarm/arbitrum/2_deploy_ufarm.ts +178 -0
  90. package/deploy/ufarm/arbitrum-sepolia/1000_prepare_arb_sepolia_env.ts +308 -0
  91. package/deploy-config.json +112 -0
  92. package/deploy-data/oracles.csv +32 -0
  93. package/deploy-data/protocols.csv +10 -0
  94. package/deploy-data/tokens.csv +32 -0
  95. package/docker-compose.yml +67 -0
  96. package/hardhat.config.ts +449 -0
  97. package/index.js +93 -0
  98. package/package.json +82 -0
  99. package/scripts/_deploy_helpers.ts +992 -0
  100. package/scripts/_deploy_network_options.ts +49 -0
  101. package/scripts/activatePool.ts +51 -0
  102. package/scripts/createPool.ts +62 -0
  103. package/scripts/deploy_1inch_proxy.ts +98 -0
  104. package/scripts/pool-data.ts +420 -0
  105. package/scripts/post-deploy.sh +24 -0
  106. package/scripts/setUniV2Rate.ts +252 -0
  107. package/scripts/swapOneInchV5.ts +94 -0
  108. package/scripts/swapUniswapV2.ts +65 -0
  109. package/scripts/swapUniswapV3.ts +71 -0
  110. package/scripts/test.ts +61 -0
  111. package/scripts/typings-copy-artifacts.ts +83 -0
  112. package/tasks/boostPool.ts +39 -0
  113. package/tasks/createFund.ts +44 -0
  114. package/tasks/deboostPool.ts +48 -0
  115. package/tasks/grantUFarmPermissions.ts +57 -0
  116. package/tasks/index.ts +7 -0
  117. package/tasks/mintUSDT.ts +62 -0
  118. package/test/Periphery.test.ts +640 -0
  119. package/test/PriceOracle.test.ts +82 -0
  120. package/test/TestCases.MD +109 -0
  121. package/test/UFarmCore.test.ts +331 -0
  122. package/test/UFarmFund.test.ts +406 -0
  123. package/test/UFarmPool.test.ts +4736 -0
  124. package/test/_fixtures.ts +783 -0
  125. package/test/_helpers.ts +2195 -0
  126. package/test/_oneInchTestData.ts +632 -0
  127. 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
+ }