Skip to content

Commit

Permalink
Merge pull request #280 from sablier-labs/feat/util-for-salt
Browse files Browse the repository at this point in the history
feat: add a util function to construct the create2 salt
  • Loading branch information
andreivladbrg authored Feb 7, 2024
2 parents 042412d + 3f3c439 commit 3e6e023
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 7 deletions.
1 change: 1 addition & 0 deletions foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

# Test the optimized contracts without re-compiling them
[profile.test-optimized]
ffi = true
src = "test"

[doc]
Expand Down
30 changes: 29 additions & 1 deletion script/Base.s.sol
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// solhint-disable no-console
pragma solidity >=0.8.19 <0.9.0;

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 {
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";

Expand Down Expand Up @@ -38,4 +44,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 <chainid>, Version <version>".
/// - The version is obtained from `package.json` using the `ffi` cheatcode:
/// https://book.getfoundry.sh/cheatcodes/ffi
/// - Requires `jq` CLI tool 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));
}
}
5 changes: 2 additions & 3 deletions script/DeployDeterministicBatch.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ import { SablierV2Batch } from "../src/SablierV2Batch.sol";
/// @notice Deploys {SablierV2Batch} at a deterministic address across chains.
/// @dev Reverts if the contract has already been deployed.
contract DeployDeterministicBatch is BaseScript {
/// @dev The presence of the salt instructs Forge to deploy contracts via this deterministic CREATE2 factory:
/// https://github.com/Arachnid/deterministic-deployment-proxy
function run(string memory create2Salt) public virtual broadcast returns (SablierV2Batch batch) {
batch = new SablierV2Batch{ salt: bytes32(abi.encodePacked(create2Salt)) }();
bytes32 salt = bytes32(abi.encodePacked(create2Salt));
batch = new SablierV2Batch{ salt: salt }();
}
}
5 changes: 2 additions & 3 deletions script/DeployDeterministicPeriphery.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ import { SablierV2MerkleStreamerFactory } from "../src/SablierV2MerkleStreamerFa
///
/// @dev Reverts if any contract has already been deployed.
contract DeployDeterministicPeriphery is BaseScript {
/// @dev The presence of the salt instructs Forge to deploy the contract via a deterministic CREATE2 factory.
/// https://github.com/Arachnid/deterministic-deployment-proxy
function run(string memory create2Salt)
public
virtual
broadcast
returns (SablierV2Batch batch, SablierV2MerkleStreamerFactory merkleStreamerFactory)
{
batch = new SablierV2Batch{ salt: bytes32(abi.encodePacked(create2Salt)) }();
bytes32 salt = constructCreate2Salt();
batch = new SablierV2Batch{ salt: salt }();
merkleStreamerFactory = new SablierV2MerkleStreamerFactory{ salt: bytes32(abi.encodePacked(create2Salt)) }();
}
}
23 changes: 23 additions & 0 deletions test/utils/BaseScript.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.19 <0.9.0;

import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { PRBTest } from "@prb/test/src/PRBTest.sol";

import { BaseScript } from "script/Base.s.sol";

contract BaseScript_Test is PRBTest {
using Strings for uint256;

BaseScript internal baseScript = new BaseScript();

function test_ConstructCreate2Salt() public {
string memory chainId = block.chainid.toString();
string memory version = "1.1.1";
string memory salt = string.concat("ChainID ", chainId, ", Version ", version);

bytes32 actualSalt = baseScript.constructCreate2Salt();
bytes32 expectedSalt = bytes32(abi.encodePacked(salt));
assertEq(actualSalt, expectedSalt, "CREATE2 salt mismatch");
}
}

0 comments on commit 3e6e023

Please sign in to comment.