@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,504 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.0;
4
+
5
+ /// INTERFACES
6
+ import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
7
+ import {IUFarmCore} from '../core/IUFarmCore.sol';
8
+ import {IUFarmFund} from './IUFarmFund.sol';
9
+ import {IUFarmPool} from '../pool/IUFarmPool.sol';
10
+ import {IPoolFactory} from '../pool/PoolFactory.sol';
11
+ import {Permissions} from '../permissions/Permissions.sol';
12
+
13
+ /// CONTRACTS
14
+ import {ECDSARecover} from '../../shared/ECDSARecover.sol';
15
+ import {NZGuard} from '../../shared/NZGuard.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 {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
23
+ import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol';
24
+ import {SafeOPS} from '../../shared/SafeOPS.sol';
25
+
26
+ /**
27
+ * @title UFarmFund contract
28
+ * @author https://ufarm.digital/
29
+ * @notice Fund contract for the UFarm protocol for managing pools and fund employees permissions
30
+ */
31
+ contract UFarmFund is
32
+ IUFarmFund,
33
+ UFarmPermissionsModel,
34
+ Permissions,
35
+ ReentrancyGuard,
36
+ NZGuard,
37
+ UFarmErrors,
38
+ ECDSARecover,
39
+ UFarmOwnableUUPSBeacon
40
+ {
41
+ using SafeERC20 for IERC20;
42
+ using EnumerableSet for EnumerableSet.AddressSet;
43
+
44
+ /// @notice Struct for the pool and pool admin address
45
+ struct PoolContracts {
46
+ address poolAddr;
47
+ address poolAdmin;
48
+ }
49
+
50
+ /**
51
+ * @notice Native asset address constant
52
+ */
53
+ address public constant NATIVE_ASSET = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE;
54
+
55
+ /**
56
+ * @inheritdoc IUFarmFund
57
+ */
58
+ FundStatus public status;
59
+
60
+ /**
61
+ * @inheritdoc IUFarmFund
62
+ */
63
+ address public ufarmCore;
64
+
65
+ /**
66
+ * @notice Check if the pool is in the fund
67
+ *
68
+ * @return _isPool True if the pool is in the fund
69
+ */
70
+ mapping(address => bool) public isPool;
71
+
72
+ PoolContracts[] private __poolContracts;
73
+
74
+ mapping(bytes32 => bool) private __acceptedInvites;
75
+
76
+ /// EVENTS
77
+ /**
78
+ * @notice Emitted when the pool is created
79
+ * @param name - pool name
80
+ * @param symbol - pool symbol
81
+ * @param minInvestment - minimum investment in the pool
82
+ * @param maxInvestment - maximum investment in the pool
83
+ * @param managementCommission - management commission
84
+ * @param packedPerformanceComission - packed performance commission [(step:uint16, fee:uint16)...]
85
+ * @param withdrawalLockupPeriod - withdrawal lockup period
86
+ * @param poolId - pool id in the fund
87
+ * @param pool - pool address
88
+ * @param poolAdmin - pool admin address
89
+ */
90
+ event PoolCreated(
91
+ string name,
92
+ string symbol,
93
+ uint256 minInvestment,
94
+ uint256 maxInvestment,
95
+ uint256 managementCommission,
96
+ uint256 packedPerformanceComission,
97
+ uint256 withdrawalLockupPeriod,
98
+ uint256 poolId,
99
+ address pool,
100
+ address poolAdmin
101
+ );
102
+
103
+ /**
104
+ * @notice Emitted when the fund status is changed
105
+ * @param status - new status of the fund
106
+ */
107
+ event FundStatusChanged(FundStatus indexed status);
108
+
109
+ /**
110
+ * @notice Emitted when the invitation is accepted
111
+ * @param inviter - inviter fund employee
112
+ * @param invitee - invitee fund employee
113
+ * @param msgHash - hash of the invitation that was accepted
114
+ */
115
+ event InvitationAccepted(
116
+ address indexed inviter,
117
+ address indexed invitee,
118
+ bytes32 indexed msgHash
119
+ );
120
+
121
+ /// ERRORS
122
+ error StatusAlreadySet(FundStatus status);
123
+ error NotAPool(address pool);
124
+ error WrongAsset();
125
+ error InvitationExpired(uint256 deadline, uint256 timeNow);
126
+ error AlreadyMember();
127
+ error EmptyPermissions();
128
+
129
+ /// MODIFIERS
130
+ /**
131
+ * @notice Reverts if the fund is not in the required status
132
+ * @param _status - required status of the fund
133
+ */
134
+ modifier requiredStatus(FundStatus _status) {
135
+ _requiredStatus(_status);
136
+ _;
137
+ }
138
+
139
+ /**
140
+ * @notice Reverts if the fund can't manage pools
141
+ */
142
+ modifier poolManagementAllowed() {
143
+ _poolManagementAllowed();
144
+ _;
145
+ }
146
+
147
+ /**
148
+ * @notice Reverts if the UFarm platform is paused
149
+ */
150
+ modifier ufarmIsNotPaused() {
151
+ _ufarmIsNotPaused();
152
+ _;
153
+ }
154
+
155
+ /**
156
+ * @notice Reverts if the caller is not the fund owner or have two permissions
157
+ * @param permission1 - first permission (often membership)
158
+ * @param permission2 - second permission (often some kind of editor)
159
+ */
160
+ modifier ownerOrHaveTwoPermissions(uint8 permission1, uint8 permission2) {
161
+ if (!_hasPermission(msg.sender, uint8(Permissions.Fund.Owner))) {
162
+ _checkForPermissions(msg.sender, _twoPermissionsToMask(permission1, permission2));
163
+ }
164
+ _;
165
+ }
166
+
167
+ function version() public pure override returns (string memory) {
168
+ return '1.0';
169
+ }
170
+
171
+ function name() public pure override(ECDSARecover) returns (string memory) {
172
+ return 'UFarmFund';
173
+ }
174
+
175
+ /**
176
+ * @notice Get the pool address by the pool id
177
+ *
178
+ * @return poolContracts struct {poolAddr: address, poolAdmin: address}
179
+ */
180
+ function getPool(uint256 index) external view returns (PoolContracts memory) {
181
+ return __poolContracts[index];
182
+ }
183
+
184
+ /**
185
+ * @notice Get the list of the pools
186
+ *
187
+ * @return _pools List of the pools
188
+ */
189
+ function getPools() external view returns (PoolContracts[] memory) {
190
+ return __poolContracts;
191
+ }
192
+
193
+ /**
194
+ * @notice Get the count of the pools
195
+ *
196
+ * @return _pools Count of the pools
197
+ */
198
+ function poolsCount() external view returns (uint256) {
199
+ return __poolContracts.length;
200
+ }
201
+
202
+ /**
203
+ * @notice Verifies the invitation to the fund
204
+ * @param invitation - invitation struct
205
+ * @param signature - signature of the invitation
206
+ * @return inviter - address of the inviter or reverts if check failed
207
+ */
208
+ function verifyInvitation(
209
+ FundMemberInvitation memory invitation,
210
+ bytes memory signature
211
+ ) public view returns (address inviter, bytes32 msgHash) {
212
+ msgHash = ECDSARecover.toEIP712MessageHash(DOMAIN_SEPARATOR(), _hashInvitation(invitation));
213
+ inviter = ECDSARecover.recoverAddress(msgHash, signature);
214
+
215
+ if (inviter == address(0)) revert ECDSARecover.WrongSignature();
216
+
217
+ if (__acceptedInvites[msgHash]) revert UFarmErrors.ActionAlreadyDone();
218
+
219
+ if (_hasPermission(invitation.invitee, uint8(Permissions.Fund.Member))) revert AlreadyMember();
220
+
221
+ if (invitation.deadline < block.timestamp)
222
+ revert InvitationExpired(invitation.deadline, block.timestamp);
223
+
224
+ if (invitation.permissionsMask > 0) {
225
+ _canUpdatePermissions(inviter, invitation.invitee, invitation.permissionsMask);
226
+ // returns inviter with hash
227
+ } else revert EmptyPermissions();
228
+ }
229
+
230
+ /**
231
+ * @notice Accepts the invitation
232
+ * @param invitation - invitation struct
233
+ * @param signature - signature of the invitation
234
+ */
235
+ function acceptInvitation(
236
+ FundMemberInvitation memory invitation,
237
+ bytes memory signature
238
+ ) external ufarmIsNotPaused {
239
+ (address inviter, bytes32 msgHash) = verifyInvitation(invitation, signature);
240
+ if (invitation.invitee == msg.sender) {
241
+ __acceptedInvites[msgHash] = true;
242
+ emit InvitationAccepted(inviter, msg.sender, msgHash);
243
+ _updatePermissions(msg.sender, invitation.permissionsMask);
244
+ } else revert NonAuthorized();
245
+ }
246
+
247
+ /**
248
+ * @notice Updates the permissions as mask for the user, replaces the old mask
249
+ *
250
+ * @param _user - user address
251
+ *
252
+ * @param _newPermissionsMask - new permissions mask
253
+ */
254
+ function updatePermissions(address _user, uint256 _newPermissionsMask) external ufarmIsNotPaused {
255
+ _canUpdatePermissions(msg.sender, _user, _newPermissionsMask);
256
+ _updatePermissions(_user, _newPermissionsMask);
257
+ }
258
+
259
+ /**
260
+ * @notice Creates a new pool in the fund
261
+ *
262
+ * @param _settings - pool creation settings
263
+ * @param salt - salt for the pool
264
+ *
265
+ * @return pool - Pool address
266
+ */
267
+ function createPool(
268
+ IUFarmPool.CreationSettings memory _settings,
269
+ bytes32 salt
270
+ )
271
+ external
272
+ ufarmIsNotPaused
273
+ ownerOrHaveTwoPermissions(uint8(Permissions.Fund.Member), uint8(Permissions.Fund.CreatePool))
274
+ poolManagementAllowed
275
+ returns (address pool, address poolAdmin)
276
+ {
277
+ (_settings.name, _settings.symbol) = (
278
+ string(abi.encodePacked('UFarm-', _settings.name)),
279
+ string(abi.encodePacked('UF-', _settings.symbol))
280
+ );
281
+ IUFarmPool.CreationSettingsWithLinks memory fullSettings = IUFarmPool
282
+ .CreationSettingsWithLinks({
283
+ params: _settings,
284
+ ufarmCore: ufarmCore,
285
+ ufarmFund: address(this)
286
+ });
287
+ (pool, poolAdmin) = IPoolFactory(IUFarmCore(ufarmCore).poolFactory()).createPool(
288
+ fullSettings,
289
+ salt
290
+ );
291
+
292
+ uint256 poolId = __poolContracts.length;
293
+ __poolContracts.push(PoolContracts({poolAddr: pool, poolAdmin: poolAdmin}));
294
+ isPool[pool] = true;
295
+
296
+ emit PoolCreated(
297
+ _settings.name,
298
+ _settings.symbol,
299
+ _settings.minInvestment,
300
+ _settings.maxInvestment,
301
+ _settings.managementCommission,
302
+ _settings.packedPerformanceCommission,
303
+ _settings.withdrawalLockupPeriod,
304
+ poolId,
305
+ pool,
306
+ poolAdmin
307
+ );
308
+ }
309
+
310
+ /**
311
+ * @notice Changes the status of the fund
312
+ * @param newStatus New status of the fund
313
+ */
314
+ function changeStatus(FundStatus newStatus) external ufarmIsNotPaused {
315
+ if (
316
+ msg.sender == address(ufarmCore) ||
317
+ ((newStatus == FundStatus.Active || newStatus == FundStatus.Terminated) &&
318
+ _hasPermission(msg.sender, uint8(Permissions.Fund.Owner)))
319
+ ) {
320
+ _changeStatus(newStatus);
321
+ } else revert UFarmErrors.NonAuthorized();
322
+ }
323
+
324
+ /**
325
+ * @notice Deposits to the pool
326
+ *
327
+ * @param _pool - pool address
328
+ * @param _amount - amount of the deposit token that will be deposited
329
+ */
330
+ function depositToPool(
331
+ address _pool,
332
+ uint256 _amount
333
+ )
334
+ external
335
+ ufarmIsNotPaused
336
+ ownerOrHaveTwoPermissions(uint8(Permissions.Fund.Member), uint8(Permissions.Fund.ManageFund))
337
+ poolManagementAllowed
338
+ {
339
+ _checkPool(_pool);
340
+ SafeOPS._forceApprove(IUFarmPool(_pool).valueToken(), _pool, _amount);
341
+ IUFarmPool(_pool).deposit(_amount);
342
+ }
343
+
344
+ /**
345
+ * @notice Withdraws from the pool
346
+ *
347
+ * @param _request - withdrawal request
348
+ */
349
+ function withdrawFromPool(
350
+ IUFarmPool.SignedWithdrawalRequest calldata _request
351
+ )
352
+ external
353
+ ufarmIsNotPaused
354
+ ownerOrHaveTwoPermissions(uint8(Permissions.Fund.Member), uint8(Permissions.Fund.ManageFund))
355
+ poolManagementAllowed
356
+ {
357
+ _checkPool(_request.body.poolAddr);
358
+ IUFarmPool(_request.body.poolAddr).withdraw(_request);
359
+ }
360
+
361
+ //// ASSETS CONTROL
362
+ /**
363
+ * @notice Withdraws assets from the fund
364
+ *
365
+ * @param _token - address of the asset to withdraw
366
+ * @param _to - address of the recipient
367
+ * @param _amount - amount of the asset to withdraw
368
+ */
369
+ function withdrawAsset(
370
+ address _token,
371
+ address _to,
372
+ uint256 _amount
373
+ )
374
+ external
375
+ ufarmIsNotPaused
376
+ ownerOrHaveTwoPermissions(uint8(Permissions.Fund.Member), uint8(Permissions.Fund.ManageFund))
377
+ {
378
+ if (_token == address(0) || isPool[_token]) revert WrongAsset();
379
+ IERC20(_token).safeTransfer(_to, _amount);
380
+ }
381
+
382
+ /**
383
+ * @notice Approves assets to the recipient
384
+ *
385
+ * @param _token - address of the asset to approve
386
+ * @param _recipient - allowed recipient
387
+ * @param _amount - new allowance
388
+ */
389
+ function approveAssetTo(
390
+ address _token,
391
+ address _recipient,
392
+ uint256 _amount
393
+ )
394
+ external
395
+ ufarmIsNotPaused
396
+ ownerOrHaveTwoPermissions(uint8(Permissions.Fund.Member), uint8(Permissions.Fund.ManageFund))
397
+ {
398
+ if (_token == NATIVE_ASSET || _token == address(0) || isPool[_token]) revert WrongAsset();
399
+ SafeOPS._forceApprove(_token, _recipient, _amount);
400
+ }
401
+
402
+ /**
403
+ * @inheritdoc IUFarmFund
404
+ */
405
+ function __init_UFarmFund(address _owner, address _ufarmCore) external checkDelegateCall initializer {
406
+ __UUPSUpgradeable_init();
407
+ __ReentrancyGuard_init();
408
+ __init_UFarmFund_unchained(_owner, _ufarmCore);
409
+ }
410
+
411
+ function __init_UFarmFund_unchained(address _owner, address _ufarmCore) internal {
412
+ ufarmCore = _ufarmCore;
413
+
414
+ _nonZeroAddress(_owner);
415
+ _updatePermissions(_owner, _FULL_PERMISSIONS_MASK);
416
+ }
417
+
418
+ function _changeStatus(FundStatus _status) private {
419
+ if (status == _status) {
420
+ revert StatusAlreadySet(status);
421
+ }
422
+
423
+ status = _status;
424
+ emit FundStatusChanged(status);
425
+ }
426
+
427
+ function _requiredStatus(FundStatus _status) private view {
428
+ if (status != _status) {
429
+ revert WrongFundStatus(_status, status);
430
+ }
431
+ }
432
+
433
+ function _checkPool(address _pool) private view {
434
+ if (!isPool[_pool]) revert NotAPool(_pool);
435
+ }
436
+
437
+ function _poolManagementAllowed() private view {
438
+ if (status != FundStatus.Approved && status != FundStatus.Active)
439
+ revert WrongFundStatus(FundStatus.Approved, status);
440
+ }
441
+
442
+ function _ufarmIsNotPaused() private view {
443
+ if (IUFarmCore(ufarmCore).isPaused()) revert UFarmIsPaused();
444
+ }
445
+
446
+ function _canUpdatePermissions(
447
+ address _updater,
448
+ address _updatee,
449
+ uint256 _newPermissionsMask
450
+ ) private view {
451
+ uint256 currentUpdateeMask = _accountMask[_updatee];
452
+ // if update owner permissions
453
+ if (_isPermissionDiff(uint8(Permissions.Fund.Owner), currentUpdateeMask, _newPermissionsMask)) {
454
+ // only owner can grant or revoke owner permissions
455
+ _checkForPermissions(_updater, _permissionToMask(uint8(Permissions.Fund.Owner))); // reverts if caller is not owner
456
+ // owner cant update his own permissions
457
+ if (_updater == _updatee) revert NonAuthorized();
458
+ } else {
459
+ // if not owner
460
+ if (!_hasPermission(_updater, uint8(Permissions.Fund.Owner))) {
461
+ // should be able to grant or revoke permissions
462
+ _checkForPermissions(
463
+ _updater,
464
+ _twoPermissionsToMask(
465
+ uint8(Permissions.Fund.Member),
466
+ uint8(Permissions.Fund.UpdateFundPermissions)
467
+ )
468
+ );
469
+ // revert if want to grant UpdateFundPermissions
470
+ if (
471
+ _isPermissionDiff(
472
+ uint8(Permissions.Fund.UpdateFundPermissions),
473
+ currentUpdateeMask,
474
+ _newPermissionsMask
475
+ )
476
+ ) revert NonAuthorized();
477
+
478
+ // revert if want to grant permissions that caller doesn't have
479
+ uint256 currentUpdaterMask = _accountMask[_updater];
480
+ uint256 hasBitsNotInCommon = _newPermissionsMask & (~currentUpdaterMask);
481
+
482
+ if (hasBitsNotInCommon > 0) {
483
+ revert NonAuthorized();
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ function _hashInvitation(FundMemberInvitation memory invitation) private pure returns (bytes32) {
490
+ return
491
+ keccak256(
492
+ abi.encode(
493
+ keccak256(
494
+ bytes('FundMemberInvitation(address invitee,uint256 permissionsMask,uint256 deadline)')
495
+ ),
496
+ invitation.invitee,
497
+ invitation.permissionsMask,
498
+ invitation.deadline
499
+ )
500
+ );
501
+ }
502
+
503
+ uint256[50] private __gap;
504
+ }
@@ -0,0 +1,71 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.0;
4
+
5
+ import {IChainlinkAggregator} from '../oracle/IChainlinkAggregator.sol';
6
+ import {Initializable} from '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';
7
+
8
+ /**
9
+ * @title ChainlinkedOracle contract
10
+ * @author https://ufarm.digital/
11
+ * @notice Calls Chainlink Aggregator contracts and checks for stale data
12
+ */
13
+ abstract contract ChainlinkedOracle is Initializable {
14
+ struct ChainlinkAnswer {
15
+ uint80 roundId;
16
+ int256 answer;
17
+ uint256 startedAt;
18
+ uint256 updatedAt;
19
+ uint80 answeredInRound;
20
+ }
21
+ uint256 constant HOUR = 3600;
22
+
23
+ uint256 public chainlinkTimeout;
24
+
25
+ event ChainlinkTimeoutSet(uint256 timeout);
26
+
27
+ error WrongChainlinkPrice(address oracle);
28
+ error IncompleteChainlinkRound(address oracle);
29
+ error StaleChainlinkPrice(address oracle);
30
+ error ChainlinkOracleOutdated(address oracle);
31
+ error ChainlinkOracleNotSet(address asset);
32
+ error ChainlinkOracleIsDown(address oracle);
33
+
34
+ function __init__ChainlinkedOracle(uint256 _chainlinkTimeout) internal virtual onlyInitializing {
35
+ __init__ChainlinkedOracle_unchained(_chainlinkTimeout);
36
+ }
37
+
38
+ function __init__ChainlinkedOracle_unchained(
39
+ uint256 _chainlinkTimeout
40
+ ) internal virtual onlyInitializing {
41
+ chainlinkTimeout = _chainlinkTimeout;
42
+ emit ChainlinkTimeoutSet(_chainlinkTimeout);
43
+ }
44
+
45
+ function _chainlinkLatestRoundData(
46
+ address _oracle
47
+ ) internal view returns (ChainlinkAnswer memory latestRoundData) {
48
+ try IChainlinkAggregator(_oracle).latestRoundData() returns (
49
+ uint80 roundId,
50
+ int256 answer,
51
+ uint256 startedAt,
52
+ uint256 updatedAt,
53
+ uint80 answeredInRound
54
+ ) {
55
+ if (answer < 1) revert WrongChainlinkPrice(_oracle);
56
+ if (updatedAt == 0) revert IncompleteChainlinkRound(_oracle);
57
+ if (roundId < answeredInRound) revert StaleChainlinkPrice(_oracle);
58
+ if ((updatedAt + chainlinkTimeout) < block.timestamp) revert ChainlinkOracleOutdated(_oracle);
59
+
60
+ return ChainlinkAnswer(roundId, answer, startedAt, updatedAt, answeredInRound);
61
+ } catch {
62
+ revert ChainlinkOracleIsDown(_oracle);
63
+ }
64
+ }
65
+
66
+ function _chainlinkLatestAnswer(address _oracle) internal view returns (int256 answer) {
67
+ return _chainlinkLatestRoundData(_oracle).answer;
68
+ }
69
+
70
+ uint256[50] private __gap;
71
+ }
@@ -0,0 +1,18 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.0;
4
+
5
+ interface IChainlinkAggregator {
6
+ function latestAnswer() external view returns (int256);
7
+ function latestRoundData()
8
+ external
9
+ view
10
+ returns (
11
+ uint80 roundId,
12
+ int256 answer,
13
+ uint256 startedAt,
14
+ uint256 updatedAt,
15
+ uint80 answeredInRound
16
+ );
17
+ function decimals() external view returns (uint8);
18
+ }
@@ -0,0 +1,55 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.0;
4
+
5
+ interface IPriceOracle {
6
+ /**
7
+ * @notice Returns total cost of the pool in terms of value token
8
+ * @param ufarmPool - address of the pool
9
+ * @param valueToken - address of the token in which the cost is calculated
10
+ */
11
+ function getTotalCostOfPool(
12
+ address ufarmPool,
13
+ address valueToken
14
+ ) external view returns (uint256 totalCost);
15
+
16
+ /**
17
+ * @notice Returns cost of the token in terms of value token
18
+ * @param tokenIn - address of the token which cost will be calculated
19
+ * @param amountIn - amount of the token which cost will be calculated
20
+ * @param tokenOut - address of the token in which the cost is calculated
21
+ */
22
+ function getCostERC20(
23
+ address tokenIn,
24
+ uint256 amountIn,
25
+ address tokenOut
26
+ ) external view returns (uint256 cost);
27
+
28
+ /**
29
+ * @notice Returns cost of the token in terms of value token
30
+ * @param tokenIn - address of the token which cost will be calculated
31
+ * @param amountIn - amount of the token which cost will be calculated
32
+ * @param tokenOut - address of the token in which the cost is calculated
33
+ * @param controller - address of the controller, which will be used to calculate the cost
34
+ */
35
+ function getCostControlledERC20(
36
+ address tokenIn,
37
+ uint256 amountIn,
38
+ address tokenOut,
39
+ address controller
40
+ ) external view returns (uint256 cost);
41
+
42
+ /**
43
+ * @notice Returns cost of the token in terms of value token
44
+ * @param tokenIn - address of the token which cost will be calculated
45
+ * @param ids - ids of the token which cost will be calculated
46
+ * @param tokenOut - address of the token in which the cost is calculated
47
+ * @param controller - address of the controller, which will be used to calculate the cost
48
+ */
49
+ function getCostERC721(
50
+ address tokenIn,
51
+ uint256[] memory ids,
52
+ address tokenOut,
53
+ address controller
54
+ ) external view returns (uint256 cost);
55
+ }
@@ -0,0 +1,20 @@
1
+ // SPDX-License-Identifier: BUSL-1.1
2
+
3
+ pragma solidity ^0.8.0;
4
+
5
+ import {PriceOracleCore} from './PriceOracleCore.sol';
6
+
7
+ /**
8
+ * @title PriceOracle
9
+ * @author https://ufarm.digital/
10
+ * @notice Calculates the cost of the pool and tokens
11
+ */
12
+ contract PriceOracle is PriceOracleCore {
13
+ /**
14
+ * @notice Initializes the contract from deployer. Sets link to UFarmCore
15
+ * @param ufarmCoreLink - address of the core contract
16
+ */
17
+ function __init__PriceOracle(address ufarmCoreLink) external onlyDeployer initializer {
18
+ __init__PriceOracleCore(ufarmCoreLink);
19
+ }
20
+ }