-
Notifications
You must be signed in to change notification settings - Fork 453
feat: multichain deployments #1474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 8 commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
7420cbc
feat: add `CrosschainDeployLib` with `CreateX` helpers
0xClandestine 399b539
refactor: cleanup
0xClandestine 3553678
feat: hardcoded release manager deploy script
0xClandestine 0878372
fix: typo
0xClandestine 8be1b2c
refactor: cleanup
0xClandestine 350a0b6
feat: add `deployCrosschainProxy`
0xClandestine a4b4a50
wip
0xClandestine 202afe5
wip
0xClandestine 49e5520
feat: deploy salted with name
0xClandestine 1b22ae0
fix: typo
0xClandestine File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.27; | ||
|
|
||
| import "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol"; | ||
| import "src/contracts/core/ReleaseManager.sol"; | ||
| import "src/contracts/permissions/PermissionController.sol"; | ||
| import "script/utils/CrosschainDeployLib.sol"; | ||
|
|
||
| import "forge-std/Script.sol"; | ||
| import "forge-std/Test.sol"; | ||
|
|
||
| contract DeployFromScratch is Script, Test { | ||
| using CrosschainDeployLib for *; | ||
|
|
||
| Vm cheats = Vm(VM_ADDRESS); | ||
|
|
||
| PermissionController constant permissionController = | ||
| PermissionController(0x0000000000000000000000000000000000000000); | ||
|
|
||
| string semver = "0.0.0"; | ||
|
|
||
| ProxyAdmin proxyAdmin; | ||
|
|
||
| function run() public { | ||
| address emptyContract = CrosschainDeployLib.deployEmptyContract(); | ||
| ReleaseManager proxy = | ||
| ReleaseManager(address(emptyContract.deployCrosschainProxy({salt: bytes11(uint88(0x1234))}))); | ||
| ReleaseManager implementation = new ReleaseManager(permissionController, semver); | ||
| ITransparentUpgradeableProxy(address(proxy)).upgradeTo(address(implementation)); | ||
| ITransparentUpgradeableProxy(address(proxy)).changeAdmin(address(proxyAdmin)); | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,141 @@ | ||
| // SPDX-License-Identifier: BUSL-1.1 | ||
| pragma solidity ^0.8.12; | ||
|
|
||
| import "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol"; | ||
| import "src/test/mocks/EmptyContract.sol"; | ||
|
|
||
| /// @dev https://github.com/pcaversaccio/createx/tree/main | ||
| ICreateX constant createx = ICreateX(0xba5Ed099633D3B313e4D5F7bdc1305d3c28ba5Ed); | ||
|
|
||
| interface ICreateX { | ||
| function deployCreate2(bytes32 salt, bytes memory initCode) external payable returns (address newContract); | ||
| function computeCreate2Address( | ||
| bytes32 salt, | ||
| bytes32 initCodeHash | ||
| ) external view returns (address computedAddress); | ||
| } | ||
|
|
||
| bytes11 constant EMPTY_CONTRACT_SALT = bytes11(uint88(0xffffffffffffffffffffff)); | ||
|
|
||
| library CrosschainDeployLib { | ||
| using CrosschainDeployLib for *; | ||
|
|
||
| /// ----------------------------------------------------------------------- | ||
| /// Write | ||
| /// ----------------------------------------------------------------------- | ||
|
|
||
| /* | ||
| * @notice Deploys a crosschain empty contract. | ||
| * @dev The empty contract MUST stay consistent across all chains/deployments. | ||
| * @dev The empty contract MUST always be deployed with the same salt. | ||
| */ | ||
| function deployEmptyContract() internal returns (address) { | ||
| address computedAddress = | ||
| computeCrosschainAddress(msg.sender, keccak256(type(EmptyContract).creationCode), EMPTY_CONTRACT_SALT); | ||
| if (computedAddress.code.length != 0) return computedAddress; | ||
| return type(EmptyContract).creationCode.deployCrosschain(EMPTY_CONTRACT_SALT); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Deploys a crosschain contract with CreateX. | ||
| * | ||
| * @dev Example usage: | ||
| * ```solidity | ||
| * type(EmptyContract).creationCode.deployCrosschain(EMPTY_CONTRACT_SALT) | ||
| * ``` | ||
| */ | ||
| function deployCrosschain(bytes memory initCode, bytes11 salt) internal returns (address) { | ||
| return createx.deployCreate2(computeProtectedSalt(msg.sender, salt), initCode); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Deploys a crosschain contract using CreateX with the `DEFAULT_SALT`. | ||
| * | ||
| * @dev Example usage: | ||
| * ```solidity | ||
| * address emptyContract = type(EmptyContract).creationCode.deployCrosschain(); | ||
| * ``` | ||
| */ | ||
| function deployCrosschain( | ||
| bytes memory initCode | ||
| ) internal returns (address) { | ||
| return deployCrosschain(initCode, EMPTY_CONTRACT_SALT); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Deploys a crosschain `TransparentUpgradeableProxy` using CreateX. | ||
| * @dev The initial admin is msg.sender. | ||
| * @dev The implementation MUST also be determinstic to ensure the contract can be deployed on all chains. | ||
| * @dev The salt MUST be unique for each proxy deployment sharing the same implementation otherwise address collisions WILL occur. | ||
| * | ||
| * @dev Example usage: | ||
| * ```solidity | ||
| * bytes11 salt = bytes11(uint88(0xffffffffffffffffffffff)); | ||
| * address emptyContract = type(EmptyContract).creationCode.deployCrosschain(); | ||
| * address proxy = emptyContract.deployCrosschainProxy(salt); | ||
| * ITransparentUpgradeableProxy(address(proxy)).upgradeTo(address(implementation)); | ||
| * ITransparentUpgradeableProxy(address(proxy)).changeAdmin(address(admin)); | ||
| * ``` | ||
| */ | ||
| function deployCrosschainProxy( | ||
| address implementation, | ||
| bytes11 salt | ||
| ) internal returns (ITransparentUpgradeableProxy) { | ||
| return ITransparentUpgradeableProxy( | ||
| deployCrosschain(computeUpgradeableProxyInitCode(implementation, msg.sender), salt) | ||
| ); | ||
| } | ||
|
|
||
| /// ----------------------------------------------------------------------- | ||
| /// Helpers | ||
| /// ----------------------------------------------------------------------- | ||
|
|
||
| /* | ||
| * @notice Returns an encoded CreateX salt. | ||
| * @dev The deployer is the only account that can use this salt via CreateX hence the name "protected". | ||
| * @dev The salt is structured as: Deployer EOA (20 bytes) | Cross-chain flag (1 byte) | Entropy (11 bytes) | ||
| * @dev Example: 0xbebebebebebebebebebebebebebebebebebebebe|ff|1212121212121212121212 | ||
| */ | ||
| function computeProtectedSalt(address deployer, bytes11 salt) internal pure returns (bytes32) { | ||
| return bytes32( | ||
| bytes.concat( | ||
| bytes20(deployer), | ||
| bytes1(uint8(1)), // Cross-chain deployments are allowed (0: false, 1: true) | ||
| bytes11(salt) | ||
| ) | ||
| ); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Returns the initialization code for a transparent upgradeable proxy. | ||
| * @dev The returned init code does not include metadata typically appended by the compiler. | ||
| */ | ||
| function computeUpgradeableProxyInitCode( | ||
| address implementation, | ||
| address admin | ||
| ) internal pure returns (bytes memory) { | ||
| return abi.encodePacked(type(TransparentUpgradeableProxy).creationCode, abi.encode(implementation, admin, "")); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Returns the predicted address of a contract deployed with CreateX. | ||
| */ | ||
| function computeCrosschainAddress( | ||
| address deployer, | ||
| bytes32 initCodeHash, | ||
| bytes11 salt | ||
| ) internal view returns (address) { | ||
| return createx.computeCreate2Address(computeProtectedSalt(deployer, salt), initCodeHash); | ||
| } | ||
|
|
||
| /* | ||
| * @notice Returns the predicted address of a `TransparentUpgradeableProxy` deployed with CreateX. | ||
| */ | ||
| function computeCrosschainUpgradeableProxyAddress( | ||
| address implementation, | ||
| address admin, | ||
| bytes11 salt | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: add deterministic salt per contract name. Discussed using FFI offline |
||
| ) internal view returns (address) { | ||
| return computeCrosschainAddress(admin, keccak256(computeUpgradeableProxyInitCode(implementation, admin)), salt); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this to
script/releases