diff --git a/.github/workflows/run-scenarios.yaml b/.github/workflows/run-scenarios.yaml index 759e813a..42f96c5a 100644 --- a/.github/workflows/run-scenarios.yaml +++ b/.github/workflows/run-scenarios.yaml @@ -2,6 +2,8 @@ name: Run Scenarios on: workflow_dispatch: pull_request: +permissions: + checks: write jobs: run-scenarios: strategy: diff --git a/Makefile b/Makefile index 8aa1c330..8b6671a2 100644 --- a/Makefile +++ b/Makefile @@ -45,6 +45,20 @@ deploy-contracts: -vvvv \ --sender $(SENDER) +# Compute contracts addresses +compute-contracts-addresses: + @echo "Computing contracts addresses..." + CHAIN_ID=$(CHAIN_ID) forge script forge/script/marketupdates/ComputeContractsAddresses.s.sol:ComputeContractAddresses \ + --rpc-url $(RPC_URL) \ + --optimize \ + --optimizer-runs 200 \ + --use $(SOLIDITY_COMPILER_VERSION) \ + --evm-version $(EVM_VERSION) \ + --via-ir \ + -vvvv \ + --skip-simulation \ + --sender $(SENDER) + # Verifying MarketUpdateTimelock verify-MarketUpdateTimelock: @echo "Verifying MarketUpdateTimelock..." diff --git a/forge/script/marketupdates/ComputeContractsAddresses.s.sol b/forge/script/marketupdates/ComputeContractsAddresses.s.sol new file mode 100644 index 00000000..dd4f7b92 --- /dev/null +++ b/forge/script/marketupdates/ComputeContractsAddresses.s.sol @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import "@forge-std/src/Script.sol"; +import "@forge-std/src/console.sol"; +import "@comet-contracts/marketupdates/MarketUpdateTimelock.sol"; +import "@comet-contracts/marketupdates/MarketUpdateProposer.sol"; +import "@comet-contracts/Configurator.sol"; +import "@comet-contracts/CometProxyAdmin.sol"; +import "@comet-contracts/marketupdates/MarketAdminPermissionChecker.sol"; +import "@comet-contracts/Create2DeployerInterface.sol"; +import "./helpers/MarketUpdateAddresses.sol"; +import "./helpers/MarketUpdateContractsDeployer.sol"; +import "./helpers/ChainAddresses.sol"; + +contract ComputeContractAddresses is Script { + address public deployedWalletAddress; + + address constant public create2DeployerAddress = 0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2; + address constant public ZER0_ADDRESS_MARKET_UPDATE_PROPOSAL_GUARDIAN = address(0); + address constant public ZER0_ADDRESS_MARKET_ADMIN_PAUSE_GUARDIAN = address(0); + address constant public INITIAL_ADDRESS_MARKET_UPDATE_MULTI_SIG = address(0x7e14050080306cd36b47DE61ce604b3a1EC70c4e); + + + function run() external { + uint256 passedChainId = vm.envUint("CHAIN_ID"); + + require(block.chainid == passedChainId, "Chain ID mismatch"); + + ChainAddresses.Chain chain = ChainAddresses.getChainBasedOnChainId(passedChainId); + ChainAddresses.ChainAddressesStruct memory chainAddresses = ChainAddresses.getChainAddresses(chain); + + console.log("Deploying contracts with sender: ", msg.sender); + + uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + address deployer = vm.rememberKey(deployerPrivateKey); + vm.startBroadcast(deployer); + + console.log("Broadcasting transaction with deployer: ", deployer); + + bytes32 salt = keccak256(abi.encodePacked(vm.envString("SALT"))); + + /// Call library function + MarketUpdateContractsDeployer.DeployedContracts memory deployedContracts = MarketUpdateContractsDeployer.calculateContractAddresses( + salt, + msg.sender, + chainAddresses.marketAdmin, + chainAddresses.marketUpdatePauseGuardian, + chainAddresses.marketUpdateProposalGuardian, + chainAddresses.governorTimelockAddress + ); + + /// Console log deployed contracts + console.log("MarketUpdateTimelock: ", deployedContracts.marketUpdateTimelock); + console.log("MarketUpdateProposer: ", deployedContracts.marketUpdateProposer); + console.log("NewConfiguratorImplementation: ", deployedContracts.newConfiguratorImplementation); + console.log("NewCometProxyAdmin: ", deployedContracts.newCometProxyAdmin); + console.log("MarketAdminPermissionChecker: ", deployedContracts.marketAdminPermissionChecker); + + vm.stopBroadcast(); + } +} diff --git a/forge/script/marketupdates/DeployContracts.s.sol b/forge/script/marketupdates/DeployContracts.s.sol index 22ad7849..19668330 100644 --- a/forge/script/marketupdates/DeployContracts.s.sol +++ b/forge/script/marketupdates/DeployContracts.s.sol @@ -42,7 +42,7 @@ contract DeployContracts is Script { bytes32 salt = keccak256(abi.encodePacked(vm.envString("SALT"))); /// Call library function - MarketUpdateContractsDeployer.DeployedContracts memory deployedContracts = MarketUpdateContractsDeployer._deployContracts( + MarketUpdateContractsDeployer.DeployedContracts memory deployedContracts = MarketUpdateContractsDeployer._prepareAndDeployContracts( salt, msg.sender, chainAddresses.marketAdmin, diff --git a/forge/script/marketupdates/helpers/MarketUpdateContractsDeployer.sol b/forge/script/marketupdates/helpers/MarketUpdateContractsDeployer.sol index 76538508..834d22c5 100644 --- a/forge/script/marketupdates/helpers/MarketUpdateContractsDeployer.sol +++ b/forge/script/marketupdates/helpers/MarketUpdateContractsDeployer.sol @@ -44,7 +44,7 @@ library MarketUpdateContractsDeployer { console.log("Deploying contracts with sender", msg.sender); vm.startBroadcast(msg.sender); - DeployedContracts memory deployedContracts = _deployContracts( + DeployedContracts memory deployedContracts = _prepareAndDeployContracts( salt, msg.sender, marketUpdateMultiSig, @@ -57,7 +57,7 @@ library MarketUpdateContractsDeployer { return deployedContracts; } - function _deployContracts( + function _prepareAndDeployContracts( bytes32 salt, address msgSender, address marketUpdateMultiSig, @@ -65,25 +65,133 @@ library MarketUpdateContractsDeployer { address marketUpdateProposalGuardianAddress, address localTimelockAddress ) internal returns (DeployedContracts memory) { - console.log("Deploying contracts with sender", msgSender); + console.log("Preparing contracts with sender", msgSender); + ICreate2Deployer create2Deployer = ICreate2Deployer(create2DeployerAddress); + + // Initialize variables to hold computed addresses + address computedMarketUpdateTimelockAddress; + address computedMarketUpdateProposerAddress; + address computedConfiguratorAddress; + address computedMarketAdminPermissionCheckerAddress; + address computedCometProxyAdminAddress; + + // Prepare and deploy MarketUpdateTimelock + ContractDeploymentParams memory marketUpdateTimelockParams = getMarketUpdateTimelockParams(msgSender); + + computedMarketUpdateTimelockAddress = computeContractAddress(create2Deployer, salt, marketUpdateTimelockParams); + + deployContractWithCreate2(create2Deployer, salt, marketUpdateTimelockParams); + // Perform any post-deployment actions + console.log("Current Governor of timelock", MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).governor()); + + // Prepare and deploy MarketUpdateProposer + ContractDeploymentParams memory marketUpdateProposerParams = getMarketUpdateProposerParams(msgSender, marketUpdateMultiSig, marketUpdateProposalGuardianAddress, computedMarketUpdateTimelockAddress); + + computedMarketUpdateProposerAddress = computeContractAddress(create2Deployer, salt, marketUpdateProposerParams); + + deployContractWithCreate2(create2Deployer, salt, marketUpdateProposerParams); + + // Post-deployment actions + MarketUpdateProposer(computedMarketUpdateProposerAddress).setMarketAdmin(marketUpdateMultiSig); + MarketUpdateProposer(computedMarketUpdateProposerAddress).setProposalGuardian(marketUpdateProposalGuardianAddress); + MarketUpdateProposer(computedMarketUpdateProposerAddress).setGovernor(localTimelockAddress); + + MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).setMarketUpdateProposer(computedMarketUpdateProposerAddress); + MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).setGovernor(localTimelockAddress); + + // Prepare and deploy Configurator + ContractDeploymentParams memory configuratorParams = getConfiguratorParams(); + + computedConfiguratorAddress = computeContractAddress(create2Deployer, salt, configuratorParams); + + deployContractWithCreate2(create2Deployer, salt, configuratorParams); + // No post-deployment actions + + // Prepare and deploy MarketAdminPermissionChecker + ContractDeploymentParams memory marketAdminPermissionCheckerParams = getMarketAdminPermissionCheckerParams(msgSender); + + computedMarketAdminPermissionCheckerAddress = computeContractAddress(create2Deployer, salt, marketAdminPermissionCheckerParams); + + deployContractWithCreate2(create2Deployer, salt, marketAdminPermissionCheckerParams); + + // Post-deployment actions + MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).setMarketAdmin(computedMarketUpdateTimelockAddress); + MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).setMarketAdminPauseGuardian(marketAdminPauseGuardianAddress); + MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).transferOwnership(localTimelockAddress); + + // Prepare and deploy CometProxyAdmin + ContractDeploymentParams memory cometProxyAdminParams = getCometProxyAdminParams(msgSender); + + computedCometProxyAdminAddress = computeContractAddress(create2Deployer, salt, cometProxyAdminParams); + + + deployContractWithCreate2(create2Deployer, salt, cometProxyAdminParams); + + // Post-deployment actions + CometProxyAdmin(computedCometProxyAdminAddress).setMarketAdminPermissionChecker(MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress)); + CometProxyAdmin(computedCometProxyAdminAddress).transferOwnership(localTimelockAddress); + + console.log("Owner of cometProxyAdmin: ", CometProxyAdmin(computedCometProxyAdminAddress).owner()); + + + return DeployedContracts({ + marketUpdateTimelock: computedMarketUpdateTimelockAddress, + marketUpdateProposer: computedMarketUpdateProposerAddress, + newCometProxyAdmin: computedCometProxyAdminAddress, + newConfiguratorImplementation: computedConfiguratorAddress, + marketAdminPermissionChecker: computedMarketAdminPermissionCheckerAddress + }); + } + + function calculateContractAddresses( + bytes32 salt, + address msgSender, + address marketUpdateMultiSig, + address marketAdminPauseGuardianAddress, + address marketUpdateProposalGuardianAddress, + address localTimelockAddress + ) internal returns (DeployedContracts memory) { ICreate2Deployer create2Deployer = ICreate2Deployer(create2DeployerAddress); + ContractDeploymentParams memory marketUpdateTimelockParams = getMarketUpdateTimelockParams(msgSender); + + address computedMarketUpdateTimelockAddress = computeContractAddress(create2Deployer, salt, marketUpdateTimelockParams); + ContractDeploymentParams memory marketUpdateProposerParams = getMarketUpdateProposerParams(msgSender, marketUpdateMultiSig, marketUpdateProposalGuardianAddress, computedMarketUpdateTimelockAddress); + address computedMarketUpdateProposerAddress = computeContractAddress(create2Deployer, salt, marketUpdateProposerParams); + ContractDeploymentParams memory configuratorParams = getConfiguratorParams(); - // Prepare deployment parameters for each contract - ContractDeploymentParams memory marketUpdateTimelockParams = ContractDeploymentParams({ + address computedConfiguratorAddress = computeContractAddress(create2Deployer, salt, configuratorParams); + ContractDeploymentParams memory marketAdminPermissionCheckerParams = getMarketAdminPermissionCheckerParams(msgSender); + + address computedMarketAdminPermissionCheckerAddress = computeContractAddress(create2Deployer, salt, marketAdminPermissionCheckerParams); + + ContractDeploymentParams memory cometProxyAdminParams = getCometProxyAdminParams(msgSender); + address computedCometProxyAdminAddress = computeContractAddress(create2Deployer, salt, cometProxyAdminParams); + + return DeployedContracts({ + marketUpdateTimelock: computedMarketUpdateTimelockAddress, + marketUpdateProposer: computedMarketUpdateProposerAddress, + newCometProxyAdmin: computedCometProxyAdminAddress, + newConfiguratorImplementation: computedConfiguratorAddress, + marketAdminPermissionChecker: computedMarketAdminPermissionCheckerAddress + }); + } + + + function getMarketUpdateTimelockParams(address msgSender) internal pure returns (ContractDeploymentParams memory) { + return ContractDeploymentParams({ creationCode: type(MarketUpdateTimelock).creationCode, - constructorArgs: abi.encode(msgSender, 2 days), // 2 days + constructorArgs: abi.encode(msgSender, 2 days), expectedRuntimeCode: type(MarketUpdateTimelock).runtimeCode, contractName: "MarketUpdateTimelock" }); + } - address computedMarketUpdateTimelockAddress = deployContractWithCreate2(create2Deployer, salt, marketUpdateTimelockParams); - - console.log("Current Governor of timelock", MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).governor()); - ContractDeploymentParams memory marketUpdateProposerParams = ContractDeploymentParams({ + function getMarketUpdateProposerParams(address msgSender, address marketUpdateMultiSig, address marketUpdateProposalGuardianAddress, address computedMarketUpdateTimelockAddress) internal pure returns (ContractDeploymentParams memory) { + return ContractDeploymentParams({ creationCode: type(MarketUpdateProposer).creationCode, constructorArgs: abi.encode( msgSender, @@ -94,70 +202,58 @@ library MarketUpdateContractsDeployer { expectedRuntimeCode: type(MarketUpdateProposer).runtimeCode, contractName: "MarketUpdateProposer" }); + } - address computedMarketUpdateProposerAddress = deployContractWithCreate2(create2Deployer, salt, marketUpdateProposerParams); - MarketUpdateProposer(computedMarketUpdateProposerAddress).setMarketAdmin(marketUpdateMultiSig); - MarketUpdateProposer(computedMarketUpdateProposerAddress).setProposalGuardian(marketUpdateProposalGuardianAddress); - MarketUpdateProposer(computedMarketUpdateProposerAddress).setGovernor(localTimelockAddress); - - MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).setMarketUpdateProposer(computedMarketUpdateProposerAddress); - MarketUpdateTimelock(payable(computedMarketUpdateTimelockAddress)).setGovernor(localTimelockAddress); - - ContractDeploymentParams memory configuratorParams = ContractDeploymentParams({ + function getConfiguratorParams() internal pure returns (ContractDeploymentParams memory) { + return ContractDeploymentParams({ creationCode: type(Configurator).creationCode, constructorArgs: "", expectedRuntimeCode: type(Configurator).runtimeCode, contractName: "Configurator" }); + } - address computedConfiguratorAddress = deployContractWithCreate2(create2Deployer, salt, configuratorParams); - - ContractDeploymentParams memory marketAdminPermissionCheckerParams = ContractDeploymentParams({ + function getMarketAdminPermissionCheckerParams(address msgSender) internal pure returns (ContractDeploymentParams memory) { + return ContractDeploymentParams({ creationCode: type(MarketAdminPermissionChecker).creationCode, constructorArgs: abi.encode(msgSender, INITIAL_ADDRESS_MARKET_UPDATE_MULTI_SIG, address(0)), expectedRuntimeCode: type(MarketAdminPermissionChecker).runtimeCode, contractName: "MarketAdminPermissionChecker" }); + } - address computedMarketAdminPermissionCheckerAddress = deployContractWithCreate2(create2Deployer, salt, marketAdminPermissionCheckerParams); - MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).setMarketAdmin(computedMarketUpdateTimelockAddress); - MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).setMarketAdminPauseGuardian(marketAdminPauseGuardianAddress); - - MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress).transferOwnership(localTimelockAddress); - ContractDeploymentParams memory cometProxyAdminParams = ContractDeploymentParams({ + function getCometProxyAdminParams(address msgSender) internal pure returns (ContractDeploymentParams memory) { + return ContractDeploymentParams({ creationCode: type(CometProxyAdmin).creationCode, constructorArgs: abi.encode(msgSender), expectedRuntimeCode: type(CometProxyAdmin).runtimeCode, contractName: "CometProxyAdmin" }); - - address computedCometProxyAdminAddress = deployContractWithCreate2(create2Deployer, salt, cometProxyAdminParams); - CometProxyAdmin(computedCometProxyAdminAddress).setMarketAdminPermissionChecker(MarketAdminPermissionChecker(computedMarketAdminPermissionCheckerAddress)); - CometProxyAdmin(computedCometProxyAdminAddress).transferOwnership(localTimelockAddress); - - console.log("Owner of cometProxyAdmin: ", CometProxyAdmin(computedCometProxyAdminAddress).owner()); - - return DeployedContracts({ - marketUpdateTimelock: computedMarketUpdateTimelockAddress, - marketUpdateProposer: computedMarketUpdateProposerAddress, - newCometProxyAdmin: computedCometProxyAdminAddress, - newConfiguratorImplementation: computedConfiguratorAddress, - marketAdminPermissionChecker: computedMarketAdminPermissionCheckerAddress - }); } + function deployContractWithCreate2( ICreate2Deployer create2Deployer, bytes32 salt, ContractDeploymentParams memory params ) internal returns (address) { + address computedAddress = computeContractAddress(create2Deployer, salt, params); bytes memory bytecode = abi.encodePacked(params.creationCode, params.constructorArgs); - address computedAddress = create2Deployer.computeAddress(salt, keccak256(bytecode)); checkOrDeployAndCompareBytecodes(create2Deployer, salt, bytecode, computedAddress, params.expectedRuntimeCode); return computedAddress; } + function computeContractAddress( + ICreate2Deployer create2Deployer, + bytes32 salt, + ContractDeploymentParams memory params + ) internal view returns (address) { + bytes memory bytecode = abi.encodePacked(params.creationCode, params.constructorArgs); + address computedAddress = create2Deployer.computeAddress(salt, keccak256(bytecode)); + return computedAddress; + } + function checkOrDeployAndCompareBytecodes( ICreate2Deployer create2Deployer, bytes32 salt, diff --git a/plugins/scenario/utils/TokenSourcer.ts b/plugins/scenario/utils/TokenSourcer.ts index c0e3191f..c87a4d75 100644 --- a/plugins/scenario/utils/TokenSourcer.ts +++ b/plugins/scenario/utils/TokenSourcer.ts @@ -12,6 +12,7 @@ interface SourceTokenParameters { asset: string; address: string; blacklist: string[]; + blockNumber?: number; } export async function fetchQuery( @@ -55,6 +56,7 @@ export async function sourceTokens({ asset, address, blacklist, + blockNumber, }: SourceTokenParameters) { let amount = BigNumber.from(amount_); if (amount.isZero()) { @@ -62,7 +64,7 @@ export async function sourceTokens({ } else if (amount.isNegative()) { await removeTokens(dm, amount.abs(), asset, address); } else { - await addTokens(dm, amount, asset, address, [address].concat(blacklist)); + await addTokens(dm, amount, asset, address, [address].concat(blacklist), blockNumber); } } diff --git a/scenario/RewardsScenario.ts b/scenario/RewardsScenario.ts index a879a2bb..2ed1bf04 100644 --- a/scenario/RewardsScenario.ts +++ b/scenario/RewardsScenario.ts @@ -260,7 +260,12 @@ async function testScalingReward(properties: CometProperties, context: CometCont [albert.address] ); await newRewards.connect(albert.signer).setRewardConfigWithMultiplier(comet.address, rewardTokenAddress, multiplier); - await context.sourceTokens(exp(1_000, rewardDecimals), rewardTokenAddress, newRewards.address); + await context.sourceTokens( + 100000, // maximum amount which can be sourced from transaction logs + rewardTokenAddress, // CometAsset + newRewards.address, // Recipient's address + 2751700 // Block number to start searching for transfer event + ); await baseAsset.approve(albert, comet.address); await albert.safeSupplyAsset({ asset: baseAssetAddress, amount: 100n * baseScale }); diff --git a/scenario/context/CometContext.ts b/scenario/context/CometContext.ts index 8354fbb7..fb55e9f2 100644 --- a/scenario/context/CometContext.ts +++ b/scenario/context/CometContext.ts @@ -254,7 +254,7 @@ export class CometContext { throw new Error(`Unable to find asset by address ${address}`); } - async sourceTokens(amount: number | bigint, asset: CometAsset | string, recipient: AddressLike) { + async sourceTokens(amount: number | bigint, asset: CometAsset | string, recipient: AddressLike, blockNumber?: number) { const { world } = this; const recipientAddress = resolveAddress(recipient); const cometAsset = typeof asset === 'string' ? this.getAssetByAddress(asset) : asset; @@ -287,6 +287,7 @@ export class CometContext { asset: cometAsset.address, address: recipientAddress, blacklist: [comet.address], + blockNumber, }); } } diff --git a/src/deploy/Network.ts b/src/deploy/Network.ts index 9f6f027d..c0ea91a5 100644 --- a/src/deploy/Network.ts +++ b/src/deploy/Network.ts @@ -124,7 +124,7 @@ export async function deployNetworkComet( const cometAdmin = await deploymentManager.deploy( 'cometAdmin', 'CometProxyAdmin.sol', - [], + [governor], maybeForce() );