diff --git a/script/Base.s.sol b/script/Base.s.sol index 2ef24e40..409ba944 100644 --- a/script/Base.s.sol +++ b/script/Base.s.sol @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-3.0-or-later pragma solidity >=0.8.22; +import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; + +import { console2 } from "forge-std/src/console2.sol"; import { Script } from "forge-std/src/Script.sol"; abstract contract BaseScript is Script { + using Strings for uint256; + /// @dev Included to enable compilation of the script without a $MNEMONIC environment variable. string internal constant TEST_MNEMONIC = "test test test test test test test test test test test junk"; @@ -38,4 +43,26 @@ abstract contract BaseScript is Script { _; vm.stopBroadcast(); } + + /// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory: + /// https://github.com/Arachnid/deterministic-deployment-proxy + /// + /// Notes: + /// - The salt format is "ChainID , Version ". + /// - The version is obtained from `package.json` using the `ffi` cheatcode: + /// https://book.getfoundry.sh/cheatcodes/ffi + /// - Requires the `jq` CLI installed: https://jqlang.github.io/jq/ + function constructCreate2Salt() public returns (bytes32) { + string memory chainId = block.chainid.toString(); + string[] memory inputs = new string[](4); + inputs[0] = "jq"; + inputs[1] = "-r"; + inputs[2] = ".version"; + inputs[3] = "./package.json"; + bytes memory result = vm.ffi(inputs); + string memory version = string(result); + string memory create2Salt = string.concat("ChainID ", chainId, ", Version ", version); + console2.log("The CREATE2 salt is \"%s\"", create2Salt); + return bytes32(abi.encodePacked(create2Salt)); + } } diff --git a/script/DeployOpenEnded.s.sol b/script/DeployOpenEnded.s.sol new file mode 100644 index 00000000..8627b19d --- /dev/null +++ b/script/DeployOpenEnded.s.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2OpenEnded } from "src/SablierV2OpenEnded.sol"; + +import { BaseScript } from "./Base.s.sol"; + +contract DeployOpenEnded is BaseScript { + function run() public broadcast returns (SablierV2OpenEnded openEnded) { + openEnded = new SablierV2OpenEnded(); + } +} diff --git a/script/DeployOpenEndedDeterministic.s.sol b/script/DeployOpenEndedDeterministic.s.sol new file mode 100644 index 00000000..3b7bed22 --- /dev/null +++ b/script/DeployOpenEndedDeterministic.s.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-3.0-or-later +pragma solidity >=0.8.22 <0.9.0; + +import { SablierV2OpenEnded } from "src/SablierV2OpenEnded.sol"; + +import { BaseScript } from "./Base.s.sol"; + +/// @notice Deploys {SablierV2OpenEnded} at a deterministic address across chains. +/// @dev Reverts if the contract has already been deployed. +contract DeployOpenEnded is BaseScript { + function run() public broadcast returns (SablierV2OpenEnded openEnded) { + openEnded = new SablierV2OpenEnded{ salt: constructCreate2Salt() }(); + } +}