-
Notifications
You must be signed in to change notification settings - Fork 357
/
Copy pathStrategyFactory.sol
128 lines (113 loc) · 4.98 KB
/
StrategyFactory.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol";
import "@openzeppelin-upgrades/contracts/access/OwnableUpgradeable.sol";
import "./StrategyFactoryStorage.sol";
import "./StrategyBase.sol";
import "../permissions/Pausable.sol";
/**
* @title Factory contract for deploying BeaconProxies of a Strategy contract implementation for arbitrary ERC20 tokens
* and automatically adding them to the StrategyWhitelist in EigenLayer.
* @author Layr Labs, Inc.
* @notice Terms of Service: https://docs.eigenlayer.xyz/overview/terms-of-service
* @dev This may not be compatible with non-standard ERC20 tokens. Caution is warranted.
*/
contract StrategyFactory is StrategyFactoryStorage, OwnableUpgradeable, Pausable {
uint8 internal constant PAUSED_NEW_STRATEGIES = 0;
/// @notice EigenLayer's StrategyManager contract
IStrategyManager public immutable strategyManager;
/// @notice Since this contract is designed to be initializable, the constructor simply sets the immutable variables.
constructor(IStrategyManager _strategyManager, IPauserRegistry _pauserRegistry) Pausable(_pauserRegistry) {
strategyManager = _strategyManager;
_disableInitializers();
}
function initialize(
address _initialOwner,
uint256 _initialPausedStatus,
IBeacon _strategyBeacon
) public virtual initializer {
_transferOwnership(_initialOwner);
_setPausedStatus(_initialPausedStatus);
_setStrategyBeacon(_strategyBeacon);
}
/**
* @notice Deploy a new StrategyBase contract for the ERC20 token, using a beacon proxy
* @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.
*/
function deployNewStrategy(
IERC20 token
) external onlyWhenNotPaused(PAUSED_NEW_STRATEGIES) returns (IStrategy newStrategy) {
require(!isBlacklisted[token], BlacklistedToken());
require(deployedStrategies[token] == IStrategy(address(0)), StrategyAlreadyExists());
IStrategy strategy = IStrategy(
address(
new BeaconProxy(
address(strategyBeacon), abi.encodeWithSelector(StrategyBase.initialize.selector, token)
)
)
);
_setStrategyForToken(token, strategy);
IStrategy[] memory strategiesToWhitelist = new IStrategy[](1);
strategiesToWhitelist[0] = strategy;
strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist);
return strategy;
}
/**
* @notice Owner-only function to prevent strategies from being created for given tokens.
* @param tokens An array of token addresses to blacklist.
*/
function blacklistTokens(
IERC20[] calldata tokens
) external onlyOwner {
IStrategy[] memory strategiesToRemove = new IStrategy[](tokens.length);
uint256 removeIdx = 0;
for (uint256 i; i < tokens.length; ++i) {
require(!isBlacklisted[tokens[i]], AlreadyBlacklisted());
isBlacklisted[tokens[i]] = true;
emit TokenBlacklisted(tokens[i]);
// If someone has already deployed a strategy for this token, add it
// to the list of strategies to remove from the StrategyManager whitelist
IStrategy deployed = deployedStrategies[tokens[i]];
if (deployed != IStrategy(address(0))) {
strategiesToRemove[removeIdx] = deployed;
removeIdx++;
}
}
// Manually adjust length to remove unused entries
// New length == removeIdx
assembly {
mstore(strategiesToRemove, removeIdx)
}
if (strategiesToRemove.length > 0) {
strategyManager.removeStrategiesFromDepositWhitelist(strategiesToRemove);
}
}
/**
* @notice Owner-only function to pass through a call to `StrategyManager.addStrategiesToDepositWhitelist`
*/
function whitelistStrategies(
IStrategy[] calldata strategiesToWhitelist
) external onlyOwner {
strategyManager.addStrategiesToDepositWhitelist(strategiesToWhitelist);
}
/**
* @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 {
deployedStrategies[token] = strategy;
emit StrategySetForToken(token, strategy);
}
function _setStrategyBeacon(
IBeacon _strategyBeacon
) internal {
emit StrategyBeaconModified(strategyBeacon, _strategyBeacon);
strategyBeacon = _strategyBeacon;
}
}