-
Notifications
You must be signed in to change notification settings - Fork 4
Add interface for CrosschainDeployAdapter #5
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 23 commits
Commits
Show all changes
44 commits
Select commit
Hold shift + click to select a range
307845a
feat(wip): foundry init, add interface for CrossChainDeployAdapter
stonecharioteer 716c3de
feat(wip): update computeContractAddress fn definition
stonecharioteer 6b217ae
fix(wip): typo with interfaces, don't use {}
stonecharioteer 8e33f39
fix(wip): fix deploy interface definition
stonecharioteer fd7434c
feat: add CrossChainDeployScript.sol, update the interface with the d…
stonecharioteer 4c2d7a6
chore: rename CrosschainDeployScript file and contract for consistenc…
stonecharioteer bd519d5
feat(wip): fix function calls and type for callData
stonecharioteer 3636d7a
chore(wip): remove FIXME
stonecharioteer 40f2c07
feat(wip): update justfile with some more planned tools
stonecharioteer 88bc0b1
feat(wip): add `value` to `deploy` call so that it gets the payment.
stonecharioteer ea929d5
feat(wip): track deployment targets using an array and store the avai…
stonecharioteer 70206c9
feat(wip): cleanup docstrings, fix typos
stonecharioteer fe7a0da
feat(wip): implement computeAddressForChain
stonecharioteer 06773c5
feat(wip): map constructorArgs and initDatas separately as well
stonecharioteer 367fbb9
feat(wip): use arrays to store a list of constructor args and init da…
stonecharioteer be4c339
feat(wip): remove unused domain IDs from the constructor
stonecharioteer 60dedd4
chore(wip): remove unnecessary custom error situation
stonecharioteer 444eba6
feat(wip): add generateSalt
stonecharioteer 8b12528
chore(wip): move deployment target check to modifier
stonecharioteer 456569e
fix(wip): use generateSalt instead of asking users to provide the salt
stonecharioteer fd883f4
fix(wip): increment randomness counter
stonecharioteer f219167
feat(wip): fix function signature for computeContractAddress, and cal…
stonecharioteer 7df5ba6
chore(wip): purge the deployment targets after deploying
stonecharioteer b4685f3
fix(wip): rename functions for uniformity, fix array reset syntax to …
stonecharioteer 25a70c2
chore(wip): update justfile to use forge's native `watch` flag
stonecharioteer 4c62035
feat(wip): add unit tests and a mock for adapter
stonecharioteer 1919e87
docs(wip): Update README to show how to use this, and also add some d…
stonecharioteer 3ce7924
feat(wip): add integration test, test steps to justfile
stonecharioteer b6998f8
feat(wip): add support for .env file for the justfile and use it for …
stonecharioteer b4b6ca5
chore: update justfile to not use private key for integration tests.
stonecharioteer f82c1e5
feat(wip): fix argument for constructor and initdata
stonecharioteer b124e3c
feat(wip): fix argument for constructor and initdata
stonecharioteer e57869d
feat(wip): Move reset steps into a new function so users can choose t…
stonecharioteer ed494e0
feat(wip): add `vm.expectCall` to ensure contract calls
stonecharioteer b926e2c
feat(wip): Add multiple deployment targets & args
stonecharioteer 05912cd
docs(wip): update README to show how to encode arguments
stonecharioteer 5105657
Update README.md
stonecharioteer 63bbcb4
docs(wip): update with installation instructions
stonecharioteer 45ccc31
docs(wip): update with link to forge install docs
stonecharioteer 59eafcf
docs(wip): update the usage example to show how to inherit from this …
stonecharioteer 749ef6a
fix: warnings and stack too deep errors. move contract name to deploy…
mpetrunic 73fdcda
update readme
mpetrunic 2581da3
add env, remove contract address calculation, add link to sygma explorer
mpetrunic e2ef7f5
more unit tests
mpetrunic 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,34 @@ | ||
| name: test | ||
|
|
||
| on: workflow_dispatch | ||
|
|
||
| env: | ||
| FOUNDRY_PROFILE: ci | ||
|
|
||
| jobs: | ||
| check: | ||
| strategy: | ||
| fail-fast: true | ||
|
|
||
| name: Foundry project | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| with: | ||
| submodules: recursive | ||
|
|
||
| - name: Install Foundry | ||
| uses: foundry-rs/foundry-toolchain@v1 | ||
| with: | ||
| version: nightly | ||
|
|
||
| - name: Run Forge build | ||
| run: | | ||
| forge --version | ||
| forge build --sizes | ||
| id: build | ||
|
|
||
| - name: Run Forge tests | ||
| run: | | ||
| forge test -vvv | ||
| id: test |
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
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,3 @@ | ||
| [submodule "lib/forge-std"] | ||
| path = lib/forge-std | ||
| url = https://github.com/foundry-rs/forge-std |
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 |
|---|---|---|
| @@ -1 +1,9 @@ | ||
| # foundry-multichain-deploy | ||
| # foundry-multichain-deploy | ||
|
|
||
| Provides `foundry` tooling for the multichain deployment contract built atop of Sygma. See [ChainSafe/hardhat-plugin-multichain-deploy]("https://github.com/ChainSafe/hardhat-plugin-multichain-deploy") for more details. | ||
|
|
||
| ## Development | ||
|
|
||
| [Install foundry](https://book.getfoundry.sh/getting-started/installation) and [`just`](https://github.com/casey/just). | ||
|
|
||
| Check the `justfile` for more instructions on how to run this project. Run `just --list` to see all the options. |
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,6 @@ | ||
| [profile.default] | ||
| src = "src" | ||
| out = "out" | ||
| libs = ["lib"] | ||
|
|
||
| # See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options |
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,33 @@ | ||
| set shell:=["bash", "-uc"] | ||
|
|
||
|
|
||
| # build the contracts | ||
| build: | ||
| forge build | ||
|
|
||
| # format source | ||
| fmt: | ||
| forge fmt | ||
|
|
||
|
|
||
| # watches the directory for changes and rebuilds. Needs `watchexec` - https://github.com/watchexec/watchexec. This is useful when developing contracts. | ||
| watch-build: | ||
| watchexec just fmt build | ||
|
|
||
| deploy-anvil: build | ||
| echo "Unimplemented" >&2 | ||
| exit 1 | ||
|
|
||
| deploy-sepolia: build | ||
| echo "Unimplemented" >&2 | ||
| exit 1 | ||
|
|
||
|
|
||
| # Builds locally using docker (useful for debugging dependency issues) | ||
| docker-build: | ||
| echo "Unimplemented" >&2 | ||
| exit 1 | ||
|
|
||
| docker-test: docker-build | ||
| echo "Unimplemented" >&2 | ||
| exit 1 |
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,153 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| pragma solidity 0.8.20; | ||
|
|
||
| import {Script} from "forge-std/Script.sol"; | ||
| import {ICrosschainDeployAdapter} from "./interfaces/CrosschainDeployAdapterInterface.sol"; | ||
|
|
||
| /** | ||
| * @title Provides a script to allow users to call the multichain deployment contract defined in `CrossChainDeployAdapter` from chainsafe/hardhat-plugin-multichain-deploy, passing it the contract bytecode and constructor arguments. | ||
| * @author ChainSafe Systems | ||
| */ | ||
| contract CrosschainDeployScript is Script { | ||
| // this is the address of the original contract defined in chainsafe/hardhat-plugin-multichain-deploy | ||
| // this address is the same across all chains | ||
| address private constant CROSS_CHAIN_DEPLOY_CONTRACT_ADDRESS = 0x85d62AD850B322152BF4ad9147bfBF097DA42217; | ||
|
|
||
| struct NetworkIds { | ||
| uint8 InternalDomainId; | ||
| uint256 ChainId; | ||
| } | ||
|
|
||
| // given a string, obtain the domain ID; | ||
| // https://www.notion.so/chainsafe/Testnet-deployment-0483991cf1ac481593d37baf8d48712a | ||
| mapping(string => NetworkIds) private _stringToNetworkIds; | ||
|
|
||
| // NOTE: All three of these need to be stored in the same order since they've | ||
| // a shared index. Storing them in a mapping isn't gas-efficient since I'd | ||
| // have to loop over these to build these arrays later, and that would not | ||
| // translate to a `bytes[] memory` object, which is what the contract method needs. | ||
| // Explicit conversion is a waste of gas. | ||
| // store the domain IDs | ||
| uint8[] private _domainIds; | ||
| // store the constructor args. | ||
| bytes[] private _constructorArgs; | ||
| // store the init datas; | ||
| bytes[] private _initDatas; | ||
| // store the chain ids | ||
| uint256[] private _chainIds; | ||
|
|
||
| uint8 private _randomCounter; | ||
|
|
||
| constructor() { | ||
| _stringToNetworkIds["goerli"] = NetworkIds(1, 5); | ||
| _stringToNetworkIds["sepolia"] = NetworkIds(2, 11155111); | ||
| _stringToNetworkIds["cronos-testnet"] = NetworkIds(5, 338); | ||
| _stringToNetworkIds["holesky"] = NetworkIds(6, 17000); | ||
| _stringToNetworkIds["mumbai"] = NetworkIds(7, 80001); | ||
| _stringToNetworkIds["arbitrum-sepolia"] = NetworkIds(8, 421614); | ||
| _stringToNetworkIds["gnosis-chiado"] = NetworkIds(9, 10200); | ||
| } | ||
|
|
||
| /** | ||
| * This function willl take the network, constructor args and initdata and | ||
| * save these to a mapping (what type?) | ||
| */ | ||
| function addDeploymentTarget(string memory deploymentTarget, bytes memory constructorArgs, bytes memory initData) | ||
|
mpetrunic marked this conversation as resolved.
|
||
| public | ||
| { | ||
| NetworkIds memory deploymentTargetNetworkIds = _stringToNetworkIds[deploymentTarget]; | ||
| uint8 deploymentTargetDomainId = deploymentTargetNetworkIds.InternalDomainId; | ||
| require(deploymentTargetDomainId != 0, "Invalid deployment target"); | ||
| _domainIds.push(deploymentTargetDomainId); | ||
| uint256 deploymentTargetChainId = deploymentTargetNetworkIds.ChainId; | ||
| _chainIds.push(deploymentTargetChainId); | ||
| _constructorArgs.push(constructorArgs); | ||
| _initDatas.push(initData); | ||
| } | ||
|
|
||
| /** | ||
| * @notice this function takes in the contract string, in the form that | ||
| * @notice `forge`'s `getCode` takes it, along with some other parameters and passes | ||
| * @notice it along to the `deploy` function of the `CrossChainDeployAdapter` | ||
| * @notice contract. | ||
| * @param contractString Contract name in the form of `ContractFile.sol`, if the name of the contract and the file are the same, or `ContractFile.sol:ContractName` if they are different. | ||
| * @param gasLimit Contract deploy and init gas. | ||
| * @param isUniquePerChain True to have unique addresses on every chain. | ||
| * Users call this function and pass only the function call string as | ||
| * `MyContract.sol:MyContract`. The function call string is then parsed | ||
| * and the `callData` and `bytesCode` are extracted from it. | ||
| * and the contract is deployed on the other chains. | ||
| */ | ||
| function deploy(string calldata contractString, uint256 gasLimit, bool isUniquePerChain) | ||
| // uint8[] memory destinationDomainIDs | ||
|
mpetrunic marked this conversation as resolved.
Outdated
|
||
| public | ||
| payable | ||
| hasDeploymentTargets | ||
| returns (address[] memory) | ||
| { | ||
| // We use the contractString to get the bytecode of the contract, | ||
| // reference: https://book.getfoundry.sh/cheatcodes/get-code | ||
| bytes memory deployByteCode = vm.getCode(contractString); | ||
| bytes32 salt = generateSalt(); | ||
| uint256[] memory fees = ICrosschainDeployAdapter(CROSS_CHAIN_DEPLOY_CONTRACT_ADDRESS).calculateDeployFee( | ||
| deployByteCode, gasLimit, salt, isUniquePerChain, _constructorArgs, _initDatas, _domainIds | ||
| ); | ||
| uint256 totalFee; | ||
| uint256 feesArrayLength = fees.length; | ||
| for (uint256 j = 0; j < feesArrayLength; j++) { | ||
| uint256 fee = fees[j]; | ||
| totalFee += fee; | ||
| } | ||
| ICrosschainDeployAdapter(CROSS_CHAIN_DEPLOY_CONTRACT_ADDRESS).deploy{value: totalFee}( | ||
| deployByteCode, gasLimit, salt, isUniquePerChain, _constructorArgs, _initDatas, _domainIds, fees | ||
| ); | ||
| address[] memory contractAddresses = new address[](_chainIds.length); | ||
| for (uint256 k = 0; k < _chainIds.length; k++) { | ||
| address contractAddress = ICrosschainDeployAdapter(CROSS_CHAIN_DEPLOY_CONTRACT_ADDRESS) | ||
| .computeContractAddressForChain(msg.sender, salt, isUniquePerChain, _chainIds[k]); | ||
|
mpetrunic marked this conversation as resolved.
Outdated
|
||
| contractAddresses[k] = contractAddress; | ||
| } | ||
| // purge the deployment targets now. | ||
| _constructorArgs = []; | ||
| _initDatas = []; | ||
| _domainIds = []; | ||
| _chainIds = []; | ||
|
|
||
| return contractAddresses; | ||
| } | ||
|
|
||
| // returns a pseudorandom bytes32 | ||
| function generateSalt() public returns (bytes32) { | ||
| _randomCounter++; | ||
| return keccak256(abi.encodePacked(block.prevrandao, block.timestamp, msg.sender, _randomCounter)); | ||
| } | ||
|
|
||
| // what does this do? | ||
| function encodeInitData() public {} | ||
|
|
||
| modifier hasDeploymentTargets() { | ||
| // check that the user has added deployment networks by calling `addDeploymentTarget` | ||
| uint256 deploymentNetworksCount = _domainIds.length; | ||
| require(deploymentNetworksCount > 0, "Need to add deployment targets. Use `addDeploymentTarget` first"); | ||
| _; | ||
| } | ||
| /** | ||
| * @notice Computes the address where the contract will be deployed on this chain. | ||
| * @param sender Address that requested deploy. | ||
| * @param salt Entropy for contract address generation. | ||
| * @param isUniquePerChain True to have unique addresses on every chain. | ||
| * @param chainId the ID of the chain on which to deploy the contract | ||
| * @return Address where the contract will be deployed on this chain. | ||
| */ | ||
|
|
||
| function computeAddressForChain(address sender, bytes32 salt, bool isUniquePerChain, uint256 chainId) | ||
|
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. Maybe also useful to have this function with network name instead of chainId?
Contributor
Author
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. YEah, that's a good idea. Changed it. |
||
| external | ||
| view | ||
| returns (address) | ||
| { | ||
| return ICrosschainDeployAdapter(CROSS_CHAIN_DEPLOY_CONTRACT_ADDRESS).computeContractAddressForChain( | ||
| sender, salt, isUniquePerChain, chainId | ||
| ); | ||
| } | ||
| } | ||
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,36 @@ | ||
| // SPDX-License-Identifier: LGPL-3.0-only | ||
|
|
||
| pragma solidity 0.8.20; | ||
|
|
||
| /** | ||
| * @title Provides an interface to the CrosschainDeployAdapter from chainsafe/hardhat-plugin-multichain-deploy | ||
| * @author ChainSafe Systems. | ||
| * @notice The original contract in question is intended to be used with the Bridge contract and Permissionless Generic Handler | ||
| */ | ||
| interface ICrosschainDeployAdapter { | ||
| function deploy( | ||
| bytes calldata deployBytecode, | ||
| uint256 gasLimit, | ||
| bytes32 salt, | ||
| bool isUniquePerChain, | ||
| bytes[] memory constructorArgs, | ||
| bytes[] memory initDatas, | ||
| uint8[] memory destinationDomainIDs, | ||
| uint256[] memory fees | ||
| ) external payable; | ||
|
|
||
| function computeContractAddressForChain(address sender, bytes32 salt, bool isUniquePerChain, uint256 chainId) | ||
| external | ||
| view | ||
| returns (address); | ||
|
|
||
| function calculateDeployFee( | ||
| bytes calldata deployBytecode, | ||
| uint256 gasLimit, | ||
| bytes32 salt, | ||
| bool isUniquePerChain, | ||
| bytes[] memory constructorArgs, | ||
| bytes[] memory initDatas, | ||
| uint8[] memory destinationDomainIds | ||
| ) external view returns (uint256[] memory fees); | ||
| } |
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.
Uh oh!
There was an error while loading. Please reload this page.