Skip to content
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ Approach:
- Zoltu deterministic deployment proxy: same address on every supported network.
- Caller-provided supported-network and dependency lists.
- Hard guards against deploying to networks where dependencies are missing.
- Pre-calculated addresses asserted post-deploy: silent failures fail loudly.
- Pre-calculated addresses asserted against the creation code before deploying,
and against the chain after: silent failures fail loudly.
- Bytecode integrity checks (e.g. via the Rain Extrospection lib) supported
post-deploy.

Expand Down
35 changes: 33 additions & 2 deletions src/lib/LibRainDeploy.sol
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,20 @@ library LibRainDeploy {
vm.etch(ZOLTU_FACTORY, ZOLTU_FACTORY_BYTECODE);
}

/// Derives the address the Zoltu factory deploys the given creation code
/// to. The factory is CREATE2 over its calldata with a zero salt, so the
/// address is a pure function of the creation code and is identical on
/// every network.
/// @param creationCode The creation code to derive the address for.
/// @return The address the creation code deploys to.
function zoltuAddress(bytes memory creationCode) internal pure returns (address) {
return address(
uint160(
uint256(keccak256(abi.encodePacked(bytes1(0xff), ZOLTU_FACTORY, bytes32(0), keccak256(creationCode))))
)
);
}

/// Deploys the given creation code via the Zoltu factory.
/// Handles the return data and errors appropriately.
/// @param creationCode The creation code to deploy.
Expand Down Expand Up @@ -185,6 +199,11 @@ library LibRainDeploy {
}

/// Deploys the given creation code to each network via the Zoltu factory.
/// `expectedAddress` MUST be the address the Zoltu factory derives for
/// `creationCode`, which is checked before any network is forked, so an
/// expected address that disagrees with the creation code fails loudly
/// rather than matching some other contract already deployed there and
/// skipping every network.
/// For each network it forks once, verifies the Zoltu factory and every
/// dependency have code (the factory codehash must also match), then
/// broadcasts the deploy on that same fork. If code already exists at
Expand All @@ -201,7 +220,8 @@ library LibRainDeploy {
/// @param deployer The deployer address.
/// @param creationCode The creation code to deploy.
/// @param contractPath The contract path for verification commands.
/// @param expectedAddress The expected deterministic address.
/// @param expectedAddress The expected deterministic address, which MUST be
/// the address the Zoltu factory derives for `creationCode`.
/// @param expectedCodeHash The expected code hash of the deployed contract.
/// @param dependencies The addresses that must have code on each network.
/// @return deployedAddress The deployed contract address.
Expand All @@ -218,6 +238,16 @@ library LibRainDeploy {
if (networks.length == 0) {
revert NoNetworks();
}
// The Zoltu factory deploys the given creation code to a single
// deterministic address on every network, so an expected address that
// disagrees with the creation code can never hold that code. Checked
// up front, before any fork, because otherwise a network that already
// has some other contract at the expected address takes the skip
// branch and reports success without ever deploying.
address derivedAddress = zoltuAddress(creationCode);
if (derivedAddress != expectedAddress) {
revert UnexpectedDeployedAddress(expectedAddress, derivedAddress);
}
for (uint256 i = 0; i < networks.length; i++) {
// createSelectFork returns a fork id that is not needed here; bind
// and reference it so the unused-return lint stays satisfied.
Expand Down Expand Up @@ -282,7 +312,8 @@ library LibRainDeploy {
/// @param deployerPrivateKey The private key to use for broadcasting.
/// @param creationCode The creation code to deploy.
/// @param contractPath The contract path for verification commands.
/// @param expectedAddress The expected deterministic address.
/// @param expectedAddress The expected deterministic address, which MUST be
/// the address the Zoltu factory derives for `creationCode`.
/// @param expectedCodeHash The expected code hash of the deployed contract.
/// @param dependencies The dependency addresses to check.
/// @return deployedAddress The address of the deployed contract.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity ^0.8.25;
pragma solidity =0.8.25;

/// @title MockDeployable
/// Minimal contract used as a deployment target for Zoltu factory tests.
Expand Down
16 changes: 16 additions & 0 deletions test/concrete/MockDeployableV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity =0.8.25;

/// @title MockDeployableV2
/// Deployment target whose creation code differs from `MockDeployable`, so the
/// two derive different Zoltu addresses. Stands in for a contract whose
/// bytecode has changed while its pinned constants have not.
contract MockDeployableV2 {
/// @notice Placeholder value to ensure the contract has non-trivial code.
uint256 public value = 43;

/// @notice Second placeholder value so the runtime code also differs from
/// `MockDeployable`.
uint256 public other = 99;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: LicenseRef-DCL-1.0
// SPDX-FileCopyrightText: Copyright (c) 2020 Rain Open Source Software Ltd
pragma solidity ^0.8.25;
pragma solidity =0.8.25;

/// @title MockReverter
/// Contract whose constructor always reverts, used to test DeployFailed with
Expand Down
Loading
Loading