// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Utils } from "./Utils.sol"; import { Proposal, IGovernance } from "@interfaces/IGovernance.sol"; contract ProposalUtils is Utils { IGovernance internal governance = IGovernance(governanceAddress); function getProposalExecutableTime(uint256 proposalId) internal view returns (uint256) { Proposal memory proposal = getProposal(proposalId); return proposal.endTime + PROPOSAL_LOCKED_DURATION + 1 seconds; } function getProposal(uint256 proposalId) internal view returns (Proposal memory) { return governance.proposals(proposalId); } function hasProposal(uint256 proposalId) internal view returns (bool) { return governance.proposalCount() >= proposalId; } function waitUntilExecutable(uint256 proposalId) internal { uint256 proposalExecutableTime = getProposalExecutableTime(proposalId); require(block.timestamp < proposalExecutableTime + PROPOSAL_EXECUTION_MAX_DURATION, "Too late to execute proposal"); vm.warp(proposalExecutableTime); } function proposeAndVote(address proposalAddress) public returns (uint256) { retrieveAndLockBalance(TEST_PRIVATE_KEY_ONE, TEST_ADDRESS_ONE, PROPOSAL_QOURUM_THRESHOLD + 1 ether); /* ----------PROPOSE------------ */ vm.startPrank(TEST_ADDRESS_ONE); uint256 proposalId = governance.propose(proposalAddress, PROPOSAL_DESCRIPTION); /* ------------------------------ */ // TIME-TRAVEL vm.warp(block.timestamp + 6 hours); /* ------------VOTE-------------- */ governance.castVote(proposalId, true); vm.stopPrank(); /* ------------------------------ */ return proposalId; } function proposeAndExecute(address proposalAddress) public { uint256 proposalId = proposeAndVote(proposalAddress); waitUntilExecutable(proposalId); governance.execute(proposalId); returnTokensToGovernanceAfterVoting(proposalId); } function returnTokensToGovernanceAfterVoting(uint256 proposalId) public { uint256 retrievedAmount = PROPOSAL_QOURUM_THRESHOLD + 1 ether; uint256 proposalExecutableTime = getProposalExecutableTime(proposalId); uint256 tokensUnlockTime = proposalExecutableTime + PROPOSAL_VOTE_EXTEND_TIME + PROPOSAL_EXECUTION_MAX_DURATION + 1 seconds; if(block.timestamp < tokensUnlockTime) vm.warp(tokensUnlockTime); vm.startPrank(TEST_ADDRESS_ONE); governance.unlock(retrievedAmount); IERC20(_tokenAddress).transfer(_governanceAddress, retrievedAmount); vm.stopPrank(); } }