diff --git a/script/deploy/Core.s.sol b/script/deploy/Core.s.sol index 68aec4f0..096a729e 100644 --- a/script/deploy/Core.s.sol +++ b/script/deploy/Core.s.sol @@ -9,7 +9,6 @@ import {MetadataPlugin} from "src/contracts/plugins/MetadataPlugin.sol"; import {MiddlewarePlugin} from "src/contracts/plugins/MiddlewarePlugin.sol"; import {NetworkOptInPlugin} from "src/contracts/plugins/NetworkOptInPlugin.sol"; import {OperatorOptInPlugin} from "src/contracts/plugins/OperatorOptInPlugin.sol"; -import {RewardsPlugin} from "src/contracts/plugins/RewardsPlugin.sol"; import {Vault} from "src/contracts/Vault.sol"; contract CoreScript is Script { @@ -31,7 +30,6 @@ contract CoreScript is Script { new OperatorOptInPlugin(address(operatorRegistry), address(vaultRegistry)); OperatorOptInPlugin operatorNetworkOptInPlugin = new OperatorOptInPlugin(address(operatorRegistry), address(networkRegistry)); - RewardsPlugin operatorRewardsPlugin = new RewardsPlugin(address(networkRegistry), address(vaultRegistry)); vaultRegistry.whitelist( address( diff --git a/script/deploy/Vault.s.sol b/script/deploy/Vault.s.sol index d45536f4..9a892a7b 100644 --- a/script/deploy/Vault.s.sol +++ b/script/deploy/Vault.s.sol @@ -14,6 +14,7 @@ contract VaultScript is Script { uint48 epochDuration, uint48 vetoDuration, uint48 slashDuration, + address rewardsDistributor, uint256 adminFee, bool depositWhitelist ) public { @@ -31,6 +32,7 @@ contract VaultScript is Script { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: rewardsDistributor, adminFee: adminFee, depositWhitelist: depositWhitelist }) diff --git a/src/contracts/Vault.sol b/src/contracts/Vault.sol index 1ffd9104..e1b63a9a 100644 --- a/src/contracts/Vault.sol +++ b/src/contracts/Vault.sol @@ -1,24 +1,24 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IVault} from "src/interfaces/IVault.sol"; -import {IRegistry} from "src/interfaces/base/IRegistry.sol"; -import {IMigratableEntity} from "src/interfaces/base/IMigratableEntity.sol"; +import {MigratableEntity} from "./base/MigratableEntity.sol"; +import {VaultStorage} from "./VaultStorage.sol"; + import {ICollateral} from "src/interfaces/base/ICollateral.sol"; import {IMiddlewarePlugin} from "src/interfaces/plugins/IMiddlewarePlugin.sol"; +import {IMigratableEntity} from "src/interfaces/base/IMigratableEntity.sol"; import {INetworkOptInPlugin} from "src/interfaces/plugins/INetworkOptInPlugin.sol"; import {IOperatorOptInPlugin} from "src/interfaces/plugins/IOperatorOptInPlugin.sol"; +import {IRegistry} from "src/interfaces/base/IRegistry.sol"; +import {IVault} from "src/interfaces/IVault.sol"; -import {VaultStorage} from "./VaultStorage.sol"; -import {MigratableEntity} from "./base/MigratableEntity.sol"; - -import {ERC4626Math} from "./libraries/ERC4626Math.sol"; import {Checkpoints} from "./libraries/Checkpoints.sol"; +import {ERC4626Math} from "./libraries/ERC4626Math.sol"; +import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; -import {AccessControlUpgradeable} from "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol"; contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, IVault { using Checkpoints for Checkpoints.Trace256; @@ -95,7 +95,9 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, IVau operatorVaultOptInPlugin, operatorNetworkOptInPlugin ) - {} + { + _disableInitializers(); + } /** * @inheritdoc IMigratableEntity @@ -125,6 +127,7 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, IVau vetoDuration = params.vetoDuration; slashDuration = params.slashDuration; + rewardsDistributor = params.rewardsDistributor; adminFee = params.adminFee; depositWhitelist = params.depositWhitelist; @@ -403,6 +406,19 @@ contract Vault is VaultStorage, MigratableEntity, AccessControlUpgradeable, IVau emit SetMaxNetworkResolverLimit(msg.sender, resolver, amount); } + /** + * @inheritdoc IVault + */ + function setRewardsDistributor(address rewardsDistributor_) external onlyRole(REWARDS_DISTRIBUTOR_SET_ROLE) { + if (rewardsDistributor == rewardsDistributor_) { + revert AlreadySet(); + } + + rewardsDistributor = rewardsDistributor_; + + emit SetRewardsDistributor(rewardsDistributor_); + } + /** * @inheritdoc IVault */ diff --git a/src/contracts/VaultStorage.sol b/src/contracts/VaultStorage.sol index 780b02ce..a9f22deb 100644 --- a/src/contracts/VaultStorage.sol +++ b/src/contracts/VaultStorage.sol @@ -23,26 +23,31 @@ contract VaultStorage is IVaultStorage { /** * @inheritdoc IVaultStorage */ - bytes32 public constant NETWORK_RESOLVER_LIMIT_SET_ROLE = keccak256("NETWORK_RESOLVER_LIMIT_SET_ROLE"); + bytes32 public constant REWARDS_DISTRIBUTOR_SET_ROLE = keccak256("REWARDS_DISTRIBUTOR_SET_ROLE"); /** * @inheritdoc IVaultStorage */ - bytes32 public constant OPERATOR_NETWORK_LIMIT_SET_ROLE = keccak256("OPERATOR_NETWORK_LIMIT_SET_ROLE"); + bytes32 public constant ADMIN_FEE_SET_ROLE = keccak256("ADMIN_FEE_SET_ROLE"); /** * @inheritdoc IVaultStorage */ - bytes32 public constant ADMIN_FEE_SET_ROLE = keccak256("ADMIN_FEE_SET_ROLE"); + bytes32 public constant DEPOSIT_WHITELIST_SET_ROLE = keccak256("DEPOSIT_WHITELIST_SET_ROLE"); + /** + * @inheritdoc IVaultStorage + */ + bytes32 public constant DEPOSITOR_WHITELIST_ROLE = keccak256("DEPOSITOR_WHITELIST_ROLE"); /** * @inheritdoc IVaultStorage */ - bytes32 public constant DEPOSIT_WHITELIST_SET_ROLE = keccak256("DEPOSIT_WHITELIST_SET_ROLE"); + bytes32 public constant NETWORK_RESOLVER_LIMIT_SET_ROLE = keccak256("NETWORK_RESOLVER_LIMIT_SET_ROLE"); + /** * @inheritdoc IVaultStorage */ - bytes32 public constant DEPOSITOR_WHITELIST_ROLE = keccak256("DEPOSITOR_WHITELIST_ROLE"); + bytes32 public constant OPERATOR_NETWORK_LIMIT_SET_ROLE = keccak256("OPERATOR_NETWORK_LIMIT_SET_ROLE"); /** * @inheritdoc IVaultStorage @@ -99,6 +104,11 @@ contract VaultStorage is IVaultStorage { */ uint48 public slashDuration; + /** + * @inheritdoc IVaultStorage + */ + address public rewardsDistributor; + /** * @inheritdoc IVaultStorage */ diff --git a/src/contracts/base/MigratableEntity.sol b/src/contracts/base/MigratableEntity.sol index 151ce087..92101e3f 100644 --- a/src/contracts/base/MigratableEntity.sol +++ b/src/contracts/base/MigratableEntity.sol @@ -4,8 +4,8 @@ pragma solidity 0.8.25; import {IMigratableEntityProxy} from "src/interfaces/base/IMigratableEntityProxy.sol"; import {IMigratableEntity} from "src/interfaces/base/IMigratableEntity.sol"; -import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; abstract contract MigratableEntity is Initializable, OwnableUpgradeable, IMigratableEntity { constructor() { diff --git a/src/contracts/base/MigratableEntityProxy.sol b/src/contracts/base/MigratableEntityProxy.sol index 4fefbf4a..a2f649f7 100644 --- a/src/contracts/base/MigratableEntityProxy.sol +++ b/src/contracts/base/MigratableEntityProxy.sol @@ -3,8 +3,8 @@ pragma solidity 0.8.25; import {IMigratableEntityProxy} from "src/interfaces/base/IMigratableEntityProxy.sol"; -import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {ERC1967Utils} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Utils.sol"; contract MigratableEntityProxy is ERC1967Proxy, IMigratableEntityProxy { // An immutable address for the admin to avoid unnecessary SLOADs before each call. diff --git a/src/contracts/base/MigratablesRegistry.sol b/src/contracts/base/MigratablesRegistry.sol index 690b5243..b338e717 100644 --- a/src/contracts/base/MigratablesRegistry.sol +++ b/src/contracts/base/MigratablesRegistry.sol @@ -1,12 +1,12 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IMigratablesRegistry} from "src/interfaces/base/IMigratablesRegistry.sol"; -import {IMigratableEntity} from "src/interfaces/base/IMigratableEntity.sol"; -import {IMigratableEntityProxy} from "src/interfaces/base/IMigratableEntityProxy.sol"; - -import {Registry} from "./Registry.sol"; import {MigratableEntityProxy} from "./MigratableEntityProxy.sol"; +import {Registry} from "./Registry.sol"; + +import {IMigratableEntityProxy} from "src/interfaces/base/IMigratableEntityProxy.sol"; +import {IMigratableEntity} from "src/interfaces/base/IMigratableEntity.sol"; +import {IMigratablesRegistry} from "src/interfaces/base/IMigratablesRegistry.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {EnumerableSet} from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol"; diff --git a/src/contracts/base/NonMigratablesRegistry.sol b/src/contracts/base/NonMigratablesRegistry.sol index 4f14eb60..4a13ea5c 100644 --- a/src/contracts/base/NonMigratablesRegistry.sol +++ b/src/contracts/base/NonMigratablesRegistry.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {INonMigratablesRegistry} from "src/interfaces/base/INonMigratablesRegistry.sol"; - import {Registry} from "./Registry.sol"; +import {INonMigratablesRegistry} from "src/interfaces/base/INonMigratablesRegistry.sol"; + contract NonMigratablesRegistry is Registry, INonMigratablesRegistry { /** * @inheritdoc INonMigratablesRegistry diff --git a/src/contracts/base/Plugin.sol b/src/contracts/base/Plugin.sol index 8ac36769..7d073cac 100644 --- a/src/contracts/base/Plugin.sol +++ b/src/contracts/base/Plugin.sol @@ -11,13 +11,17 @@ abstract contract Plugin is IPlugin { address public immutable REGISTRY; modifier onlyEntity() { - if (!IRegistry(REGISTRY).isEntity(msg.sender)) { - revert NotEntity(); - } + _checkEntity(msg.sender); _; } constructor(address registry) { REGISTRY = registry; } + + function _checkEntity(address account) internal view { + if (!IRegistry(REGISTRY).isEntity(account)) { + revert NotEntity(); + } + } } diff --git a/src/contracts/base/Registry.sol b/src/contracts/base/Registry.sol index e3bd92f6..f5e4e857 100644 --- a/src/contracts/base/Registry.sol +++ b/src/contracts/base/Registry.sol @@ -10,10 +10,8 @@ abstract contract Registry is IRegistry { EnumerableSet.AddressSet private _entities; - modifier checkEntity(address entity_) { - if (!isEntity(entity_)) { - revert EntityNotExist(); - } + modifier checkEntity(address account) { + _checkEntity(account); _; } @@ -43,4 +41,10 @@ abstract contract Registry is IRegistry { emit AddEntity(entity_); } + + function _checkEntity(address account) internal view { + if (!isEntity(account)) { + revert EntityNotExist(); + } + } } diff --git a/src/contracts/base/RewardsDistributor.sol b/src/contracts/base/RewardsDistributor.sol new file mode 100644 index 00000000..75b45f30 --- /dev/null +++ b/src/contracts/base/RewardsDistributor.sol @@ -0,0 +1,23 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {RewardsDistributorBase} from "./RewardsDistributorBase.sol"; + +import {IRewardsDistributorBase} from "src/interfaces/base/IRewardsDistributorBase.sol"; +import {IRewardsDistributor} from "src/interfaces/base/IRewardsDistributor.sol"; + +abstract contract RewardsDistributor is RewardsDistributorBase, IRewardsDistributor { + constructor(address networkRegistry) RewardsDistributorBase(networkRegistry) {} + + /** + * @inheritdoc IRewardsDistributorBase + */ + function version() external pure override(RewardsDistributorBase, IRewardsDistributorBase) returns (uint64) { + return 1; + } + + /** + * @inheritdoc IRewardsDistributor + */ + function distributeReward(address network, address token, uint256 amount, uint48 timestamp) external virtual {} +} diff --git a/src/contracts/base/RewardsDistributorBase.sol b/src/contracts/base/RewardsDistributorBase.sol new file mode 100644 index 00000000..a00d5ec9 --- /dev/null +++ b/src/contracts/base/RewardsDistributorBase.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IRegistry} from "src/interfaces/base/IRegistry.sol"; +import {IRewardsDistributorBase} from "src/interfaces/base/IRewardsDistributorBase.sol"; + +abstract contract RewardsDistributorBase is IRewardsDistributorBase { + /** + * @inheritdoc IRewardsDistributorBase + */ + address public immutable NETWORK_REGISTRY; + + modifier checkNetwork(address account) { + _checkNetwork(account); + _; + } + + constructor(address networkRegistry) { + NETWORK_REGISTRY = networkRegistry; + } + + /** + * @inheritdoc IRewardsDistributorBase + */ + function VAULT() public view virtual override returns (address) {} + + /** + * @inheritdoc IRewardsDistributorBase + */ + function version() external view virtual override returns (uint64) {} + + function _checkNetwork(address account) internal view { + if (!IRegistry(NETWORK_REGISTRY).isEntity(account)) { + revert NotNetwork(); + } + } +} diff --git a/src/contracts/defaultCollateral/DefaultCollateral.sol b/src/contracts/defaultCollateral/DefaultCollateral.sol index adcdbfa5..286608cb 100644 --- a/src/contracts/defaultCollateral/DefaultCollateral.sol +++ b/src/contracts/defaultCollateral/DefaultCollateral.sol @@ -1,14 +1,14 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IDefaultCollateral} from "src/interfaces/defaultCollateral/IDefaultCollateral.sol"; import {ICollateral} from "src/interfaces/base/ICollateral.sol"; +import {IDefaultCollateral} from "src/interfaces/defaultCollateral/IDefaultCollateral.sol"; import {Permit2Lib} from "src/contracts/libraries/Permit2Lib.sol"; -import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; contract DefaultCollateral is ERC20Upgradeable, ReentrancyGuardUpgradeable, IDefaultCollateral { diff --git a/src/contracts/defaultCollateral/DefaultCollateralFactory.sol b/src/contracts/defaultCollateral/DefaultCollateralFactory.sol index ef36fe6a..d2faec08 100644 --- a/src/contracts/defaultCollateral/DefaultCollateralFactory.sol +++ b/src/contracts/defaultCollateral/DefaultCollateralFactory.sol @@ -1,8 +1,9 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {Registry} from "src/contracts/base/Registry.sol"; import {DefaultCollateral} from "./DefaultCollateral.sol"; +import {Registry} from "src/contracts/base/Registry.sol"; + import {IDefaultCollateralFactory} from "src/interfaces/defaultCollateral/IDefaultCollateralFactory.sol"; import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; diff --git a/src/contracts/plugins/RewardsPlugin.sol b/src/contracts/defaultRewardsDistributor/DefaultRewardsDistributor.sol similarity index 57% rename from src/contracts/plugins/RewardsPlugin.sol rename to src/contracts/defaultRewardsDistributor/DefaultRewardsDistributor.sol index 9cb40cd2..bc955a5b 100644 --- a/src/contracts/plugins/RewardsPlugin.sol +++ b/src/contracts/defaultRewardsDistributor/DefaultRewardsDistributor.sol @@ -1,101 +1,107 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IRewardsPlugin} from "src/interfaces/plugins/IRewardsPlugin.sol"; +import {RewardsDistributorBase} from "src/contracts/base/RewardsDistributorBase.sol"; +import {RewardsDistributor} from "src/contracts/base/RewardsDistributor.sol"; + +import {IDefaultRewardsDistributor} from "src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributor.sol"; import {IRegistry} from "src/interfaces/base/IRegistry.sol"; +import {IRewardsDistributorBase} from "src/interfaces/base/IRewardsDistributorBase.sol"; +import {IRewardsDistributor} from "src/interfaces/base/IRewardsDistributor.sol"; import {IVault} from "src/interfaces/IVault.sol"; import {ERC4626Math} from "src/contracts/libraries/ERC4626Math.sol"; -import {Plugin} from "src/contracts/base/Plugin.sol"; - import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; -import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; -import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; +import {ReentrancyGuardUpgradeable} from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol"; +import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; -contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { +contract DefaultRewardsDistributor is RewardsDistributor, ReentrancyGuardUpgradeable, IDefaultRewardsDistributor { using SafeERC20 for IERC20; using Math for uint256; /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ - mapping(address vault => mapping(address token => RewardDistribution[] rewards_)) public rewards; + address public immutable VAULT_REGISTRY; + + address private _VAULT; + + /** + * @inheritdoc IDefaultRewardsDistributor + */ + mapping(address token => RewardDistribution[] rewards_) public rewards; /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ - mapping(address vault => mapping(address account => mapping(address token => uint256 rewardIndex))) public - lastUnclaimedReward; + mapping(address account => mapping(address token => uint256 rewardIndex)) public lastUnclaimedReward; /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ - mapping(address vault => mapping(address token => uint256 amount)) public claimableAdminFee; + mapping(address token => uint256 amount) public claimableAdminFee; + + mapping(uint48 timestamp => uint256 amount) internal _activeSharesCache; - mapping(address vault => mapping(uint48 timestamp => uint256 amount)) internal _activeSharesCache; + mapping(uint48 timestamp => uint256 amount) internal _activeSuppliesCache; - mapping(address vault => mapping(uint48 timestamp => uint256 amount)) internal _activeSuppliesCache; + constructor(address networkRegistry, address vaultRegistry) RewardsDistributor(networkRegistry) { + _disableInitializers(); + + VAULT_REGISTRY = vaultRegistry; + } /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IRewardsDistributorBase */ - address public immutable VAULT_REGISTRY; + function VAULT() public view override(RewardsDistributorBase, IRewardsDistributorBase) returns (address) { + return _VAULT; + } - modifier isVault(address account) { - if (!IRegistry(VAULT_REGISTRY).isEntity(account)) { + function initialize(address vault) external initializer { + if (!IRegistry(VAULT_REGISTRY).isEntity(vault)) { revert NotVault(); } - _; - } - constructor(address networkRegistry, address vaultRegistry) Plugin(networkRegistry) { - VAULT_REGISTRY = vaultRegistry; + __ReentrancyGuard_init(); + + _VAULT = vault; } /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ - function rewardsLength(address vault, address token) external view isVault(vault) returns (uint256) { - return rewards[vault][token].length; + function rewardsLength(address token) external view returns (uint256) { + return rewards[token].length; } /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IRewardsDistributor */ function distributeReward( - address vault, address network, address token, uint256 amount, - uint48 timestamp, - uint256 acceptedAdminFee - ) external nonReentrant isVault(vault) returns (uint256 rewardIndex) { - if (!IRegistry(REGISTRY).isEntity(network)) { - revert NotNetwork(); - } - + uint48 timestamp + ) external override(RewardsDistributor, IRewardsDistributor) nonReentrant checkNetwork(network) { if (timestamp >= Time.timestamp()) { revert InvalidRewardTimestamp(); } - if (acceptedAdminFee < IVault(vault).adminFee()) { - revert UnacceptedAdminFee(); - } - - if (_activeSharesCache[vault][timestamp] == 0) { - uint256 activeShares_ = IVault(vault).activeSharesAt(timestamp); - uint256 activeSupply_ = IVault(vault).activeSupplyAt(timestamp); + if (_activeSharesCache[timestamp] == 0) { + uint256 activeShares_ = IVault(VAULT()).activeSharesAt(timestamp); + uint256 activeSupply_ = IVault(VAULT()).activeSupplyAt(timestamp); if (activeShares_ == 0 || activeSupply_ == 0) { revert InvalidRewardTimestamp(); } - _activeSharesCache[vault][timestamp] = activeShares_; - _activeSuppliesCache[vault][timestamp] = activeSupply_; + _activeSharesCache[timestamp] = activeShares_; + _activeSuppliesCache[timestamp] = activeSupply_; } uint256 balanceBefore = IERC20(token).balanceOf(address(this)); @@ -106,12 +112,10 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { revert InsufficientReward(); } - uint256 adminFeeAmount = amount.mulDiv(IVault(vault).adminFee(), IVault(vault).ADMIN_FEE_BASE()); - claimableAdminFee[vault][token] += adminFeeAmount; - - rewardIndex = rewards[vault][token].length; + uint256 adminFeeAmount = amount.mulDiv(IVault(VAULT()).adminFee(), IVault(VAULT()).ADMIN_FEE_BASE()); + claimableAdminFee[token] += adminFeeAmount; - rewards[vault][token].push( + rewards[token].push( RewardDistribution({ network: network, amount: amount - adminFeeAmount, @@ -120,26 +124,25 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { }) ); - emit DistributeReward(vault, token, rewardIndex, network, amount, timestamp); + emit DistributeReward(token, network, amount, timestamp); } /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ function claimRewards( - address vault, address recipient, address token, uint256 maxRewards, uint32[] calldata activeSharesOfHints ) external { - uint48 firstDepositAt_ = IVault(vault).firstDepositAt(msg.sender); + uint48 firstDepositAt_ = IVault(VAULT()).firstDepositAt(msg.sender); if (firstDepositAt_ == 0) { revert NoDeposits(); } - RewardDistribution[] storage rewardsByToken = rewards[vault][token]; - uint256 rewardIndex = lastUnclaimedReward[vault][msg.sender][token]; + RewardDistribution[] storage rewardsByToken = rewards[token]; + uint256 rewardIndex = lastUnclaimedReward[msg.sender][token]; if (rewardIndex == 0) { rewardIndex = _firstUnclaimedReward(rewardsByToken, firstDepositAt_); } @@ -155,8 +158,8 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { revert InvalidHintsLength(); } - mapping(uint48 => uint256) storage _activeSharesCacheByVault = _activeSharesCache[vault]; - mapping(uint48 => uint256) storage _activeSuppliesCacheByVault = _activeSuppliesCache[vault]; + mapping(uint48 => uint256) storage _activeSharesCacheByVault = _activeSharesCache; + mapping(uint48 => uint256) storage _activeSuppliesCacheByVault = _activeSuppliesCache; uint256 amount; for (uint256 j; j < rewardsToClaim;) { @@ -166,8 +169,8 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { if (reward.timestamp >= firstDepositAt_) { uint256 activeSupply_ = _activeSuppliesCacheByVault[reward.timestamp]; uint256 activeSharesOf_ = hasHints - ? IVault(vault).activeSharesOfAtHint(msg.sender, reward.timestamp, activeSharesOfHints[j]) - : IVault(vault).activeSharesOfAt(msg.sender, reward.timestamp); + ? IVault(VAULT()).activeSharesOfAtHint(msg.sender, reward.timestamp, activeSharesOfHints[j]) + : IVault(VAULT()).activeSharesOfAt(msg.sender, reward.timestamp); uint256 activeBalanceOf_ = ERC4626Math.previewRedeem( activeSharesOf_, activeSupply_, _activeSharesCacheByVault[reward.timestamp] ); @@ -176,7 +179,7 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { amount += claimedAmount; } - emit ClaimReward(vault, token, rewardIndex, msg.sender, recipient, claimedAmount); + emit ClaimReward(token, rewardIndex, msg.sender, recipient, claimedAmount); unchecked { ++j; @@ -184,7 +187,7 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { } } - lastUnclaimedReward[vault][msg.sender][token] = rewardIndex; + lastUnclaimedReward[msg.sender][token] = rewardIndex; if (amount != 0) { IERC20(token).safeTransfer(recipient, amount); @@ -192,23 +195,23 @@ contract RewardsPlugin is Plugin, ReentrancyGuard, IRewardsPlugin { } /** - * @inheritdoc IRewardsPlugin + * @inheritdoc IDefaultRewardsDistributor */ - function claimAdminFee(address vault, address recipient, address token) external { - if (Ownable(vault).owner() != msg.sender) { + function claimAdminFee(address recipient, address token) external { + if (Ownable(VAULT()).owner() != msg.sender) { revert NotOwner(); } - uint256 claimableAdminFee_ = claimableAdminFee[vault][token]; + uint256 claimableAdminFee_ = claimableAdminFee[token]; if (claimableAdminFee_ == 0) { revert InsufficientAdminFee(); } - claimableAdminFee[vault][token] = 0; + claimableAdminFee[token] = 0; IERC20(token).safeTransfer(recipient, claimableAdminFee_); - emit ClaimAdminFee(vault, token, claimableAdminFee_); + emit ClaimAdminFee(token, claimableAdminFee_); } /** diff --git a/src/contracts/defaultRewardsDistributor/DefaultRewardsDistributorFactory.sol b/src/contracts/defaultRewardsDistributor/DefaultRewardsDistributorFactory.sol new file mode 100644 index 00000000..471e17d3 --- /dev/null +++ b/src/contracts/defaultRewardsDistributor/DefaultRewardsDistributorFactory.sol @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {DefaultRewardsDistributor} from "./DefaultRewardsDistributor.sol"; +import {Registry} from "src/contracts/base/Registry.sol"; + +import {IDefaultRewardsDistributorFactory} from + "src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributorFactory.sol"; + +import {Clones} from "@openzeppelin/contracts/proxy/Clones.sol"; + +contract DefaultRewardsDistributorFactory is Registry, IDefaultRewardsDistributorFactory { + using Clones for address; + + address private immutable REWARDS_DISTRIBUTOR_IMPLEMENTATION; + + constructor(address networkRegistry, address vaultRegistry) { + REWARDS_DISTRIBUTOR_IMPLEMENTATION = address(new DefaultRewardsDistributor(networkRegistry, vaultRegistry)); + } + + /** + * @inheritdoc IDefaultRewardsDistributorFactory + */ + function create(address vault) external returns (address) { + address rewardsDistributor = REWARDS_DISTRIBUTOR_IMPLEMENTATION.clone(); + DefaultRewardsDistributor(rewardsDistributor).initialize(vault); + + _addEntity(rewardsDistributor); + + return rewardsDistributor; + } +} diff --git a/src/contracts/libraries/Permit2Lib.sol b/src/contracts/libraries/Permit2Lib.sol index fb9fa6a0..4bfe9c9c 100644 --- a/src/contracts/libraries/Permit2Lib.sol +++ b/src/contracts/libraries/Permit2Lib.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.17; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; +import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IDAIPermit} from "permit2/src/interfaces/IDAIPermit.sol"; import {IAllowanceTransfer} from "permit2/src/interfaces/IAllowanceTransfer.sol"; +import {IDAIPermit} from "permit2/src/interfaces/IDAIPermit.sol"; import {SafeCast160} from "permit2/src/libraries/SafeCast160.sol"; /// @title Permit2Lib diff --git a/src/contracts/plugins/MetadataPlugin.sol b/src/contracts/plugins/MetadataPlugin.sol index a3330231..9dbbc989 100644 --- a/src/contracts/plugins/MetadataPlugin.sol +++ b/src/contracts/plugins/MetadataPlugin.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IMetadataPlugin} from "src/interfaces/plugins/IMetadataPlugin.sol"; - import {Plugin} from "src/contracts/base/Plugin.sol"; +import {IMetadataPlugin} from "src/interfaces/plugins/IMetadataPlugin.sol"; + import {Strings} from "@openzeppelin/contracts/utils/Strings.sol"; contract MetadataPlugin is Plugin, IMetadataPlugin { diff --git a/src/contracts/plugins/MiddlewarePlugin.sol b/src/contracts/plugins/MiddlewarePlugin.sol index d2c80f6f..3f0fafa1 100644 --- a/src/contracts/plugins/MiddlewarePlugin.sol +++ b/src/contracts/plugins/MiddlewarePlugin.sol @@ -1,10 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IMiddlewarePlugin} from "src/interfaces/plugins/IMiddlewarePlugin.sol"; - import {Plugin} from "src/contracts/base/Plugin.sol"; +import {IMiddlewarePlugin} from "src/interfaces/plugins/IMiddlewarePlugin.sol"; + contract MiddlewarePlugin is Plugin, IMiddlewarePlugin { /** * @inheritdoc IMiddlewarePlugin diff --git a/src/contracts/plugins/NetworkOptInPlugin.sol b/src/contracts/plugins/NetworkOptInPlugin.sol index f4b67472..6b4a650f 100644 --- a/src/contracts/plugins/NetworkOptInPlugin.sol +++ b/src/contracts/plugins/NetworkOptInPlugin.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; +import {Plugin} from "src/contracts/base/Plugin.sol"; + import {INetworkOptInPlugin} from "src/interfaces/plugins/INetworkOptInPlugin.sol"; import {IRegistry} from "src/interfaces/base/IRegistry.sol"; -import {Plugin} from "src/contracts/base/Plugin.sol"; - import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; contract NetworkOptInPlugin is Plugin, INetworkOptInPlugin { diff --git a/src/contracts/plugins/OperatorOptInPlugin.sol b/src/contracts/plugins/OperatorOptInPlugin.sol index 495f7e2a..25b758f6 100644 --- a/src/contracts/plugins/OperatorOptInPlugin.sol +++ b/src/contracts/plugins/OperatorOptInPlugin.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; +import {Plugin} from "src/contracts/base/Plugin.sol"; + import {IOperatorOptInPlugin} from "src/interfaces/plugins/IOperatorOptInPlugin.sol"; import {IRegistry} from "src/interfaces/base/IRegistry.sol"; -import {Plugin} from "src/contracts/base/Plugin.sol"; - import {Time} from "@openzeppelin/contracts/utils/types/Time.sol"; contract OperatorOptInPlugin is Plugin, IOperatorOptInPlugin { diff --git a/src/interfaces/IVault.sol b/src/interfaces/IVault.sol index fa52b5bf..b8c7a56d 100644 --- a/src/interfaces/IVault.sol +++ b/src/interfaces/IVault.sol @@ -37,6 +37,7 @@ interface IVault is IVaultStorage { * @param epochDuration duration of the vault epoch * @param vetoDuration duration of the veto period for a slash request * @param slashDuration duration of the slash period for a slash request (after veto period) + * @param rewardsDistributor address of the rewards distributor * @param adminFee admin fee (up to ADMIN_FEE_BASE inclusively) * @param depositWhitelist enable/disable deposit whitelist */ @@ -46,6 +47,7 @@ interface IVault is IVaultStorage { uint48 epochDuration; uint48 vetoDuration; uint48 slashDuration; + address rewardsDistributor; uint256 adminFee; bool depositWhitelist; } @@ -120,6 +122,12 @@ interface IVault is IVaultStorage { */ event SetMaxNetworkResolverLimit(address indexed network, address indexed resolver, uint256 amount); + /** + * @notice Emitted when a rewards distributor is set. + * @param rewardsDistributor address of the rewards distributor + */ + event SetRewardsDistributor(address rewardsDistributor); + /** * @notice Emitted when an admin fee is set. * @param adminFee admin fee @@ -271,6 +279,13 @@ interface IVault is IVaultStorage { */ function setMaxNetworkResolverLimit(address resolver, uint256 amount) external; + /** + * @notice Set a rewards distributor. + * @param rewardsDistributor address of the rewards distributor + * @dev Only the REWARDS_DISTRIBUTOR_SET_ROLE holder can call this function. + */ + function setRewardsDistributor(address rewardsDistributor) external; + /** * @notice Set an admin fee. * @param adminFee admin fee (up to ADMIN_FEE_BASE inclusively) diff --git a/src/interfaces/IVaultStorage.sol b/src/interfaces/IVaultStorage.sol index aba9686e..9da565b3 100644 --- a/src/interfaces/IVaultStorage.sol +++ b/src/interfaces/IVaultStorage.sol @@ -48,14 +48,9 @@ interface IVaultStorage { function ADMIN_FEE_BASE() external view returns (uint256); /** - * @notice Get the network-resolver limit setter's role. - */ - function NETWORK_RESOLVER_LIMIT_SET_ROLE() external view returns (bytes32); - - /** - * @notice Get the operator-network limit setter's role. + * @notice Get the rewards distributor setter's role. */ - function OPERATOR_NETWORK_LIMIT_SET_ROLE() external view returns (bytes32); + function REWARDS_DISTRIBUTOR_SET_ROLE() external view returns (bytes32); /** * @notice Get the admin fee setter's role. @@ -72,9 +67,19 @@ interface IVaultStorage { */ function DEPOSITOR_WHITELIST_ROLE() external view returns (bytes32); + /** + * @notice Get the network-resolver limit setter's role. + */ + function NETWORK_RESOLVER_LIMIT_SET_ROLE() external view returns (bytes32); + + /** + * @notice Get the operator-network limit setter's role. + */ + function OPERATOR_NETWORK_LIMIT_SET_ROLE() external view returns (bytes32); + /** * @notice Get the network registry's address. - * @return address of the registry + * @return address of the network registry */ function NETWORK_REGISTRY() external view returns (address); @@ -156,6 +161,12 @@ interface IVaultStorage { */ function slashDuration() external view returns (uint48); + /** + * @notice Get a rewards distributor. + * @return address of the rewards distributor + */ + function rewardsDistributor() external view returns (address); + /** * @notice Get an admin fee. * @return admin fee diff --git a/src/interfaces/base/IRewardsDistributor.sol b/src/interfaces/base/IRewardsDistributor.sol new file mode 100644 index 00000000..49ab0271 --- /dev/null +++ b/src/interfaces/base/IRewardsDistributor.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IRewardsDistributorBase} from "./IRewardsDistributorBase.sol"; + +interface IRewardsDistributor is IRewardsDistributorBase { + /** + * @notice Emitted when a reward is distributed. + * @param token address of the token to be distributed + * @param network network on behalf of which the reward is distributed + * @param amount amount of tokens distributed + * @param timestamp time point stakes must taken into account at + */ + event DistributeReward(address indexed token, address indexed network, uint256 amount, uint48 timestamp); + + /** + * @notice Distribute rewards on behalf of a particular network using a given token. + * @param network address of the network + * @param token address of the token + * @param amount amount of tokens to distribute + * @param timestamp time point stakes must taken into account at + */ + function distributeReward(address network, address token, uint256 amount, uint48 timestamp) external; +} diff --git a/src/interfaces/base/IRewardsDistributorBase.sol b/src/interfaces/base/IRewardsDistributorBase.sol new file mode 100644 index 00000000..d4aa9ba5 --- /dev/null +++ b/src/interfaces/base/IRewardsDistributorBase.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +interface IRewardsDistributorBase { + error NotNetwork(); + + /** + * @notice Get the network registry's address. + * @return address of the network registry + * @dev Must be an immutable. + */ + function NETWORK_REGISTRY() external view returns (address); + + /** + * @notice Get the address of the vault. + * @return address of the vault + * @dev Must not change once set. + */ + function VAULT() external view returns (address); + + /** + * @notice Get a version of the rewards distributor (different versions mean different interfaces). + * @return version of the rewards distributor + * @dev May change for upgradable rewards distributors. + */ + function version() external view returns (uint64); +} diff --git a/src/interfaces/plugins/IRewardsPlugin.sol b/src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributor.sol similarity index 59% rename from src/interfaces/plugins/IRewardsPlugin.sol rename to src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributor.sol index 916b2d29..80c9fce3 100644 --- a/src/interfaces/plugins/IRewardsPlugin.sol +++ b/src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributor.sol @@ -1,19 +1,17 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.25; -import {IPlugin} from "src/interfaces/base/IPlugin.sol"; +import {IRewardsDistributor} from "src/interfaces/base/IRewardsDistributor.sol"; -interface IRewardsPlugin is IPlugin { +interface IDefaultRewardsDistributor is IRewardsDistributor { error InsufficientAdminFee(); error InsufficientReward(); error InvalidHintsLength(); error InvalidRewardTimestamp(); error NoDeposits(); error NoRewardsToClaim(); - error NotNetwork(); error NotOwner(); error NotVault(); - error UnacceptedAdminFee(); /** * @notice Structure for a reward distribution. @@ -29,27 +27,8 @@ interface IRewardsPlugin is IPlugin { uint48 creation; } - /** - * @notice Emitted when a reward is distributed. - * @param vault address of the vault - * @param token address of the token to be distributed - * @param rewardIndex index of the reward distribution - * @param network network on behalf of which the reward is distributed - * @param amount amount of tokens distributed (admin fee is included) - * @param timestamp time point stakes must taken into account at - */ - event DistributeReward( - address indexed vault, - address indexed token, - uint256 rewardIndex, - address indexed network, - uint256 amount, - uint48 timestamp - ); - /** * @notice Emitted when a reward is claimed. - * @param vault address of the vault * @param token address of the token claimed * @param rewardIndex index of the reward distribution * @param claimer account that claimed the reward @@ -57,9 +36,8 @@ interface IRewardsPlugin is IPlugin { * @param claimedAmount amount of tokens claimed */ event ClaimReward( - address indexed vault, address indexed token, - uint256 rewardIndex, + uint256 indexed rewardIndex, address indexed claimer, address recipient, uint256 claimedAmount @@ -67,29 +45,26 @@ interface IRewardsPlugin is IPlugin { /** * @notice Emitted when an admin fee is claimed. - * @param vault address of the vault * @param recipient account that received the fee * @param amount amount of the fee claimed */ - event ClaimAdminFee(address indexed vault, address indexed recipient, uint256 amount); + event ClaimAdminFee(address indexed recipient, uint256 amount); /** - * @notice Get the address of the vault registry. + * @notice Get the vault registry's address. * @return address of the vault registry */ function VAULT_REGISTRY() external view returns (address); /** * @notice Get a total number of rewards using a particular token. - * @param vault address of the vault * @param token address of the token * @return total number of rewards using the token */ - function rewardsLength(address vault, address token) external view returns (uint256); + function rewardsLength(address token) external view returns (uint256); /** * @notice Get a reward distribution. - * @param vault address of the vault * @param token address of the token * @param rewardIndex index of the reward distribution * @return network network on behalf of which the reward is distributed @@ -98,57 +73,33 @@ interface IRewardsPlugin is IPlugin { * @return creation timestamp when the reward distribution was created */ function rewards( - address vault, address token, uint256 rewardIndex ) external view returns (address network, uint256 amount, uint48 timestamp, uint48 creation); /** * @notice Get a first index of the unclaimed rewards using a particular token by a given account. - * @param vault address of the vault * @param account address of the account * @param token address of the token * @return first index of the unclaimed rewards */ - function lastUnclaimedReward(address vault, address account, address token) external view returns (uint256); + function lastUnclaimedReward(address account, address token) external view returns (uint256); /** * @notice Get a claimable fee amount for a particular token. - * @param vault address of the vault * @param token address of the token * @return claimable fee */ - function claimableAdminFee(address vault, address token) external view returns (uint256); - - /** - * @notice Distribute rewards on behalf of a particular network using a given token. - * @param vault address of the vault - * @param network address of the network - * @param token address of the token - * @param amount amount of tokens to distribute - * @param timestamp time point stakes must taken into account at - * @param acceptedAdminFee maximum accepted admin fee - * @return rewardIndex index of the reward distribution - */ - function distributeReward( - address vault, - address network, - address token, - uint256 amount, - uint48 timestamp, - uint256 acceptedAdminFee - ) external returns (uint256 rewardIndex); + function claimableAdminFee(address token) external view returns (uint256); /** * @notice Claim rewards for a particular token. - * @param vault address of the vault * @param recipient account that will receive the rewards * @param token address of the token * @param maxRewards max amount of rewards to process * @param activeSharesOfHints hint indexes to optimize `activeSharesOf()` processing */ function claimRewards( - address vault, address recipient, address token, uint256 maxRewards, @@ -157,10 +108,9 @@ interface IRewardsPlugin is IPlugin { /** * @notice Claim admin fee. - * @param vault address of the vault * @param recipient account that receives the fee * @param token address of the token * @dev Only the owner can call this function. */ - function claimAdminFee(address vault, address recipient, address token) external; + function claimAdminFee(address recipient, address token) external; } diff --git a/src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributorFactory.sol b/src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributorFactory.sol new file mode 100644 index 00000000..700ddb58 --- /dev/null +++ b/src/interfaces/defaultRewardsDistributor/IDefaultRewardsDistributorFactory.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.25; + +import {IRegistry} from "src/interfaces/base/IRegistry.sol"; + +interface IDefaultRewardsDistributorFactory is IRegistry { + /** + * @notice Create a default rewards ditributor for a given vault. + * @param vault address of the vault + */ + function create(address vault) external returns (address); +} diff --git a/test/Vault.t.sol b/test/Vault.t.sol index 01ae6400..bc04c2fd 100644 --- a/test/Vault.t.sol +++ b/test/Vault.t.sol @@ -79,6 +79,7 @@ contract VaultTest is Test { uint48 epochDuration, uint48 vetoDuration, uint48 slashDuration, + address rewardsDistributor, uint256 adminFee, bool depositWhitelist ) public { @@ -98,6 +99,7 @@ contract VaultTest is Test { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: rewardsDistributor, adminFee: adminFee, depositWhitelist: depositWhitelist }) @@ -1507,6 +1509,7 @@ contract VaultTest is Test { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: address(0), adminFee: 0, depositWhitelist: false }) @@ -1537,6 +1540,7 @@ contract VaultTest is Test { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: address(0), adminFee: 0, depositWhitelist: false }) @@ -1564,6 +1568,7 @@ contract VaultTest is Test { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: address(0), adminFee: adminFee, depositWhitelist: false }) @@ -2093,6 +2098,7 @@ contract VaultTest is Test { epochDuration: epochDuration, vetoDuration: vetoDuration, slashDuration: slashDuration, + rewardsDistributor: address(0), adminFee: 0, depositWhitelist: false }) diff --git a/test/plugins/RewardsPlugin.t.sol b/test/plugins/RewardsPlugin.t.sol index 8f950f3d..50e6d353 100644 --- a/test/plugins/RewardsPlugin.t.sol +++ b/test/plugins/RewardsPlugin.t.sol @@ -1,727 +1,728 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.25; - -import {Test, console2} from "forge-std/Test.sol"; - -import {MigratablesRegistry} from "src/contracts/base/MigratablesRegistry.sol"; -import {NonMigratablesRegistry} from "src/contracts/base/NonMigratablesRegistry.sol"; -import {MetadataPlugin} from "src/contracts/plugins/MetadataPlugin.sol"; -import {MiddlewarePlugin} from "src/contracts/plugins/MiddlewarePlugin.sol"; -import {NetworkOptInPlugin} from "src/contracts/plugins/NetworkOptInPlugin.sol"; -import {OperatorOptInPlugin} from "src/contracts/plugins/OperatorOptInPlugin.sol"; -import {RewardsPlugin} from "src/contracts/plugins/RewardsPlugin.sol"; - -import {Vault} from "src/contracts/Vault.sol"; -import {IVault} from "src/interfaces/IVault.sol"; -import {IVault} from "src/interfaces/IVault.sol"; -import {IRewardsPlugin} from "src/interfaces/plugins/IRewardsPlugin.sol"; - -import {Token} from "test/mocks/Token.sol"; -import {FeeOnTransferToken} from "test/mocks/FeeOnTransferToken.sol"; -import {SimpleCollateral} from "test/mocks/SimpleCollateral.sol"; -import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; - -contract RewardsPluginTest is Test { - using Math for uint256; - - address owner; - address alice; - uint256 alicePrivateKey; - address bob; - uint256 bobPrivateKey; - - NonMigratablesRegistry operatorRegistry; - MigratablesRegistry vaultRegistry; - NonMigratablesRegistry networkRegistry; - MetadataPlugin operatorMetadataPlugin; - MetadataPlugin networkMetadataPlugin; - MiddlewarePlugin networkMiddlewarePlugin; - NetworkOptInPlugin networkVaultOptInPlugin; - OperatorOptInPlugin operatorVaultOptInPlugin; - OperatorOptInPlugin operatorNetworkOptInPlugin; - - IVault vault; - IRewardsPlugin plugin; - - SimpleCollateral collateral; - - function setUp() public { - owner = address(this); - (alice, alicePrivateKey) = makeAddrAndKey("alice"); - (bob, bobPrivateKey) = makeAddrAndKey("bob"); - - operatorRegistry = new NonMigratablesRegistry(); - vaultRegistry = new MigratablesRegistry(owner); - networkRegistry = new NonMigratablesRegistry(); - operatorMetadataPlugin = new MetadataPlugin(address(operatorRegistry)); - networkMetadataPlugin = new MetadataPlugin(address(networkRegistry)); - networkMiddlewarePlugin = new MiddlewarePlugin(address(networkRegistry)); - networkVaultOptInPlugin = new NetworkOptInPlugin(address(networkRegistry), address(vaultRegistry)); - operatorVaultOptInPlugin = new OperatorOptInPlugin(address(operatorRegistry), address(vaultRegistry)); - operatorNetworkOptInPlugin = new OperatorOptInPlugin(address(operatorRegistry), address(networkRegistry)); - - vaultRegistry.whitelist( - address( - new Vault( - address(networkRegistry), - address(operatorRegistry), - address(networkMiddlewarePlugin), - address(networkVaultOptInPlugin), - address(operatorVaultOptInPlugin), - address(operatorNetworkOptInPlugin) - ) - ) - ); - - Token token = new Token("Token"); - collateral = new SimpleCollateral(address(token)); - - collateral.mint(token.totalSupply()); - } - - function test_Create() public { - plugin = _getPlugin(); - - assertEq(plugin.REGISTRY(), address(networkRegistry)); - assertEq(plugin.VAULT_REGISTRY(), address(vaultRegistry)); - - vm.expectRevert(); - vm.expectRevert(IRewardsPlugin.NotVault.selector); - plugin.rewardsLength(alice, alice); - vm.expectRevert(); - plugin.rewards(alice, alice, 0); - assertEq(plugin.lastUnclaimedReward(alice, alice, alice), 0); - assertEq(plugin.claimableAdminFee(alice, alice), 0); - } - - function test_DistributeReward(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); - - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); - - plugin = _getPlugin(); - - _grantAdminFeeSetRole(alice, alice); - _setAdminFee(alice, adminFee); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } - - IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); - feeOnTransferToken.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - feeOnTransferToken.approve(address(plugin), type(uint256).max); - vm.stopPrank(); - - uint256 balanceBefore = feeOnTransferToken.balanceOf(address(plugin)); - uint256 balanceBeforeBob = feeOnTransferToken.balanceOf(bob); - uint48 timestamp = 3; - _distributeReward(bob, network, address(feeOnTransferToken), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - assertEq(feeOnTransferToken.balanceOf(address(plugin)) - balanceBefore, ditributeAmount - 1); - assertEq(balanceBeforeBob - feeOnTransferToken.balanceOf(bob), ditributeAmount); - - assertEq(plugin.rewardsLength(address(vault), address(feeOnTransferToken)), 1); - (address network_, uint256 amount_, uint48 timestamp_, uint48 creation) = - plugin.rewards(address(vault), address(feeOnTransferToken), 0); - assertEq(network_, network); - uint256 amount__ = ditributeAmount - 1; - uint256 adminFeeAmount = amount__.mulDiv(adminFee, vault.ADMIN_FEE_BASE()); - amount__ -= adminFeeAmount; - assertEq(amount_, amount__); - assertEq(timestamp_, timestamp); - assertEq(creation, blockTimestamp); - assertEq(plugin.claimableAdminFee(address(vault), address(feeOnTransferToken)), adminFeeAmount); - } - - function test_DistributeRewardRevertNotNetwork(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); - - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); - - plugin = _getPlugin(); - - _grantAdminFeeSetRole(alice, alice); - _setAdminFee(alice, adminFee); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } - - IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); - feeOnTransferToken.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - feeOnTransferToken.approve(address(plugin), type(uint256).max); - vm.stopPrank(); - - uint48 timestamp = 3; - uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); - vm.expectRevert(IRewardsPlugin.NotNetwork.selector); - _distributeReward(bob, address(0), address(feeOnTransferToken), ditributeAmount, timestamp, acceptedAdminFee); - } - - function test_DistributeRewardRevertInvalidRewardTimestamp(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); - - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - - plugin = _getPlugin(); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } - - IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); - feeOnTransferToken.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - feeOnTransferToken.approve(address(plugin), type(uint256).max); - vm.stopPrank(); - - uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); - vm.expectRevert(IRewardsPlugin.InvalidRewardTimestamp.selector); - _distributeReward( - bob, network, address(feeOnTransferToken), ditributeAmount, uint48(blockTimestamp), acceptedAdminFee - ); - } - - function test_DistributeRewardRevertInsufficientReward(uint256 amount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - - plugin = _getPlugin(); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// // SPDX-License-Identifier: MIT +// pragma solidity 0.8.25; + +// import {Test, console2} from "forge-std/Test.sol"; + +// import {MigratablesRegistry} from "src/contracts/base/MigratablesRegistry.sol"; +// import {NonMigratablesRegistry} from "src/contracts/base/NonMigratablesRegistry.sol"; +// import {MetadataPlugin} from "src/contracts/plugins/MetadataPlugin.sol"; +// import {MiddlewarePlugin} from "src/contracts/plugins/MiddlewarePlugin.sol"; +// import {NetworkOptInPlugin} from "src/contracts/plugins/NetworkOptInPlugin.sol"; +// import {OperatorOptInPlugin} from "src/contracts/plugins/OperatorOptInPlugin.sol"; +// import {RewardsPlugin} from "src/contracts/plugins/RewardsPlugin.sol"; + +// import {Vault} from "src/contracts/Vault.sol"; +// import {IVault} from "src/interfaces/IVault.sol"; +// import {IVault} from "src/interfaces/IVault.sol"; +// import {IRewardsPlugin} from "src/interfaces/plugins/IRewardsPlugin.sol"; + +// import {Token} from "test/mocks/Token.sol"; +// import {FeeOnTransferToken} from "test/mocks/FeeOnTransferToken.sol"; +// import {SimpleCollateral} from "test/mocks/SimpleCollateral.sol"; +// import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +// import {Math} from "@openzeppelin/contracts/utils/math/Math.sol"; + +// contract RewardsPluginTest is Test { +// using Math for uint256; + +// address owner; +// address alice; +// uint256 alicePrivateKey; +// address bob; +// uint256 bobPrivateKey; + +// NonMigratablesRegistry operatorRegistry; +// MigratablesRegistry vaultRegistry; +// NonMigratablesRegistry networkRegistry; +// MetadataPlugin operatorMetadataPlugin; +// MetadataPlugin networkMetadataPlugin; +// MiddlewarePlugin networkMiddlewarePlugin; +// NetworkOptInPlugin networkVaultOptInPlugin; +// OperatorOptInPlugin operatorVaultOptInPlugin; +// OperatorOptInPlugin operatorNetworkOptInPlugin; + +// IVault vault; +// IRewardsPlugin plugin; + +// SimpleCollateral collateral; + +// function setUp() public { +// owner = address(this); +// (alice, alicePrivateKey) = makeAddrAndKey("alice"); +// (bob, bobPrivateKey) = makeAddrAndKey("bob"); + +// operatorRegistry = new NonMigratablesRegistry(); +// vaultRegistry = new MigratablesRegistry(owner); +// networkRegistry = new NonMigratablesRegistry(); +// operatorMetadataPlugin = new MetadataPlugin(address(operatorRegistry)); +// networkMetadataPlugin = new MetadataPlugin(address(networkRegistry)); +// networkMiddlewarePlugin = new MiddlewarePlugin(address(networkRegistry)); +// networkVaultOptInPlugin = new NetworkOptInPlugin(address(networkRegistry), address(vaultRegistry)); +// operatorVaultOptInPlugin = new OperatorOptInPlugin(address(operatorRegistry), address(vaultRegistry)); +// operatorNetworkOptInPlugin = new OperatorOptInPlugin(address(operatorRegistry), address(networkRegistry)); + +// vaultRegistry.whitelist( +// address( +// new Vault( +// address(networkRegistry), +// address(operatorRegistry), +// address(networkMiddlewarePlugin), +// address(networkVaultOptInPlugin), +// address(operatorVaultOptInPlugin), +// address(operatorNetworkOptInPlugin) +// ) +// ) +// ); + +// Token token = new Token("Token"); +// collateral = new SimpleCollateral(address(token)); + +// collateral.mint(token.totalSupply()); +// } + +// function test_Create() public { +// plugin = _getPlugin(); + +// assertEq(plugin.REGISTRY(), address(networkRegistry)); +// assertEq(plugin.VAULT_REGISTRY(), address(vaultRegistry)); + +// vm.expectRevert(); +// vm.expectRevert(IRewardsPlugin.NotVault.selector); +// plugin.rewardsLength(alice, alice); +// vm.expectRevert(); +// plugin.rewards(alice, alice, 0); +// assertEq(plugin.lastUnclaimedReward(alice, alice, alice), 0); +// assertEq(plugin.claimableAdminFee(alice, alice), 0); +// } + +// function test_DistributeReward(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); + +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); +// adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); + +// plugin = _getPlugin(); + +// _grantAdminFeeSetRole(alice, alice); +// _setAdminFee(alice, adminFee); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); + +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } + +// IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); +// feeOnTransferToken.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// feeOnTransferToken.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); + +// uint256 balanceBefore = feeOnTransferToken.balanceOf(address(plugin)); +// uint256 balanceBeforeBob = feeOnTransferToken.balanceOf(bob); +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(feeOnTransferToken), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); +// assertEq(feeOnTransferToken.balanceOf(address(plugin)) - balanceBefore, ditributeAmount - 1); +// assertEq(balanceBeforeBob - feeOnTransferToken.balanceOf(bob), ditributeAmount); + +// assertEq(plugin.rewardsLength(address(vault), address(feeOnTransferToken)), 1); +// (address network_, uint256 amount_, uint48 timestamp_, uint48 creation) = +// plugin.rewards(address(vault), address(feeOnTransferToken), 0); +// assertEq(network_, network); +// uint256 amount__ = ditributeAmount - 1; +// uint256 adminFeeAmount = amount__.mulDiv(adminFee, vault.ADMIN_FEE_BASE()); +// amount__ -= adminFeeAmount; +// assertEq(amount_, amount__); +// assertEq(timestamp_, timestamp); +// assertEq(creation, blockTimestamp); +// assertEq(plugin.claimableAdminFee(address(vault), address(feeOnTransferToken)), adminFeeAmount); +// } + +// function test_DistributeRewardRevertNotNetwork(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); + +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); +// adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); + +// plugin = _getPlugin(); + +// _grantAdminFeeSetRole(alice, alice); +// _setAdminFee(alice, adminFee); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); + +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } + +// IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); +// feeOnTransferToken.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// feeOnTransferToken.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); + +// uint48 timestamp = 3; +// uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); +// vm.expectRevert(IRewardsPlugin.NotNetwork.selector); +// _distributeReward(bob, address(0), address(feeOnTransferToken), ditributeAmount, timestamp, acceptedAdminFee); +// } + +// function test_DistributeRewardRevertInvalidRewardTimestamp(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 2, 100 * 10 ** 18); + +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); + +// plugin = _getPlugin(); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); + +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } + +// IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); +// feeOnTransferToken.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// feeOnTransferToken.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); + +// uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); +// vm.expectRevert(IRewardsPlugin.InvalidRewardTimestamp.selector); +// _distributeReward( +// bob, network, address(feeOnTransferToken), ditributeAmount, uint48(blockTimestamp), acceptedAdminFee +// ); +// } + +// function test_DistributeRewardRevertInsufficientReward(uint256 amount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); + +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); + +// plugin = _getPlugin(); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); - feeOnTransferToken.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - feeOnTransferToken.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); +// feeOnTransferToken.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// feeOnTransferToken.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint48 timestamp = 3; - uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); - vm.expectRevert(IRewardsPlugin.InsufficientReward.selector); - _distributeReward(bob, network, address(feeOnTransferToken), 1, timestamp, acceptedAdminFee); - } +// uint48 timestamp = 3; +// uint256 acceptedAdminFee = vault.ADMIN_FEE_BASE(); +// vm.expectRevert(IRewardsPlugin.InsufficientReward.selector); +// _distributeReward(bob, network, address(feeOnTransferToken), 1, timestamp, acceptedAdminFee); +// } - function test_DistributeRewardRevertUnacceptedAdminFee(uint256 amount, uint256 adminFee) public { - amount = bound(amount, 1, 100 * 10 ** 18); +// function test_DistributeRewardRevertUnacceptedAdminFee(uint256 amount, uint256 adminFee) public { +// amount = bound(amount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); +// adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); - plugin = _getPlugin(); +// plugin = _getPlugin(); - _grantAdminFeeSetRole(alice, alice); - _setAdminFee(alice, adminFee); +// _grantAdminFeeSetRole(alice, alice); +// _setAdminFee(alice, adminFee); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); - feeOnTransferToken.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - feeOnTransferToken.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 feeOnTransferToken = IERC20(new FeeOnTransferToken("FeeOnTransferToken")); +// feeOnTransferToken.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// feeOnTransferToken.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint48 timestamp = 3; - uint256 acceptedAdminFee = adminFee - 1; - vm.expectRevert(IRewardsPlugin.UnacceptedAdminFee.selector); - _distributeReward( - bob, network, address(feeOnTransferToken), uint48(blockTimestamp), timestamp, acceptedAdminFee - ); - } +// uint48 timestamp = 3; +// uint256 acceptedAdminFee = adminFee - 1; +// vm.expectRevert(IRewardsPlugin.UnacceptedAdminFee.selector); +// _distributeReward( +// bob, network, address(feeOnTransferToken), uint48(blockTimestamp), timestamp, acceptedAdminFee +// ); +// } - function test_ClaimRewards(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewards(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint48 timestamp = 3; - _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - uint256 balanceBefore = token.balanceOf(alice); - uint32[] memory activeSharesOfHints = new uint32[](1); - _claimRewards(alice, address(token), 1, activeSharesOfHints); - assertEq(token.balanceOf(alice) - balanceBefore, ditributeAmount); +// uint256 balanceBefore = token.balanceOf(alice); +// uint32[] memory activeSharesOfHints = new uint32[](1); +// _claimRewards(alice, address(token), 1, activeSharesOfHints); +// assertEq(token.balanceOf(alice) - balanceBefore, ditributeAmount); - assertEq(plugin.lastUnclaimedReward(address(vault), alice, address(token)), 1); - } +// assertEq(plugin.lastUnclaimedReward(address(vault), alice, address(token)), 1); +// } - function test_ClaimRewardsManyWithoutHints(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsManyWithoutHints(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 slashDuration = 1; - uint48 vetoDuration = 0; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 slashDuration = 1; +// uint48 vetoDuration = 0; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 105; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 105; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint256 numRewards = 50; - for (uint48 i = 1; i < numRewards + 1; ++i) { - _distributeReward(bob, network, address(token), ditributeAmount, i, vault.ADMIN_FEE_BASE()); - } +// uint256 numRewards = 50; +// for (uint48 i = 1; i < numRewards + 1; ++i) { +// _distributeReward(bob, network, address(token), ditributeAmount, i, vault.ADMIN_FEE_BASE()); +// } - uint32[] memory activeSharesOfHints = new uint32[](0); +// uint32[] memory activeSharesOfHints = new uint32[](0); - uint256 gasLeft = gasleft(); - _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); - uint256 gasLeft2 = gasleft(); - console2.log("Gas1", gasLeft - gasLeft2 - 100); - } +// uint256 gasLeft = gasleft(); +// _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); +// uint256 gasLeft2 = gasleft(); +// console2.log("Gas1", gasLeft - gasLeft2 - 100); +// } - function test_ClaimRewardsManyWithHints(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsManyWithHints(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 slashDuration = 1; - uint48 vetoDuration = 0; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 slashDuration = 1; +// uint48 vetoDuration = 0; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 105; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 105; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint256 numRewards = 50; - for (uint48 i = 1; i < numRewards + 1; ++i) { - _distributeReward(bob, network, address(token), ditributeAmount, i, vault.ADMIN_FEE_BASE()); - } +// uint256 numRewards = 50; +// for (uint48 i = 1; i < numRewards + 1; ++i) { +// _distributeReward(bob, network, address(token), ditributeAmount, i, vault.ADMIN_FEE_BASE()); +// } - uint32[] memory activeSharesOfHints = new uint32[](numRewards); - for (uint32 i; i < numRewards; ++i) { - activeSharesOfHints[i] = i; - } +// uint32[] memory activeSharesOfHints = new uint32[](numRewards); +// for (uint32 i; i < numRewards; ++i) { +// activeSharesOfHints[i] = i; +// } - uint256 gasLeft = gasleft(); - _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); - uint256 gasLeft2 = gasleft(); - console2.log("Gas2", gasLeft - gasLeft2 - 100); - } +// uint256 gasLeft = gasleft(); +// _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); +// uint256 gasLeft2 = gasleft(); +// console2.log("Gas2", gasLeft - gasLeft2 - 100); +// } - function test_ClaimRewardsRevertNoRewardsToClaim1(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsRevertNoRewardsToClaim1(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); +// IERC20 token = IERC20(new Token("Token")); - uint32[] memory activeSharesOfHints = new uint32[](1); - vm.expectRevert(IRewardsPlugin.NoRewardsToClaim.selector); - _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); - } +// uint32[] memory activeSharesOfHints = new uint32[](1); +// vm.expectRevert(IRewardsPlugin.NoRewardsToClaim.selector); +// _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); +// } - function test_ClaimRewardsRevertNoRewardsToClaim2(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsRevertNoRewardsToClaim2(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); +// IERC20 token = IERC20(new Token("Token")); - uint32[] memory activeSharesOfHints = new uint32[](1); - vm.expectRevert(IRewardsPlugin.NoRewardsToClaim.selector); - _claimRewards(alice, address(token), 0, activeSharesOfHints); - } +// uint32[] memory activeSharesOfHints = new uint32[](1); +// vm.expectRevert(IRewardsPlugin.NoRewardsToClaim.selector); +// _claimRewards(alice, address(token), 0, activeSharesOfHints); +// } - function test_ClaimRewardsRevertNoDeposits(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsRevertNoDeposits(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(bob, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(bob, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint48 timestamp = 3; - _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - uint32[] memory activeSharesOfHints = new uint32[](1); - vm.expectRevert(IRewardsPlugin.NoDeposits.selector); - _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); - } +// uint32[] memory activeSharesOfHints = new uint32[](1); +// vm.expectRevert(IRewardsPlugin.NoDeposits.selector); +// _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); +// } - function test_ClaimRewardsRevertInvalidHintsLength(uint256 amount, uint256 ditributeAmount) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimRewardsRevertInvalidHintsLength(uint256 amount, uint256 ditributeAmount) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); - plugin = _getPlugin(); +// plugin = _getPlugin(); - address network = bob; - _registerNetwork(network, bob); +// address network = bob; +// _registerNetwork(network, bob); - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); - uint48 timestamp = 3; - _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - uint32[] memory activeSharesOfHints = new uint32[](2); - vm.expectRevert(IRewardsPlugin.InvalidHintsLength.selector); - _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); - } +// uint32[] memory activeSharesOfHints = new uint32[](2); +// vm.expectRevert(IRewardsPlugin.InvalidHintsLength.selector); +// _claimRewards(alice, address(token), type(uint256).max, activeSharesOfHints); +// } - function test_ClaimAdminFee(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); +// function test_ClaimAdminFee(uint256 amount, uint256 ditributeAmount, uint256 adminFee) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); - - plugin = _getPlugin(); - - _grantAdminFeeSetRole(alice, alice); - _setAdminFee(alice, adminFee); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } - - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); - - uint48 timestamp = 3; - _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - - uint256 adminFeeAmount = ditributeAmount.mulDiv(adminFee, vault.ADMIN_FEE_BASE()); - vm.assume(adminFeeAmount != 0); - uint256 balanceBefore = token.balanceOf(address(plugin)); - uint256 balanceBeforeAlice = token.balanceOf(alice); - _claimAdminFee(alice, address(token)); - assertEq(balanceBefore - token.balanceOf(address(plugin)), adminFeeAmount); - assertEq(token.balanceOf(alice) - balanceBeforeAlice, adminFeeAmount); - assertEq(plugin.claimableAdminFee(address(vault), address(token)), 0); - } - - function test_ClaimAdminFeeRevertInsufficientAdminFee( - uint256 amount, - uint256 ditributeAmount, - uint256 adminFee - ) public { - amount = bound(amount, 1, 100 * 10 ** 18); - ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); - - uint48 epochDuration = 1; - uint48 vetoDuration = 0; - uint48 slashDuration = 1; - vault = _getVault(epochDuration, vetoDuration, slashDuration); - adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); - - plugin = _getPlugin(); - - _grantAdminFeeSetRole(alice, alice); - _setAdminFee(alice, adminFee); - - address network = bob; - _registerNetwork(network, bob); - - uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; - - for (uint256 i; i < 10; ++i) { - _deposit(alice, amount); - - blockTimestamp = blockTimestamp + 1; - vm.warp(blockTimestamp); - } - - IERC20 token = IERC20(new Token("Token")); - token.transfer(bob, 100_000 * 1e18); - vm.startPrank(bob); - token.approve(address(plugin), type(uint256).max); - vm.stopPrank(); - - uint48 timestamp = 3; - _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); - - vm.assume(plugin.claimableAdminFee(address(vault), address(token)) != 0); - _claimAdminFee(alice, address(token)); - - vm.expectRevert(IRewardsPlugin.InsufficientAdminFee.selector); - _claimAdminFee(alice, address(token)); - } - - function _getVault(uint48 epochDuration, uint48 vetoDuration, uint48 slashDuration) internal returns (IVault) { - return IVault( - vaultRegistry.create( - vaultRegistry.lastVersion(), - abi.encode( - IVault.InitParams({ - owner: alice, - collateral: address(collateral), - epochDuration: epochDuration, - vetoDuration: vetoDuration, - slashDuration: slashDuration, - adminFee: 0, - depositWhitelist: false - }) - ) - ) - ); - } - - function _getPlugin() internal returns (IRewardsPlugin) { - return IRewardsPlugin(address(new RewardsPlugin(address(networkRegistry), address(vaultRegistry)))); - } - - function _registerNetwork(address user, address middleware) internal { - vm.startPrank(user); - networkRegistry.register(); - networkMiddlewarePlugin.setMiddleware(middleware); - vm.stopPrank(); - } - - function _grantAdminFeeSetRole(address user, address account) internal { - vm.startPrank(user); - Vault(address(vault)).grantRole(vault.ADMIN_FEE_SET_ROLE(), account); - vm.stopPrank(); - } - - function _deposit(address user, uint256 amount) internal returns (uint256 shares) { - collateral.transfer(user, amount); - vm.startPrank(user); - collateral.approve(address(vault), amount); - shares = vault.deposit(user, amount); - vm.stopPrank(); - } - - function _distributeReward( - address user, - address network, - address token, - uint256 amount, - uint48 timestamp, - uint256 acceptedAdminFee - ) internal { - vm.startPrank(user); - plugin.distributeReward(address(vault), network, token, amount, timestamp, acceptedAdminFee); - vm.stopPrank(); - } - - function _claimRewards( - address user, - address token, - uint256 maxRewards, - uint32[] memory activeSharesOfHints - ) internal { - vm.startPrank(user); - plugin.claimRewards(address(vault), user, token, maxRewards, activeSharesOfHints); - vm.stopPrank(); - } - - function _setAdminFee(address user, uint256 adminFee) internal { - vm.startPrank(user); - vault.setAdminFee(adminFee); - vm.stopPrank(); - } - - function _claimAdminFee(address user, address token) internal { - vm.startPrank(user); - plugin.claimAdminFee(address(vault), user, token); - vm.stopPrank(); - } -} +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); +// adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); + +// plugin = _getPlugin(); + +// _grantAdminFeeSetRole(alice, alice); +// _setAdminFee(alice, adminFee); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); + +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } + +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); + +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); + +// uint256 adminFeeAmount = ditributeAmount.mulDiv(adminFee, vault.ADMIN_FEE_BASE()); +// vm.assume(adminFeeAmount != 0); +// uint256 balanceBefore = token.balanceOf(address(plugin)); +// uint256 balanceBeforeAlice = token.balanceOf(alice); +// _claimAdminFee(alice, address(token)); +// assertEq(balanceBefore - token.balanceOf(address(plugin)), adminFeeAmount); +// assertEq(token.balanceOf(alice) - balanceBeforeAlice, adminFeeAmount); +// assertEq(plugin.claimableAdminFee(address(vault), address(token)), 0); +// } + +// function test_ClaimAdminFeeRevertInsufficientAdminFee( +// uint256 amount, +// uint256 ditributeAmount, +// uint256 adminFee +// ) public { +// amount = bound(amount, 1, 100 * 10 ** 18); +// ditributeAmount = bound(ditributeAmount, 1, 100 * 10 ** 18); + +// uint48 epochDuration = 1; +// uint48 vetoDuration = 0; +// uint48 slashDuration = 1; +// vault = _getVault(epochDuration, vetoDuration, slashDuration); +// adminFee = bound(adminFee, 1, vault.ADMIN_FEE_BASE()); + +// plugin = _getPlugin(); + +// _grantAdminFeeSetRole(alice, alice); +// _setAdminFee(alice, adminFee); + +// address network = bob; +// _registerNetwork(network, bob); + +// uint256 blockTimestamp = block.timestamp * block.timestamp / block.timestamp * block.timestamp / block.timestamp; + +// for (uint256 i; i < 10; ++i) { +// _deposit(alice, amount); + +// blockTimestamp = blockTimestamp + 1; +// vm.warp(blockTimestamp); +// } + +// IERC20 token = IERC20(new Token("Token")); +// token.transfer(bob, 100_000 * 1e18); +// vm.startPrank(bob); +// token.approve(address(plugin), type(uint256).max); +// vm.stopPrank(); + +// uint48 timestamp = 3; +// _distributeReward(bob, network, address(token), ditributeAmount, timestamp, vault.ADMIN_FEE_BASE()); + +// vm.assume(plugin.claimableAdminFee(address(vault), address(token)) != 0); +// _claimAdminFee(alice, address(token)); + +// vm.expectRevert(IRewardsPlugin.InsufficientAdminFee.selector); +// _claimAdminFee(alice, address(token)); +// } + +// function _getVault(uint48 epochDuration, uint48 vetoDuration, uint48 slashDuration) internal returns (IVault) { +// return IVault( +// vaultRegistry.create( +// vaultRegistry.lastVersion(), +// abi.encode( +// IVault.InitParams({ +// owner: alice, +// collateral: address(collateral), +// epochDuration: epochDuration, +// vetoDuration: vetoDuration, +// slashDuration: slashDuration, +// rewardsDistributor: address(0), +// adminFee: 0, +// depositWhitelist: false +// }) +// ) +// ) +// ); +// } + +// function _getPlugin() internal returns (IRewardsPlugin) { +// return IRewardsPlugin(address(new RewardsPlugin(address(networkRegistry), address(vaultRegistry)))); +// } + +// function _registerNetwork(address user, address middleware) internal { +// vm.startPrank(user); +// networkRegistry.register(); +// networkMiddlewarePlugin.setMiddleware(middleware); +// vm.stopPrank(); +// } + +// function _grantAdminFeeSetRole(address user, address account) internal { +// vm.startPrank(user); +// Vault(address(vault)).grantRole(vault.ADMIN_FEE_SET_ROLE(), account); +// vm.stopPrank(); +// } + +// function _deposit(address user, uint256 amount) internal returns (uint256 shares) { +// collateral.transfer(user, amount); +// vm.startPrank(user); +// collateral.approve(address(vault), amount); +// shares = vault.deposit(user, amount); +// vm.stopPrank(); +// } + +// function _distributeReward( +// address user, +// address network, +// address token, +// uint256 amount, +// uint48 timestamp, +// uint256 acceptedAdminFee +// ) internal { +// vm.startPrank(user); +// plugin.distributeReward(address(vault), network, token, amount, timestamp, acceptedAdminFee); +// vm.stopPrank(); +// } + +// function _claimRewards( +// address user, +// address token, +// uint256 maxRewards, +// uint32[] memory activeSharesOfHints +// ) internal { +// vm.startPrank(user); +// plugin.claimRewards(address(vault), user, token, maxRewards, activeSharesOfHints); +// vm.stopPrank(); +// } + +// function _setAdminFee(address user, uint256 adminFee) internal { +// vm.startPrank(user); +// vault.setAdminFee(adminFee); +// vm.stopPrank(); +// } + +// function _claimAdminFee(address user, address token) internal { +// vm.startPrank(user); +// plugin.claimAdminFee(address(vault), user, token); +// vm.stopPrank(); +// } +// }