-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move ScriptUtils from aave-helpers (#40)
- Loading branch information
Showing
1 changed file
with
156 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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,156 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
|
||
import {Script} from 'forge-std/Script.sol'; | ||
import {ChainIds} from './ChainHelpers.sol'; | ||
|
||
/** | ||
* Helper contract to enforce correct chain selection in scripts | ||
*/ | ||
abstract contract WithChainIdValidation is Script { | ||
constructor(uint256 chainId) { | ||
require(block.chainid == chainId, 'CHAIN_ID_MISMATCH'); | ||
} | ||
|
||
modifier broadcast() { | ||
vm.startBroadcast(); | ||
_; | ||
vm.stopBroadcast(); | ||
} | ||
} | ||
|
||
abstract contract EthereumScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.MAINNET) {} | ||
} | ||
|
||
abstract contract OptimismScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.OPTIMISM) {} | ||
} | ||
|
||
abstract contract ArbitrumScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.ARBITRUM) {} | ||
} | ||
|
||
abstract contract PolygonScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.POLYGON) {} | ||
} | ||
|
||
abstract contract AvalancheScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.AVALANCHE) {} | ||
} | ||
|
||
abstract contract FantomScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.FANTOM) {} | ||
} | ||
|
||
abstract contract HarmonyScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.HARMONY) {} | ||
} | ||
|
||
abstract contract MetisScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.METIS) {} | ||
} | ||
|
||
abstract contract BaseScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.BASE) {} | ||
} | ||
|
||
abstract contract BNBScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.BNB) {} | ||
} | ||
|
||
abstract contract GnosisScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.GNOSIS) {} | ||
} | ||
|
||
abstract contract ScrollScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.SCROLL) {} | ||
} | ||
|
||
abstract contract PolygonZkEvmScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.ZK_EVM) {} | ||
} | ||
|
||
abstract contract SepoliaScript is WithChainIdValidation { | ||
constructor() WithChainIdValidation(ChainIds.SEPOLIA) {} | ||
} | ||
|
||
library Create2Utils { | ||
// https://github.com/safe-global/safe-singleton-factory | ||
address public constant CREATE2_FACTORY = 0x914d7Fec6aaC8cd542e72Bca78B30650d45643d7; | ||
|
||
function create2Deploy( | ||
bytes32 salt, | ||
bytes memory bytecode, | ||
bytes memory arguments | ||
) internal returns (address) { | ||
if (isContractDeployed(CREATE2_FACTORY) == false) { | ||
revert('MISSING_CREATE2_FACTORY'); | ||
} | ||
address computed = computeCreate2Address(salt, bytecode, arguments); | ||
|
||
if (isContractDeployed(computed)) { | ||
return computed; | ||
} else { | ||
bytes memory creationBytecode = abi.encodePacked(salt, abi.encodePacked(bytecode, arguments)); | ||
bytes memory returnData; | ||
(, returnData) = CREATE2_FACTORY.call(creationBytecode); | ||
address deployedAt = address(uint160(bytes20(returnData))); | ||
require(deployedAt == computed, 'failure at create2 address derivation'); | ||
return deployedAt; | ||
} | ||
} | ||
|
||
function create2Deploy(bytes32 salt, bytes memory bytecode) internal returns (address) { | ||
if (isContractDeployed(CREATE2_FACTORY) == false) { | ||
revert('MISSING_CREATE2_FACTORY'); | ||
} | ||
address computed = computeCreate2Address(salt, bytecode); | ||
|
||
if (isContractDeployed(computed)) { | ||
return computed; | ||
} else { | ||
bytes memory creationBytecode = abi.encodePacked(salt, bytecode); | ||
bytes memory returnData; | ||
(, returnData) = CREATE2_FACTORY.call(creationBytecode); | ||
address deployedAt = address(uint160(bytes20(returnData))); | ||
require(deployedAt == computed, 'failure at create2 address derivation'); | ||
return deployedAt; | ||
} | ||
} | ||
|
||
function isContractDeployed(address _addr) internal view returns (bool isContract) { | ||
return (_addr.code.length > 0); | ||
} | ||
|
||
function computeCreate2Address(bytes32 salt, bytes32 initcodeHash) | ||
internal | ||
pure | ||
returns (address) | ||
{ | ||
return | ||
addressFromLast20Bytes( | ||
keccak256(abi.encodePacked(bytes1(0xff), CREATE2_FACTORY, salt, initcodeHash)) | ||
); | ||
} | ||
|
||
function computeCreate2Address(bytes32 salt, bytes memory bytecode) | ||
internal | ||
pure | ||
returns (address) | ||
{ | ||
return computeCreate2Address(salt, keccak256(abi.encodePacked(bytecode))); | ||
} | ||
|
||
function computeCreate2Address( | ||
bytes32 salt, | ||
bytes memory bytecode, | ||
bytes memory arguments | ||
) internal pure returns (address) { | ||
return computeCreate2Address(salt, keccak256(abi.encodePacked(bytecode, arguments))); | ||
} | ||
|
||
function addressFromLast20Bytes(bytes32 bytesValue) internal pure returns (address) { | ||
return address(uint160(uint256(bytesValue))); | ||
} | ||
} |