@@ -11,21 +11,24 @@ import { Initializable } from "../utils/Initializable.sol";
1111/// @author Origin Protocol
1212/// @notice Factory contract to create CurvePoolBoosterPlain instances
1313contract CurvePoolBoosterFactory is Initializable , Strategizable {
14-
1514 /// @notice Address of the CreateX contract
16- ICreateX public constant CREATEX = ICreateX (0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed );
15+ ICreateX public constant CREATEX =
16+ ICreateX (0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed );
1717 event CurvePoolBoosterPlainCreated (address indexed poolBoosterAddress );
1818
1919 /// @notice Initialize the contract. Normally we'd rather have the governor and strategist set in the constructor,
2020 /// but since this contract is deployed by CreateX we need to set them in the initialize function because
2121 /// the constructor's parameters influence the address of the contract when deployed using CreateX.
22- /// And having different governor and strategist on the same address on different chains would
22+ /// And having different governor and strategist on the same address on different chains would
2323 /// cause issues.
2424 /// @param _governor Address of the governor
2525 /// @param _strategist Address of the strategist
26- function initialize (address _governor , address _strategist ) external initializer {
27- _setGovernor (_governor);
28- _setStrategistAddr (_strategist);
26+ function initialize (address _governor , address _strategist )
27+ external
28+ initializer
29+ {
30+ _setGovernor (_governor);
31+ _setStrategistAddr (_strategist);
2932 }
3033
3134 /// @notice Create a new CurvePoolBoosterPlain instance
@@ -42,60 +45,71 @@ contract CurvePoolBoosterFactory is Initializable, Strategizable {
4245 /// was deployed at the expected address, otherwise the transaction batch will revert. If set to 0 then the
4346 /// address verification is skipped.
4447 function createCurvePoolBoosterPlain (
45- address _rewardToken ,
46- address _gauge ,
47- address _feeCollector ,
48- uint16 _fee ,
49- address _campaignRemoteManager ,
50- address _votemarket ,
51- bytes32 _salt ,
52- address _expectedAddress
48+ address _rewardToken ,
49+ address _gauge ,
50+ address _feeCollector ,
51+ uint16 _fee ,
52+ address _campaignRemoteManager ,
53+ address _votemarket ,
54+ bytes32 _salt ,
55+ address _expectedAddress
5356 ) external onlyGovernorOrStrategist returns (address ) {
54- require (governor () != address (0 ), "Governor not set " );
55- require (strategistAddr != address (0 ), "Strategist not set " );
56- // salt encoded sender
57- address senderAddress = address (bytes20 (_salt));
58- // the contract that calls the CreateX should be encoded in the salt to protect against front-running
59- require (senderAddress == address (this ), "Front-run protection failed " );
60-
61- address poolBoosterAddress = CREATEX.deployCreate2 (
62- _salt,
63- getInitCode (_rewardToken, _gauge)
64- );
65-
66- require (
67- _expectedAddress == address (0 ) ||
68- poolBoosterAddress == _expectedAddress,
69- "Pool booster deployed at unexpected address "
70- );
71-
72- CurvePoolBoosterPlain (payable (poolBoosterAddress)).initialize (
73- governor (),
74- strategistAddr,
75- _fee,
76- _feeCollector,
77- _campaignRemoteManager,
78- _votemarket);
79-
80- emit CurvePoolBoosterPlainCreated (poolBoosterAddress);
81- return poolBoosterAddress;
57+ require (governor () != address (0 ), "Governor not set " );
58+ require (strategistAddr != address (0 ), "Strategist not set " );
59+ // salt encoded sender
60+ address senderAddress = address (bytes20 (_salt));
61+ // the contract that calls the CreateX should be encoded in the salt to protect against front-running
62+ require (senderAddress == address (this ), "Front-run protection failed " );
63+
64+ address poolBoosterAddress = CREATEX.deployCreate2 (
65+ _salt,
66+ getInitCode (_rewardToken, _gauge)
67+ );
68+
69+ require (
70+ _expectedAddress == address (0 ) ||
71+ poolBoosterAddress == _expectedAddress,
72+ "Pool booster deployed at unexpected address "
73+ );
74+
75+ CurvePoolBoosterPlain (payable (poolBoosterAddress)).initialize (
76+ governor (),
77+ strategistAddr,
78+ _fee,
79+ _feeCollector,
80+ _campaignRemoteManager,
81+ _votemarket
82+ );
83+
84+ emit CurvePoolBoosterPlainCreated (poolBoosterAddress);
85+ return poolBoosterAddress;
8286 }
8387
8488 // get initialisation code contract code + constructor arguments
85- function getInitCode (
86- address _rewardToken ,
87- address _gauge
88- ) internal pure returns (bytes memory ) {
89- return abi.encodePacked (
90- type (CurvePoolBoosterPlain).creationCode,
91- abi.encode (_rewardToken, _gauge)
92- );
89+ function getInitCode (address _rewardToken , address _gauge )
90+ internal
91+ pure
92+ returns (bytes memory )
93+ {
94+ return
95+ abi.encodePacked (
96+ type (CurvePoolBoosterPlain).creationCode,
97+ abi.encode (_rewardToken, _gauge)
98+ );
9399 }
94100
95101 /// @notice Compute the guarded salt for CreateX protections. This version of guarded
96102 /// salt expects that this factory contract is the one doing calls to the CreateX contract.
97- function _computeGuardedSalt (bytes32 _salt ) internal view returns (bytes32 ) {
98- return _efficientHash ({a: bytes32 (uint256 (uint160 (address (this )))), b: _salt});
103+ function _computeGuardedSalt (bytes32 _salt )
104+ internal
105+ view
106+ returns (bytes32 )
107+ {
108+ return
109+ _efficientHash ({
110+ a: bytes32 (uint256 (uint160 (address (this )))),
111+ b: _salt
112+ });
99113 }
100114
101115 /**
@@ -104,9 +118,13 @@ contract CurvePoolBoosterFactory is Initializable, Strategizable {
104118 * @param b The second 32-byte value to be concatenated and hashed.
105119 * @return hash The 32-byte `keccak256` hash of `a` and `b`.
106120 */
107- function _efficientHash (bytes32 a , bytes32 b ) internal pure returns (bytes32 hash ) {
108- // solhint-disable-next-line no-inline-assembly
109- assembly ("memory-safe" ) {
121+ function _efficientHash (bytes32 a , bytes32 b )
122+ internal
123+ pure
124+ returns (bytes32 hash )
125+ {
126+ // solhint-disable-next-line no-inline-assembly
127+ assembly {
110128 mstore (0x00 , a)
111129 mstore (0x20 , b)
112130 hash := keccak256 (0x00 , 0x40 )
@@ -124,42 +142,47 @@ contract CurvePoolBoosterFactory is Initializable, Strategizable {
124142 address _gauge ,
125143 bytes32 _salt
126144 ) external view returns (address ) {
127- bytes32 guardedSalt = _computeGuardedSalt (_salt);
128- return CREATEX.computeCreate2Address (
129- guardedSalt,
130- keccak256 (getInitCode (_rewardToken, _gauge)),
131- address (CREATEX)
132- );
145+ bytes32 guardedSalt = _computeGuardedSalt (_salt);
146+ return
147+ CREATEX.computeCreate2Address (
148+ guardedSalt,
149+ keccak256 (getInitCode (_rewardToken, _gauge)),
150+ address (CREATEX)
151+ );
133152 }
134153
135154 /**
136- * @dev Encodes a salt for CreateX by concatenating deployer address (bytes20), cross-chain protection flag (bytes1),
137- * and the first 11 bytes of the provided salt (most significant bytes). This function is exposed for easier
138- * operations. For the salt value itself just use the epoch time when the operation is performed.
139- * @param salt The raw salt as uint256; converted to bytes32, then only the first 11 bytes (MSB) are used.
140- * @return encodedSalt The resulting 32-byte encoded salt.
141- */
142- function encodeSaltForCreateX (
143- uint256 salt
144- ) external view returns (bytes32 encodedSalt ) {
145- // prepare encoded salt guarded by this factory address. When the deployer part of the salt is the same as the
155+ * @dev Encodes a salt for CreateX by concatenating deployer address (bytes20), cross-chain protection flag
156+ * (bytes1), and the first 11 bytes of the provided salt (most significant bytes). This function is exposed
157+ * for easier operations. For the salt value itself just use the epoch time when the operation is performed.
158+ * @param salt The raw salt as uint256; converted to bytes32, then only the first 11 bytes (MSB) are used.
159+ * @return encodedSalt The resulting 32-byte encoded salt.
160+ */
161+ function encodeSaltForCreateX (uint256 salt )
162+ external
163+ view
164+ returns (bytes32 encodedSalt )
165+ {
166+ // only the right most 11 bytes are considered when encoding salt. Which is limited by the number in the below
167+ // require. If salt were higher, the higher bytes would need to be set to 0 to not affect the "or" way of
168+ // encoding the salt.
169+ require (salt <= 309485009821345068724781055 , "Invalid salt " );
170+
171+ // prepare encoded salt guarded by this factory address. When the deployer part of the salt is the same as the
146172 // caller of CreateX the salt is re-hashed and thus guarded from front-running.
147173 address deployer = address (this );
148-
174+
149175 // Flag as uint8 (0)
150176 uint8 flag = 0 ;
151-
152- // Salt prefix: high 11 bytes (88 bits) shifted to low position
153- uint256 saltPrefix = uint256 (bytes32 (salt)) >> 168 ;
154-
177+
155178 // Precompute parts
156- uint256 deployerPart = uint256 (uint160 (deployer)) << 96 ; // 20 bytes shifted left 96 bits (12 bytes)
157- uint256 flagPart = uint256 (flag) << 88 ; // 1 byte shifted left 88 bits (11 bytes)
158-
179+ uint256 deployerPart = uint256 (uint160 (deployer)) << 96 ; // 20 bytes shifted left 96 bits (12 bytes)
180+ uint256 flagPart = uint256 (flag) << 88 ; // 1 byte shifted left 88 bits (11 bytes)
181+
159182 // Concat via nested OR
160183 // solhint-disable-next-line no-inline-assembly
161- assembly ( "memory-safe" ) {
162- encodedSalt := or (or (deployerPart, flagPart), saltPrefix )
184+ assembly {
185+ encodedSalt := or (or (deployerPart, flagPart), salt )
163186 }
164187 }
165- }
188+ }
0 commit comments