Timelock Proposal
Overview
Proposal Contract
function name() public pure override returns (string memory) { return "TIMELOCK_MOCK"; }function description() public pure override returns (string memory) { return "Timelock proposal mock"; }function deploy() public override { // Deploy vault address if not already deployed and transfer ownership to timelock. if (!addresses.isAddressSet("TIMELOCK_VAULT")) { Vault timelockVault = new Vault(); addresses.addAddress( "TIMELOCK_VAULT", address(timelockVault), true ); timelockVault.transferOwnership(address(timelock)); } // Deploy token address if not already deployed, transfer ownership to timelock // and transfer all initial minted tokens from deployer to timelock. if (!addresses.isAddressSet("TIMELOCK_TOKEN")) { Token token = new Token(); addresses.addAddress("TIMELOCK_TOKEN", address(token), true); token.transferOwnership(address(timelock)); // During forge script execution, the deployer of the contracts is // the DEPLOYER_EOA. However, when running through forge test, the deployer of the contracts is this contract. uint256 balance = token.balanceOf(address(this)) > 0 ? token.balanceOf(address(this)) : token.balanceOf(addresses.getAddress("DEPLOYER_EOA")); token.transfer(address(timelock), balance); } }function build() public override buildModifier(address(timelock)) { /// STATICCALL -- non-mutative and hence not recorded for the run stage // Get vault address address timelockVault = addresses.getAddress("TIMELOCK_VAULT"); // Get token address address token = addresses.getAddress("TIMELOCK_TOKEN"); // Get timelock's token balance. uint256 balance = Token(token).balanceOf(address(timelock)); /// CALLS -- mutative and recorded // Whitelists the deployed token on the deployed vault. Vault(timelockVault).whitelistToken(token, true); // Approve the token for the vault. Token(token).approve(timelockVault, balance); // Deposit all tokens into the vault. Vault(timelockVault).deposit(token, balance); }function run() public override { // Create and select the sepolia fork for proposal execution primaryForkId = vm.createFork("sepolia"); vm.selectFork(primaryForkId); string memory addressesFolderPath = "./addresses"; uint256[] memory chainIds = new uint256[](1); chainIds[0] = 11155111; // Set the addresses object by reading addresses from the json file. setAddresses( new Addresses(addressesFolderPath, chainIds) ); // Set the timelock; this address is used for proposal simulation and checking on-chain proposal state setTimelock(addresses.getAddress("PROTOCOL_TIMELOCK")); // Call the run function of the parent contract 'Proposal.sol' super.run(); }function simulate() public override { // Get dev address for simulation address dev = addresses.getAddress("DEPLOYER_EOA"); /// Dev is proposer and executor of timelock _simulateActions(dev, dev); }function validate() public override { // Get vault address Vault timelockVault = Vault(addresses.getAddress("TIMELOCK_VAULT")); // Get token address Token token = Token(addresses.getAddress("TIMELOCK_TOKEN")); // Ensure the total supply of tokens is 10 million assertEq(token.totalSupply(), 10_000_000e18); // Ensure the timelock is the owner of the deployed token assertEq(token.owner(), address(timelock)); // Ensure the timelock is the owner of the deployed vault assertEq(timelockVault.owner(), address(timelock)); // Ensure the vault is not paused assertFalse(timelockVault.paused()); // Ensure the token is whitelisted on the vault assertTrue(timelockVault.tokenWhitelist(address(token))); // Get the vault's token balance uint256 balance = token.balanceOf(address(timelockVault)); // Get the timelock deposits in the vault (uint256 amount, ) = timelockVault.deposits( address(token), address(timelock) ); // Ensure the timelock deposit is the same as the vault's token balance assertEq(amount, balance); // Ensure all minted tokens are deposited into the vault assertEq(token.balanceOf(address(timelockVault)), token.totalSupply()); }
Proposal Simulation
Deploying a Timelock Controller on Testnet
Setting Up the Addresses JSON
Running the Proposal
Last updated