├── .gitattributes ├── .gitignore ├── migrations ├── 1_initial_migration.js ├── 2_deploy_savior.js └── save.js ├── contracts ├── Migrations.sol ├── lib │ ├── Babylonian.sol │ ├── UniswapV2OracleLibrary.sol │ ├── IUniswapV2Pair.sol │ ├── IERC20.sol │ ├── FixedPoint.sol │ ├── SafeERC20.sol │ ├── SafeMath.sol │ └── Address.sol └── YAMGovernorAlpha.sol ├── package.json └── truffle-config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sol linguist-language=Solidity 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | wrangler.toml 4 | -------------------------------------------------------------------------------- /migrations/1_initial_migration.js: -------------------------------------------------------------------------------- 1 | const Migrations = artifacts.require("Migrations"); 2 | 3 | module.exports = function(deployer) { 4 | deployer.deploy(Migrations); 5 | }; 6 | -------------------------------------------------------------------------------- /contracts/Migrations.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | pragma solidity >=0.4.21 <0.7.0; 3 | 4 | contract Migrations { 5 | address public owner; 6 | uint public last_completed_migration; 7 | 8 | constructor() public { 9 | owner = msg.sender; 10 | } 11 | 12 | modifier restricted() { 13 | if (msg.sender == owner) _; 14 | } 15 | 16 | function setCompleted(uint completed) public restricted { 17 | last_completed_migration = completed; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /migrations/2_deploy_savior.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | // ============ Contracts ============ 4 | 5 | // Governance 6 | // deployed third 7 | const SaviorGov = artifacts.require("GovernorAlpha"); 8 | 9 | 10 | 11 | // ============ Main Migration ============ 12 | 13 | const migration = async (deployer, network, accounts) => { 14 | await Promise.all([ 15 | deploySaveGovernance(deployer, network), 16 | ]); 17 | }; 18 | 19 | module.exports = migration; 20 | 21 | 22 | async function deploySaveGovernance(deployer, network) { 23 | await deployer.deploy(SaviorGov, "0xae99ff8fe2236af5083ea979ecf1dbaa0efd07e3", "0x0e2298e3b3390e3b945a5456fbf59ecc3f55da16"); 24 | } 25 | -------------------------------------------------------------------------------- /contracts/lib/Babylonian.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.4.0; 4 | 5 | // computes square roots using the babylonian method 6 | // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method 7 | library Babylonian { 8 | function sqrt(uint y) internal pure returns (uint z) { 9 | if (y > 3) { 10 | z = y; 11 | uint x = y / 2 + 1; 12 | while (x < z) { 13 | z = x; 14 | x = (y / x + x) / 2; 15 | } 16 | } else if (y != 0) { 17 | z = 1; 18 | } 19 | // else z = 0 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "saveyam", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "truffle-config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "test": "echo \"Error: no test specified\" && exit 1" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/yam-finance/saveYAM.git" 15 | }, 16 | "author": "", 17 | "license": "ISC", 18 | "bugs": { 19 | "url": "https://github.com/yam-finance/saveYAM/issues" 20 | }, 21 | "homepage": "https://github.com/yam-finance/saveYAM#readme", 22 | "dependencies": { 23 | "dotenv-flow": "^3.2.0" 24 | }, 25 | "devDependencies": { 26 | "@truffle/hdwallet-provider": "^1.0.42" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /migrations/save.js: -------------------------------------------------------------------------------- 1 | /// RENAME to 3_save.js when ready to propose! 2 | 3 | 4 | 5 | // ============ Contracts ============ 6 | 7 | // Governance 8 | // deployed third 9 | const SaviorGov = artifacts.require("GovernorAlpha"); 10 | const Timelock = artifacts.require("Timelock"); 11 | 12 | 13 | 14 | // ============ Main Migration ============ 15 | 16 | const migration = async (deployer, network, accounts) => { 17 | await Promise.all([ 18 | saveYAM(deployer, network), 19 | ]); 20 | }; 21 | 22 | module.exports = migration; 23 | 24 | 25 | async function saveYAM(deployer, network) { 26 | let curr_gov = "0x6abA376e3331E3090456495e8292ecdFA1ab4920" 27 | let gov = new web3.eth.Contract(SaviorGov.abi, curr_gov); 28 | gov.methods.propose( 29 | [ 30 | "0xaE99fF8fe2236AF5083Ea979Ecf1DbAA0EFD07E3", "0x0e2298E3B3390e3b945a5456fBf59eCc3f55DA16" 31 | ], 32 | [0, 0], 33 | ["setPendingAdmin(address)", "_setRebaser(address)"], 34 | [ 35 | SaviorGov.address, 36 | "0x0000000000000000000000000000000000000000" 37 | ], 38 | "Save YAM. Decrease quorum & threshold to static amounts, Remove rebasing." 39 | ).send({from: "0x683A78bA1f6b25E29fbBC9Cd1BFA29A51520De84", gas: 1000000}); 40 | } 41 | -------------------------------------------------------------------------------- /contracts/lib/UniswapV2OracleLibrary.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | import './IUniswapV2Pair.sol'; 4 | import './FixedPoint.sol'; 5 | 6 | // library with helper methods for oracles that are concerned with computing average prices 7 | library UniswapV2OracleLibrary { 8 | using FixedPoint for *; 9 | 10 | // helper function that returns the current block timestamp within the range of uint32, i.e. [0, 2**32 - 1] 11 | function currentBlockTimestamp() internal view returns (uint32) { 12 | return uint32(block.timestamp % 2 ** 32); 13 | } 14 | 15 | // produces the cumulative price using counterfactuals to save gas and avoid a call to sync. 16 | function currentCumulativePrices( 17 | address pair, 18 | bool isToken0 19 | ) internal view returns (uint priceCumulative, uint32 blockTimestamp) { 20 | blockTimestamp = currentBlockTimestamp(); 21 | (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast) = UniswapPair(pair).getReserves(); 22 | if (isToken0) { 23 | priceCumulative = UniswapPair(pair).price0CumulativeLast(); 24 | 25 | // if time has elapsed since the last update on the pair, mock the accumulated price values 26 | if (blockTimestampLast != blockTimestamp) { 27 | // subtraction overflow is desired 28 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; 29 | // addition overflow is desired 30 | // counterfactual 31 | priceCumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; 32 | } 33 | } else { 34 | priceCumulative = UniswapPair(pair).price1CumulativeLast(); 35 | // if time has elapsed since the last update on the pair, mock the accumulated price values 36 | if (blockTimestampLast != blockTimestamp) { 37 | // subtraction overflow is desired 38 | uint32 timeElapsed = blockTimestamp - blockTimestampLast; 39 | // addition overflow is desired 40 | // counterfactual 41 | priceCumulative += uint(FixedPoint.fraction(reserve1, reserve0)._x) * timeElapsed; 42 | } 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /truffle-config.js: -------------------------------------------------------------------------------- 1 | require('dotenv-flow').config(); 2 | const HDWalletProvider = require("@truffle/hdwallet-provider"); 3 | var Web3 = require('web3'); 4 | // var p = ; 5 | module.exports = { 6 | compilers: { 7 | solc: { 8 | version: '0.5.17', 9 | docker: process.env.DOCKER_COMPILER !== undefined 10 | ? process.env.DOCKER_COMPILER === 'true' : true, 11 | parser: 'solcjs', 12 | settings: { 13 | optimizer: { 14 | enabled: true, 15 | runs: 50000 16 | }, 17 | evmVersion: 'istanbul', 18 | }, 19 | }, 20 | }, 21 | networks: { 22 | test: { 23 | host: '0.0.0.0', 24 | port: 8545, 25 | network_id: '1001', 26 | gasPrice: 50000000000, 27 | gas: 8000000, 28 | network_id: '1001', 29 | }, 30 | distribution: { 31 | host: '0.0.0.0', 32 | port: 8545, 33 | network_id: '1001', 34 | gasPrice: 50000000000, 35 | gas: 8000000, 36 | network_id: '1001', 37 | }, 38 | test_ci: { 39 | host: '0.0.0.0', 40 | port: 8545, 41 | gasPrice: 1, 42 | gas: 10000000, 43 | network_id: '1001', 44 | }, 45 | mainnet: { 46 | network_id: '1', 47 | provider: () => new HDWalletProvider( 48 | [process.env.DEPLOYER_PRIVATE_KEY], 49 | "https://mainnet.infura.io/v3/731a2b3d28e445b7ac56f23507614fea", 50 | 0, 51 | 1, 52 | ), 53 | gasPrice: Number(process.env.GAS_PRICE), 54 | gas: 8000000, 55 | from: process.env.DEPLOYER_ACCOUNT, 56 | timeoutBlocks: 800, 57 | }, 58 | kovan: { 59 | network_id: '42', 60 | provider: () => new HDWalletProvider( 61 | [process.env.DEPLOYER_PRIVATE_KEY], 62 | 'https://kovan.infura.io/v3/04c5f76635f24c70b28488be34dbd838', 63 | 0, 64 | 1, 65 | ), 66 | gasPrice: 10000000000, // 10 gwei 67 | gas: 6900000, 68 | from: process.env.DEPLOYER_ACCOUNT, 69 | timeoutBlocks: 500, 70 | }, 71 | dev: { 72 | host: 'localhost', 73 | port: 8445, 74 | network_id: '1005', 75 | gasPrice: 1000000000, // 1 gwei 76 | gas: 8000000, 77 | }, 78 | coverage: { 79 | host: '0.0.0.0', 80 | network_id: '1002', 81 | port: 8555, 82 | gas: 0xfffffffffff, 83 | gasPrice: 1, 84 | }, 85 | docker: { 86 | host: 'localhost', 87 | network_id: '1313', 88 | port: 8545, 89 | gasPrice: 1, 90 | }, 91 | }, 92 | }; 93 | -------------------------------------------------------------------------------- /contracts/lib/IUniswapV2Pair.sol: -------------------------------------------------------------------------------- 1 | pragma solidity >=0.5.0; 2 | 3 | interface UniswapPair { 4 | event Approval(address indexed owner, address indexed spender, uint value); 5 | event Transfer(address indexed from, address indexed to, uint value); 6 | 7 | function name() external pure returns (string memory); 8 | function symbol() external pure returns (string memory); 9 | function decimals() external pure returns (uint8); 10 | function totalSupply() external view returns (uint); 11 | function balanceOf(address owner) external view returns (uint); 12 | function allowance(address owner, address spender) external view returns (uint); 13 | 14 | function approve(address spender, uint value) external returns (bool); 15 | function transfer(address to, uint value) external returns (bool); 16 | function transferFrom(address from, address to, uint value) external returns (bool); 17 | 18 | function DOMAIN_SEPARATOR() external view returns (bytes32); 19 | function PERMIT_TYPEHASH() external pure returns (bytes32); 20 | function nonces(address owner) external view returns (uint); 21 | 22 | function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external; 23 | 24 | event Mint(address indexed sender, uint amount0, uint amount1); 25 | event Burn(address indexed sender, uint amount0, uint amount1, address indexed to); 26 | event Swap( 27 | address indexed sender, 28 | uint amount0In, 29 | uint amount1In, 30 | uint amount0Out, 31 | uint amount1Out, 32 | address indexed to 33 | ); 34 | event Sync(uint112 reserve0, uint112 reserve1); 35 | 36 | function MINIMUM_LIQUIDITY() external pure returns (uint); 37 | function factory() external view returns (address); 38 | function token0() external view returns (address); 39 | function token1() external view returns (address); 40 | function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast); 41 | function price0CumulativeLast() external view returns (uint); 42 | function price1CumulativeLast() external view returns (uint); 43 | function kLast() external view returns (uint); 44 | 45 | function mint(address to) external returns (uint liquidity); 46 | function burn(address to) external returns (uint amount0, uint amount1); 47 | function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external; 48 | function skim(address to) external; 49 | function sync() external; 50 | 51 | function initialize(address, address) external; 52 | } 53 | -------------------------------------------------------------------------------- /contracts/lib/IERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | /** 6 | * @dev Interface of the ERC20 standard as defined in the EIP. 7 | */ 8 | interface IERC20 { 9 | /** 10 | * @dev Returns the amount of tokens in existence. 11 | */ 12 | function totalSupply() external view returns (uint256); 13 | 14 | /** 15 | * @dev Returns the amount of tokens owned by `account`. 16 | */ 17 | function balanceOf(address account) external view returns (uint256); 18 | 19 | /** 20 | * @dev Moves `amount` tokens from the caller's account to `recipient`. 21 | * 22 | * Returns a boolean value indicating whether the operation succeeded. 23 | * 24 | * Emits a {Transfer} event. 25 | */ 26 | function transfer(address recipient, uint256 amount) external returns (bool); 27 | 28 | /** 29 | * @dev Returns the remaining number of tokens that `spender` will be 30 | * allowed to spend on behalf of `owner` through {transferFrom}. This is 31 | * zero by default. 32 | * 33 | * This value changes when {approve} or {transferFrom} are called. 34 | */ 35 | function allowance(address owner, address spender) external view returns (uint256); 36 | 37 | /** 38 | * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. 39 | * 40 | * Returns a boolean value indicating whether the operation succeeded. 41 | * 42 | * IMPORTANT: Beware that changing an allowance with this method brings the risk 43 | * that someone may use both the old and the new allowance by unfortunate 44 | * transaction ordering. One possible solution to mitigate this race 45 | * condition is to first reduce the spender's allowance to 0 and set the 46 | * desired value afterwards: 47 | * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 48 | * 49 | * Emits an {Approval} event. 50 | */ 51 | function approve(address spender, uint256 amount) external returns (bool); 52 | 53 | /** 54 | * @dev Moves `amount` tokens from `sender` to `recipient` using the 55 | * allowance mechanism. `amount` is then deducted from the caller's 56 | * allowance. 57 | * 58 | * Returns a boolean value indicating whether the operation succeeded. 59 | * 60 | * Emits a {Transfer} event. 61 | */ 62 | function transferFrom(address sender, address recipient, uint256 amount) external returns (bool); 63 | 64 | /** 65 | * @dev Emitted when `value` tokens are moved from one account (`from`) to 66 | * another (`to`). 67 | * 68 | * Note that `value` may be zero. 69 | */ 70 | event Transfer(address indexed from, address indexed to, uint256 value); 71 | 72 | /** 73 | * @dev Emitted when the allowance of a `spender` for an `owner` is set by 74 | * a call to {approve}. `value` is the new allowance. 75 | */ 76 | event Approval(address indexed owner, address indexed spender, uint256 value); 77 | } 78 | -------------------------------------------------------------------------------- /contracts/lib/FixedPoint.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-3.0-or-later 2 | 3 | pragma solidity >=0.4.0; 4 | 5 | import './Babylonian.sol'; 6 | 7 | // a library for handling binary fixed point numbers (https://en.wikipedia.org/wiki/Q_(number_format)) 8 | library FixedPoint { 9 | // range: [0, 2**112 - 1] 10 | // resolution: 1 / 2**112 11 | struct uq112x112 { 12 | uint224 _x; 13 | } 14 | 15 | // range: [0, 2**144 - 1] 16 | // resolution: 1 / 2**112 17 | struct uq144x112 { 18 | uint _x; 19 | } 20 | 21 | uint8 private constant RESOLUTION = 112; 22 | uint private constant Q112 = uint(1) << RESOLUTION; 23 | uint private constant Q224 = Q112 << RESOLUTION; 24 | 25 | // encode a uint112 as a UQ112x112 26 | function encode(uint112 x) internal pure returns (uq112x112 memory) { 27 | return uq112x112(uint224(x) << RESOLUTION); 28 | } 29 | 30 | // encodes a uint144 as a UQ144x112 31 | function encode144(uint144 x) internal pure returns (uq144x112 memory) { 32 | return uq144x112(uint256(x) << RESOLUTION); 33 | } 34 | 35 | // divide a UQ112x112 by a uint112, returning a UQ112x112 36 | function div(uq112x112 memory self, uint112 x) internal pure returns (uq112x112 memory) { 37 | require(x != 0, 'FixedPoint: DIV_BY_ZERO'); 38 | return uq112x112(self._x / uint224(x)); 39 | } 40 | 41 | // multiply a UQ112x112 by a uint, returning a UQ144x112 42 | // reverts on overflow 43 | function mul(uq112x112 memory self, uint y) internal pure returns (uq144x112 memory) { 44 | uint z; 45 | require(y == 0 || (z = uint(self._x) * y) / y == uint(self._x), "FixedPoint: MULTIPLICATION_OVERFLOW"); 46 | return uq144x112(z); 47 | } 48 | 49 | // returns a UQ112x112 which represents the ratio of the numerator to the denominator 50 | // equivalent to encode(numerator).div(denominator) 51 | function fraction(uint112 numerator, uint112 denominator) internal pure returns (uq112x112 memory) { 52 | require(denominator > 0, "FixedPoint: DIV_BY_ZERO"); 53 | return uq112x112((uint224(numerator) << RESOLUTION) / denominator); 54 | } 55 | 56 | // decode a UQ112x112 into a uint112 by truncating after the radix point 57 | function decode(uq112x112 memory self) internal pure returns (uint112) { 58 | return uint112(self._x >> RESOLUTION); 59 | } 60 | 61 | // decode a UQ144x112 into a uint144 by truncating after the radix point 62 | function decode144(uq144x112 memory self) internal pure returns (uint144) { 63 | return uint144(self._x >> RESOLUTION); 64 | } 65 | 66 | // take the reciprocal of a UQ112x112 67 | function reciprocal(uq112x112 memory self) internal pure returns (uq112x112 memory) { 68 | require(self._x != 0, 'FixedPoint: ZERO_RECIPROCAL'); 69 | return uq112x112(uint224(Q224 / self._x)); 70 | } 71 | 72 | // square root of a UQ112x112 73 | function sqrt(uq112x112 memory self) internal pure returns (uq112x112 memory) { 74 | return uq112x112(uint224(Babylonian.sqrt(uint256(self._x)) << 56)); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /contracts/lib/SafeERC20.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | import "./IERC20.sol"; 6 | import "./SafeMath.sol"; 7 | import "./Address.sol"; 8 | 9 | /** 10 | * @title SafeERC20 11 | * @dev Wrappers around ERC20 operations that throw on failure (when the token 12 | * contract returns false). Tokens that return no value (and instead revert or 13 | * throw on failure) are also supported, non-reverting calls are assumed to be 14 | * successful. 15 | * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, 16 | * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. 17 | */ 18 | library SafeERC20 { 19 | using SafeMath for uint256; 20 | using Address for address; 21 | 22 | function safeTransfer(IERC20 token, address to, uint256 value) internal { 23 | _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); 24 | } 25 | 26 | function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal { 27 | _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); 28 | } 29 | 30 | /** 31 | * @dev Deprecated. This function has issues similar to the ones found in 32 | * {IERC20-approve}, and its usage is discouraged. 33 | * 34 | * Whenever possible, use {safeIncreaseAllowance} and 35 | * {safeDecreaseAllowance} instead. 36 | */ 37 | function safeApprove(IERC20 token, address spender, uint256 value) internal { 38 | // safeApprove should only be called when setting an initial allowance, 39 | // or when resetting it to zero. To increase and decrease it, use 40 | // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' 41 | // solhint-disable-next-line max-line-length 42 | require((value == 0) || (token.allowance(address(this), spender) == 0), 43 | "SafeERC20: approve from non-zero to non-zero allowance" 44 | ); 45 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); 46 | } 47 | 48 | function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal { 49 | uint256 newAllowance = token.allowance(address(this), spender).add(value); 50 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 51 | } 52 | 53 | function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal { 54 | uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero"); 55 | _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); 56 | } 57 | 58 | /** 59 | * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement 60 | * on the return value: the return value is optional (but if data is returned, it must not be false). 61 | * @param token The token targeted by the call. 62 | * @param data The call data (encoded using abi.encode or one of its variants). 63 | */ 64 | function _callOptionalReturn(IERC20 token, bytes memory data) private { 65 | // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since 66 | // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that 67 | // the target address contains contract code and also asserts for success in the low-level call. 68 | 69 | bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); 70 | if (returndata.length > 0) { // Return data is optional 71 | // solhint-disable-next-line max-line-length 72 | require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /contracts/lib/SafeMath.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | /** 6 | * @dev Wrappers over Solidity's arithmetic operations with added overflow 7 | * checks. 8 | * 9 | * Arithmetic operations in Solidity wrap on overflow. This can easily result 10 | * in bugs, because programmers usually assume that an overflow raises an 11 | * error, which is the standard behavior in high level programming languages. 12 | * `SafeMath` restores this intuition by reverting the transaction when an 13 | * operation overflows. 14 | * 15 | * Using this library instead of the unchecked operations eliminates an entire 16 | * class of bugs, so it's recommended to use it always. 17 | */ 18 | library SafeMath { 19 | /** 20 | * @dev Returns the addition of two unsigned integers, reverting on 21 | * overflow. 22 | * 23 | * Counterpart to Solidity's `+` operator. 24 | * 25 | * Requirements: 26 | * 27 | * - Addition cannot overflow. 28 | */ 29 | function add(uint256 a, uint256 b) internal pure returns (uint256) { 30 | uint256 c = a + b; 31 | require(c >= a, "SafeMath: addition overflow"); 32 | 33 | return c; 34 | } 35 | 36 | /** 37 | * @dev Returns the subtraction of two unsigned integers, reverting on 38 | * overflow (when the result is negative). 39 | * 40 | * Counterpart to Solidity's `-` operator. 41 | * 42 | * Requirements: 43 | * 44 | * - Subtraction cannot overflow. 45 | */ 46 | function sub(uint256 a, uint256 b) internal pure returns (uint256) { 47 | return sub(a, b, "SafeMath: subtraction overflow"); 48 | } 49 | 50 | /** 51 | * @dev Returns the subtraction of two unsigned integers, reverting with custom message on 52 | * overflow (when the result is negative). 53 | * 54 | * Counterpart to Solidity's `-` operator. 55 | * 56 | * Requirements: 57 | * 58 | * - Subtraction cannot overflow. 59 | */ 60 | function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 61 | require(b <= a, errorMessage); 62 | uint256 c = a - b; 63 | 64 | return c; 65 | } 66 | 67 | /** 68 | * @dev Returns the multiplication of two unsigned integers, reverting on 69 | * overflow. 70 | * 71 | * Counterpart to Solidity's `*` operator. 72 | * 73 | * Requirements: 74 | * 75 | * - Multiplication cannot overflow. 76 | */ 77 | function mul(uint256 a, uint256 b) internal pure returns (uint256) { 78 | // Gas optimization: this is cheaper than requiring 'a' not being zero, but the 79 | // benefit is lost if 'b' is also tested. 80 | // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522 81 | if (a == 0) { 82 | return 0; 83 | } 84 | 85 | uint256 c = a * b; 86 | require(c / a == b, "SafeMath: multiplication overflow"); 87 | 88 | return c; 89 | } 90 | 91 | /** 92 | * @dev Returns the integer division of two unsigned integers. Reverts on 93 | * division by zero. The result is rounded towards zero. 94 | * 95 | * Counterpart to Solidity's `/` operator. Note: this function uses a 96 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 97 | * uses an invalid opcode to revert (consuming all remaining gas). 98 | * 99 | * Requirements: 100 | * 101 | * - The divisor cannot be zero. 102 | */ 103 | function div(uint256 a, uint256 b) internal pure returns (uint256) { 104 | return div(a, b, "SafeMath: division by zero"); 105 | } 106 | 107 | /** 108 | * @dev Returns the integer division of two unsigned integers. Reverts with custom message on 109 | * division by zero. The result is rounded towards zero. 110 | * 111 | * Counterpart to Solidity's `/` operator. Note: this function uses a 112 | * `revert` opcode (which leaves remaining gas untouched) while Solidity 113 | * uses an invalid opcode to revert (consuming all remaining gas). 114 | * 115 | * Requirements: 116 | * 117 | * - The divisor cannot be zero. 118 | */ 119 | function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 120 | require(b > 0, errorMessage); 121 | uint256 c = a / b; 122 | // assert(a == b * c + a % b); // There is no case in which this doesn't hold 123 | 124 | return c; 125 | } 126 | 127 | /** 128 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 129 | * Reverts when dividing by zero. 130 | * 131 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 132 | * opcode (which leaves remaining gas untouched) while Solidity uses an 133 | * invalid opcode to revert (consuming all remaining gas). 134 | * 135 | * Requirements: 136 | * 137 | * - The divisor cannot be zero. 138 | */ 139 | function mod(uint256 a, uint256 b) internal pure returns (uint256) { 140 | return mod(a, b, "SafeMath: modulo by zero"); 141 | } 142 | 143 | /** 144 | * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo), 145 | * Reverts with custom message when dividing by zero. 146 | * 147 | * Counterpart to Solidity's `%` operator. This function uses a `revert` 148 | * opcode (which leaves remaining gas untouched) while Solidity uses an 149 | * invalid opcode to revert (consuming all remaining gas). 150 | * 151 | * Requirements: 152 | * 153 | * - The divisor cannot be zero. 154 | */ 155 | function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) { 156 | require(b != 0, errorMessage); 157 | return a % b; 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /contracts/lib/Address.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.5.17; 4 | 5 | /** 6 | * @dev Collection of functions related to the address type 7 | */ 8 | library Address { 9 | /** 10 | * @dev Returns true if `account` is a contract. 11 | * 12 | * [IMPORTANT] 13 | * ==== 14 | * It is unsafe to assume that an address for which this function returns 15 | * false is an externally-owned account (EOA) and not a contract. 16 | * 17 | * Among others, `isContract` will return false for the following 18 | * types of addresses: 19 | * 20 | * - an externally-owned account 21 | * - a contract in construction 22 | * - an address where a contract will be created 23 | * - an address where a contract lived, but was destroyed 24 | * ==== 25 | */ 26 | function isContract(address account) internal view returns (bool) { 27 | // This method relies in extcodesize, which returns 0 for contracts in 28 | // construction, since the code is only stored at the end of the 29 | // constructor execution. 30 | 31 | uint256 size; 32 | // solhint-disable-next-line no-inline-assembly 33 | assembly { size := extcodesize(account) } 34 | return size > 0; 35 | } 36 | 37 | /** 38 | * @dev Replacement for Solidity's `transfer`: sends `amount` wei to 39 | * `recipient`, forwarding all available gas and reverting on errors. 40 | * 41 | * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost 42 | * of certain opcodes, possibly making contracts go over the 2300 gas limit 43 | * imposed by `transfer`, making them unable to receive funds via 44 | * `transfer`. {sendValue} removes this limitation. 45 | * 46 | * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. 47 | * 48 | * IMPORTANT: because control is transferred to `recipient`, care must be 49 | * taken to not create reentrancy vulnerabilities. Consider using 50 | * {ReentrancyGuard} or the 51 | * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. 52 | */ 53 | function sendValue(address payable recipient, uint256 amount) internal { 54 | require(address(this).balance >= amount, "Address: insufficient balance"); 55 | 56 | // solhint-disable-next-line avoid-low-level-calls, avoid-call-value 57 | (bool success, ) = recipient.call.value(amount)(""); 58 | require(success, "Address: unable to send value, recipient may have reverted"); 59 | } 60 | 61 | /** 62 | * @dev Performs a Solidity function call using a low level `call`. A 63 | * plain`call` is an unsafe replacement for a function call: use this 64 | * function instead. 65 | * 66 | * If `target` reverts with a revert reason, it is bubbled up by this 67 | * function (like regular Solidity function calls). 68 | * 69 | * Returns the raw returned data. To convert to the expected return value, 70 | * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. 71 | * 72 | * Requirements: 73 | * 74 | * - `target` must be a contract. 75 | * - calling `target` with `data` must not revert. 76 | * 77 | * _Available since v3.1._ 78 | */ 79 | function functionCall(address target, bytes memory data) internal returns (bytes memory) { 80 | return functionCall(target, data, "Address: low-level call failed"); 81 | } 82 | 83 | /** 84 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with 85 | * `errorMessage` as a fallback revert reason when `target` reverts. 86 | * 87 | * _Available since v3.1._ 88 | */ 89 | function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) { 90 | return _functionCallWithValue(target, data, 0, errorMessage); 91 | } 92 | 93 | /** 94 | * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], 95 | * but also transferring `value` wei to `target`. 96 | * 97 | * Requirements: 98 | * 99 | * - the calling contract must have an ETH balance of at least `value`. 100 | * - the called Solidity function must be `payable`. 101 | * 102 | * _Available since v3.1._ 103 | */ 104 | function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) { 105 | return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); 106 | } 107 | 108 | /** 109 | * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but 110 | * with `errorMessage` as a fallback revert reason when `target` reverts. 111 | * 112 | * _Available since v3.1._ 113 | */ 114 | function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) { 115 | require(address(this).balance >= value, "Address: insufficient balance for call"); 116 | return _functionCallWithValue(target, data, value, errorMessage); 117 | } 118 | 119 | function _functionCallWithValue(address target, bytes memory data, uint256 weiValue, string memory errorMessage) private returns (bytes memory) { 120 | require(isContract(target), "Address: call to non-contract"); 121 | 122 | // solhint-disable-next-line avoid-low-level-calls 123 | (bool success, bytes memory returndata) = target.call.value(weiValue)(data); 124 | if (success) { 125 | return returndata; 126 | } else { 127 | // Look for revert reason and bubble it up if present 128 | if (returndata.length > 0) { 129 | // The easiest way to bubble the revert reason is using memory via assembly 130 | 131 | // solhint-disable-next-line no-inline-assembly 132 | assembly { 133 | let returndata_size := mload(returndata) 134 | revert(add(32, returndata), returndata_size) 135 | } 136 | } else { 137 | revert(errorMessage); 138 | } 139 | } 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /contracts/YAMGovernorAlpha.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.17; 2 | pragma experimental ABIEncoderV2; 3 | 4 | // SAVE YAM. 5 | 6 | 7 | import "./lib/SafeMath.sol"; 8 | 9 | contract GovernorAlpha { 10 | /// @notice The name of this contract 11 | string public constant name = "YAM Governor Alpha"; 12 | 13 | /// @notice The number of votes in support of a proposal required in order for a quorum to be reached and for a vote to succeed 14 | function quorumVotes() public view returns (uint256) { return 35000*10**24; } // 1% of inital YAM 15 | 16 | /// @notice The number of votes required in order for a voter to become a proposer 17 | function proposalThreshold() public view returns (uint256) { return 10000*10**24; } // .5% of initial YAM 18 | 19 | /// @notice The maximum number of actions that can be included in a proposal 20 | function proposalMaxOperations() public pure returns (uint256) { return 10; } // 10 actions 21 | 22 | /// @notice The delay before voting on a proposal may take place, once proposed 23 | function votingDelay() public pure returns (uint256) { return 1; } // 1 block 24 | 25 | /// @notice The duration of voting on a proposal, in blocks 26 | function votingPeriod() public pure returns (uint256) { return 1920; } // ~8 hours 27 | 28 | /// @notice The address of the Compound Protocol Timelock 29 | TimelockInterface public timelock; 30 | 31 | /// @notice The address of the Compound governance token 32 | YAMInterface public yam; 33 | 34 | /// @notice The address of the Governor Guardian 35 | address public guardian; 36 | 37 | /// @notice The total number of proposals 38 | uint256 public proposalCount; 39 | 40 | struct Proposal { 41 | /// @notice Unique id for looking up a proposal 42 | uint256 id; 43 | 44 | /// @notice Creator of the proposal 45 | address proposer; 46 | 47 | /// @notice The timestamp that the proposal will be available for execution, set once the vote succeeds 48 | uint256 eta; 49 | 50 | /// @notice the ordered list of target addresses for calls to be made 51 | address[] targets; 52 | 53 | /// @notice The ordered list of values (i.e. msg.value) to be passed to the calls to be made 54 | uint[] values; 55 | 56 | /// @notice The ordered list of function signatures to be called 57 | string[] signatures; 58 | 59 | /// @notice The ordered list of calldata to be passed to each call 60 | bytes[] calldatas; 61 | 62 | /// @notice The block at which voting begins: holders must delegate their votes prior to this block 63 | uint256 startBlock; 64 | 65 | /// @notice The block at which voting ends: votes must be cast prior to this block 66 | uint256 endBlock; 67 | 68 | /// @notice Current number of votes in favor of this proposal 69 | uint256 forVotes; 70 | 71 | /// @notice Current number of votes in opposition to this proposal 72 | uint256 againstVotes; 73 | 74 | /// @notice Flag marking whether the proposal has been canceled 75 | bool canceled; 76 | 77 | /// @notice Flag marking whether the proposal has been executed 78 | bool executed; 79 | 80 | /// @notice Receipts of ballots for the entire set of voters 81 | mapping (address => Receipt) receipts; 82 | } 83 | 84 | /// @notice Ballot receipt record for a voter 85 | struct Receipt { 86 | /// @notice Whether or not a vote has been cast 87 | bool hasVoted; 88 | 89 | /// @notice Whether or not the voter supports the proposal 90 | bool support; 91 | 92 | /// @notice The number of votes the voter had, which were cast 93 | uint256 votes; 94 | } 95 | 96 | /// @notice Possible states that a proposal may be in 97 | enum ProposalState { 98 | Pending, 99 | Active, 100 | Canceled, 101 | Defeated, 102 | Succeeded, 103 | Queued, 104 | Expired, 105 | Executed 106 | } 107 | 108 | /// @notice The official record of all proposals ever proposed 109 | mapping (uint256 => Proposal) public proposals; 110 | 111 | /// @notice The latest proposal for each proposer 112 | mapping (address => uint256) public latestProposalIds; 113 | 114 | /// @notice The EIP-712 typehash for the contract's domain 115 | bytes32 public constant DOMAIN_TYPEHASH = keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)"); 116 | 117 | /// @notice The EIP-712 typehash for the ballot struct used by the contract 118 | bytes32 public constant BALLOT_TYPEHASH = keccak256("Ballot(uint256 proposalId,bool support)"); 119 | 120 | /// @notice An event emitted when a new proposal is created 121 | event ProposalCreated(uint256 id, address proposer, address[] targets, uint[] values, string[] signatures, bytes[] calldatas, uint256 startBlock, uint256 endBlock, string description); 122 | 123 | /// @notice An event emitted when a vote has been cast on a proposal 124 | event VoteCast(address voter, uint256 proposalId, bool support, uint256 votes); 125 | 126 | /// @notice An event emitted when a proposal has been canceled 127 | event ProposalCanceled(uint256 id); 128 | 129 | /// @notice An event emitted when a proposal has been queued in the Timelock 130 | event ProposalQueued(uint256 id, uint256 eta); 131 | 132 | /// @notice An event emitted when a proposal has been executed in the Timelock 133 | event ProposalExecuted(uint256 id); 134 | 135 | constructor(address timelock_, address yam_) public { 136 | timelock = TimelockInterface(timelock_); 137 | yam = YAMInterface(yam_); 138 | guardian = msg.sender; 139 | } 140 | 141 | function propose( 142 | address[] memory targets, 143 | uint[] memory values, 144 | string[] memory signatures, 145 | bytes[] memory calldatas, 146 | string memory description 147 | ) 148 | public 149 | returns (uint256) 150 | { 151 | require(yam.getPriorVotes(msg.sender, sub256(block.number, 1)) > proposalThreshold(), "GovernorAlpha::propose: proposer votes below proposal threshold"); 152 | require(targets.length == values.length && targets.length == signatures.length && targets.length == calldatas.length, "GovernorAlpha::propose: proposal function information arity mismatch"); 153 | require(targets.length != 0, "GovernorAlpha::propose: must provide actions"); 154 | require(targets.length <= proposalMaxOperations(), "GovernorAlpha::propose: too many actions"); 155 | 156 | uint256 latestProposalId = latestProposalIds[msg.sender]; 157 | if (latestProposalId != 0) { 158 | ProposalState proposersLatestProposalState = state(latestProposalId); 159 | require(proposersLatestProposalState != ProposalState.Active, "GovernorAlpha::propose: one live proposal per proposer, found an already active proposal"); 160 | require(proposersLatestProposalState != ProposalState.Pending, "GovernorAlpha::propose: one live proposal per proposer, found an already pending proposal"); 161 | } 162 | 163 | uint256 startBlock = add256(block.number, votingDelay()); 164 | uint256 endBlock = add256(startBlock, votingPeriod()); 165 | 166 | proposalCount++; 167 | Proposal memory newProposal = Proposal({ 168 | id: proposalCount, 169 | proposer: msg.sender, 170 | eta: 0, 171 | targets: targets, 172 | values: values, 173 | signatures: signatures, 174 | calldatas: calldatas, 175 | startBlock: startBlock, 176 | endBlock: endBlock, 177 | forVotes: 0, 178 | againstVotes: 0, 179 | canceled: false, 180 | executed: false 181 | }); 182 | 183 | proposals[newProposal.id] = newProposal; 184 | latestProposalIds[newProposal.proposer] = newProposal.id; 185 | 186 | emit ProposalCreated( 187 | newProposal.id, 188 | msg.sender, 189 | targets, 190 | values, 191 | signatures, 192 | calldatas, 193 | startBlock, 194 | endBlock, 195 | description 196 | ); 197 | return newProposal.id; 198 | } 199 | 200 | function queue(uint256 proposalId) 201 | public 202 | { 203 | require(state(proposalId) == ProposalState.Succeeded, "GovernorAlpha::queue: proposal can only be queued if it is succeeded"); 204 | Proposal storage proposal = proposals[proposalId]; 205 | uint256 eta = add256(block.timestamp, timelock.delay()); 206 | for (uint256 i = 0; i < proposal.targets.length; i++) { 207 | _queueOrRevert( 208 | proposal.targets[i], 209 | proposal.values[i], 210 | proposal.signatures[i], 211 | proposal.calldatas[i], 212 | eta 213 | ); 214 | } 215 | proposal.eta = eta; 216 | emit ProposalQueued(proposalId, eta); 217 | } 218 | 219 | function _queueOrRevert( 220 | address target, 221 | uint256 value, 222 | string memory signature, 223 | bytes memory data, 224 | uint256 eta 225 | ) 226 | internal 227 | { 228 | require(!timelock.queuedTransactions( 229 | keccak256( 230 | abi.encode( 231 | target, 232 | value, 233 | signature, 234 | data, 235 | eta 236 | ) 237 | ) 238 | ), 239 | "GovernorAlpha::_queueOrRevert: proposal action already queued at eta" 240 | ); 241 | 242 | timelock.queueTransaction(target, value, signature, data, eta); 243 | } 244 | 245 | function execute(uint256 proposalId) 246 | public 247 | payable 248 | { 249 | require(state(proposalId) == ProposalState.Queued, "GovernorAlpha::execute: proposal can only be executed if it is queued"); 250 | Proposal storage proposal = proposals[proposalId]; 251 | proposal.executed = true; 252 | for (uint256 i = 0; i < proposal.targets.length; i++) { 253 | timelock.executeTransaction.value(proposal.values[i])(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta); 254 | } 255 | emit ProposalExecuted(proposalId); 256 | } 257 | 258 | function cancel(uint256 proposalId) 259 | public 260 | { 261 | ProposalState state = state(proposalId); 262 | require(state != ProposalState.Executed, "GovernorAlpha::cancel: cannot cancel executed proposal"); 263 | 264 | Proposal storage proposal = proposals[proposalId]; 265 | require(msg.sender == guardian || yam.getPriorVotes(proposal.proposer, sub256(block.number, 1)) < proposalThreshold(), "GovernorAlpha::cancel: proposer above threshold"); 266 | 267 | proposal.canceled = true; 268 | for (uint256 i = 0; i < proposal.targets.length; i++) { 269 | timelock.cancelTransaction(proposal.targets[i], proposal.values[i], proposal.signatures[i], proposal.calldatas[i], proposal.eta); 270 | } 271 | 272 | emit ProposalCanceled(proposalId); 273 | } 274 | 275 | function getActions(uint256 proposalId) 276 | public 277 | view 278 | returns ( 279 | address[] memory targets, 280 | uint[] memory values, 281 | string[] memory signatures, 282 | bytes[] memory calldatas 283 | ) 284 | { 285 | Proposal storage p = proposals[proposalId]; 286 | return (p.targets, p.values, p.signatures, p.calldatas); 287 | } 288 | 289 | function getReceipt(uint256 proposalId, address voter) 290 | public 291 | view 292 | returns (Receipt memory) 293 | { 294 | return proposals[proposalId].receipts[voter]; 295 | } 296 | 297 | function state(uint256 proposalId) 298 | public 299 | view 300 | returns (ProposalState) 301 | { 302 | require(proposalCount >= proposalId && proposalId > 0, "GovernorAlpha::state: invalid proposal id"); 303 | Proposal storage proposal = proposals[proposalId]; 304 | if (proposal.canceled) { 305 | return ProposalState.Canceled; 306 | } else if (block.number <= proposal.startBlock) { 307 | return ProposalState.Pending; 308 | } else if (block.number <= proposal.endBlock) { 309 | return ProposalState.Active; 310 | } else if (proposal.forVotes <= proposal.againstVotes || proposal.forVotes < quorumVotes()) { 311 | return ProposalState.Defeated; 312 | } else if (proposal.eta == 0) { 313 | return ProposalState.Succeeded; 314 | } else if (proposal.executed) { 315 | return ProposalState.Executed; 316 | } else if (block.timestamp >= add256(proposal.eta, timelock.GRACE_PERIOD())) { 317 | return ProposalState.Expired; 318 | } else { 319 | return ProposalState.Queued; 320 | } 321 | } 322 | 323 | function castVote(uint256 proposalId, bool support) 324 | public 325 | { 326 | return _castVote(msg.sender, proposalId, support); 327 | } 328 | 329 | function castVoteBySig( 330 | uint256 proposalId, 331 | bool support, 332 | uint8 v, 333 | bytes32 r, 334 | bytes32 s 335 | ) 336 | public 337 | { 338 | bytes32 domainSeparator = keccak256( 339 | abi.encode( 340 | DOMAIN_TYPEHASH, 341 | keccak256(bytes(name)), 342 | getChainId(), 343 | address(this) 344 | ) 345 | ); 346 | 347 | bytes32 structHash = keccak256( 348 | abi.encode( 349 | BALLOT_TYPEHASH, 350 | proposalId, 351 | support 352 | ) 353 | ); 354 | 355 | bytes32 digest = keccak256( 356 | abi.encodePacked( 357 | "\x19\x01", 358 | domainSeparator, 359 | structHash 360 | ) 361 | ); 362 | 363 | address signatory = ecrecover(digest, v, r, s); 364 | require(signatory != address(0), "GovernorAlpha::castVoteBySig: invalid signature"); 365 | return _castVote(signatory, proposalId, support); 366 | } 367 | 368 | function _castVote( 369 | address voter, 370 | uint256 proposalId, 371 | bool support 372 | ) 373 | internal 374 | { 375 | require(state(proposalId) == ProposalState.Active, "GovernorAlpha::_castVote: voting is closed"); 376 | Proposal storage proposal = proposals[proposalId]; 377 | Receipt storage receipt = proposal.receipts[voter]; 378 | require(receipt.hasVoted == false, "GovernorAlpha::_castVote: voter already voted"); 379 | uint256 votes = yam.getPriorVotes(voter, proposal.startBlock); 380 | 381 | if (support) { 382 | proposal.forVotes = add256(proposal.forVotes, votes); 383 | } else { 384 | proposal.againstVotes = add256(proposal.againstVotes, votes); 385 | } 386 | 387 | receipt.hasVoted = true; 388 | receipt.support = support; 389 | receipt.votes = votes; 390 | 391 | emit VoteCast(voter, proposalId, support, votes); 392 | } 393 | 394 | function __acceptAdmin() 395 | public 396 | { 397 | require(msg.sender == guardian, "GovernorAlpha::__acceptAdmin: sender must be gov guardian"); 398 | timelock.acceptAdmin(); 399 | } 400 | 401 | function __abdicate() 402 | public 403 | { 404 | require(msg.sender == guardian, "GovernorAlpha::__abdicate: sender must be gov guardian"); 405 | guardian = address(0); 406 | } 407 | 408 | function __queueSetTimelockPendingAdmin( 409 | address newPendingAdmin, 410 | uint256 eta 411 | ) 412 | public 413 | { 414 | require(msg.sender == guardian, "GovernorAlpha::__queueSetTimelockPendingAdmin: sender must be gov guardian"); 415 | timelock.queueTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); 416 | } 417 | 418 | function __executeSetTimelockPendingAdmin( 419 | address newPendingAdmin, 420 | uint256 eta 421 | ) 422 | public 423 | { 424 | require(msg.sender == guardian, "GovernorAlpha::__executeSetTimelockPendingAdmin: sender must be gov guardian"); 425 | timelock.executeTransaction(address(timelock), 0, "setPendingAdmin(address)", abi.encode(newPendingAdmin), eta); 426 | } 427 | 428 | function add256(uint256 a, uint256 b) internal pure returns (uint256) { 429 | uint256 c = a + b; 430 | require(c >= a, "addition overflow"); 431 | return c; 432 | } 433 | 434 | function sub256(uint256 a, uint256 b) internal pure returns (uint256) { 435 | require(b <= a, "subtraction underflow"); 436 | return a - b; 437 | } 438 | 439 | function getChainId() internal pure returns (uint256) { 440 | uint256 chainId; 441 | assembly { chainId := chainid() } 442 | return chainId; 443 | } 444 | } 445 | 446 | interface TimelockInterface { 447 | function delay() external view returns (uint256); 448 | function GRACE_PERIOD() external view returns (uint256); 449 | function acceptAdmin() external; 450 | function queuedTransactions(bytes32 hash) external view returns (bool); 451 | function queueTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external returns (bytes32); 452 | function cancelTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external; 453 | function executeTransaction(address target, uint256 value, string calldata signature, bytes calldata data, uint256 eta) external payable returns (bytes memory); 454 | } 455 | 456 | interface YAMInterface { 457 | function getPriorVotes(address account, uint256 blockNumber) external view returns (uint256); 458 | function initSupply() external view returns (uint256); 459 | function _acceptGov() external; 460 | } 461 | --------------------------------------------------------------------------------