From f6344db59e9b13e04d41cf514813b509288a3810 Mon Sep 17 00:00:00 2001 From: voith Date: Mon, 31 Mar 2025 23:17:43 +0530 Subject: [PATCH 1/3] added CIP 36 and a forge script to test proposals --- scripts/CIP-36.ts | 67 +++++++++++++++++ test/proposals/TestProposal.t.sol | 121 ++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+) create mode 100644 scripts/CIP-36.ts create mode 100644 test/proposals/TestProposal.t.sol diff --git a/scripts/CIP-36.ts b/scripts/CIP-36.ts new file mode 100644 index 00000000..5933e077 --- /dev/null +++ b/scripts/CIP-36.ts @@ -0,0 +1,67 @@ +// run with +// npx hardhat run ./scripts/CIP-36.ts --network hardhat +import hre, { deployments, network, hardhatArguments } from "hardhat"; +import { + castVote, + createProposal, + executeProposal, + fundMultisign, + queueProposal, +} from "./utils"; +import { BigNumber } from "ethers"; + +async function main() { + const ethers = hre.ethers; + + let subDAOMultisigAddress = "0x41187c70eB8eeEfDaEd4ED0bFF20005C53c3a7DD" + let ctx = await deployments.get("Ctx"); + let ctxContract = await ethers.getContractAt("Ctx", ctx.address); + let ctxAmount = ethers.utils.parseEther("125000") + + const abi = new ethers.utils.AbiCoder(); + const targets = [ctx.address]; + const values = [BigNumber.from(0)]; + const signatures = ["transfer(address,uint256)"]; + const calldatas = [ + abi.encode(["address", "uint256"], [subDAOMultisigAddress, ctxAmount]), + ]; + const description = "CIP-36: Regulatory Advocacy & Public Affairs Strategy"; + console.log(targets); + console.log(values.toString()); + console.log(signatures); + console.log(calldatas); + console.log(description); + + let ctxbalance = await ctxContract.balanceOf(subDAOMultisigAddress); + console.log(" old subDAOMultisig CTX balance", ethers.utils.formatEther(ctxbalance)); + + if (hardhatArguments.network === "hardhat") { + //Fund Multisign with ETH + await fundMultisign("10000000000000000000"); + + // Create Proposal + await createProposal(targets, values, signatures, calldatas, description); + + // Vote + await castVote(20, true); + + // Wait to queue + await queueProposal(20); + + // Execute transaction + await executeProposal(20); + + // Validate Results + console.log("==================Check Results=================="); + + let ctxbalance = await ctxContract.balanceOf(subDAOMultisigAddress); + console.log("new subDAOMultisig CTX balance", ethers.utils.formatEther(ctxbalance)); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/test/proposals/TestProposal.t.sol b/test/proposals/TestProposal.t.sol new file mode 100644 index 00000000..64e0ed87 --- /dev/null +++ b/test/proposals/TestProposal.t.sol @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {Test, console2} from "forge-std/Test.sol"; +import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol"; +import {GovernanceCCIPRelay, IGovernanceCCIPRelay} from "contracts/ccip/GovernanceCCIPRelay.sol"; +import {GovernanceCCIPReceiver, IGovernanceCCIPReceiver} from "contracts/ccip/GovernanceCCIPReceiver.sol"; + +import {IGovernorBeta} from "../interfaces/IGovernorBeta.sol"; +import {ITimelock} from "../interfaces/ITimelock.sol"; +import {ICtx} from "../interfaces/ICtx.sol"; + + +contract GovernanceCCIPIntegrationTest is Test { + uint256 public ethereumMainnetForkId; + + ICtx ctx = ICtx(0x321C2fE4446C7c963dc41Dd58879AF648838f98D); + IGovernorBeta public governorBeta = IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); + ITimelock public timelock = ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); + + address public user = address(0x51); + address public owner = address(0x52); + + function setUp() public { + // Create forks of both networks + string memory ETHEREUM_MAINNET_RPC_URL = vm.envString( + "ETHEREUM_MAINNET_RPC_URL" + ); + ethereumMainnetForkId = vm.createFork(ETHEREUM_MAINNET_RPC_URL); + vm.selectFork(ethereumMainnetForkId); + deal(address(ctx), user, 100_000_000 ether); + vm.prank(user); + ctx.delegate(user); + vm.makePersistent(user); + + // Deploy GovernanceRelay on Ethereum +// vm.selectFork(ethereumMainnetForkId); +// address timelockComputedAddress = computeCreateAddress( +// address(user), +// vm.getNonce(user) + 1 +// ); +// vm.startPrank(user); +// address ctxAddress = deployCode( +// "Ctx.sol", +// abi.encode(user, user, block.timestamp) +// ); +// ctx = ICtx(ctxAddress); +// address GovernorBetaComputedAddress = computeCreateAddress( +// address(user), +// vm.getNonce(user) + 1 +// ); +// address timeLockAddress = deployCode( +// "Timelock.sol", +// abi.encode(GovernorBetaComputedAddress, 2 days) +// ); +// timelock = ITimelock(timeLockAddress); +// address governorBetaAddress = deployCode( +// "GovernorBeta.sol:GovernorBeta", +// abi.encode(address(timelock), ctx, user) +// ); +// governorBeta = IGovernorBeta(governorBetaAddress); +// ctx.delegate(user); +// vm.stopPrank(); +// vm.deal(timeLockAddress, 10 ether); +// vm.makePersistent(address(governanceRelay)); +// vm.makePersistent(ctxAddress); +// vm.makePersistent(timeLockAddress); +// vm.makePersistent(governorBetaAddress); + } + + function testCIP36() external { + vm.selectFork(ethereumMainnetForkId); + address[] memory targets = new address[](1); + uint256[] memory values = new uint256[](1); + string[] memory signatures = new string[](1); + bytes[] memory calldatas = new bytes[](1); + string memory description; + + address subDAOMultisig = 0x41187c70eB8eeEfDaEd4ED0bFF20005C53c3a7DD; + + targets[0] = 0x321C2fE4446C7c963dc41Dd58879AF648838f98D; + values[0] = 0; + signatures[0] = "transfer(address,uint256)"; + calldatas[0] = hex"00000000000000000000000041187c70eb8eeefdaed4ed0bff20005c53c3a7dd000000000000000000000000000000000000000000001a784379d99db4200000"; + description = "CIP-36: Regulatory Advocacy & Public Affairs Strategy"; + uint256 oldBalance = ctx.balanceOf(subDAOMultisig); + createAndExecuteGovernanceProposal( + targets, + values, + signatures, + calldatas, + description + ); + uint256 newBalance = ctx.balanceOf(subDAOMultisig); + assertEq(newBalance - oldBalance, 125_000 ether); + } + + function createAndExecuteGovernanceProposal( + address[] memory targets, + uint256[] memory values, + string[] memory signatures, + bytes[] memory calldatas, + string memory description + ) internal { + vm.startPrank(user); + vm.roll(block.number + 100); + governorBeta.propose(targets, values, signatures, calldatas, description); + uint256 proposalID = governorBeta.latestProposalIds(user); + vm.roll(block.number + governorBeta.votingDelay() + 1); + governorBeta.castVote(proposalID, true); + vm.roll(block.number + governorBeta.votingPeriod() + 1); + governorBeta.queue(proposalID); + vm.warp(block.timestamp + timelock.delay() + 1 days); + governorBeta.execute(proposalID); + assertEq( + uint256(governorBeta.state(proposalID)), + uint256(IGovernorBeta.ProposalState.Executed) + ); + vm.stopPrank(); + } +} From 30a75bed5d709c21c78e8971e666b10fc32c0f32 Mon Sep 17 00:00:00 2001 From: voith Date: Mon, 31 Mar 2025 23:19:30 +0530 Subject: [PATCH 2/3] lint --- test/proposals/TestProposal.t.sol | 96 +++++++++++-------------------- 1 file changed, 32 insertions(+), 64 deletions(-) diff --git a/test/proposals/TestProposal.t.sol b/test/proposals/TestProposal.t.sol index 64e0ed87..9c8ce04d 100644 --- a/test/proposals/TestProposal.t.sol +++ b/test/proposals/TestProposal.t.sol @@ -10,97 +10,65 @@ import {IGovernorBeta} from "../interfaces/IGovernorBeta.sol"; import {ITimelock} from "../interfaces/ITimelock.sol"; import {ICtx} from "../interfaces/ICtx.sol"; - contract GovernanceCCIPIntegrationTest is Test { uint256 public ethereumMainnetForkId; ICtx ctx = ICtx(0x321C2fE4446C7c963dc41Dd58879AF648838f98D); - IGovernorBeta public governorBeta = IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); - ITimelock public timelock = ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); + IGovernorBeta public governorBeta = + IGovernorBeta(0x874C5D592AfC6803c3DD60d6442357879F196d5b); + ITimelock public timelock = + ITimelock(0xa54074b2cc0e96a43048d4a68472F7F046aC0DA8); address public user = address(0x51); address public owner = address(0x52); function setUp() public { - // Create forks of both networks string memory ETHEREUM_MAINNET_RPC_URL = vm.envString( "ETHEREUM_MAINNET_RPC_URL" ); ethereumMainnetForkId = vm.createFork(ETHEREUM_MAINNET_RPC_URL); vm.selectFork(ethereumMainnetForkId); - deal(address(ctx), user, 100_000_000 ether); - vm.prank(user); - ctx.delegate(user); - vm.makePersistent(user); - - // Deploy GovernanceRelay on Ethereum -// vm.selectFork(ethereumMainnetForkId); -// address timelockComputedAddress = computeCreateAddress( -// address(user), -// vm.getNonce(user) + 1 -// ); -// vm.startPrank(user); -// address ctxAddress = deployCode( -// "Ctx.sol", -// abi.encode(user, user, block.timestamp) -// ); -// ctx = ICtx(ctxAddress); -// address GovernorBetaComputedAddress = computeCreateAddress( -// address(user), -// vm.getNonce(user) + 1 -// ); -// address timeLockAddress = deployCode( -// "Timelock.sol", -// abi.encode(GovernorBetaComputedAddress, 2 days) -// ); -// timelock = ITimelock(timeLockAddress); -// address governorBetaAddress = deployCode( -// "GovernorBeta.sol:GovernorBeta", -// abi.encode(address(timelock), ctx, user) -// ); -// governorBeta = IGovernorBeta(governorBetaAddress); -// ctx.delegate(user); -// vm.stopPrank(); -// vm.deal(timeLockAddress, 10 ether); -// vm.makePersistent(address(governanceRelay)); -// vm.makePersistent(ctxAddress); -// vm.makePersistent(timeLockAddress); -// vm.makePersistent(governorBetaAddress); + deal(address(ctx), user, 100_000_000 ether); + vm.prank(user); + ctx.delegate(user); + vm.makePersistent(user); } - function testCIP36() external { - vm.selectFork(ethereumMainnetForkId); - address[] memory targets = new address[](1); + function testCIP36() external { + vm.selectFork(ethereumMainnetForkId); + address[] memory targets = new address[](1); uint256[] memory values = new uint256[](1); string[] memory signatures = new string[](1); bytes[] memory calldatas = new bytes[](1); - string memory description; + string memory description; - address subDAOMultisig = 0x41187c70eB8eeEfDaEd4ED0bFF20005C53c3a7DD; + address subDAOMultisig = 0x41187c70eB8eeEfDaEd4ED0bFF20005C53c3a7DD; - targets[0] = 0x321C2fE4446C7c963dc41Dd58879AF648838f98D; - values[0] = 0; - signatures[0] = "transfer(address,uint256)"; - calldatas[0] = hex"00000000000000000000000041187c70eb8eeefdaed4ed0bff20005c53c3a7dd000000000000000000000000000000000000000000001a784379d99db4200000"; - description = "CIP-36: Regulatory Advocacy & Public Affairs Strategy"; - uint256 oldBalance = ctx.balanceOf(subDAOMultisig); - createAndExecuteGovernanceProposal( - targets, - values, - signatures, - calldatas, - description - ); - uint256 newBalance = ctx.balanceOf(subDAOMultisig); - assertEq(newBalance - oldBalance, 125_000 ether); - } + targets[0] = 0x321C2fE4446C7c963dc41Dd58879AF648838f98D; + values[0] = 0; + signatures[0] = "transfer(address,uint256)"; + calldatas[ + 0 + ] = hex"00000000000000000000000041187c70eb8eeefdaed4ed0bff20005c53c3a7dd000000000000000000000000000000000000000000001a784379d99db4200000"; + description = "CIP-36: Regulatory Advocacy & Public Affairs Strategy"; + uint256 oldBalance = ctx.balanceOf(subDAOMultisig); + createAndExecuteGovernanceProposal( + targets, + values, + signatures, + calldatas, + description + ); + uint256 newBalance = ctx.balanceOf(subDAOMultisig); + assertEq(newBalance - oldBalance, 125_000 ether); + } function createAndExecuteGovernanceProposal( address[] memory targets, uint256[] memory values, string[] memory signatures, bytes[] memory calldatas, - string memory description + string memory description ) internal { vm.startPrank(user); vm.roll(block.number + 100); From b0deb0953764daa21cc4aa4d12e5b0373b666cd6 Mon Sep 17 00:00:00 2001 From: voith Date: Thu, 24 Apr 2025 22:55:25 +0530 Subject: [PATCH 3/3] added cip-37 --- scripts/CIP-37.ts | 70 +++++++++++++++++++++++++++++++ test/proposals/TestProposal.t.sol | 29 +++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 scripts/CIP-37.ts diff --git a/scripts/CIP-37.ts b/scripts/CIP-37.ts new file mode 100644 index 00000000..a8a1cf26 --- /dev/null +++ b/scripts/CIP-37.ts @@ -0,0 +1,70 @@ +// run with +// npx hardhat run ./scripts/CIP-37.ts --network hardhat +import hre, { deployments, network, hardhatArguments } from "hardhat"; +import { + castVote, + createProposal, + executeProposal, + fundMultisign, + queueProposal, +} from "./utils"; +import { BigNumber } from "ethers"; + +async function main() { + const ethers = hre.ethers; + let multisig = "0xa70b638B70154EdfCbb8DbbBd04900F328F32c35"; + let ctxAmount = ethers.utils.parseEther("120000"); + let ctx = await deployments.get("Ctx"); + let ctxContract = await ethers.getContractAt("Ctx", ctx.address); + + const abi = new ethers.utils.AbiCoder(); + const targets = [ctx.address]; + const values = [BigNumber.from(0)]; + const signatures = ["transfer(address,uint256)"]; + const calldatas = [ + abi.encode(["address", "uint256"], [multisig, ctxAmount]), + ]; + const description = + "CIP-37: Supplemental Treasury Transfer to Sustain Q2 2025 Operations"; + console.log(targets); + console.log(values.toString()); + console.log(signatures); + console.log(calldatas); + console.log(description); + + let ctxbalance = await ctxContract.balanceOf(multisig); + console.log("multisig old CTX balance", ethers.utils.formatEther(ctxbalance)); + + if (hardhatArguments.network === "hardhat") { + //Fund Multisign with ETH + await fundMultisign("10000000000000000000"); + + // Create Proposal + await createProposal(targets, values, signatures, calldatas, description); + + // Vote + await castVote(17, true); + + // Wait to queue + await queueProposal(17); + + // Execute transaction + await executeProposal(17); + + // Validate Results + console.log("==================Check Results=================="); + + ctxbalance = await ctxContract.balanceOf(multisig); + console.log( + "multisig new CTX balance", + ethers.utils.formatEther(ctxbalance) + ); + } +} + +main() + .then(() => process.exit(0)) + .catch((error) => { + console.error(error); + process.exit(1); + }); diff --git a/test/proposals/TestProposal.t.sol b/test/proposals/TestProposal.t.sol index 9c8ce04d..2c6c8e63 100644 --- a/test/proposals/TestProposal.t.sol +++ b/test/proposals/TestProposal.t.sol @@ -63,6 +63,35 @@ contract GovernanceCCIPIntegrationTest is Test { assertEq(newBalance - oldBalance, 125_000 ether); } + function testCIP37() external { + vm.selectFork(ethereumMainnetForkId); + address[] memory targets = new address[](1); + uint256[] memory values = new uint256[](1); + string[] memory signatures = new string[](1); + bytes[] memory calldatas = new bytes[](1); + string memory description; + + address teamMultisig = 0xa70b638B70154EdfCbb8DbbBd04900F328F32c35; + + targets[0] = 0x321C2fE4446C7c963dc41Dd58879AF648838f98D; + values[0] = 0; + signatures[0] = "transfer(address,uint256)"; + calldatas[ + 0 + ] = hex"000000000000000000000000a70b638b70154edfcbb8dbbbd04900f328f32c35000000000000000000000000000000000000000000001969368974c05b000000"; + description = "CIP-37: Supplemental Treasury Transfer to Sustain Q2 2025 Operations"; + uint256 oldBalance = ctx.balanceOf(teamMultisig); + createAndExecuteGovernanceProposal( + targets, + values, + signatures, + calldatas, + description + ); + uint256 newBalance = ctx.balanceOf(teamMultisig); + assertEq(newBalance - oldBalance, 120_000 ether); + } + function createAndExecuteGovernanceProposal( address[] memory targets, uint256[] memory values,