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/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 new file mode 100644 index 00000000..2c6c8e63 --- /dev/null +++ b/test/proposals/TestProposal.t.sol @@ -0,0 +1,118 @@ +// 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 { + 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); + } + + 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 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, + 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(); + } +}