@@ -10,6 +10,7 @@ import { Artifacts } from "scripts/Artifacts.s.sol";
1010import { LibString } from "@solady/utils/LibString.sol " ;
1111import { Bytes } from "src/libraries/Bytes.sol " ;
1212import { Constants } from "src/libraries/Constants.sol " ;
13+ import { Blueprint } from "src/libraries/Blueprint.sol " ;
1314
1415// Interfaces
1516import { IProxy } from "interfaces/universal/IProxy.sol " ;
@@ -20,6 +21,8 @@ import { IResolvedDelegateProxy } from "interfaces/legacy/IResolvedDelegateProxy
2021library DeployUtils {
2122 Vm internal constant vm = Vm (address (uint160 (uint256 (keccak256 ("hevm cheat code " )))));
2223
24+ bytes32 internal constant DEFAULT_SALT = keccak256 ("op-stack-contract-impls-salt-v0 " );
25+
2326 /// @notice Deploys a contract with the given name and arguments via CREATE.
2427 /// @param _name Name of the contract to deploy.
2528 /// @param _args ABI-encoded constructor arguments.
@@ -97,19 +100,11 @@ library DeployUtils {
97100 /// @param _args ABI-encoded constructor arguments.
98101 /// @param _salt Salt for the CREATE2 operation.
99102 /// @return addr_ Address of the deployed contract.
100- function create2 (string memory _name , bytes memory _args , bytes32 _salt ) internal returns (address payable addr_ ) {
103+ function create2 (string memory _name , bytes memory _args , bytes32 _salt ) internal returns (address payable ) {
101104 bytes memory initCode = abi.encodePacked (vm.getCode (_name), _args);
102105 address preComputedAddress = vm.computeCreate2Address (_salt, keccak256 (initCode));
103106 require (preComputedAddress.code.length == 0 , "DeployUtils: contract already deployed " );
104- assembly {
105- addr_ := create2 (0 , add (initCode, 0x20 ), mload (initCode), _salt)
106- if iszero (addr_) {
107- let size := returndatasize ()
108- returndatacopy (0 , 0 , size)
109- revert (0 , size)
110- }
111- }
112- assertValidContractAddress (addr_);
107+ return create2asm (initCode, _salt);
113108 }
114109
115110 /// @notice Deploys a contract with the given name via CREATE2.
@@ -120,6 +115,18 @@ library DeployUtils {
120115 return create2 (_name, hex "" , _salt);
121116 }
122117
118+ function create2asm (bytes memory _initCode , bytes32 _salt ) internal returns (address payable addr_ ) {
119+ assembly {
120+ addr_ := create2 (0 , add (_initCode, 0x20 ), mload (_initCode), _salt)
121+ if iszero (addr_) {
122+ let size := returndatasize ()
123+ returndatacopy (0 , 0 , size)
124+ revert (0 , size)
125+ }
126+ }
127+ assertValidContractAddress (addr_);
128+ }
129+
123130 /// @notice Deploys a contract with the given name and arguments via CREATE2 and saves the result.
124131 /// @param _save Artifacts contract.
125132 /// @param _name Name of the contract to deploy.
@@ -195,6 +202,64 @@ library DeployUtils {
195202 return create2AndSave (_save, _name, _name, hex "" , _salt);
196203 }
197204
205+ /// @notice Deploys a contract with the given name using CREATE2. If the contract is already deployed, this method
206+ /// does nothing.
207+ /// @param _name Name of the contract to deploy.
208+ /// @param _args ABI-encoded constructor arguments.
209+ function createDeterministic (
210+ string memory _name ,
211+ bytes memory _args ,
212+ bytes32 _salt
213+ )
214+ internal
215+ returns (address payable addr_ )
216+ {
217+ bytes memory initCode = abi.encodePacked (vm.getCode (_name), _args);
218+ address preComputedAddress = vm.computeCreate2Address (_salt, keccak256 (initCode));
219+ if (preComputedAddress.code.length > 0 ) {
220+ addr_ = payable (preComputedAddress);
221+ } else {
222+ addr_ = DeployUtils.create2asm (initCode, _salt);
223+ }
224+ }
225+
226+ /// @notice Deploys a blueprint contract with the given name using CREATE2. If the contract is already deployed,
227+ /// this method does nothing.
228+ /// @param _rawBytecode Raw bytecode of the contract the blueprint will deploy.
229+ function createDeterministicBlueprint (
230+ bytes memory _rawBytecode ,
231+ bytes32 _salt
232+ )
233+ internal
234+ returns (address newContract1_ , address newContract2_ )
235+ {
236+ uint32 maxSize = Blueprint.maxInitCodeSize ();
237+ if (_rawBytecode.length <= maxSize) {
238+ bytes memory bpBytecode = Blueprint.blueprintDeployerBytecode (_rawBytecode);
239+ newContract1_ = vm.computeCreate2Address (_salt, keccak256 (bpBytecode));
240+ if (newContract1_.code.length == 0 ) {
241+ (address deployedContract ) = Blueprint.deploySmallBytecode (bpBytecode, _salt);
242+ require (deployedContract == newContract1_, "DeployUtils: unexpected blueprint address " );
243+ }
244+ newContract2_ = address (0 );
245+ } else {
246+ bytes memory part1Slice = Bytes.slice (_rawBytecode, 0 , maxSize);
247+ bytes memory part2Slice = Bytes.slice (_rawBytecode, maxSize, _rawBytecode.length - maxSize);
248+ bytes memory bp1Bytecode = Blueprint.blueprintDeployerBytecode (part1Slice);
249+ bytes memory bp2Bytecode = Blueprint.blueprintDeployerBytecode (part2Slice);
250+ newContract1_ = vm.computeCreate2Address (_salt, keccak256 (bp1Bytecode));
251+ if (newContract1_.code.length == 0 ) {
252+ address deployedContract = Blueprint.deploySmallBytecode (bp1Bytecode, _salt);
253+ require (deployedContract == newContract1_, "DeployUtils: unexpected part 1 blueprint address " );
254+ }
255+ newContract2_ = vm.computeCreate2Address (_salt, keccak256 (bp2Bytecode));
256+ if (newContract2_.code.length == 0 ) {
257+ address deployedContract = Blueprint.deploySmallBytecode (bp2Bytecode, _salt);
258+ require (deployedContract == newContract2_, "DeployUtils: unexpected part 2 blueprint address " );
259+ }
260+ }
261+ }
262+
198263 /// @notice Takes a sender and an identifier and returns a deterministic address based on the
199264 /// two. The result is used to etch the input and output contracts to a deterministic
200265 /// address based on those two values, where the identifier represents the input or
0 commit comments