Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/contracts/interfaces/IStrategyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface IStrategyFactory {

/**
* @notice Deploy a new strategyBeacon contract for the ERC20 token.
* @param token the token to deploy a strategy for
* @dev A strategy contract must not yet exist for the token.
* $dev Immense caution is warranted for non-standard ERC20 tokens, particularly "reentrant" tokens
* like those that conform to ERC777.
Expand All @@ -37,6 +38,16 @@ interface IStrategyFactory {
bool[] calldata thirdPartyTransfersForbiddenValues
) external;

/**
* @notice Owner-only function to pass through a call to `StrategyManager.setThirdPartyTransfersForbidden`
*/
function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external;

/**
* @notice Owner-only function to pass through a call to `StrategyManager.removeStrategiesFromDepositWhitelist`
*/
function removeStrategiesFromWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;

// @notice Emitted when the `strategyBeacon` is changed
event StrategyBeaconModified(IBeacon previousBeacon, IBeacon newBeacon);

Expand Down
9 changes: 9 additions & 0 deletions src/contracts/interfaces/IStrategyManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,15 @@ interface IStrategyManager {
*/
function removeStrategiesFromDepositWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external;

/**
* If true for a strategy, a user cannot depositIntoStrategyWithSignature into that strategy for another staker
* and also when performing DelegationManager.queueWithdrawals, a staker can only withdraw to themselves.
* Defaulted to false for all existing strategies.
* @param strategy The strategy to set `thirdPartyTransfersForbidden` value to
* @param value bool value to set `thirdPartyTransfersForbidden` to
*/
function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external;

/// @notice Returns the single, central Delegation contract of EigenLayer
function delegation() external view returns (IDelegationManager);

Expand Down
14 changes: 14 additions & 0 deletions src/contracts/strategies/StrategyFactory.sol
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,20 @@ contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable
strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist, thirdPartyTransfersForbiddenValues);
}

/**
* @notice Owner-only function to pass through a call to `StrategyManager.setThirdPartyTransfersForbidden`
*/
function setThirdPartyTransfersForbidden(IStrategy strategy, bool value) external onlyOwner {
strategyManager.setThirdPartyTransfersForbidden(strategy, value);
}

/**
* @notice Owner-only function to pass through a call to `StrategyManager.removeStrategiesFromDepositWhitelist`
*/
function removeStrategiesFromWhitelist(IStrategy[] calldata strategiesToRemoveFromWhitelist) external onlyOwner {
strategyManager.removeStrategiesFromDepositWhitelist(strategiesToRemoveFromWhitelist);
}

function _setStrategyForToken(IERC20 token, IStrategy strategy) internal {
tokenStrategy[token] = strategy;
emit StrategySetForToken(token, strategy);
Expand Down
64 changes: 49 additions & 15 deletions src/test/unit/StrategyFactoryUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,8 @@ import "src/test/utils/EigenLayerUnitTestSetup.sol";
import "../../contracts/permissions/PauserRegistry.sol";

/**
* @notice Unit testing of the AVSDirectory contract. An AVSs' service manager contract will
* call this to register an operator with the AVS.
* Contracts tested: AVSDirectory
* Contracts not mocked: DelegationManager
* @notice Unit testing of the StrategyFactory contract.
* Contracts tested: StrategyFactory
*/
contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup {
// Contract under test
Expand Down Expand Up @@ -141,23 +139,14 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup {
}

function test_whitelistStrategies() public {
StrategyBase strategy = StrategyBase(
address(
new TransparentUpgradeableProxy(
address(strategyImplementation),
address(eigenLayerProxyAdmin),
abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry)
)
)
);


StrategyBase strategy = _deployStrategy();
IStrategy[] memory strategiesToWhitelist = new IStrategy[](1);
bool[] memory thirdPartyTransfersForbiddenValues = new bool[](1);
strategiesToWhitelist[0] = strategy;
thirdPartyTransfersForbiddenValues[0] = true;
strategyFactory.whitelistStrategies(strategiesToWhitelist, thirdPartyTransfersForbiddenValues);

assertTrue(strategyManagerMock.strategyIsWhitelistedForDeposit(strategy), "Strategy not whitelisted");
require(strategyManagerMock.thirdPartyTransfersForbidden(strategy), "3rd party transfers forbidden not set correctly");
}

Expand All @@ -169,4 +158,49 @@ contract StrategyFactoryUnitTests is EigenLayerUnitTestSetup {
cheats.prank(notOwner);
strategyFactory.whitelistStrategies(strategiesToWhitelist, thirdPartyTransfersForbiddenValues);
}

function test_setThirdPartyTransfersForbidden_revert_notOwner() public {
IStrategy strategy;

cheats.expectRevert("Ownable: caller is not the owner");
cheats.prank(notOwner);
strategyFactory.setThirdPartyTransfersForbidden(strategy, true);
}

function test_setThirdPartyTransfersFrobidden() public {
StrategyBase strategy = _deployStrategy();
bool thirdPartyTransfersForbidden = true;

strategyFactory.setThirdPartyTransfersForbidden(strategy, thirdPartyTransfersForbidden);
assertTrue(strategyManagerMock.thirdPartyTransfersForbidden(strategy), "3rd party transfers forbidden not set");
}

function test_removeStrategiesFromWhitelist_revert_notOwner() public {
IStrategy[] memory strategiesToRemove = new IStrategy[](1);

cheats.expectRevert("Ownable: caller is not the owner");
cheats.prank(notOwner);
strategyFactory.removeStrategiesFromWhitelist(strategiesToRemove);
}

function test_removeStrategiesFromWhitelist() public {
IStrategy[] memory strategiesToRemove = new IStrategy[](1);
strategiesToRemove[0] = IStrategy(_deployStrategy());

strategyFactory.removeStrategiesFromWhitelist(strategiesToRemove);
assertFalse(strategyManagerMock.strategyIsWhitelistedForDeposit(strategiesToRemove[0]), "Strategy not removed from whitelist");
}


function _deployStrategy() internal returns (StrategyBase) {
return StrategyBase(
address(
new TransparentUpgradeableProxy(
address(strategyImplementation),
address(eigenLayerProxyAdmin),
abi.encodeWithSelector(StrategyBase.initialize.selector, underlyingToken, pauserRegistry)
)
)
);
}
}