diff --git a/.changeset/spotty-rivers-impress.md b/.changeset/spotty-rivers-impress.md new file mode 100644 index 000000000..aaf60c920 --- /dev/null +++ b/.changeset/spotty-rivers-impress.md @@ -0,0 +1,7 @@ +--- +'@chugsplash/contracts': patch +'@chugsplash/core': patch +'@chugsplash/plugins': patch +--- + +Use creation bytecode instead of the `DEPLOY_CODE_PREFIX` to deploy implementation contracts for Etherscan compatibility diff --git a/packages/contracts/contracts/ChugSplashManager.sol b/packages/contracts/contracts/ChugSplashManager.sol index 50dc5ea57..1798a5c95 100644 --- a/packages/contracts/contracts/ChugSplashManager.sol +++ b/packages/contracts/contracts/ChugSplashManager.sol @@ -16,11 +16,14 @@ import { IProxyAdapter } from "./IProxyAdapter.sol"; import { ProxyUpdater } from "./ProxyUpdater.sol"; import { Create2 } from "./libraries/Create2.sol"; import { MerkleTree } from "./libraries/MerkleTree.sol"; +import { + ReentrancyGuardUpgradeable +} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; /** * @title ChugSplashManager */ -contract ChugSplashManager is OwnableUpgradeable { +contract ChugSplashManager is OwnableUpgradeable, ReentrancyGuardUpgradeable { /** * @notice Emitted when a ChugSplash bundle is proposed. * @@ -136,12 +139,6 @@ contract ChugSplashManager is OwnableUpgradeable { bytes32 internal constant EIP1967_IMPLEMENTATION_KEY = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; - /** - * @notice "Magic" prefix. When prepended to some arbitrary runtime bytecode and used to create - * a contract, the appended bytecode will be deployed as given. - */ - bytes13 internal constant DEPLOY_CODE_PREFIX = 0x600D380380600D6000396000f3; - /** * @notice Address of the ChugSplashRegistry. */ @@ -397,8 +394,9 @@ contract ChugSplashManager is OwnableUpgradeable { /** * @notice Executes a specific action within the current active bundle for a project. Actions - * can only be executed once. If executing this action would complete the bundle, will - * mark the bundle as completed and make it possible for a new bundle to be approved. + * can only be executed once. A re-entrancy guard is added to prevent an implementation + * contract's constructor from calling another contract which in turn calls back into + * this function. * * @param _action Action to execute. * @param _actionIndex Index of the action in the bundle. @@ -408,7 +406,7 @@ contract ChugSplashManager is OwnableUpgradeable { ChugSplashAction memory _action, uint256 _actionIndex, bytes32[] memory _proof - ) public { + ) public nonReentrant { uint256 initialGasLeft = gasleft(); require( @@ -788,34 +786,14 @@ contract ChugSplashManager is OwnableUpgradeable { * interacting with a proxy whose storage has not fully been initialized. * * @param _target Target that corresponds to the implementation. - * @param _code Runtime bytecode of the implementation to be deployed. + * @param _code Creation bytecode of the implementation contract. */ function _deployImplementation(string memory _target, bytes memory _code) internal { - // TODO: Add a re-entrancy guard to this function if we move away from using - // `DEPLOY_CODE_PREFIX`. There is currently no risk of re-entrancy because the prefix - // guarantees that no sub-calls can be made in the implementation contract's constructor. In - // the future, we might want to move away from the prefix to add support for constructors - // that can run arbitrary creation bytecode. It will then become become necessary to add a - // re-entrancy guard to prevent a constructor from calling another contract which in turn - // calls back into deployImplementation or setStorage. - - // Create the deploycode by prepending the magic prefix to the runtime bytecode. - bytes memory deploycode = abi.encodePacked(DEPLOY_CODE_PREFIX, _code); - address implementation; assembly { - implementation := create(0x0, add(deploycode, 0x20), mload(deploycode)) + implementation := create2(0x0, add(_code, 0x20), mload(_code), 0x0) } - // Check that the code was actually deployed correctly. It might be impossible to fail this - // check. Should only happen if the contract creation from above runs out of gas but this - // parent execution thread does NOT run out of gas. Seems like we should be doing this check - // anyway though. - require( - _getAccountCodeHash(implementation) == keccak256(_code), - "ChugSplashManager: code was not correctly deployed" - ); - // Set the target to its newly deployed implementation. implementations[_target] = implementation; } diff --git a/packages/contracts/test/ChugSplashManager.t.sol b/packages/contracts/test/ChugSplashManager.t.sol index 0590e3faa..eea867289 100644 --- a/packages/contracts/test/ChugSplashManager.t.sol +++ b/packages/contracts/test/ChugSplashManager.t.sol @@ -66,34 +66,24 @@ contract ChugSplashManager_Test is Test { 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; ChugSplashAction[] actions; - uint256[5] actionIndexes = [0, 1, 2, 3, 4]; + uint256[3] actionIndexes = [0, 1, 2]; bytes32[][] proofs = [ [ - bytes32(0xf539d9cfd2f6cfd83005272cc243415442566202271f3f3a3b28a1fa79eab380), - bytes32(0xd33f38d8e7717c42f56fd69bd89d1cd342db4dbcd5dc9b6f6ee9d4218dba12ca), - bytes32(0x5b9583f6f66c6cf60306fd44a7c099f3f909696845eca2535f93f6e652990f9b) + bytes32(0x9ef420ca34e65ccc237ad848489a9cbd981fafa6149ff4ab1a580f6fee74cc8d), + bytes32(0x65270d352485b005d92e8f8ac8cf10b7219be4e2698fe30a4fada427ad5f18bd) ], [ - bytes32(0x87be4989370b875185d46cf43d02f59cd61f068ad3acc2d43d2f6216085fbaff), - bytes32(0xd33f38d8e7717c42f56fd69bd89d1cd342db4dbcd5dc9b6f6ee9d4218dba12ca), - bytes32(0x5b9583f6f66c6cf60306fd44a7c099f3f909696845eca2535f93f6e652990f9b) - ], - [ - bytes32(0xe321b2956757a1fb8900391f73dd458c220deebdcd59df71afd1db74c5b0d188), - bytes32(0x6617fc8c8fcf99c45dd175b357de082de4df28db1d9ae135c25ddef820a2027b), - bytes32(0x5b9583f6f66c6cf60306fd44a7c099f3f909696845eca2535f93f6e652990f9b) - ], - [ - bytes32(0x73c8aae26938675cf88daa0cd76d20350425311fbb264b6c369b6f62c51753b1), - bytes32(0x6617fc8c8fcf99c45dd175b357de082de4df28db1d9ae135c25ddef820a2027b), - bytes32(0x5b9583f6f66c6cf60306fd44a7c099f3f909696845eca2535f93f6e652990f9b) + bytes32(0x651679e022c1442620c92d5866e72525eadd105427745782b5923d1f5a383087), + bytes32(0x65270d352485b005d92e8f8ac8cf10b7219be4e2698fe30a4fada427ad5f18bd) ], [ bytes32(0x290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e563), - bytes32(0x633dc4d7da7256660a892f8f1604a44b5432649cc8ec5cb3ced4c4e6ac94dd1d), - bytes32(0x34a7560c84331917a9447a4c46b264e415ff532b5c6977123ba682081de9e8e9) + bytes32(0x0c88ea174f64e74049bc6e056e3f2a3945cbbbc7c12cd2859495aab96a1d361d) ] ]; + string configUri = "ipfs://QmXdc7np4jdkHLwrumWXHhy9adK4qYsqEFX9VkEdBqMpPm"; + bytes32 bundleId = 0xacdebe08df0d7c9650dfca6191bc88c5a50eb099b18d5cfa663e6f0f11165e2b; + bytes32 bundleRoot = 0xbe5e67004de3ec5f536e2b5d1ccb2d6d924956a55a866706e97b671f33a8b648; address owner = address(128); address nonOwner = address(256); @@ -107,9 +97,6 @@ contract ChugSplashManager_Test is Test { uint256 executorBondAmount = 1 ether; uint256 executionLockTime = 15 minutes; uint256 executorPaymentPercentage = 20; - string configUri = "ipfs://QmcEeWAg8JXuzLYj4M2DUT12EM63epDPS8XzSa9YKTEe5t"; - bytes32 bundleId = 0xb6e2353b745f3f0696f786ad60124e48e15c903cdc85ee623a25f5dee8d5f18d; - bytes32 bundleRoot = 0x1353da0ad8f49ed7386a7258615dcdf904404ae699cd956e8f7a71979b47cdc9; uint256 bundleSize = actionIndexes.length; ChugSplashAction firstAction; ChugSplashAction secondAction; @@ -125,42 +112,28 @@ contract ChugSplashManager_Test is Test { function setUp() external { firstAction = ChugSplashAction({ - target: "MyToken", + target: "SecondSimpleStorage", actionType: ChugSplashActionType.DEPLOY_IMPLEMENTATION, - data: hex"608060405234801561001057600080fd5b50600436106100cf5760003560e01c806340c10f191161008c57806395d89b411161006657806395d89b4114610228578063a9059cbb14610246578063d505accf14610276578063dd62ed3e14610292576100cf565b806340c10f19146101ac57806370a08231146101c85780637ecebe00146101f8576100cf565b806306fdde03146100d4578063095ea7b3146100f257806318160ddd1461012257806323b872dd14610140578063313ce567146101705780633644e5151461018e575b600080fd5b6100dc6102c2565b6040516100e99190610e06565b60405180910390f35b61010c60048036038101906101079190610ec1565b610350565b6040516101199190610f1c565b60405180910390f35b61012a610442565b6040516101379190610f46565b60405180910390f35b61015a60048036038101906101559190610f61565b610448565b6040516101679190610f1c565b60405180910390f35b610178610692565b6040516101859190610fd0565b60405180910390f35b6101966106b6565b6040516101a39190611004565b60405180910390f35b6101c660048036038101906101c19190610ec1565b610713565b005b6101e260048036038101906101dd919061101f565b610721565b6040516101ef9190610f46565b60405180910390f35b610212600480360381019061020d919061101f565b610739565b60405161021f9190610f46565b60405180910390f35b610230610751565b60405161023d9190610e06565b60405180910390f35b610260600480360381019061025b9190610ec1565b6107df565b60405161026d9190610f1c565b60405180910390f35b610290600480360381019061028b91906110a4565b6108f3565b005b6102ac60048036038101906102a79190611146565b610bec565b6040516102b99190610f46565b60405180910390f35b600080546102cf906111b5565b80601f01602080910402602001604051908101604052809291908181526020018280546102fb906111b5565b80156103485780601f1061031d57610100808354040283529160200191610348565b820191906000526020600020905b81548152906001019060200180831161032b57829003601f168201915b505050505081565b600081600460003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925846040516104309190610f46565b60405180910390a36001905092915050565b60025481565b600080600460008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000205490507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff811461057e5782816104fd9190611215565b600460008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020819055505b82600360008773ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546105cd9190611215565b9250508190555082600360008673ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508373ffffffffffffffffffffffffffffffffffffffff168573ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8560405161067e9190610f46565b60405180910390a360019150509392505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b60007f000000000000000000000000000000000000000000000000000000000000000046146106ec576106e7610c11565b61070e565b7f00000000000000000000000000000000000000000000000000000000000000005b905090565b61071d8282610c9d565b5050565b60036020528060005260406000206000915090505481565b60056020528060005260406000206000915090505481565b6001805461075e906111b5565b80601f016020809104026020016040519081016040528092919081815260200182805461078a906111b5565b80156107d75780601f106107ac576101008083540402835291602001916107d7565b820191906000526020600020905b8154815290600101906020018083116107ba57829003601f168201915b505050505081565b600081600360003373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008282546108309190611215565b9250508190555081600360008573ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516108e19190610f46565b60405180910390a36001905092915050565b42841015610936576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161092d90611295565b60405180910390fd5b600060016109426106b6565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98a8a8a600560008f73ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000815480929190600101919050558b6040516020016109ca969594939291906112c4565b604051602081830303815290604052805190602001206040516020016109f192919061139d565b6040516020818303038152906040528051906020012085858560405160008152602001604052604051610a2794939291906113d4565b6020604051602081039080840390855afa158015610a49573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614158015610abd57508773ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b610afc576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610af390611465565b60405180910390fd5b85600460008373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060008973ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002081905550508573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92587604051610bdb9190610f46565b60405180910390a350505050505050565b6004602052816000526040600020602052806000526040600020600091509150505481565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051610c439190611524565b60405180910390207fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc64630604051602001610c8295949392919061153b565b60405160208183030381529060405280519060200120905090565b8060026000828254610caf919061158e565b9250508190555080600360008473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600082825401925050819055508173ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef83604051610d619190610f46565b60405180910390a35050565b600081519050919050565b600082825260208201905092915050565b60005b83811015610da7578082015181840152602081019050610d8c565b83811115610db6576000848401525b50505050565b6000601f19601f8301169050919050565b6000610dd882610d6d565b610de28185610d78565b9350610df2818560208601610d89565b610dfb81610dbc565b840191505092915050565b60006020820190508181036000830152610e208184610dcd565b905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610e5882610e2d565b9050919050565b610e6881610e4d565b8114610e7357600080fd5b50565b600081359050610e8581610e5f565b92915050565b6000819050919050565b610e9e81610e8b565b8114610ea957600080fd5b50565b600081359050610ebb81610e95565b92915050565b60008060408385031215610ed857610ed7610e28565b5b6000610ee685828601610e76565b9250506020610ef785828601610eac565b9150509250929050565b60008115159050919050565b610f1681610f01565b82525050565b6000602082019050610f316000830184610f0d565b92915050565b610f4081610e8b565b82525050565b6000602082019050610f5b6000830184610f37565b92915050565b600080600060608486031215610f7a57610f79610e28565b5b6000610f8886828701610e76565b9350506020610f9986828701610e76565b9250506040610faa86828701610eac565b9150509250925092565b600060ff82169050919050565b610fca81610fb4565b82525050565b6000602082019050610fe56000830184610fc1565b92915050565b6000819050919050565b610ffe81610feb565b82525050565b60006020820190506110196000830184610ff5565b92915050565b60006020828403121561103557611034610e28565b5b600061104384828501610e76565b91505092915050565b61105581610fb4565b811461106057600080fd5b50565b6000813590506110728161104c565b92915050565b61108181610feb565b811461108c57600080fd5b50565b60008135905061109e81611078565b92915050565b600080600080600080600060e0888a0312156110c3576110c2610e28565b5b60006110d18a828b01610e76565b97505060206110e28a828b01610e76565b96505060406110f38a828b01610eac565b95505060606111048a828b01610eac565b94505060806111158a828b01611063565b93505060a06111268a828b0161108f565b92505060c06111378a828b0161108f565b91505092959891949750929550565b6000806040838503121561115d5761115c610e28565b5b600061116b85828601610e76565b925050602061117c85828601610e76565b9150509250929050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b600060028204905060018216806111cd57607f821691505b6020821081036111e0576111df611186565b5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600061122082610e8b565b915061122b83610e8b565b92508282101561123e5761123d6111e6565b5b828203905092915050565b7f5045524d49545f444541444c494e455f45585049524544000000000000000000600082015250565b600061127f601783610d78565b915061128a82611249565b602082019050919050565b600060208201905081810360008301526112ae81611272565b9050919050565b6112be81610e4d565b82525050565b600060c0820190506112d96000830189610ff5565b6112e660208301886112b5565b6112f360408301876112b5565b6113006060830186610f37565b61130d6080830185610f37565b61131a60a0830184610f37565b979650505050505050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611366600283611325565b915061137182611330565b600282019050919050565b6000819050919050565b61139761139282610feb565b61137c565b82525050565b60006113a882611359565b91506113b48285611386565b6020820191506113c48284611386565b6020820191508190509392505050565b60006080820190506113e96000830187610ff5565b6113f66020830186610fc1565b6114036040830185610ff5565b6114106060830184610ff5565b95945050505050565b7f494e56414c49445f5349474e4552000000000000000000000000000000000000600082015250565b600061144f600e83610d78565b915061145a82611419565b602082019050919050565b6000602082019050818103600083015261147e81611442565b9050919050565b600081905092915050565b60008190508160005260206000209050919050565b600081546114b2816111b5565b6114bc8186611485565b945060018216600081146114d757600181146114e85761151b565b60ff1983168652818601935061151b565b6114f185611490565b60005b83811015611513578154818901526001820191506020810190506114f4565b838801955050505b50505092915050565b600061153082846114a5565b915081905092915050565b600060a0820190506115506000830188610ff5565b61155d6020830187610ff5565b61156a6040830186610ff5565b6115776060830185610f37565b61158460808301846112b5565b9695505050505050565b600061159982610e8b565b91506115a483610e8b565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156115d9576115d86111e6565b5b82820190509291505056fea26469706673582212204b5b201d52d98beb54a59dcb666e4fb3836ce5490fc24bc297d611a24030c05864736f6c634300080d0033" + data: hex"60e060405234801561001057600080fd5b506040516105cb3803806105cb8339818101604052810190610032919061015c565b8260ff1660808160ff168152505081151560a0811515815250508073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff16815250505050506101af565b600080fd5b600060ff82169050919050565b6100a38161008d565b81146100ae57600080fd5b50565b6000815190506100c08161009a565b92915050565b60008115159050919050565b6100db816100c6565b81146100e657600080fd5b50565b6000815190506100f8816100d2565b92915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610129826100fe565b9050919050565b6101398161011e565b811461014457600080fd5b50565b60008151905061015681610130565b92915050565b60008060006060848603121561017557610174610088565b5b6000610183868287016100b1565b9350506020610194868287016100e9565b92505060406101a586828701610147565b9150509250925092565b60805160a05160c0516103ed6101de600039600061015f01526000610187015260006101af01526103ed6000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c80631ca6cbeb146100515780632277fe821461006f578063ee460c641461008d578063f2c9ecd8146100ab575b600080fd5b6100596100c9565b604051610066919061026c565b60405180910390f35b61007761015b565b60405161008491906102cf565b60405180910390f35b610095610183565b6040516100a29190610305565b60405180910390f35b6100b36101ab565b6040516100c0919061033c565b60405180910390f35b6060600080546100d890610386565b80601f016020809104026020016040519081016040528092919081815260200182805461010490610386565b80156101515780601f1061012657610100808354040283529160200191610151565b820191906000526020600020905b81548152906001019060200180831161013457829003601f168201915b5050505050905090565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b60007f0000000000000000000000000000000000000000000000000000000000000000905090565b600081519050919050565b600082825260208201905092915050565b60005b8381101561020d5780820151818401526020810190506101f2565b8381111561021c576000848401525b50505050565b6000601f19601f8301169050919050565b600061023e826101d3565b61024881856101de565b93506102588185602086016101ef565b61026181610222565b840191505092915050565b600060208201905081810360008301526102868184610233565b905092915050565b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006102b98261028e565b9050919050565b6102c9816102ae565b82525050565b60006020820190506102e460008301846102c0565b92915050565b60008115159050919050565b6102ff816102ea565b82525050565b600060208201905061031a60008301846102f6565b92915050565b600060ff82169050919050565b61033681610320565b82525050565b6000602082019050610351600083018461032d565b92915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061039e57607f821691505b6020821081036103b1576103b0610357565b5b5091905056fea26469706673582212201bf5707496ec5c58e6da2f78bf4f13bb8a3e0d2dede540dedb15a521ee12ad3b64736f6c634300080f0033000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000001111111111111111111111111111111111111111" }); secondAction = ChugSplashAction({ - target: "MyToken", + target: "SecondSimpleStorage", actionType: ChugSplashActionType.SET_STORAGE, - data: hex"00000000000000000000000000000000000000000000000000000000000000004d79546f6b656e0000000000000000000000000000000000000000000000000e" + data: hex"00000000000000000000000000000000000000000000000000000000000000005365636f6e64000000000000000000000000000000000000000000000000000c" }); actions.push(firstAction); actions.push(secondAction); - actions.push( - ChugSplashAction({ - target: "MyToken", - actionType: ChugSplashActionType.SET_STORAGE, - data: hex"00000000000000000000000000000000000000000000000000000000000000014d59540000000000000000000000000000000000000000000000000000000006" - }) - ); - actions.push( - ChugSplashAction({ - target: "MyToken", - actionType: ChugSplashActionType.SET_STORAGE, - data: hex"000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000003e8" - }) - ); setImplementationActionArray.push( ChugSplashAction({ - target: "MyToken", + target: "SecondSimpleStorage", actionType: ChugSplashActionType.SET_IMPLEMENTATION, data: new bytes(0) }) ); - setImplementationActionIndexArray = [actionIndexes[4]]; - setImplementationProofArray = [proofs[4]]; + setImplementationActionIndexArray = [actionIndexes[2]]; + setImplementationProofArray = [proofs[2]]; vm.warp(initialTimestamp); vm.fee(baseFee); @@ -398,9 +371,11 @@ contract ChugSplashManager_Test is Test { helper_proposeThenApproveThenFundThenClaimBundle(); address payable proxyAddress = manager.getProxyByTargetName(firstAction.target); assertEq(proxyAddress.code.length, 0); - // We add 1 here to account for the Proxy deployment that occurs before the implementation deployment. - uint256 implementationDeploymentNonce = 1 + vm.getNonce(address(manager)); - address implementationAddress = computeCreateAddress(address(manager), implementationDeploymentNonce); + address implementationAddress = Create2.compute( + address(manager), + bytes32(0), + firstAction.data + ); assertEq(implementationAddress.code.length, 0); uint256 initialTotalDebt = manager.totalDebt(); uint256 initialExecutorDebt = manager.debt(executor1); @@ -419,7 +394,7 @@ contract ChugSplashManager_Test is Test { uint256 finalExecutorDebt = manager.debt(executor1); ChugSplashBundleState memory bundle = manager.bundles(bundleId); - uint256 executionGasUsed = 1696119; + uint256 executionGasUsed = 760437; uint256 estExecutorPayment = baseFee * executionGasUsed * (100 + executorPaymentPercentage) / 100; assertGt(proxyAddress.code.length, 0); diff --git a/packages/core/src/config/parse.ts b/packages/core/src/config/parse.ts index 96fe5216f..a1493c3b5 100644 --- a/packages/core/src/config/parse.ts +++ b/packages/core/src/config/parse.ts @@ -141,7 +141,7 @@ export const makeActionBundleFromConfig = async ( config: ChugSplashConfig, artifacts: { [name: string]: { - deployedBytecode: string + creationCode: string storageLayout: SolidityStorageLayout immutableVariables: string[] } @@ -162,7 +162,7 @@ export const makeActionBundleFromConfig = async ( // Add a DEPLOY_IMPLEMENTATION action for each contract first. actions.push({ target: referenceName, - code: artifact.deployedBytecode, + code: artifact.creationCode, }) // Next, add a SET_IMPLEMENTATION action for each contract. diff --git a/packages/plugins/src/hardhat/artifacts.ts b/packages/plugins/src/hardhat/artifacts.ts index 7b6e8e710..d75fb1b40 100644 --- a/packages/plugins/src/hardhat/artifacts.ts +++ b/packages/plugins/src/hardhat/artifacts.ts @@ -1,12 +1,8 @@ import path from 'path' import * as semver from 'semver' -import { - SolidityStorageLayout, - ContractConfig, - ChugSplashConfig, -} from '@chugsplash/core' -import { add0x, remove0x } from '@eth-optimism/core-utils' +import { SolidityStorageLayout, ChugSplashConfig } from '@chugsplash/core' +import { remove0x } from '@eth-optimism/core-utils' import { ethers, utils } from 'ethers' // TODO @@ -92,15 +88,45 @@ export const getStorageLayout = async ( return (output as any).storageLayout } -export const generateRuntimeBytecode = async ( - provider: ethers.providers.JsonRpcProvider, +export const getCreationCode = async ( parsedConfig: ChugSplashConfig, referenceName: string ): Promise => { const contractConfig = parsedConfig.contracts[referenceName] - const { sourceName, contractName, bytecode, abi } = getContractArtifact( + + const { bytecode } = getContractArtifact(contractConfig.contract) + + const { constructorArgTypes, constructorArgValues } = + await getConstructorArgs(parsedConfig, referenceName) + + const creationCodeWithConstructorArgs = bytecode.concat( + remove0x( + utils.defaultAbiCoder.encode(constructorArgTypes, constructorArgValues) + ) + ) + + return creationCodeWithConstructorArgs +} + +export const getConstructorArgs = async ( + parsedConfig: ChugSplashConfig, + referenceName: string +): Promise<{ constructorArgTypes: any[]; constructorArgValues: any[] }> => { + const contractConfig = parsedConfig.contracts[referenceName] + + const { sourceName, contractName, abi } = getContractArtifact( contractConfig.contract ) + + const constructorFragment = abi.find( + (fragment) => fragment.type === 'constructor' + ) + const constructorArgTypes = [] + const constructorArgValues = [] + if (constructorFragment === undefined) { + return { constructorArgTypes, constructorArgValues } + } + const buildInfo = await getBuildInfo(sourceName, contractName) const output = buildInfo.output.contracts[sourceName][contractName] const immutableReferences: { @@ -109,14 +135,6 @@ export const generateRuntimeBytecode = async ( start: number }[] } = output.evm.deployedBytecode.immutableReferences - const deployedBytecode = output.evm.deployedBytecode.object - - if (Object.keys(immutableReferences).length === 0) { - return add0x(deployedBytecode) - } - - // Maps a variable's AST ID to its ABI encoded value - const astIdToAbiEncodedValue = {} // Maps a constructor argument name to the corresponding variable name in the ChugSplash config const constructorArgNamesToImmutableNames = {} @@ -146,79 +164,28 @@ export const generateRuntimeBytecode = async ( node.name ) constructorArgNamesToImmutableNames[constructorArgName] = node.name - - let typeString: string - if (node.typeDescriptions.typeString.startsWith('contract')) { - typeString = 'address' - } else if (node.typeDescriptions.typeString.startsWith('enum')) { - typeString = 'uint8' - } else { - typeString = node.typeDescriptions.typeString - } - const abiEncodedValue = utils.defaultAbiCoder.encode( - [typeString], - [contractConfig.variables[node.name]] - ) - astIdToAbiEncodedValue[node.id] = remove0x(abiEncodedValue) } } } } } - let bytecodeInjectedWithImmutables = deployedBytecode - for (const [astId, referenceArray] of Object.entries(immutableReferences)) { - for (const { start, length } of referenceArray) { - bytecodeInjectedWithImmutables = bytecodeInjectedWithImmutables - .substring(0, start * 2) - .concat(astIdToAbiEncodedValue[astId]) - .concat( - bytecodeInjectedWithImmutables.substring( - start * 2 + length * 2, - bytecodeInjectedWithImmutables.length - ) - ) - } - } - - const constructorFragment = abi.find( - (fragment) => fragment.type === 'constructor' - ) - const constructorArgTypes = [] - const constructorArgValues = [] - constructorFragment.inputs.forEach((fragment) => { - constructorArgTypes.push(fragment.type) - if (constructorArgNamesToImmutableNames.hasOwnProperty(fragment.name)) { + constructorFragment.inputs.forEach((input) => { + constructorArgTypes.push(input.type) + if (constructorArgNamesToImmutableNames.hasOwnProperty(input.name)) { constructorArgValues.push( contractConfig.variables[ - constructorArgNamesToImmutableNames[fragment.name] + constructorArgNamesToImmutableNames[input.name] ] ) } else { throw new Error( - `Detected a non-immutable constructor argument, "${fragment.name}", in ${contractConfig.contract}. Please remove it or make the corresponding variable immutable.` + `Detected a non-immutable constructor argument, "${input.name}", in ${contractConfig.contract}. Please remove it or make the corresponding variable immutable.` ) } }) - const creationBytecodeWithConstructorArgs = bytecode.concat( - remove0x( - utils.defaultAbiCoder.encode(constructorArgTypes, constructorArgValues) - ) - ) - const bytecodeDeployedWithConstructorArgs = await provider.call({ - data: creationBytecodeWithConstructorArgs, - }) - if ( - add0x(bytecodeInjectedWithImmutables) !== - bytecodeDeployedWithConstructorArgs - ) { - throw new Error( - `ChugSplash cannot generate the deployed bytecode for ${contractConfig.contract}. Please report this error.` - ) - } - - return bytecodeDeployedWithConstructorArgs + return { constructorArgTypes, constructorArgValues } } export const getDeployedBytecode = async ( @@ -229,60 +196,6 @@ export const getDeployedBytecode = async ( return deployedBytecode } -export const getConstructorArgValues = async ( - contractConfig: ContractConfig -): Promise => { - const { sourceName, contractName, abi } = getContractArtifact( - contractConfig.contract - ) - const constructorFragment = abi.find( - (fragment) => fragment.type === 'constructor' - ) - if ( - constructorFragment === undefined || - constructorFragment.inputs.length === 0 - ) { - return [] - } - const buildInfo = await getBuildInfo(sourceName, contractName) - - // Maps a constructor argument name to the corresponding variable name in the ChugSplash config - const constructorArgNamesToImmutableNames = {} - - for (const source of Object.values(buildInfo.output.sources)) { - for (const contractNode of (source as any).ast.nodes) { - if (contractNode.nodeType === 'ContractDefinition') { - for (const node of contractNode.nodes) { - if ( - node.nodeType === 'VariableDeclaration' && - node.mutability === 'immutable' - ) { - const constructorArgName = - getConstructorArgNameForImmutableVariable( - contractConfig.contract, - contractNode.nodes, - node.name - ) - constructorArgNamesToImmutableNames[constructorArgName] = node.name - } - } - } - } - } - - const constructorArgTypes = [] - const constructorArgValues = [] - constructorFragment.inputs.forEach((fragment) => { - constructorArgTypes.push(fragment.type) - constructorArgValues.push( - contractConfig.variables[ - constructorArgNamesToImmutableNames[fragment.name] - ] - ) - }) - return constructorArgValues -} - export const getNestedConstructorArg = (variableName: string, args): string => { let remainingArguments = args[0] while (remainingArguments !== undefined) { @@ -304,9 +217,13 @@ export const getConstructorArgNameForImmutableVariable = ( for (const node of nodes) { if (node.kind === 'constructor') { for (const statement of node.body.statements) { - if (statement.expression.nodeType !== 'Assignment') { + if (statement.expression.nodeType === 'FunctionCall') { + throw new Error( + `Please remove the "${statement.expression.expression.name}" call in the constructor for ${contractName}.` + ) + } else if (statement.expression.nodeType !== 'Assignment') { throw new Error( - `disallowed statement constructor for ${contractName}: ${statement.expression.nodeType}` + `disallowed statement in constructor for ${contractName}: ${statement.expression.nodeType}` ) } if (statement.expression.leftHandSide.name === variableName) { diff --git a/packages/plugins/src/hardhat/deployments.ts b/packages/plugins/src/hardhat/deployments.ts index dfb55132a..723240fb0 100644 --- a/packages/plugins/src/hardhat/deployments.ts +++ b/packages/plugins/src/hardhat/deployments.ts @@ -29,10 +29,10 @@ import { import { getChainId } from '@eth-optimism/core-utils' import { - getConstructorArgValues, getContractArtifact, getStorageLayout, getBuildInfo, + getConstructorArgs, } from './artifacts' import { writeHardhatSnapshotId } from './utils' @@ -273,6 +273,10 @@ export const deployChugSplashConfig = async ( const metadata = buildInfo.output.contracts[sourceName][contractName].metadata const { devdoc, userdoc } = JSON.parse(metadata).output + const { constructorArgValues } = await getConstructorArgs( + parsedConfig, + referenceName + ) const artifact = { contractName, address: contractConfig.address, @@ -282,7 +286,7 @@ export const deployChugSplashConfig = async ( receipt: finalDeploymentReceipt, numDeployments: 1, metadata, - args: await getConstructorArgValues(contractConfig), + args: constructorArgValues, bytecode, deployedBytecode: await hre.ethers.provider.getCode( contractConfig.address diff --git a/packages/plugins/src/hardhat/tasks.ts b/packages/plugins/src/hardhat/tasks.ts index 7caf59eb8..b1936ce27 100644 --- a/packages/plugins/src/hardhat/tasks.ts +++ b/packages/plugins/src/hardhat/tasks.ts @@ -35,7 +35,7 @@ import Hash from 'ipfs-only-hash' import * as dotenv from 'dotenv' import { - generateRuntimeBytecode, + getCreationCode, getImmutableVariables, getStorageLayout, } from './artifacts' @@ -93,14 +93,10 @@ subtask(TASK_CHUGSPLASH_BUNDLE_LOCAL) parsed.contracts )) { const storageLayout = await getStorageLayout(contractConfig.contract) - const deployedBytecode = await generateRuntimeBytecode( - hre.ethers.provider, - parsed, - referenceName - ) + const creationCode = await getCreationCode(parsed, referenceName) const immutableVariables = await getImmutableVariables(contractConfig) artifacts[referenceName] = { - deployedBytecode, + creationCode, storageLayout, immutableVariables, }