ETH Price: $3,791.17 (+1.23%)
Gas: 5 Gwei

Transaction Decoder

Block:
18588986 at Nov-17-2023 03:41:35 AM +UTC
Transaction Fee:
0.00243082508254256 ETH $9.22
Gas Used:
103,840 Gas / 23.409332459 Gwei

Emitted Events:

217 DydxGovernor.VoteEmitted( id=16, voter=[Sender] 0xb85737d0d9c81e4cfaa6453374d08bea87e1c705, support=True, votingPower=5444409909657363168 )

Account State Difference:

  Address   Before After State Difference Code
0x7E9B1672...79A9018D2
(dYdX: Governance)
0xB85737D0...a87e1c705
0.245578951550203614 Eth
Nonce: 669
0.243148126467661054 Eth
Nonce: 670
0.00243082508254256
(Flashbots: Builder)
14.009175961343522468 Eth14.009186345343522468 Eth0.000010384

Execution Trace

DydxGovernor.submitVote( proposalId=16, support=True )
  • GovernanceStrategyV2.getVotingPowerAt( user=0xB85737D0D9C81E4cfAa6453374D08bea87e1c705, blockNumber=18572574 ) => ( 5444409909657363168 )
    • WrappedEthereumDydxToken.getPowerAtBlock( user=0xB85737D0D9C81E4cfAa6453374D08bea87e1c705, blockNumber=18572574, delegationType=0 ) => ( 5444409909657363168 )
    • InitializableAdminUpgradeabilityProxy.c2ffbb91( )
      • SafetyModuleV2.getPowerAtBlock( user=0xB85737D0D9C81E4cfAa6453374D08bea87e1c705, blockNumber=18572574, delegationType=0 ) => ( 0 )
      • DydxToken.getPowerAtBlock( user=0xB85737D0D9C81E4cfAa6453374D08bea87e1c705, blockNumber=18572574, delegationType=0 ) => ( 0 )
        File 1 of 6: DydxGovernor
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.5;
        import "./Context.sol";
        import "./Strings.sol";
        import "./ERC165.sol";
        /**
         * @dev External interface of AccessControl declared to support ERC165 detection.
         */
        interface IAccessControl {
            function hasRole(bytes32 role, address account) external view returns (bool);
            function getRoleAdmin(bytes32 role) external view returns (bytes32);
            function grantRole(bytes32 role, address account) external;
            function revokeRole(bytes32 role, address account) external;
            function renounceRole(bytes32 role, address account) external;
        }
        /**
         * @dev Contract module that allows children to implement role-based access
         * control mechanisms. This is a lightweight version that doesn't allow enumerating role
         * members except through off-chain means by accessing the contract event logs. Some
         * applications may benefit from on-chain enumerability, for those cases see
         * {AccessControlEnumerable}.
         *
         * Roles are referred to by their `bytes32` identifier. These should be exposed
         * in the external API and be unique. The best way to achieve this is by
         * using `public constant` hash digests:
         *
         * ```
         * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
         * ```
         *
         * Roles can be used to represent a set of permissions. To restrict access to a
         * function call, use {hasRole}:
         *
         * ```
         * function foo() public {
         *     require(hasRole(MY_ROLE, msg.sender));
         *     ...
         * }
         * ```
         *
         * Roles can be granted and revoked dynamically via the {grantRole} and
         * {revokeRole} functions. Each role has an associated admin role, and only
         * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
         *
         * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
         * that only accounts with this role will be able to grant or revoke other
         * roles. More complex role relationships can be created by using
         * {_setRoleAdmin}.
         *
         * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
         * grant and revoke this role. Extra precautions should be taken to secure
         * accounts that have been granted it.
         */
        abstract contract AccessControl is Context, IAccessControl, ERC165 {
            struct RoleData {
                mapping(address => bool) members;
                bytes32 adminRole;
            }
            mapping(bytes32 => RoleData) private _roles;
            bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
            /**
             * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
             *
             * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
             * {RoleAdminChanged} not being emitted signaling this.
             *
             * _Available since v3.1._
             */
            event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);
            /**
             * @dev Emitted when `account` is granted `role`.
             *
             * `sender` is the account that originated the contract call, an admin role
             * bearer except when using {_setupRole}.
             */
            event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
            /**
             * @dev Emitted when `account` is revoked `role`.
             *
             * `sender` is the account that originated the contract call:
             *   - if using `revokeRole`, it is the admin role bearer
             *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
             */
            event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
            /**
             * @dev Modifier that checks that an account has a specific role. Reverts
             * with a standardized message including the required role.
             *
             * The format of the revert reason is given by the following regular expression:
             *
             *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
             *
             * _Available since v4.1._
             */
            modifier onlyRole(bytes32 role) {
                _checkRole(role, _msgSender());
                _;
            }
            /**
             * @dev See {IERC165-supportsInterface}.
             */
            function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
                return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
            }
            /**
             * @dev Returns `true` if `account` has been granted `role`.
             */
            function hasRole(bytes32 role, address account) public view override returns (bool) {
                return _roles[role].members[account];
            }
            /**
             * @dev Revert with a standard message if `account` is missing `role`.
             *
             * The format of the revert reason is given by the following regular expression:
             *
             *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
             */
            function _checkRole(bytes32 role, address account) internal view {
                if (!hasRole(role, account)) {
                    revert(
                        string(
                            abi.encodePacked(
                                "AccessControl: account ",
                                Strings.toHexString(uint160(account), 20),
                                " is missing role ",
                                Strings.toHexString(uint256(role), 32)
                            )
                        )
                    );
                }
            }
            /**
             * @dev Returns the admin role that controls `role`. See {grantRole} and
             * {revokeRole}.
             *
             * To change a role's admin, use {_setRoleAdmin}.
             */
            function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
                return _roles[role].adminRole;
            }
            /**
             * @dev Grants `role` to `account`.
             *
             * If `account` had not been already granted `role`, emits a {RoleGranted}
             * event.
             *
             * Requirements:
             *
             * - the caller must have ``role``'s admin role.
             */
            function grantRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                _grantRole(role, account);
            }
            /**
             * @dev Revokes `role` from `account`.
             *
             * If `account` had been granted `role`, emits a {RoleRevoked} event.
             *
             * Requirements:
             *
             * - the caller must have ``role``'s admin role.
             */
            function revokeRole(bytes32 role, address account) public virtual override onlyRole(getRoleAdmin(role)) {
                _revokeRole(role, account);
            }
            /**
             * @dev Revokes `role` from the calling account.
             *
             * Roles are often managed via {grantRole} and {revokeRole}: this function's
             * purpose is to provide a mechanism for accounts to lose their privileges
             * if they are compromised (such as when a trusted device is misplaced).
             *
             * If the calling account had been granted `role`, emits a {RoleRevoked}
             * event.
             *
             * Requirements:
             *
             * - the caller must be `account`.
             */
            function renounceRole(bytes32 role, address account) public virtual override {
                require(account == _msgSender(), "AccessControl: can only renounce roles for self");
                _revokeRole(role, account);
            }
            /**
             * @dev Grants `role` to `account`.
             *
             * If `account` had not been already granted `role`, emits a {RoleGranted}
             * event. Note that unlike {grantRole}, this function doesn't perform any
             * checks on the calling account.
             *
             * [WARNING]
             * ====
             * This function should only be called from the constructor when setting
             * up the initial roles for the system.
             *
             * Using this function in any other way is effectively circumventing the admin
             * system imposed by {AccessControl}.
             * ====
             */
            function _setupRole(bytes32 role, address account) internal virtual {
                _grantRole(role, account);
            }
            /**
             * @dev Sets `adminRole` as ``role``'s admin role.
             *
             * Emits a {RoleAdminChanged} event.
             */
            function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
                emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
                _roles[role].adminRole = adminRole;
            }
            function _grantRole(bytes32 role, address account) private {
                if (!hasRole(role, account)) {
                    _roles[role].members[account] = true;
                    emit RoleGranted(role, account, _msgSender());
                }
            }
            function _revokeRole(bytes32 role, address account) private {
                if (hasRole(role, account)) {
                    _roles[role].members[account] = false;
                    emit RoleRevoked(role, account, _msgSender());
                }
            }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev String operations.
         */
        library Strings {
          bytes16 private constant alphabet = '0123456789abcdef';
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            if (value == 0) {
              return '0';
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
              digits++;
              temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
              digits -= 1;
              buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
              value /= 10;
            }
            return string(buffer);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
              return '0x00';
            }
            uint256 temp = value;
            uint256 length = 0;
            while (temp != 0) {
              length++;
              temp >>= 8;
            }
            return toHexString(value, length);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = '0';
            buffer[1] = 'x';
            for (uint256 i = 2 * length + 1; i > 1; --i) {
              buffer[i] = alphabet[value & 0xf];
              value >>= 4;
            }
            require(value == 0, 'Strings: hex length insufficient');
            return string(buffer);
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './IERC165.sol';
        /**
         * @dev Implementation of the {IERC165} interface.
         *
         * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
         * for the additional interface id that will be supported. For example:
         *
         * ```solidity
         * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
         *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
         * }
         * ```
         *
         * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
         */
        abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * https://eips.ethereum.org/EIPS/eip-165[EIP].
         *
         * Implementers can declare support of contract interfaces, which can then be
         * queried by others ({ERC165Checker}).
         *
         * For an implementation, see {ERC165}.
         */
        interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        // SPDX-License-Identifier: AGPL-3.0
        //
        // Contracts by dYdX Foundation. Individual files are released under different licenses.
        //
        // https://dydx.community
        // https://github.com/dydxfoundation/governance-contracts
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { AccessControl } from '../dependencies/open-zeppelin/AccessControl.sol';
        import { SafeMath } from '../dependencies/open-zeppelin/SafeMath.sol';
        import { IDydxGovernor } from '../interfaces/IDydxGovernor.sol';
        import { IExecutorWithTimelock } from '../interfaces/IExecutorWithTimelock.sol';
        import { IGovernanceStrategy } from '../interfaces/IGovernanceStrategy.sol';
        import { IProposalValidator } from '../interfaces/IProposalValidator.sol';
        import { IVotingStrategy } from '../interfaces/IVotingStrategy.sol';
        import { isContract, getChainId } from '../misc/Helpers.sol';
        /**
         * @title dYdX governor contract.
         * @author dYdX
         *
         * @notice Main point of interaction for dYdX governance. Holds governance proposals. Delegates to
         *  the governance strategy contract to determine how voting and proposing powers are counted. The
         *  content of a proposal is a sequence of function calls. These function calls must be made
         *  through authorized executor contracts.
         *
         *  Functionality includes:
         *    - Create a proposal
         *    - Cancel a proposal
         *    - Queue a proposal
         *    - Execute a proposal
         *    - Submit a vote to a proposal
         *
         *  Proposal state transitions in success case:
         *
         *    Pending => Active => Succeeded => Queued => Executed
         *
         *  Proposal state transitions in failure cases:
         *
         *    Pending => Active => Failed
         *    Pending => Active => Succeeded => Queued => Expired
         *    Pending => Canceled
         *    Pending => Active => Canceled
         *    Pending => Active => Succeeded => Canceled
         *    Pending => Active => Succeeded => Queued => Canceled
         **/
        contract DydxGovernor is
          AccessControl,
          IDydxGovernor
        {
          using SafeMath for uint256;
          // ============ Constants ============
          bytes32 public constant OWNER_ROLE = keccak256('OWNER_ROLE');
          bytes32 public constant ADD_EXECUTOR_ROLE = keccak256('ADD_EXECUTOR_ROLE');
          // ============ Storage ============
          address private _governanceStrategy;
          uint256 private _votingDelay;
          uint256 private _proposalsCount;
          mapping(uint256 => Proposal) private _proposals;
          mapping(address => bool) private _authorizedExecutors;
          bytes32 public constant DOMAIN_TYPEHASH = keccak256(
            'EIP712Domain(string name,uint256 chainId,address verifyingContract)'
          );
          bytes32 public constant VOTE_EMITTED_TYPEHASH = keccak256(
            'VoteEmitted(uint256 id,bool support)'
          );
          string public constant EIP712_DOMAIN_NAME = 'dYdX Governance';
          constructor(
            address governanceStrategy,
            uint256 votingDelay,
            address addExecutorAdmin
          ) {
            _setGovernanceStrategy(governanceStrategy);
            _setVotingDelay(votingDelay);
            // Assign roles.
            _setupRole(OWNER_ROLE, msg.sender);
            _setupRole(ADD_EXECUTOR_ROLE, addExecutorAdmin);
            // Set OWNER_ROLE as the admin for all roles.
            _setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
            _setRoleAdmin(ADD_EXECUTOR_ROLE, OWNER_ROLE);
          }
          struct CreateVars {
            uint256 startBlock;
            uint256 endBlock;
            uint256 previousProposalsCount;
          }
          /**
           * @notice Creates a Proposal (needs to be validated by the Proposal Validator)
           * @param executor The ExecutorWithTimelock contract that will execute the proposal
           * @param targets list of contracts called by proposal's associated transactions
           * @param values list of value in wei for each propoposal's associated transaction
           * @param signatures list of function signatures (can be empty) to be used when created the callData
           * @param calldatas list of calldatas: if associated signature empty, calldata ready, else calldata is arguments
           * @param withDelegatecalls boolean, true = transaction delegatecalls the taget, else calls the target
           * @param ipfsHash IPFS hash of the proposal
           **/
          function create(
            IExecutorWithTimelock executor,
            address[] memory targets,
            uint256[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas,
            bool[] memory withDelegatecalls,
            bytes32 ipfsHash
          ) external override returns (uint256) {
            require(targets.length != 0, 'INVALID_EMPTY_TARGETS');
            require(
              targets.length == values.length &&
                targets.length == signatures.length &&
                targets.length == calldatas.length &&
                targets.length == withDelegatecalls.length,
              'INCONSISTENT_PARAMS_LENGTH'
            );
            require(isExecutorAuthorized(address(executor)), 'EXECUTOR_NOT_AUTHORIZED');
            require(
              IProposalValidator(address(executor)).validateCreatorOfProposal(
                this,
                msg.sender,
                block.number - 1
              ),
              'PROPOSITION_CREATION_INVALID'
            );
            CreateVars memory vars;
            vars.startBlock = block.number.add(_votingDelay);
            vars.endBlock = vars.startBlock.add(IProposalValidator(address(executor)).VOTING_DURATION());
            vars.previousProposalsCount = _proposalsCount;
            Proposal storage newProposal = _proposals[vars.previousProposalsCount];
            newProposal.id = vars.previousProposalsCount;
            newProposal.creator = msg.sender;
            newProposal.executor = executor;
            newProposal.targets = targets;
            newProposal.values = values;
            newProposal.signatures = signatures;
            newProposal.calldatas = calldatas;
            newProposal.withDelegatecalls = withDelegatecalls;
            newProposal.startBlock = vars.startBlock;
            newProposal.endBlock = vars.endBlock;
            newProposal.strategy = _governanceStrategy;
            newProposal.ipfsHash = ipfsHash;
            _proposalsCount = vars.previousProposalsCount + 1;
            emit ProposalCreated(
              vars.previousProposalsCount,
              msg.sender,
              executor,
              targets,
              values,
              signatures,
              calldatas,
              withDelegatecalls,
              vars.startBlock,
              vars.endBlock,
              _governanceStrategy,
              ipfsHash
            );
            return newProposal.id;
          }
          /**
           * @dev Cancels a Proposal. Callable by anyone if the conditions on the executor are fulfilled.
           * @param proposalId id of the proposal
           **/
          function cancel(uint256 proposalId) external override {
            ProposalState state = getProposalState(proposalId);
            require(
              state != ProposalState.Canceled &&
                state != ProposalState.Failed &&
                state != ProposalState.Expired &&
                state != ProposalState.Executed,
              'ONLY_BEFORE_EXECUTED'
            );
            Proposal storage proposal = _proposals[proposalId];
            require(
              IProposalValidator(address(proposal.executor)).validateProposalCancellation(
                this,
                proposal.creator,
                block.number - 1
              ),
              'PROPOSITION_CANCELLATION_INVALID'
            );
            proposal.canceled = true;
            for (uint256 i = 0; i < proposal.targets.length; i++) {
              proposal.executor.cancelTransaction(
                proposal.targets[i],
                proposal.values[i],
                proposal.signatures[i],
                proposal.calldatas[i],
                proposal.executionTime,
                proposal.withDelegatecalls[i]
              );
            }
            emit ProposalCanceled(proposalId);
          }
          /**
           * @dev Queue the proposal. Requires that the proposal succeeded.
           * @param proposalId id of the proposal to queue
           **/
          function queue(uint256 proposalId) external override {
            require(getProposalState(proposalId) == ProposalState.Succeeded, 'INVALID_STATE_FOR_QUEUE');
            Proposal storage proposal = _proposals[proposalId];
            uint256 executionTime = block.timestamp.add(proposal.executor.getDelay());
            for (uint256 i = 0; i < proposal.targets.length; i++) {
              _queueOrRevert(
                proposal.executor,
                proposal.targets[i],
                proposal.values[i],
                proposal.signatures[i],
                proposal.calldatas[i],
                executionTime,
                proposal.withDelegatecalls[i]
              );
            }
            proposal.executionTime = executionTime;
            emit ProposalQueued(proposalId, executionTime, msg.sender);
          }
          /**
           * @dev Execute the proposal. Requires that the proposal is queued.
           * @param proposalId id of the proposal to execute
           **/
          function execute(uint256 proposalId) external payable override {
            require(getProposalState(proposalId) == ProposalState.Queued, 'ONLY_QUEUED_PROPOSALS');
            Proposal storage proposal = _proposals[proposalId];
            proposal.executed = true;
            for (uint256 i = 0; i < proposal.targets.length; i++) {
              proposal.executor.executeTransaction{value: proposal.values[i]}(
                proposal.targets[i],
                proposal.values[i],
                proposal.signatures[i],
                proposal.calldatas[i],
                proposal.executionTime,
                proposal.withDelegatecalls[i]
              );
            }
            emit ProposalExecuted(proposalId, msg.sender);
          }
          /**
           * @dev Function allowing msg.sender to vote for/against a proposal
           * @param proposalId id of the proposal
           * @param support boolean, true = vote for, false = vote against
           **/
          function submitVote(uint256 proposalId, bool support) external override {
            return _submitVote(msg.sender, proposalId, support);
          }
          /**
           * @dev Function to register the vote of user that has voted offchain via signature
           * @param proposalId id of the proposal
           * @param support boolean, true = vote for, false = vote against
           * @param v v part of the voter signature
           * @param r r part of the voter signature
           * @param s s part of the voter signature
           **/
          function submitVoteBySignature(
            uint256 proposalId,
            bool support,
            uint8 v,
            bytes32 r,
            bytes32 s
          ) external override {
            bytes32 digest = keccak256(
              abi.encodePacked(
                '\\x19\\x01',
                keccak256(
                  abi.encode(
                    DOMAIN_TYPEHASH,
                    keccak256(bytes(EIP712_DOMAIN_NAME)),
                    getChainId(),
                    address(this)
                  )
                ),
                keccak256(abi.encode(VOTE_EMITTED_TYPEHASH, proposalId, support))
              )
            );
            address signer = ecrecover(digest, v, r, s);
            require(signer != address(0), 'INVALID_SIGNATURE');
            return _submitVote(signer, proposalId, support);
          }
          /**
           * @dev Set new GovernanceStrategy
           * Note: owner should be a timelocked executor, so needs to make a proposal
           * @param governanceStrategy new Address of the GovernanceStrategy contract
           **/
          function setGovernanceStrategy(address governanceStrategy)
            external
            override
            onlyRole(OWNER_ROLE)
          {
            _setGovernanceStrategy(governanceStrategy);
          }
          /**
           * @dev Set new Voting Delay (delay before a newly created proposal can be voted on)
           * Note: owner should be a timelocked executor, so needs to make a proposal
           * @param votingDelay new voting delay in terms of blocks
           **/
          function setVotingDelay(uint256 votingDelay)
            external
            override
            onlyRole(OWNER_ROLE)
          {
            _setVotingDelay(votingDelay);
          }
          /**
           * @dev Add new addresses to the list of authorized executors
           * @param executors list of new addresses to be authorized executors
           **/
          function authorizeExecutors(address[] memory executors)
            public
            override
            onlyRole(ADD_EXECUTOR_ROLE)
          {
            for (uint256 i = 0; i < executors.length; i++) {
              _authorizeExecutor(executors[i]);
            }
          }
          /**
           * @dev Remove addresses to the list of authorized executors
           * @param executors list of addresses to be removed as authorized executors
           **/
          function unauthorizeExecutors(address[] memory executors)
            public
            override
            onlyRole(OWNER_ROLE)
          {
            for (uint256 i = 0; i < executors.length; i++) {
              _unauthorizeExecutor(executors[i]);
            }
          }
          /**
           * @dev Getter of the current GovernanceStrategy address
           * @return The address of the current GovernanceStrategy contracts
           **/
          function getGovernanceStrategy() external view override returns (address) {
            return _governanceStrategy;
          }
          /**
           * @dev Getter of the current Voting Delay (delay before a created proposal can be voted on)
           * Different from the voting duration
           * @return The voting delay in number of blocks
           **/
          function getVotingDelay() external view override returns (uint256) {
            return _votingDelay;
          }
          /**
           * @dev Returns whether an address is an authorized executor
           * @param executor address to evaluate as authorized executor
           * @return true if authorized
           **/
          function isExecutorAuthorized(address executor) public view override returns (bool) {
            return _authorizedExecutors[executor];
          }
          /**
           * @dev Getter of the proposal count (the current number of proposals ever created)
           * @return the proposal count
           **/
          function getProposalsCount() external view override returns (uint256) {
            return _proposalsCount;
          }
          /**
           * @dev Getter of a proposal by id
           * @param proposalId id of the proposal to get
           * @return the proposal as ProposalWithoutVotes memory object
           **/
          function getProposalById(uint256 proposalId)
            external
            view
            override
            returns (ProposalWithoutVotes memory)
          {
            Proposal storage proposal = _proposals[proposalId];
            ProposalWithoutVotes memory proposalWithoutVotes = ProposalWithoutVotes({
              id: proposal.id,
              creator: proposal.creator,
              executor: proposal.executor,
              targets: proposal.targets,
              values: proposal.values,
              signatures: proposal.signatures,
              calldatas: proposal.calldatas,
              withDelegatecalls: proposal.withDelegatecalls,
              startBlock: proposal.startBlock,
              endBlock: proposal.endBlock,
              executionTime: proposal.executionTime,
              forVotes: proposal.forVotes,
              againstVotes: proposal.againstVotes,
              executed: proposal.executed,
              canceled: proposal.canceled,
              strategy: proposal.strategy,
              ipfsHash: proposal.ipfsHash
            });
            return proposalWithoutVotes;
          }
          /**
           * @notice Get information about a voter's vote on a proposal.
           * Note: Vote is a struct: ({bool support, uint248 votingPower})
           * @param proposalId id of the proposal
           * @param voter address of the voter
           * @return The associated Vote object
           **/
          function getVoteOnProposal(uint256 proposalId, address voter)
            external
            view
            override
            returns (Vote memory)
          {
            return _proposals[proposalId].votes[voter];
          }
          /**
           * @notice Get the current state of a proposal.
           * @param proposalId id of the proposal
           * @return The current state of the proposal
           **/
          function getProposalState(uint256 proposalId) public view override returns (ProposalState) {
            require(_proposalsCount > proposalId, 'INVALID_PROPOSAL_ID');
            Proposal storage proposal = _proposals[proposalId];
            if (proposal.canceled) {
              return ProposalState.Canceled;
            } else if (block.number <= proposal.startBlock) {
              return ProposalState.Pending;
            } else if (block.number <= proposal.endBlock) {
              return ProposalState.Active;
            } else if (!IProposalValidator(address(proposal.executor)).isProposalPassed(this, proposalId)) {
              return ProposalState.Failed;
            } else if (proposal.executionTime == 0) {
              return ProposalState.Succeeded;
            } else if (proposal.executed) {
              return ProposalState.Executed;
            } else if (proposal.executor.isProposalOverGracePeriod(this, proposalId)) {
              return ProposalState.Expired;
            } else {
              return ProposalState.Queued;
            }
          }
          function _queueOrRevert(
            IExecutorWithTimelock executor,
            address target,
            uint256 value,
            string memory signature,
            bytes memory callData,
            uint256 executionTime,
            bool withDelegatecall
          ) internal {
            require(
              !executor.isActionQueued(
                keccak256(abi.encode(target, value, signature, callData, executionTime, withDelegatecall))
              ),
              'DUPLICATED_ACTION'
            );
            executor.queueTransaction(target, value, signature, callData, executionTime, withDelegatecall);
          }
          function _submitVote(
            address voter,
            uint256 proposalId,
            bool support
          ) internal {
            require(getProposalState(proposalId) == ProposalState.Active, 'VOTING_CLOSED');
            Proposal storage proposal = _proposals[proposalId];
            Vote storage vote = proposal.votes[voter];
            require(vote.votingPower == 0, 'VOTE_ALREADY_SUBMITTED');
            uint256 votingPower = IVotingStrategy(proposal.strategy).getVotingPowerAt(
              voter,
              proposal.startBlock
            );
            if (support) {
              proposal.forVotes = proposal.forVotes.add(votingPower);
            } else {
              proposal.againstVotes = proposal.againstVotes.add(votingPower);
            }
            vote.support = support;
            vote.votingPower = uint248(votingPower);
            emit VoteEmitted(proposalId, voter, support, votingPower);
          }
          function _setGovernanceStrategy(address governanceStrategy) internal {
            _governanceStrategy = governanceStrategy;
            emit GovernanceStrategyChanged(governanceStrategy, msg.sender);
          }
          function _setVotingDelay(uint256 votingDelay) internal {
            _votingDelay = votingDelay;
            emit VotingDelayChanged(votingDelay, msg.sender);
          }
          function _authorizeExecutor(address executor) internal {
            _authorizedExecutors[executor] = true;
            emit ExecutorAuthorized(executor);
          }
          function _unauthorizeExecutor(address executor) internal {
            _authorizedExecutors[executor] = false;
            emit ExecutorUnauthorized(executor);
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when an
         * operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         */
        library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, 'SafeMath: addition overflow');
            return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, 'SafeMath: subtraction overflow');
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
              return 0;
            }
            uint256 c = a * b;
            require(c / a == b, 'SafeMath: multiplication overflow');
            return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, 'SafeMath: division by zero');
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, 'SafeMath: modulo by zero');
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { IExecutorWithTimelock } from './IExecutorWithTimelock.sol';
        interface IDydxGovernor {
          enum ProposalState {
            Pending,
            Canceled,
            Active,
            Failed,
            Succeeded,
            Queued,
            Expired,
            Executed
          }
          struct Vote {
            bool support;
            uint248 votingPower;
          }
          struct Proposal {
            uint256 id;
            address creator;
            IExecutorWithTimelock executor;
            address[] targets;
            uint256[] values;
            string[] signatures;
            bytes[] calldatas;
            bool[] withDelegatecalls;
            uint256 startBlock;
            uint256 endBlock;
            uint256 executionTime;
            uint256 forVotes;
            uint256 againstVotes;
            bool executed;
            bool canceled;
            address strategy;
            bytes32 ipfsHash;
            mapping(address => Vote) votes;
          }
          struct ProposalWithoutVotes {
            uint256 id;
            address creator;
            IExecutorWithTimelock executor;
            address[] targets;
            uint256[] values;
            string[] signatures;
            bytes[] calldatas;
            bool[] withDelegatecalls;
            uint256 startBlock;
            uint256 endBlock;
            uint256 executionTime;
            uint256 forVotes;
            uint256 againstVotes;
            bool executed;
            bool canceled;
            address strategy;
            bytes32 ipfsHash;
          }
          /**
           * @dev emitted when a new proposal is created
           * @param id Id of the proposal
           * @param creator address of the creator
           * @param executor The ExecutorWithTimelock contract that will execute the proposal
           * @param targets list of contracts called by proposal's associated transactions
           * @param values list of value in wei for each propoposal's associated transaction
           * @param signatures list of function signatures (can be empty) to be used when created the callData
           * @param calldatas list of calldatas: if associated signature empty, calldata ready, else calldata is arguments
           * @param withDelegatecalls boolean, true = transaction delegatecalls the taget, else calls the target
           * @param startBlock block number when vote starts
           * @param endBlock block number when vote ends
           * @param strategy address of the governanceStrategy contract
           * @param ipfsHash IPFS hash of the proposal
           **/
          event ProposalCreated(
            uint256 id,
            address indexed creator,
            IExecutorWithTimelock indexed executor,
            address[] targets,
            uint256[] values,
            string[] signatures,
            bytes[] calldatas,
            bool[] withDelegatecalls,
            uint256 startBlock,
            uint256 endBlock,
            address strategy,
            bytes32 ipfsHash
          );
          /**
           * @dev emitted when a proposal is canceled
           * @param id Id of the proposal
           **/
          event ProposalCanceled(uint256 id);
          /**
           * @dev emitted when a proposal is queued
           * @param id Id of the proposal
           * @param executionTime time when proposal underlying transactions can be executed
           * @param initiatorQueueing address of the initiator of the queuing transaction
           **/
          event ProposalQueued(uint256 id, uint256 executionTime, address indexed initiatorQueueing);
          /**
           * @dev emitted when a proposal is executed
           * @param id Id of the proposal
           * @param initiatorExecution address of the initiator of the execution transaction
           **/
          event ProposalExecuted(uint256 id, address indexed initiatorExecution);
          /**
           * @dev emitted when a vote is registered
           * @param id Id of the proposal
           * @param voter address of the voter
           * @param support boolean, true = vote for, false = vote against
           * @param votingPower Power of the voter/vote
           **/
          event VoteEmitted(uint256 id, address indexed voter, bool support, uint256 votingPower);
          event GovernanceStrategyChanged(address indexed newStrategy, address indexed initiatorChange);
          event VotingDelayChanged(uint256 newVotingDelay, address indexed initiatorChange);
          event ExecutorAuthorized(address executor);
          event ExecutorUnauthorized(address executor);
          /**
           * @dev Creates a Proposal (needs Proposition Power of creator > Threshold)
           * @param executor The ExecutorWithTimelock contract that will execute the proposal
           * @param targets list of contracts called by proposal's associated transactions
           * @param values list of value in wei for each propoposal's associated transaction
           * @param signatures list of function signatures (can be empty) to be used when created the callData
           * @param calldatas list of calldatas: if associated signature empty, calldata ready, else calldata is arguments
           * @param withDelegatecalls if true, transaction delegatecalls the taget, else calls the target
           * @param ipfsHash IPFS hash of the proposal
           **/
          function create(
            IExecutorWithTimelock executor,
            address[] memory targets,
            uint256[] memory values,
            string[] memory signatures,
            bytes[] memory calldatas,
            bool[] memory withDelegatecalls,
            bytes32 ipfsHash
          ) external returns (uint256);
          /**
           * @dev Cancels a Proposal, when proposal is Pending/Active and threshold no longer reached
           * @param proposalId id of the proposal
           **/
          function cancel(uint256 proposalId) external;
          /**
           * @dev Queue the proposal (If Proposal Succeeded)
           * @param proposalId id of the proposal to queue
           **/
          function queue(uint256 proposalId) external;
          /**
           * @dev Execute the proposal (If Proposal Queued)
           * @param proposalId id of the proposal to execute
           **/
          function execute(uint256 proposalId) external payable;
          /**
           * @dev Function allowing msg.sender to vote for/against a proposal
           * @param proposalId id of the proposal
           * @param support boolean, true = vote for, false = vote against
           **/
          function submitVote(uint256 proposalId, bool support) external;
          /**
           * @dev Function to register the vote of user that has voted offchain via signature
           * @param proposalId id of the proposal
           * @param support boolean, true = vote for, false = vote against
           * @param v v part of the voter signature
           * @param r r part of the voter signature
           * @param s s part of the voter signature
           **/
          function submitVoteBySignature(
            uint256 proposalId,
            bool support,
            uint8 v,
            bytes32 r,
            bytes32 s
          ) external;
          /**
           * @dev Set new GovernanceStrategy
           * Note: owner should be a timelocked executor, so needs to make a proposal
           * @param governanceStrategy new Address of the GovernanceStrategy contract
           **/
          function setGovernanceStrategy(address governanceStrategy) external;
          /**
           * @dev Set new Voting Delay (delay before a newly created proposal can be voted on)
           * Note: owner should be a timelocked executor, so needs to make a proposal
           * @param votingDelay new voting delay in seconds
           **/
          function setVotingDelay(uint256 votingDelay) external;
          /**
           * @dev Add new addresses to the list of authorized executors
           * @param executors list of new addresses to be authorized executors
           **/
          function authorizeExecutors(address[] memory executors) external;
          /**
           * @dev Remove addresses to the list of authorized executors
           * @param executors list of addresses to be removed as authorized executors
           **/
          function unauthorizeExecutors(address[] memory executors) external;
          /**
           * @dev Getter of the current GovernanceStrategy address
           * @return The address of the current GovernanceStrategy contracts
           **/
          function getGovernanceStrategy() external view returns (address);
          /**
           * @dev Getter of the current Voting Delay (delay before a created proposal can be voted on)
           * Different from the voting duration
           * @return The voting delay in seconds
           **/
          function getVotingDelay() external view returns (uint256);
          /**
           * @dev Returns whether an address is an authorized executor
           * @param executor address to evaluate as authorized executor
           * @return true if authorized
           **/
          function isExecutorAuthorized(address executor) external view returns (bool);
          /**
           * @dev Getter of the proposal count (the current number of proposals ever created)
           * @return the proposal count
           **/
          function getProposalsCount() external view returns (uint256);
          /**
           * @dev Getter of a proposal by id
           * @param proposalId id of the proposal to get
           * @return the proposal as ProposalWithoutVotes memory object
           **/
          function getProposalById(uint256 proposalId) external view returns (ProposalWithoutVotes memory);
          /**
           * @dev Getter of the Vote of a voter about a proposal
           * Note: Vote is a struct: ({bool support, uint248 votingPower})
           * @param proposalId id of the proposal
           * @param voter address of the voter
           * @return The associated Vote memory object
           **/
          function getVoteOnProposal(uint256 proposalId, address voter) external view returns (Vote memory);
          /**
           * @dev Get the current state of a proposal
           * @param proposalId id of the proposal
           * @return The current state if the proposal
           **/
          function getProposalState(uint256 proposalId) external view returns (ProposalState);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { IDydxGovernor } from './IDydxGovernor.sol';
        interface IExecutorWithTimelock {
          /**
           * @dev emitted when a new pending admin is set
           * @param newPendingAdmin address of the new pending admin
           **/
          event NewPendingAdmin(address newPendingAdmin);
          /**
           * @dev emitted when a new admin is set
           * @param newAdmin address of the new admin
           **/
          event NewAdmin(address newAdmin);
          /**
           * @dev emitted when a new delay (between queueing and execution) is set
           * @param delay new delay
           **/
          event NewDelay(uint256 delay);
          /**
           * @dev emitted when a new (trans)action is Queued.
           * @param actionHash hash of the action
           * @param target address of the targeted contract
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           **/
          event QueuedAction(
            bytes32 actionHash,
            address indexed target,
            uint256 value,
            string signature,
            bytes data,
            uint256 executionTime,
            bool withDelegatecall
          );
          /**
           * @dev emitted when an action is Cancelled
           * @param actionHash hash of the action
           * @param target address of the targeted contract
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           **/
          event CancelledAction(
            bytes32 actionHash,
            address indexed target,
            uint256 value,
            string signature,
            bytes data,
            uint256 executionTime,
            bool withDelegatecall
          );
          /**
           * @dev emitted when an action is Cancelled
           * @param actionHash hash of the action
           * @param target address of the targeted contract
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           * @param resultData the actual callData used on the target
           **/
          event ExecutedAction(
            bytes32 actionHash,
            address indexed target,
            uint256 value,
            string signature,
            bytes data,
            uint256 executionTime,
            bool withDelegatecall,
            bytes resultData
          );
          /**
           * @dev Getter of the current admin address (should be governance)
           * @return The address of the current admin
           **/
          function getAdmin() external view returns (address);
          /**
           * @dev Getter of the current pending admin address
           * @return The address of the pending admin
           **/
          function getPendingAdmin() external view returns (address);
          /**
           * @dev Getter of the delay between queuing and execution
           * @return The delay in seconds
           **/
          function getDelay() external view returns (uint256);
          /**
           * @dev Returns whether an action (via actionHash) is queued
           * @param actionHash hash of the action to be checked
           * keccak256(abi.encode(target, value, signature, data, executionTime, withDelegatecall))
           * @return true if underlying action of actionHash is queued
           **/
          function isActionQueued(bytes32 actionHash) external view returns (bool);
          /**
           * @dev Checks whether a proposal is over its grace period
           * @param governance Governance contract
           * @param proposalId Id of the proposal against which to test
           * @return true of proposal is over grace period
           **/
          function isProposalOverGracePeriod(IDydxGovernor governance, uint256 proposalId)
            external
            view
            returns (bool);
          /**
           * @dev Getter of grace period constant
           * @return grace period in seconds
           **/
          function GRACE_PERIOD() external view returns (uint256);
          /**
           * @dev Getter of minimum delay constant
           * @return minimum delay in seconds
           **/
          function MINIMUM_DELAY() external view returns (uint256);
          /**
           * @dev Getter of maximum delay constant
           * @return maximum delay in seconds
           **/
          function MAXIMUM_DELAY() external view returns (uint256);
          /**
           * @dev Function, called by Governance, that queue a transaction, returns action hash
           * @param target smart contract target
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           **/
          function queueTransaction(
            address target,
            uint256 value,
            string memory signature,
            bytes memory data,
            uint256 executionTime,
            bool withDelegatecall
          ) external returns (bytes32);
          /**
           * @dev Function, called by Governance, that executes a transaction, returns the callData executed
           * @param target smart contract target
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           **/
          function executeTransaction(
            address target,
            uint256 value,
            string memory signature,
            bytes memory data,
            uint256 executionTime,
            bool withDelegatecall
          ) external payable returns (bytes memory);
          /**
           * @dev Function, called by Governance, that cancels a transaction, returns action hash
           * @param target smart contract target
           * @param value wei value of the transaction
           * @param signature function signature of the transaction
           * @param data function arguments of the transaction or callData if signature empty
           * @param executionTime time at which to execute the transaction
           * @param withDelegatecall boolean, true = transaction delegatecalls the target, else calls the target
           **/
          function cancelTransaction(
            address target,
            uint256 value,
            string memory signature,
            bytes memory data,
            uint256 executionTime,
            bool withDelegatecall
          ) external returns (bytes32);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        interface IGovernanceStrategy {
          /**
           * @dev Returns the Proposition Power of a user at a specific block number.
           * @param user Address of the user.
           * @param blockNumber Blocknumber at which to fetch Proposition Power
           * @return Power number
           **/
          function getPropositionPowerAt(address user, uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the total supply of Outstanding Proposition Tokens
           * @param blockNumber Blocknumber at which to evaluate
           * @return total supply at blockNumber
           **/
          function getTotalPropositionSupplyAt(uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the total supply of Outstanding Voting Tokens
           * @param blockNumber Blocknumber at which to evaluate
           * @return total supply at blockNumber
           **/
          function getTotalVotingSupplyAt(uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the Vote Power of a user at a specific block number.
           * @param user Address of the user.
           * @param blockNumber Blocknumber at which to fetch Vote Power
           * @return Vote number
           **/
          function getVotingPowerAt(address user, uint256 blockNumber) external view returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { IDydxGovernor } from './IDydxGovernor.sol';
        interface IProposalValidator {
          /**
           * @dev Called to validate a proposal (e.g when creating new proposal in Governance)
           * @param governance Governance Contract
           * @param user Address of the proposal creator
           * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
           * @return boolean, true if can be created
           **/
          function validateCreatorOfProposal(
            IDydxGovernor governance,
            address user,
            uint256 blockNumber
          ) external view returns (bool);
          /**
           * @dev Called to validate the cancellation of a proposal
           * @param governance Governance Contract
           * @param user Address of the proposal creator
           * @param blockNumber Block Number against which to make the test (e.g proposal creation block -1).
           * @return boolean, true if can be cancelled
           **/
          function validateProposalCancellation(
            IDydxGovernor governance,
            address user,
            uint256 blockNumber
          ) external view returns (bool);
          /**
           * @dev Returns whether a user has enough Proposition Power to make a proposal.
           * @param governance Governance Contract
           * @param user Address of the user to be challenged.
           * @param blockNumber Block Number against which to make the challenge.
           * @return true if user has enough power
           **/
          function isPropositionPowerEnough(
            IDydxGovernor governance,
            address user,
            uint256 blockNumber
          ) external view returns (bool);
          /**
           * @dev Returns the minimum Proposition Power needed to create a proposition.
           * @param governance Governance Contract
           * @param blockNumber Blocknumber at which to evaluate
           * @return minimum Proposition Power needed
           **/
          function getMinimumPropositionPowerNeeded(IDydxGovernor governance, uint256 blockNumber)
            external
            view
            returns (uint256);
          /**
           * @dev Returns whether a proposal passed or not
           * @param governance Governance Contract
           * @param proposalId Id of the proposal to set
           * @return true if proposal passed
           **/
          function isProposalPassed(IDydxGovernor governance, uint256 proposalId)
            external
            view
            returns (bool);
          /**
           * @dev Check whether a proposal has reached quorum, ie has enough FOR-voting-power
           * Here quorum is not to understand as number of votes reached, but number of for-votes reached
           * @param governance Governance Contract
           * @param proposalId Id of the proposal to verify
           * @return voting power needed for a proposal to pass
           **/
          function isQuorumValid(IDydxGovernor governance, uint256 proposalId)
            external
            view
            returns (bool);
          /**
           * @dev Check whether a proposal has enough extra FOR-votes than AGAINST-votes
           * FOR VOTES - AGAINST VOTES > VOTE_DIFFERENTIAL * voting supply
           * @param governance Governance Contract
           * @param proposalId Id of the proposal to verify
           * @return true if enough For-Votes
           **/
          function isVoteDifferentialValid(IDydxGovernor governance, uint256 proposalId)
            external
            view
            returns (bool);
          /**
           * @dev Calculates the minimum amount of Voting Power needed for a proposal to Pass
           * @param votingSupply Total number of oustanding voting tokens
           * @return voting power needed for a proposal to pass
           **/
          function getMinimumVotingPowerNeeded(uint256 votingSupply) external view returns (uint256);
          /**
           * @dev Get proposition threshold constant value
           * @return the proposition threshold value (100 <=> 1%)
           **/
          function PROPOSITION_THRESHOLD() external view returns (uint256);
          /**
           * @dev Get voting duration constant value
           * @return the voting duration value in seconds
           **/
          function VOTING_DURATION() external view returns (uint256);
          /**
           * @dev Get the vote differential threshold constant value
           * to compare with % of for votes/total supply - % of against votes/total supply
           * @return the vote differential threshold value (100 <=> 1%)
           **/
          function VOTE_DIFFERENTIAL() external view returns (uint256);
          /**
           * @dev Get quorum threshold constant value
           * to compare with % of for votes/total supply
           * @return the quorum threshold value (100 <=> 1%)
           **/
          function MINIMUM_QUORUM() external view returns (uint256);
          /**
           * @dev precision helper: 100% = 10000
           * @return one hundred percents with our chosen precision
           **/
          function ONE_HUNDRED_WITH_PRECISION() external view returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        interface IVotingStrategy {
          function getVotingPowerAt(address user, uint256 blockNumber) external view returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        function getChainId() pure returns (uint256) {
          uint256 chainId;
          assembly {
            chainId := chainid()
          }
          return chainId;
        }
        function isContract(address account) view returns (bool) {
          // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
          // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
          // for accounts without code, i.e. `keccak256('')`
          bytes32 codehash;
          bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
          // solhint-disable-next-line no-inline-assembly
          assembly {
            codehash := extcodehash(account)
          }
          return (codehash != accountHash && codehash != 0x0);
        }
        

        File 2 of 6: GovernanceStrategyV2
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              codehash := extcodehash(account)
            }
            return (codehash != accountHash && codehash != 0x0);
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, 'Address: insufficient balance');
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}('');
            require(success, 'Address: unable to send value, recipient may have reverted');
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.5;
        import "../../interfaces/IERC20.sol";
        import "./Context.sol";
        import "./SafeMath.sol";
        import "./Address.sol";
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin guidelines: functions revert instead
         * of returning `false` on failure. This behavior is nonetheless conventional
         * and does not conflict with the expectations of ERC20 applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20 {
            using SafeMath for uint256;
            using Address for address;
            mapping (address => uint256) private _balances;
            mapping (address => mapping (address => uint256)) private _allowances;
            uint256 private _totalSupply;
            string internal _name;
            string internal _symbol;
            uint8 private _decimals;
            /**
             * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
             * a default value of 18.
             *
             * To select a different value for {decimals}, use {_setupDecimals}.
             *
             * All three of these values are immutable: they can only be set once during
             * construction.
             */
            constructor (string memory name, string memory symbol) public {
                _name = name;
                _symbol = symbol;
                _decimals = 18;
            }
            /**
             * @dev Returns the name of the token.
             */
            function name() virtual public view returns (string memory) {
                return _name;
            }
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() virtual public view returns (string memory) {
                return _symbol;
            }
            /**
             * @dev Returns the number of decimals used to get its user representation.
             * For example, if `decimals` equals `2`, a balance of `505` tokens should
             * be displayed to a user as `5,05` (`505 / 10 ** 2`).
             *
             * Tokens usually opt for a value of 18, imitating the relationship between
             * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
             * called.
             *
             * NOTE: This information is only used for _display_ purposes: it in
             * no way affects any of the arithmetic of the contract, including
             * {IERC20-balanceOf} and {IERC20-transfer}.
             */
            function decimals() virtual public view returns (uint8) {
                return _decimals;
            }
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view override returns (uint256) {
                return _totalSupply;
            }
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view override returns (uint256) {
                return _balances[account];
            }
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20};
             *
             * Requirements:
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
                _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                return true;
            }
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                return true;
            }
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                return true;
            }
            /**
             * @dev Moves tokens `amount` from `sender` to `recipient`.
             *
             * This is internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
                _beforeTokenTransfer(sender, recipient, amount);
                _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                _balances[recipient] = _balances[recipient].add(amount);
                emit Transfer(sender, recipient, amount);
            }
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements
             *
             * - `to` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
                _beforeTokenTransfer(address(0), account, amount);
                _totalSupply = _totalSupply.add(amount);
                _balances[account] = _balances[account].add(amount);
                emit Transfer(address(0), account, amount);
            }
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
                _beforeTokenTransfer(account, address(0), amount);
                _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                _totalSupply = _totalSupply.sub(amount);
                emit Transfer(account, address(0), amount);
            }
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
             *
             * This is internal function is equivalent to `approve`, and can be used to
             * e.g. set automatic allowances for certain subsystems, etc.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(address owner, address spender, uint256 amount) internal virtual {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
            /**
             * @dev Sets {decimals} to a value other than the default one of 18.
             *
             * WARNING: This function should only be called from the constructor. Most
             * applications that interact with token contracts will not expect
             * {decimals} to ever change, and may work incorrectly if it does.
             */
            function _setupDecimals(uint8 decimals_) internal {
                _decimals = decimals_;
            }
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be to transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when an
         * operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         */
        library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, 'SafeMath: addition overflow');
            return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, 'SafeMath: subtraction overflow');
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
              return 0;
            }
            uint256 c = a * b;
            require(c / a == b, 'SafeMath: multiplication overflow');
            return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, 'SafeMath: division by zero');
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, 'SafeMath: modulo by zero');
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { IGovernancePowerDelegationERC20 } from '../../interfaces/IGovernancePowerDelegationERC20.sol';
        import { IGovernanceStrategy } from '../../interfaces/IGovernanceStrategy.sol';
        import { GovernancePowerDelegationERC20Mixin } from '../token/GovernancePowerDelegationERC20Mixin.sol';
        interface IDydxToken {
          function _totalSupplySnapshots(
            uint256
          )
            external
            view
            returns (GovernancePowerDelegationERC20Mixin.Snapshot memory);
          function _totalSupplySnapshotsCount()
            external
            view
            returns (uint256);
        }
        /**
         * @title GovernanceStrategyV2
         * @author dYdX
         *
         * @notice Smart contract containing logic to measure users' relative governance power for creating
         *  and voting on proposals.
         *
         *  User Power = User Power from each of: DYDX, stkDYDX, wethDYDX.
         *  User Power from Token = Token Power + Token Power as Delegatee [- Token Power if user has delegated]
         * Two wrapper functions linked to DYDX tokens's GovernancePowerDelegationERC20Mixin.sol implementation
         * - getPropositionPowerAt: fetching a user Proposition Power at a specified block
         * - getVotingPowerAt: fetching a user Voting Power at a specified block
         */
        contract GovernanceStrategyV2 is
          IGovernanceStrategy
        {
          // ============ Constants ============
          /// @notice The DYDX governance token.
          address public immutable DYDX_TOKEN;
          /// @notice Token representing staked positions of the DYDX token.
          address public immutable STAKED_DYDX_TOKEN;
          /// @notice Token representing Wrapped Ethereum DYDX tokens.
          address public immutable WRAPPED_ETHEREUM_DYDX_TOKEN;
          // ============ Constructor ============
          constructor(
            address dydxToken,
            address stakedDydxToken,
            address wrappedEthereumDydxToken
          ) {
            DYDX_TOKEN = dydxToken;
            STAKED_DYDX_TOKEN = stakedDydxToken;
            WRAPPED_ETHEREUM_DYDX_TOKEN = wrappedEthereumDydxToken;
          }
          // ============ Other Functions ============
          /**
           * @notice Get the total supply of proposition power, for the purpose of determining if a
           *  proposing threshold was reached.
           *
           * @param  blockNumber  Block number at which to evaluate.
           *
           * @return The total proposition power supply at the given block number.
           */
          function getTotalPropositionSupplyAt(
            uint256 blockNumber
          )
            public
            view
            override
            returns (uint256)
          {
            return _getTotalSupplyAt(blockNumber);
          }
          /**
           * @notice Get the total supply of voting power, for the purpose of determining if quorum or vote
           *  differential tresholds were reached.
           *
           * @param  blockNumber  Block number at which to evaluate.
           *
           * @return The total voting power supply at the given block number.
           */
          function getTotalVotingSupplyAt(
            uint256 blockNumber
          )
            public
            view
            override
            returns (uint256)
          {
            return _getTotalSupplyAt(blockNumber);
          }
          /**
           * @notice The proposition power of an address at a given block number.
           *
           * @param  user         Address to check.
           * @param  blockNumber  Block number at which to evaluate.
           *
           * @return The proposition power of the address at the given block number.
           */
          function getPropositionPowerAt(
            address user,
            uint256 blockNumber
          )
            public
            view
            override
            returns (uint256)
          {
            return _getPowerByTypeAt(
              user,
              blockNumber,
              IGovernancePowerDelegationERC20.DelegationType.PROPOSITION_POWER
            );
          }
          /**
           * @notice The voting power of an address at a given block number.
           *
           * @param  user         Address of the user.
           * @param  blockNumber  Block number at which to evaluate.
           *
           * @return The voting power of the address at the given block number.
           */
          function getVotingPowerAt(
            address user,
            uint256 blockNumber
          )
            public
            view
            override
            returns (uint256)
          {
            return _getPowerByTypeAt(
              user,
              blockNumber,
              IGovernancePowerDelegationERC20.DelegationType.VOTING_POWER
            );
          }
          function _getPowerByTypeAt(
            address user,
            uint256 blockNumber,
            IGovernancePowerDelegationERC20.DelegationType powerType
          )
            internal
            view
            returns (uint256)
          {
            return (
              IGovernancePowerDelegationERC20(DYDX_TOKEN).getPowerAtBlock(
                user,
                blockNumber,
                powerType
              ) +
              IGovernancePowerDelegationERC20(STAKED_DYDX_TOKEN).getPowerAtBlock(
                user,
                blockNumber,
                powerType
              ) +
              IGovernancePowerDelegationERC20(WRAPPED_ETHEREUM_DYDX_TOKEN).getPowerAtBlock(
                user,
                blockNumber,
                powerType
              )
            );
          }
          /**
           * @dev The total supply of the DYDX token at a given block number.
           *
           * @param  blockNumber  Block number at which to evaluate.
           *
           * @return The total DYDX token supply at the given block number.
           */
          function _getTotalSupplyAt(
            uint256 blockNumber
          )
            internal
            view
            returns (uint256)
          {
            IDydxToken dydxToken = IDydxToken(DYDX_TOKEN);
            uint256 snapshotsCount = dydxToken._totalSupplySnapshotsCount();
            // Iterate in reverse over the total supply snapshots, up to index 1.
            for (uint256 i = snapshotsCount - 1; i != 0; i--) {
              GovernancePowerDelegationERC20Mixin.Snapshot memory snapshot = (
                dydxToken._totalSupplySnapshots(i)
              );
              if (snapshot.blockNumber <= blockNumber) {
                return snapshot.value;
              }
            }
            // If blockNumber was on or after the first snapshot, then return the initial supply.
            // Else, blockNumber is before token launch so return 0.
            GovernancePowerDelegationERC20Mixin.Snapshot memory firstSnapshot = (
              dydxToken._totalSupplySnapshots(0)
            );
            if (firstSnapshot.blockNumber <= blockNumber) {
              return firstSnapshot.value;
            } else {
              return 0;
            }
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        import { ERC20 } from '../../dependencies/open-zeppelin/ERC20.sol';
        import { SafeMath } from '../../dependencies/open-zeppelin/SafeMath.sol';
        import {
          IGovernancePowerDelegationERC20
        } from '../../interfaces/IGovernancePowerDelegationERC20.sol';
        /**
         * @title GovernancePowerDelegationERC20Mixin
         * @author dYdX
         *
         * @notice Provides support for two types of governance powers, both endowed by the governance
         *  token, and separately delegatable. Provides functions for delegation and for querying a user's
         *  power at a certain block number.
         */
        abstract contract GovernancePowerDelegationERC20Mixin is
          ERC20,
          IGovernancePowerDelegationERC20
        {
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice EIP-712 typehash for delegation by signature of a specific governance power type.
          bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256(
            'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)'
          );
          /// @notice EIP-712 typehash for delegation by signature of all governance powers.
          bytes32 public constant DELEGATE_TYPEHASH = keccak256(
            'Delegate(address delegatee,uint256 nonce,uint256 expiry)'
          );
          // ============ Structs ============
          /// @dev Snapshot of a value on a specific block, used to track voting power for proposals.
          struct Snapshot {
            uint128 blockNumber;
            uint128 value;
          }
          // ============ External Functions ============
          /**
           * @notice Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType)
            external
            override
          {
            _delegateByType(msg.sender, delegatee, delegationType);
          }
          /**
           * @notice Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The address to delegate power to.
           */
          function delegate(address delegatee)
            external
            override
          {
            _delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER);
          }
          /**
           * @notice Returns the delegatee of a user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            override
            view
            returns (address)
          {
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            return _getDelegatee(delegator, delegates);
          }
          /**
           * @notice Returns the current power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            override
            view
            returns (uint256)
          {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, block.number);
          }
          /**
           * @notice Returns the power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          ) external override view returns (uint256) {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, blockNumber);
          }
          // ============ Internal Functions ============
          /**
           * @dev Delegates one specific power to a delegatee.
           *
           * @param  delegator       The user whose power to delegate.
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _delegateByType(
            address delegator,
            address delegatee,
            DelegationType delegationType
          ) internal {
            require(delegatee != address(0), 'INVALID_DELEGATEE');
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            uint256 delegatorBalance = balanceOf(delegator);
            address previousDelegatee = _getDelegatee(delegator, delegates);
            delegates[delegator] = delegatee;
            _moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType);
            emit DelegateChanged(delegator, delegatee, delegationType);
          }
          /**
           * @dev Moves power from one user to another.
           *
           * @param  from            The user from which delegated power is moved.
           * @param  to              The user that will receive the delegated power.
           * @param  amount          The amount of power to be moved.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _moveDelegatesByType(
            address from,
            address to,
            uint256 amount,
            DelegationType delegationType
          ) internal {
            if (from == to) {
              return;
            }
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            if (from != address(0)) {
              uint256 previous = 0;
              uint256 fromSnapshotsCount = snapshotsCounts[from];
              if (fromSnapshotsCount != 0) {
                previous = snapshots[from][fromSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(from);
              }
              uint256 newAmount = previous.sub(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                from,
                uint128(newAmount)
              );
              emit DelegatedPowerChanged(from, newAmount, delegationType);
            }
            if (to != address(0)) {
              uint256 previous = 0;
              uint256 toSnapshotsCount = snapshotsCounts[to];
              if (toSnapshotsCount != 0) {
                previous = snapshots[to][toSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(to);
              }
              uint256 newAmount = previous.add(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                to,
                uint128(newAmount)
              );
              emit DelegatedPowerChanged(to, newAmount, delegationType);
            }
          }
          /**
           * @dev Searches for a balance snapshot by block number using binary search.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  user             The user for which the snapshot is being searched.
           * @param  blockNumber      The block number being searched.
           */
          function _searchByBlockNumber(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address user,
            uint256 blockNumber
          ) internal view returns (uint256) {
            require(blockNumber <= block.number, 'INVALID_BLOCK_NUMBER');
            uint256 snapshotsCount = snapshotsCounts[user];
            if (snapshotsCount == 0) {
              return balanceOf(user);
            }
            // First check most recent balance
            if (snapshots[user][snapshotsCount - 1].blockNumber <= blockNumber) {
              return snapshots[user][snapshotsCount - 1].value;
            }
            // Next check implicit zero balance
            if (snapshots[user][0].blockNumber > blockNumber) {
              return 0;
            }
            uint256 lower = 0;
            uint256 upper = snapshotsCount - 1;
            while (upper > lower) {
              uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
              Snapshot memory snapshot = snapshots[user][center];
              if (snapshot.blockNumber == blockNumber) {
                return snapshot.value;
              } else if (snapshot.blockNumber < blockNumber) {
                lower = center;
              } else {
                upper = center - 1;
              }
            }
            return snapshots[user][lower].value;
          }
          /**
           * @dev Returns delegation data (snapshot, snapshotsCount, delegates) by delegation type.
           *
           *  Note: This mixin contract does not itself define any storage, and we require the inheriting
           *  contract to implement this method to provide access to the relevant mappings in storage.
           *  This pattern was implemented by Aave for legacy reasons and we have decided not to change it.
           *
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _getDelegationDataByType(DelegationType delegationType)
            internal
            virtual
            view
            returns (
              mapping(address => mapping(uint256 => Snapshot)) storage, // snapshots
              mapping(address => uint256) storage, // snapshotsCount
              mapping(address => address) storage // delegates
            );
          /**
           * @dev Writes a snapshot of a user's token/power balance.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  owner            The user whose power to snapshot.
           * @param  newValue         The new balance to snapshot at the current block.
           */
          function _writeSnapshot(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address owner,
            uint128 newValue
          ) internal {
            uint128 currentBlock = uint128(block.number);
            uint256 ownerSnapshotsCount = snapshotsCounts[owner];
            mapping(uint256 => Snapshot) storage ownerSnapshots = snapshots[owner];
            if (
              ownerSnapshotsCount != 0 &&
              ownerSnapshots[ownerSnapshotsCount - 1].blockNumber == currentBlock
            ) {
              // Doing multiple operations in the same block
              ownerSnapshots[ownerSnapshotsCount - 1].value = newValue;
            } else {
              ownerSnapshots[ownerSnapshotsCount] = Snapshot(currentBlock, newValue);
              snapshotsCounts[owner] = ownerSnapshotsCount + 1;
            }
          }
          /**
           * @dev Returns the delegatee of a user. If a user never performed any delegation, their
           *  delegated address will be 0x0, in which case we return the user's own address.
           *
           * @param  delegator  The address of the user for which return the delegatee.
           * @param  delegates  The mapping of delegates for a particular type of delegation.
           */
          function _getDelegatee(
            address delegator,
            mapping(address => address) storage delegates
          )
            internal
            view
            returns (address)
          {
            address previousDelegatee = delegates[delegator];
            if (previousDelegatee == address(0)) {
              return delegator;
            }
            return previousDelegatee;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
        * @dev Interface of the ERC20 standard as defined in the EIP.
        */
        interface IERC20 {
          /**
            * @dev Returns the amount of tokens in existence.
            */
          function totalSupply() external view returns (uint256);
          /**
            * @dev Returns the amount of tokens owned by `account`.
            */
          function balanceOf(address account) external view returns (uint256);
          /**
            * @dev Moves `amount` tokens from the caller's account to `recipient`.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Returns the remaining number of tokens that `spender` will be
            * allowed to spend on behalf of `owner` through {transferFrom}. This is
            * zero by default.
            *
            * This value changes when {approve} or {transferFrom} are called.
            */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
            * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * IMPORTANT: Beware that changing an allowance with this method brings the risk
            * that someone may use both the old and the new allowance by unfortunate
            * transaction ordering. One possible solution to mitigate this race
            * condition is to first reduce the spender's allowance to 0 and set the
            * desired value afterwards:
            * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
            *
            * Emits an {Approval} event.
            */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
            * @dev Moves `amount` tokens from `sender` to `recipient` using the
            * allowance mechanism. `amount` is then deducted from the caller's
            * allowance.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Emitted when `value` tokens are moved from one account (`from`) to
            * another (`to`).
            *
            * Note that `value` may be zero.
            */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
            * @dev Emitted when the allowance of a `spender` for an `owner` is set by
            * a call to {approve}. `value` is the new allowance.
            */
          event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        interface IGovernancePowerDelegationERC20 {
          enum DelegationType {
            VOTING_POWER,
            PROPOSITION_POWER
          }
          /**
           * @dev Emitted when a user delegates governance power to another user.
           *
           * @param  delegator       The delegator.
           * @param  delegatee       The delegatee.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegateChanged(
            address indexed delegator,
            address indexed delegatee,
            DelegationType delegationType
          );
          /**
           * @dev Emitted when an action changes the delegated power of a user.
           *
           * @param  user            The user whose delegated power has changed.
           * @param  amount          The new amount of delegated power for the user.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType);
          /**
           * @dev Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType) external virtual;
          /**
           * @dev Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The user to which the power will be delegated.
           */
          function delegate(address delegatee) external virtual;
          /**
           * @dev Returns the delegatee of an user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            view
            virtual
            returns (address);
          /**
           * @dev Returns the current delegated power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            view
            virtual
            returns (uint256);
          /**
           * @dev Returns the delegated power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            external
            view
            virtual
            returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        interface IGovernanceStrategy {
          /**
           * @dev Returns the Proposition Power of a user at a specific block number.
           * @param user Address of the user.
           * @param blockNumber Blocknumber at which to fetch Proposition Power
           * @return Power number
           **/
          function getPropositionPowerAt(address user, uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the total supply of Outstanding Proposition Tokens
           * @param blockNumber Blocknumber at which to evaluate
           * @return total supply at blockNumber
           **/
          function getTotalPropositionSupplyAt(uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the total supply of Outstanding Voting Tokens
           * @param blockNumber Blocknumber at which to evaluate
           * @return total supply at blockNumber
           **/
          function getTotalVotingSupplyAt(uint256 blockNumber) external view returns (uint256);
          /**
           * @dev Returns the Vote Power of a user at a specific block number.
           * @param user Address of the user.
           * @param blockNumber Blocknumber at which to fetch Vote Power
           * @return Vote number
           **/
          function getVotingPowerAt(address user, uint256 blockNumber) external view returns (uint256);
        }
        

        File 3 of 6: WrappedEthereumDydxToken
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              codehash := extcodehash(account)
            }
            return (codehash != accountHash && codehash != 0x0);
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, 'Address: insufficient balance');
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}('');
            require(success, 'Address: unable to send value, recipient may have reverted');
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.5;
        import "../../interfaces/IERC20.sol";
        import "./Context.sol";
        import "./SafeMath.sol";
        import "./Address.sol";
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin guidelines: functions revert instead
         * of returning `false` on failure. This behavior is nonetheless conventional
         * and does not conflict with the expectations of ERC20 applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20 {
            using SafeMath for uint256;
            using Address for address;
            mapping (address => uint256) private _balances;
            mapping (address => mapping (address => uint256)) private _allowances;
            uint256 private _totalSupply;
            string internal _name;
            string internal _symbol;
            uint8 private _decimals;
            /**
             * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
             * a default value of 18.
             *
             * To select a different value for {decimals}, use {_setupDecimals}.
             *
             * All three of these values are immutable: they can only be set once during
             * construction.
             */
            constructor (string memory name, string memory symbol) public {
                _name = name;
                _symbol = symbol;
                _decimals = 18;
            }
            /**
             * @dev Returns the name of the token.
             */
            function name() virtual public view returns (string memory) {
                return _name;
            }
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() virtual public view returns (string memory) {
                return _symbol;
            }
            /**
             * @dev Returns the number of decimals used to get its user representation.
             * For example, if `decimals` equals `2`, a balance of `505` tokens should
             * be displayed to a user as `5,05` (`505 / 10 ** 2`).
             *
             * Tokens usually opt for a value of 18, imitating the relationship between
             * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
             * called.
             *
             * NOTE: This information is only used for _display_ purposes: it in
             * no way affects any of the arithmetic of the contract, including
             * {IERC20-balanceOf} and {IERC20-transfer}.
             */
            function decimals() virtual public view returns (uint8) {
                return _decimals;
            }
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view override returns (uint256) {
                return _totalSupply;
            }
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view override returns (uint256) {
                return _balances[account];
            }
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20};
             *
             * Requirements:
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
                _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                return true;
            }
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                return true;
            }
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                return true;
            }
            /**
             * @dev Moves tokens `amount` from `sender` to `recipient`.
             *
             * This is internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
                _beforeTokenTransfer(sender, recipient, amount);
                _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                _balances[recipient] = _balances[recipient].add(amount);
                emit Transfer(sender, recipient, amount);
            }
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements
             *
             * - `to` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
                _beforeTokenTransfer(address(0), account, amount);
                _totalSupply = _totalSupply.add(amount);
                _balances[account] = _balances[account].add(amount);
                emit Transfer(address(0), account, amount);
            }
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
                _beforeTokenTransfer(account, address(0), amount);
                _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                _totalSupply = _totalSupply.sub(amount);
                emit Transfer(account, address(0), amount);
            }
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
             *
             * This is internal function is equivalent to `approve`, and can be used to
             * e.g. set automatic allowances for certain subsystems, etc.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(address owner, address spender, uint256 amount) internal virtual {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
            /**
             * @dev Sets {decimals} to a value other than the default one of 18.
             *
             * WARNING: This function should only be called from the constructor. Most
             * applications that interact with token contracts will not expect
             * {decimals} to ever change, and may work incorrectly if it does.
             */
            function _setupDecimals(uint8 decimals_) internal {
                _decimals = decimals_;
            }
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be to transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import { IERC20 } from '../../interfaces/IERC20.sol';
        import { SafeMath } from './SafeMath.sol';
        import { Address } from './Address.sol';
        /**
         * @title SafeERC20
         * @dev From https://github.com/OpenZeppelin/openzeppelin-contracts
         * Wrappers around ERC20 operations that throw on failure (when the token
         * contract returns false). Tokens that return no value (and instead revert or
         * throw on failure) are also supported, non-reverting calls are assumed to be
         * successful.
         * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
         * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
         */
        library SafeERC20 {
          using SafeMath for uint256;
          using Address for address;
          function safeTransfer(
            IERC20 token,
            address to,
            uint256 value
          ) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
          function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
          ) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
          function safeApprove(
            IERC20 token,
            address spender,
            uint256 value
          ) internal {
            require(
              (value == 0) || (token.allowance(address(this), spender) == 0),
              'SafeERC20: approve from non-zero to non-zero allowance'
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
          function callOptionalReturn(IERC20 token, bytes memory data) private {
            require(address(token).isContract(), 'SafeERC20: call to non-contract');
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, 'SafeERC20: low-level call failed');
            if (returndata.length > 0) {
              // Return data is optional
              // solhint-disable-next-line max-line-length
              require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
            }
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when an
         * operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         */
        library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, 'SafeMath: addition overflow');
            return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, 'SafeMath: subtraction overflow');
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
              return 0;
            }
            uint256 c = a * b;
            require(c / a == b, 'SafeMath: multiplication overflow');
            return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, 'SafeMath: division by zero');
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, 'SafeMath: modulo by zero');
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Interface of a bridge contract.
         */
        interface IBridge {
          /**
           * @dev Emitted when a bridge event occurs.
           *
           * @param  id          Unique ID of the bridge event.
           * @param  amount      Amount of tokens bridged.
           * @param  from        The Ethereum address the tokens were transferred from.
           * @param  accAddress  The address to send to.
           * @param  data        Any arbitrary data.
           */
          event Bridge(
            uint256 indexed id,
            uint256 amount,
            address from,
            bytes accAddress,
            bytes data
          );
          /**
           * @notice Bridge a token.
           *
           * @param  amount       The amount of tokens to bridge
           * @param  accAddress   The address to send to.
           * @param  memo         Arbitrary memo to include in the event.
           */
          function bridge(
            uint256 amount,
            bytes calldata accAddress,
            bytes calldata memo
          ) external;
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        import { IBridge } from './IBridge.sol';
        import { ERC20 } from '../../dependencies/open-zeppelin/ERC20.sol';
        import { SafeERC20 } from '../../dependencies/open-zeppelin/SafeERC20.sol';
        import { SafeMath } from '../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../interfaces/IERC20.sol';
        import { GovernancePowerDelegationERC20Mixin } from '../token/GovernancePowerDelegationERC20Mixin.sol';
        /**
         * @title WrappedEthereumDydxToken
         * @author dYdX
         *
         * @notice The Wrapped Ethereum DYDX governance token.
         */
        contract WrappedEthereumDydxToken is
          GovernancePowerDelegationERC20Mixin,
          IBridge
        {
          using SafeERC20 for IERC20;
          using SafeMath for uint256;
          // ============ Constants ============
          string internal constant NAME = 'Wrapped Ethereum DYDX';
          string internal constant SYMBOL = 'wethDYDX';
          bytes32 public immutable DOMAIN_SEPARATOR;
          bytes public constant EIP712_VERSION = '1';
          bytes32 public constant EIP712_DOMAIN = keccak256(
            'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
          );
          bytes32 public constant PERMIT_TYPEHASH = keccak256(
            'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
          );
          IERC20 public immutable DYDX_TOKEN;
          // ============ Storage ============
          /// @dev Mapping from (owner) => (next valid nonce) for EIP-712 signatures.
          mapping(address => uint256) internal _nonces;
          mapping(address => mapping(uint256 => Snapshot)) public _votingSnapshots;
          mapping(address => uint256) public _votingSnapshotsCounts;
          mapping(address => address) public _votingDelegates;
          mapping(address => mapping(uint256 => Snapshot)) public _propositionPowerSnapshots;
          mapping(address => uint256) public _propositionPowerSnapshotsCounts;
          mapping(address => address) public _propositionPowerDelegates;
          /// @notice The next available (unused) id for the bridge event. Equal to the number of events.
          uint256 public _nextAvailableBridgeId;
          // ============ Constructor ============
          /**
           * @notice Constructor.
           * @param  tokenAddress  The address of the token to bridge.
           */
          constructor(
            ERC20 tokenAddress
          )
            ERC20(NAME, SYMBOL)
          {
            uint256 chainId;
            // solium-disable-next-line
            assembly {
              chainId := chainid()
            }
            DOMAIN_SEPARATOR = keccak256(
              abi.encode(
                EIP712_DOMAIN,
                keccak256(bytes(NAME)),
                keccak256(bytes(EIP712_VERSION)),
                chainId,
                address(this)
              )
            );
            DYDX_TOKEN = tokenAddress;
          }
          /**
           * @notice Bridge the DYDX token and receive wethDYDX.
           *
           * @param  amount       The amount of tokens to bridge
           * @param  accAddress   The address to send to.
           * @param  memo         Arbitrary memo to include in the event. For possible future compatibility.
           */
          function bridge(
            uint256 amount,
            bytes calldata accAddress,
            bytes calldata memo
          )
            external
            override
          {
            // Wrap the tokens.
            DYDX_TOKEN.safeTransferFrom(msg.sender, address(this), amount);
            _mint(msg.sender, amount);
            // Emit the event and increase the nonce.
            uint256 nonce = _nextAvailableBridgeId;
            emit Bridge(
              nonce,
              amount,
              msg.sender,
              accAddress,
              memo
            );
            _nextAvailableBridgeId = nonce + 1;
          }
          /**
           * @notice Implements the permit function as specified in EIP-2612.
           *
           * @param  owner     Address of the token owner.
           * @param  spender   Address of the spender.
           * @param  value     Amount of allowance.
           * @param  deadline  Expiration timestamp for the signature.
           * @param  v         Signature param.
           * @param  r         Signature param.
           * @param  s         Signature param.
           */
          function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            external
          {
            require(owner != address(0), 'INVALID_OWNER');
            require(block.timestamp <= deadline, 'INVALID_EXPIRATION');
            uint256 currentValidNonce = _nonces[owner];
            bytes32 digest = keccak256(
              abi.encodePacked(
                '\\x19\\x01',
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
              )
            );
            require(owner == ecrecover(digest, v, r, s), 'INVALID_SIGNATURE');
            _nonces[owner] = currentValidNonce.add(1);
            _approve(owner, spender, value);
          }
          /**
           * @notice Get the next valid nonce for EIP-712 signatures.
           *
           *  This nonce should be used when signing for any of the following functions:
           *   - permit()
           *   - delegateByTypeBySig()
           *   - delegateBySig()
           */
          function nonces(address owner)
            external
            view
            returns (uint256)
          {
            return _nonces[owner];
          }
          /**
           * @dev Writes a snapshot before any transfer operation, including: _transfer, _mint and _burn.
           *  - On _transfer, it writes snapshots for both 'from' and 'to'.
           *  - On _mint, only for `to`.
           *  - On _burn, only for `from`.
           *
           * @param  from    The sender.
           * @param  to      The recipient.
           * @param  amount  The amount being transfered.
           */
          function _beforeTokenTransfer(
            address from,
            address to,
            uint256 amount
          )
            internal
            override
          {
            address votingFromDelegatee = _getDelegatee(from, _votingDelegates);
            address votingToDelegatee = _getDelegatee(to, _votingDelegates);
            _moveDelegatesByType(
              votingFromDelegatee,
              votingToDelegatee,
              amount,
              DelegationType.VOTING_POWER
            );
            address propPowerFromDelegatee = _getDelegatee(from, _propositionPowerDelegates);
            address propPowerToDelegatee = _getDelegatee(to, _propositionPowerDelegates);
            _moveDelegatesByType(
              propPowerFromDelegatee,
              propPowerToDelegatee,
              amount,
              DelegationType.PROPOSITION_POWER
            );
          }
          function _getDelegationDataByType(DelegationType delegationType)
            internal
            override
            view
            returns (
              mapping(address => mapping(uint256 => Snapshot)) storage, // snapshots
              mapping(address => uint256) storage, // snapshots count
              mapping(address => address) storage // delegatees list
            )
          {
            if (delegationType == DelegationType.VOTING_POWER) {
              return (_votingSnapshots, _votingSnapshotsCounts, _votingDelegates);
            } else {
              return (
                _propositionPowerSnapshots,
                _propositionPowerSnapshotsCounts,
                _propositionPowerDelegates
              );
            }
          }
          /**
           * @dev Delegates specific governance power from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee       The address to delegate votes to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           * @param  nonce           The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry          Expiration timestamp for the signature.
           * @param  v               Signature param.
           * @param  r               Signature param.
           * @param  s               Signature param.
           */
          function delegateByTypeBySig(
            address delegatee,
            DelegationType delegationType,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            public
          {
            bytes32 structHash = keccak256(
              abi.encode(DELEGATE_BY_TYPE_TYPEHASH, delegatee, uint256(delegationType), nonce, expiry)
            );
            bytes32 digest = keccak256(abi.encodePacked('\\x19\\x01', DOMAIN_SEPARATOR, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(signer != address(0), 'INVALID_SIGNATURE');
            require(nonce == _nonces[signer]++, 'INVALID_NONCE');
            require(block.timestamp <= expiry, 'INVALID_EXPIRATION');
            _delegateByType(signer, delegatee, delegationType);
          }
          /**
           * @dev Delegates both governance powers from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee  The address to delegate votes to.
           * @param  nonce      The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry     Expiration timestamp for the signature.
           * @param  v          Signature param.
           * @param  r          Signature param.
           * @param  s          Signature param.
           */
          function delegateBySig(
            address delegatee,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            public
          {
            bytes32 structHash = keccak256(abi.encode(DELEGATE_TYPEHASH, delegatee, nonce, expiry));
            bytes32 digest = keccak256(abi.encodePacked('\\x19\\x01', DOMAIN_SEPARATOR, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(signer != address(0), 'INVALID_SIGNATURE');
            require(nonce == _nonces[signer]++, 'INVALID_NONCE');
            require(block.timestamp <= expiry, 'INVALID_EXPIRATION');
            _delegateByType(signer, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(signer, delegatee, DelegationType.PROPOSITION_POWER);
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        import { ERC20 } from '../../dependencies/open-zeppelin/ERC20.sol';
        import { SafeMath } from '../../dependencies/open-zeppelin/SafeMath.sol';
        import {
          IGovernancePowerDelegationERC20
        } from '../../interfaces/IGovernancePowerDelegationERC20.sol';
        /**
         * @title GovernancePowerDelegationERC20Mixin
         * @author dYdX
         *
         * @notice Provides support for two types of governance powers, both endowed by the governance
         *  token, and separately delegatable. Provides functions for delegation and for querying a user's
         *  power at a certain block number.
         */
        abstract contract GovernancePowerDelegationERC20Mixin is
          ERC20,
          IGovernancePowerDelegationERC20
        {
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice EIP-712 typehash for delegation by signature of a specific governance power type.
          bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256(
            'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)'
          );
          /// @notice EIP-712 typehash for delegation by signature of all governance powers.
          bytes32 public constant DELEGATE_TYPEHASH = keccak256(
            'Delegate(address delegatee,uint256 nonce,uint256 expiry)'
          );
          // ============ Structs ============
          /// @dev Snapshot of a value on a specific block, used to track voting power for proposals.
          struct Snapshot {
            uint128 blockNumber;
            uint128 value;
          }
          // ============ External Functions ============
          /**
           * @notice Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType)
            external
            override
          {
            _delegateByType(msg.sender, delegatee, delegationType);
          }
          /**
           * @notice Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The address to delegate power to.
           */
          function delegate(address delegatee)
            external
            override
          {
            _delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER);
          }
          /**
           * @notice Returns the delegatee of a user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            override
            view
            returns (address)
          {
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            return _getDelegatee(delegator, delegates);
          }
          /**
           * @notice Returns the current power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            override
            view
            returns (uint256)
          {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, block.number);
          }
          /**
           * @notice Returns the power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          ) external override view returns (uint256) {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, blockNumber);
          }
          // ============ Internal Functions ============
          /**
           * @dev Delegates one specific power to a delegatee.
           *
           * @param  delegator       The user whose power to delegate.
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _delegateByType(
            address delegator,
            address delegatee,
            DelegationType delegationType
          ) internal {
            require(delegatee != address(0), 'INVALID_DELEGATEE');
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            uint256 delegatorBalance = balanceOf(delegator);
            address previousDelegatee = _getDelegatee(delegator, delegates);
            delegates[delegator] = delegatee;
            _moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType);
            emit DelegateChanged(delegator, delegatee, delegationType);
          }
          /**
           * @dev Moves power from one user to another.
           *
           * @param  from            The user from which delegated power is moved.
           * @param  to              The user that will receive the delegated power.
           * @param  amount          The amount of power to be moved.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _moveDelegatesByType(
            address from,
            address to,
            uint256 amount,
            DelegationType delegationType
          ) internal {
            if (from == to) {
              return;
            }
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
            if (from != address(0)) {
              uint256 previous = 0;
              uint256 fromSnapshotsCount = snapshotsCounts[from];
              if (fromSnapshotsCount != 0) {
                previous = snapshots[from][fromSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(from);
              }
              uint256 newAmount = previous.sub(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                from,
                uint128(newAmount)
              );
              emit DelegatedPowerChanged(from, newAmount, delegationType);
            }
            if (to != address(0)) {
              uint256 previous = 0;
              uint256 toSnapshotsCount = snapshotsCounts[to];
              if (toSnapshotsCount != 0) {
                previous = snapshots[to][toSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(to);
              }
              uint256 newAmount = previous.add(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                to,
                uint128(newAmount)
              );
              emit DelegatedPowerChanged(to, newAmount, delegationType);
            }
          }
          /**
           * @dev Searches for a balance snapshot by block number using binary search.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  user             The user for which the snapshot is being searched.
           * @param  blockNumber      The block number being searched.
           */
          function _searchByBlockNumber(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address user,
            uint256 blockNumber
          ) internal view returns (uint256) {
            require(blockNumber <= block.number, 'INVALID_BLOCK_NUMBER');
            uint256 snapshotsCount = snapshotsCounts[user];
            if (snapshotsCount == 0) {
              return balanceOf(user);
            }
            // First check most recent balance
            if (snapshots[user][snapshotsCount - 1].blockNumber <= blockNumber) {
              return snapshots[user][snapshotsCount - 1].value;
            }
            // Next check implicit zero balance
            if (snapshots[user][0].blockNumber > blockNumber) {
              return 0;
            }
            uint256 lower = 0;
            uint256 upper = snapshotsCount - 1;
            while (upper > lower) {
              uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
              Snapshot memory snapshot = snapshots[user][center];
              if (snapshot.blockNumber == blockNumber) {
                return snapshot.value;
              } else if (snapshot.blockNumber < blockNumber) {
                lower = center;
              } else {
                upper = center - 1;
              }
            }
            return snapshots[user][lower].value;
          }
          /**
           * @dev Returns delegation data (snapshot, snapshotsCount, delegates) by delegation type.
           *
           *  Note: This mixin contract does not itself define any storage, and we require the inheriting
           *  contract to implement this method to provide access to the relevant mappings in storage.
           *  This pattern was implemented by Aave for legacy reasons and we have decided not to change it.
           *
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _getDelegationDataByType(DelegationType delegationType)
            internal
            virtual
            view
            returns (
              mapping(address => mapping(uint256 => Snapshot)) storage, // snapshots
              mapping(address => uint256) storage, // snapshotsCount
              mapping(address => address) storage // delegates
            );
          /**
           * @dev Writes a snapshot of a user's token/power balance.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  owner            The user whose power to snapshot.
           * @param  newValue         The new balance to snapshot at the current block.
           */
          function _writeSnapshot(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address owner,
            uint128 newValue
          ) internal {
            uint128 currentBlock = uint128(block.number);
            uint256 ownerSnapshotsCount = snapshotsCounts[owner];
            mapping(uint256 => Snapshot) storage ownerSnapshots = snapshots[owner];
            if (
              ownerSnapshotsCount != 0 &&
              ownerSnapshots[ownerSnapshotsCount - 1].blockNumber == currentBlock
            ) {
              // Doing multiple operations in the same block
              ownerSnapshots[ownerSnapshotsCount - 1].value = newValue;
            } else {
              ownerSnapshots[ownerSnapshotsCount] = Snapshot(currentBlock, newValue);
              snapshotsCounts[owner] = ownerSnapshotsCount + 1;
            }
          }
          /**
           * @dev Returns the delegatee of a user. If a user never performed any delegation, their
           *  delegated address will be 0x0, in which case we return the user's own address.
           *
           * @param  delegator  The address of the user for which return the delegatee.
           * @param  delegates  The mapping of delegates for a particular type of delegation.
           */
          function _getDelegatee(
            address delegator,
            mapping(address => address) storage delegates
          )
            internal
            view
            returns (address)
          {
            address previousDelegatee = delegates[delegator];
            if (previousDelegatee == address(0)) {
              return delegator;
            }
            return previousDelegatee;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
        * @dev Interface of the ERC20 standard as defined in the EIP.
        */
        interface IERC20 {
          /**
            * @dev Returns the amount of tokens in existence.
            */
          function totalSupply() external view returns (uint256);
          /**
            * @dev Returns the amount of tokens owned by `account`.
            */
          function balanceOf(address account) external view returns (uint256);
          /**
            * @dev Moves `amount` tokens from the caller's account to `recipient`.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Returns the remaining number of tokens that `spender` will be
            * allowed to spend on behalf of `owner` through {transferFrom}. This is
            * zero by default.
            *
            * This value changes when {approve} or {transferFrom} are called.
            */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
            * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * IMPORTANT: Beware that changing an allowance with this method brings the risk
            * that someone may use both the old and the new allowance by unfortunate
            * transaction ordering. One possible solution to mitigate this race
            * condition is to first reduce the spender's allowance to 0 and set the
            * desired value afterwards:
            * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
            *
            * Emits an {Approval} event.
            */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
            * @dev Moves `amount` tokens from `sender` to `recipient` using the
            * allowance mechanism. `amount` is then deducted from the caller's
            * allowance.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Emitted when `value` tokens are moved from one account (`from`) to
            * another (`to`).
            *
            * Note that `value` may be zero.
            */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
            * @dev Emitted when the allowance of a `spender` for an `owner` is set by
            * a call to {approve}. `value` is the new allowance.
            */
          event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        interface IGovernancePowerDelegationERC20 {
          enum DelegationType {
            VOTING_POWER,
            PROPOSITION_POWER
          }
          /**
           * @dev Emitted when a user delegates governance power to another user.
           *
           * @param  delegator       The delegator.
           * @param  delegatee       The delegatee.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegateChanged(
            address indexed delegator,
            address indexed delegatee,
            DelegationType delegationType
          );
          /**
           * @dev Emitted when an action changes the delegated power of a user.
           *
           * @param  user            The user whose delegated power has changed.
           * @param  amount          The new amount of delegated power for the user.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType);
          /**
           * @dev Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType) external virtual;
          /**
           * @dev Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The user to which the power will be delegated.
           */
          function delegate(address delegatee) external virtual;
          /**
           * @dev Returns the delegatee of an user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            view
            virtual
            returns (address);
          /**
           * @dev Returns the current delegated power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            view
            virtual
            returns (uint256);
          /**
           * @dev Returns the delegated power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            external
            view
            virtual
            returns (uint256);
        }
        

        File 4 of 6: InitializableAdminUpgradeabilityProxy
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              codehash := extcodehash(account)
            }
            return (codehash != accountHash && codehash != 0x0);
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, 'Address: insufficient balance');
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}('');
            require(success, 'Address: unable to send value, recipient may have reverted');
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './Proxy.sol';
        import './Address.sol';
        /**
         * @title BaseUpgradeabilityProxy
         * @dev This contract implements a proxy that allows to change the
         * implementation address to which it will delegate.
         * Such a change is called an implementation upgrade.
         */
        contract BaseUpgradeabilityProxy is Proxy {
          /**
           * @dev Emitted when the implementation is upgraded.
           * @param implementation Address of the new implementation.
           */
          event Upgraded(address indexed implementation);
          /**
           * @dev Storage slot with the address of the current implementation.
           * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
           * validated in the constructor.
           */
          bytes32
            internal constant IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
          /**
           * @dev Returns the current implementation.
           * @return impl Address of the current implementation
           */
          function _implementation() internal override view returns (address impl) {
            bytes32 slot = IMPLEMENTATION_SLOT;
            assembly {
              impl := sload(slot)
            }
          }
          /**
           * @dev Upgrades the proxy to a new implementation.
           * @param newImplementation Address of the new implementation.
           */
          function _upgradeTo(address newImplementation) internal {
            _setImplementation(newImplementation);
            emit Upgraded(newImplementation);
          }
          /**
           * @dev Sets the implementation address of the proxy.
           * @param newImplementation Address of the new implementation.
           */
          function _setImplementation(address newImplementation) internal {
            require(
              Address.isContract(newImplementation),
              'Cannot set a proxy implementation to a non-contract address'
            );
            bytes32 slot = IMPLEMENTATION_SLOT;
            assembly {
              sstore(slot, newImplementation)
            }
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @title Proxy
         * @dev Implements delegation of calls to other contracts, with proper
         * forwarding of return values and bubbling of failures.
         * It defines a fallback function that delegates all calls to the address
         * returned by the abstract _implementation() internal function.
         */
        abstract contract Proxy {
          /**
           * @dev Fallback function.
           * Implemented entirely in `_fallback`.
           */
          fallback() external payable {
            _fallback();
          }
          /**
           * @return The Address of the implementation.
           */
          function _implementation() internal virtual view returns (address);
          /**
           * @dev Delegates execution to an implementation contract.
           * This is a low level function that doesn't return to its internal call site.
           * It will return to the external caller whatever the implementation returns.
           * @param implementation Address to delegate.
           */
          function _delegate(address implementation) internal {
            assembly {
              // Copy msg.data. We take full control of memory in this inline assembly
              // block because it will not return to Solidity code. We overwrite the
              // Solidity scratch pad at memory position 0.
              calldatacopy(0, 0, calldatasize())
              // Call the implementation.
              // out and outsize are 0 because we don't know the size yet.
              let result := delegatecall(gas(), implementation, 0, calldatasize(), 0, 0)
              // Copy the returned data.
              returndatacopy(0, 0, returndatasize())
              switch result
                // delegatecall returns 0 on error.
                case 0 {
                  revert(0, returndatasize())
                }
                default {
                  return(0, returndatasize())
                }
            }
          }
          /**
           * @dev Function that is run as the first thing in the fallback function.
           * Can be redefined in derived contracts to add functionality.
           * Redefinitions must call super._willFallback().
           */
          function _willFallback() internal virtual {}
          /**
           * @dev fallback implementation.
           * Extracted to enable manual triggering.
           */
          function _fallback() internal {
            _willFallback();
            _delegate(_implementation());
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        import './BaseUpgradeabilityProxy.sol';
        /**
         * @title InitializableUpgradeabilityProxy
         * @dev Extends BaseUpgradeabilityProxy with an initializer for initializing
         * implementation and init data.
         */
        contract InitializableUpgradeabilityProxy is BaseUpgradeabilityProxy {
          /**
           * @dev Contract initializer.
           * @param _logic Address of the initial implementation.
           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
           * It should include the signature and the parameters of the function to be called, as described in
           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
           */
          function initialize(address _logic, bytes memory _data) public payable {
            require(_implementation() == address(0));
            assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
            _setImplementation(_logic);
            if (_data.length > 0) {
              (bool success, ) = _logic.delegatecall(_data);
              require(success);
            }
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        //
        // Contracts by dYdX Foundation. Individual files are released under different licenses.
        //
        // https://dydx.community
        // https://github.com/dydxfoundation/governance-contracts
        pragma solidity 0.7.5;
        import './BaseAdminUpgradeabilityProxy.sol';
        import './InitializableUpgradeabilityProxy.sol';
        /**
         * @title InitializableAdminUpgradeabilityProxy
         * @dev Extends from BaseAdminUpgradeabilityProxy with an initializer for
         * initializing the implementation, admin, and init data.
         */
        contract InitializableAdminUpgradeabilityProxy is
          BaseAdminUpgradeabilityProxy,
          InitializableUpgradeabilityProxy
        {
          /**
           * Contract initializer.
           * @param _logic address of the initial implementation.
           * @param _admin Address of the proxy administrator.
           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
           * It should include the signature and the parameters of the function to be called, as described in
           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
           */
          function initialize(
            address _logic,
            address _admin,
            bytes memory _data
          ) public payable {
            require(_implementation() == address(0));
            InitializableUpgradeabilityProxy.initialize(_logic, _data);
            assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
            _setAdmin(_admin);
          }
          /**
           * @dev Only fall back when the sender is not the admin.
           */
          function _willFallback() internal override(BaseAdminUpgradeabilityProxy, Proxy) {
            BaseAdminUpgradeabilityProxy._willFallback();
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './UpgradeabilityProxy.sol';
        /**
         * @title BaseAdminUpgradeabilityProxy
         * @dev This contract combines an upgradeability proxy with an authorization
         * mechanism for administrative tasks.
         * All external functions in this contract must be guarded by the
         * `ifAdmin` modifier. See ethereum/solidity#3864 for a Solidity
         * feature proposal that would enable this to be done automatically.
         */
        contract BaseAdminUpgradeabilityProxy is BaseUpgradeabilityProxy {
          /**
           * @dev Emitted when the administration has been transferred.
           * @param previousAdmin Address of the previous admin.
           * @param newAdmin Address of the new admin.
           */
          event AdminChanged(address previousAdmin, address newAdmin);
          /**
           * @dev Storage slot with the admin of the contract.
           * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
           * validated in the constructor.
           */
          bytes32
            internal constant ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;
          /**
           * @dev Modifier to check whether the `msg.sender` is the admin.
           * If it is, it will run the function. Otherwise, it will delegate the call
           * to the implementation.
           */
          modifier ifAdmin() {
            if (msg.sender == _admin()) {
              _;
            } else {
              _fallback();
            }
          }
          /**
           * @return The address of the proxy admin.
           */
          function admin() external ifAdmin returns (address) {
            return _admin();
          }
          /**
           * @return The address of the implementation.
           */
          function implementation() external ifAdmin returns (address) {
            return _implementation();
          }
          /**
           * @dev Changes the admin of the proxy.
           * Only the current admin can call this function.
           * @param newAdmin Address to transfer proxy administration to.
           */
          function changeAdmin(address newAdmin) external ifAdmin {
            require(newAdmin != address(0), 'Cannot change the admin of a proxy to the zero address');
            emit AdminChanged(_admin(), newAdmin);
            _setAdmin(newAdmin);
          }
          /**
           * @dev Upgrade the backing implementation of the proxy.
           * Only the admin can call this function.
           * @param newImplementation Address of the new implementation.
           */
          function upgradeTo(address newImplementation) external ifAdmin {
            _upgradeTo(newImplementation);
          }
          /**
           * @dev Upgrade the backing implementation of the proxy and call a function
           * on the new implementation.
           * This is useful to initialize the proxied contract.
           * @param newImplementation Address of the new implementation.
           * @param data Data to send as msg.data in the low level call.
           * It should include the signature and the parameters of the function to be called, as described in
           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
           */
          function upgradeToAndCall(address newImplementation, bytes calldata data)
            external
            payable
            ifAdmin
          {
            _upgradeTo(newImplementation);
            (bool success, ) = newImplementation.delegatecall(data);
            require(success);
          }
          /**
           * @return adm The admin slot.
           */
          function _admin() internal view returns (address adm) {
            bytes32 slot = ADMIN_SLOT;
            assembly {
              adm := sload(slot)
            }
          }
          /**
           * @dev Sets the address of the proxy admin.
           * @param newAdmin Address of the new proxy admin.
           */
          function _setAdmin(address newAdmin) internal {
            bytes32 slot = ADMIN_SLOT;
            assembly {
              sstore(slot, newAdmin)
            }
          }
          /**
           * @dev Only fall back when the sender is not the admin.
           */
          function _willFallback() internal virtual override {
            require(msg.sender != _admin(), 'Cannot call fallback function from the proxy admin');
            super._willFallback();
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './BaseUpgradeabilityProxy.sol';
        /**
         * @title UpgradeabilityProxy
         * @dev Extends BaseUpgradeabilityProxy with a constructor for initializing
         * implementation and init data.
         */
        contract UpgradeabilityProxy is BaseUpgradeabilityProxy {
          /**
           * @dev Contract constructor.
           * @param _logic Address of the initial implementation.
           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
           * It should include the signature and the parameters of the function to be called, as described in
           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
           */
          constructor(address _logic, bytes memory _data) public payable {
            assert(IMPLEMENTATION_SLOT == bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1));
            _setImplementation(_logic);
            if (_data.length > 0) {
              (bool success, ) = _logic.delegatecall(_data);
              require(success);
            }
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity ^0.7.5;
        import './BaseAdminUpgradeabilityProxy.sol';
        /**
         * @title AdminUpgradeabilityProxy
         * @dev Extends from BaseAdminUpgradeabilityProxy with a constructor for
         * initializing the implementation, admin, and init data.
         */
        contract AdminUpgradeabilityProxy is BaseAdminUpgradeabilityProxy, UpgradeabilityProxy {
          /**
           * Contract constructor.
           * @param _logic address of the initial implementation.
           * @param _admin Address of the proxy administrator.
           * @param _data Data to send as msg.data to the implementation to initialize the proxied contract.
           * It should include the signature and the parameters of the function to be called, as described in
           * https://solidity.readthedocs.io/en/v0.4.24/abi-spec.html#function-selector-and-argument-encoding.
           * This parameter is optional, if no data is given the initialization call to proxied contract will be skipped.
           */
          constructor(address _logic, address _admin, bytes memory _data) UpgradeabilityProxy(_logic, _data) public payable {
            assert(ADMIN_SLOT == bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1));
            _setAdmin(_admin);
          }
          /**
           * @dev Only fall back when the sender is not the admin.
           */
          function _willFallback() internal override(BaseAdminUpgradeabilityProxy, Proxy) {
            require(msg.sender != _admin(), 'Cannot call fallback function from the proxy admin');
            super._willFallback();
          }
        }
        

        File 5 of 6: SafetyModuleV2
        // Contracts by dYdX Foundation. Individual files are released under different licenses.
        //
        // https://dydx.community
        // https://github.com/dydxfoundation/governance-contracts
        //
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeERC20 } from '../../dependencies/open-zeppelin/SafeERC20.sol';
        import { IERC20 } from '../../interfaces/IERC20.sol';
        import { SM1Admin } from '../v1_1/impl/SM1Admin.sol';
        import { SM1Getters } from '../v1_1/impl/SM1Getters.sol';
        import { SM1Operators } from '../v1_1/impl/SM1Operators.sol';
        import { SM1Slashing } from '../v1_1/impl/SM1Slashing.sol';
        import { SM1Staking } from '../v1_1/impl/SM1Staking.sol';
        /**
         * @title SafetyModuleV2
         * @author dYdX
         *
         * @notice Contract for staking tokens, which may be slashed by the permissioned slasher.
         *
         *  NOTE: Most functions will revert if epoch zero has not started.
         */
        contract SafetyModuleV2 is
          SM1Slashing,
          SM1Operators,
          SM1Admin,
          SM1Getters
        {
          using SafeERC20 for IERC20;
          // ============ Constants ============
          string public constant EIP712_DOMAIN_NAME = 'dYdX Safety Module';
          string public constant EIP712_DOMAIN_VERSION = '1';
          bytes32 public constant EIP712_DOMAIN_SCHEMA_HASH = keccak256(
            'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
          );
          // ============ Constructor ============
          constructor(
            IERC20 stakedToken,
            IERC20 rewardsToken,
            address rewardsTreasury,
            uint256 distributionStart,
            uint256 distributionEnd
          )
            SM1Staking(stakedToken, rewardsToken, rewardsTreasury, distributionStart, distributionEnd)
          {}
          // ============ External Functions ============
          /**
           * @notice Initializer for v2, intended to fix the deployment bug that affected v1.
           *
           *  Responsible for the following:
           *
           *    1. Funds recovery:
           *        - Transfer all Safety Module DYDX to the rewards treasury.
           *
           *    2. Storage recovery and cleanup:
           *        - Set the _EXCHANGE_RATE_ to EXCHANGE_RATE_BASE.
           *        - Clean up invalid storage values at slots 115 and 125.
           */
          function initialize()
            external
            initializer
          {
            // Funds recovery and staker compensation.
            uint256 balance = STAKED_TOKEN.balanceOf(address(this));
            STAKED_TOKEN.safeTransfer(REWARDS_TREASURY, balance);
            // Storage recovery and cleanup.
            __SM1ExchangeRate_init();
            // solhint-disable-next-line no-inline-assembly
            assembly {
              sstore(115, 0)
              sstore(125, 0)
            }
          }
          // ============ Internal Functions ============
          /**
           * @dev Returns the revision of the implementation contract.
           *
           * @return The revision number.
           */
          function getRevision()
            internal
            pure
            override
            returns (uint256)
          {
            return 2;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import { IERC20 } from '../../interfaces/IERC20.sol';
        import { SafeMath } from './SafeMath.sol';
        import { Address } from './Address.sol';
        /**
         * @title SafeERC20
         * @dev From https://github.com/OpenZeppelin/openzeppelin-contracts
         * Wrappers around ERC20 operations that throw on failure (when the token
         * contract returns false). Tokens that return no value (and instead revert or
         * throw on failure) are also supported, non-reverting calls are assumed to be
         * successful.
         * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
         * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
         */
        library SafeERC20 {
          using SafeMath for uint256;
          using Address for address;
          function safeTransfer(
            IERC20 token,
            address to,
            uint256 value
          ) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
          }
          function safeTransferFrom(
            IERC20 token,
            address from,
            address to,
            uint256 value
          ) internal {
            callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
          }
          function safeApprove(
            IERC20 token,
            address spender,
            uint256 value
          ) internal {
            require(
              (value == 0) || (token.allowance(address(this), spender) == 0),
              'SafeERC20: approve from non-zero to non-zero allowance'
            );
            callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
          }
          function callOptionalReturn(IERC20 token, bytes memory data) private {
            require(address(token).isContract(), 'SafeERC20: call to non-contract');
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = address(token).call(data);
            require(success, 'SafeERC20: low-level call failed');
            if (returndata.length > 0) {
              // Return data is optional
              // solhint-disable-next-line max-line-length
              require(abi.decode(returndata, (bool)), 'SafeERC20: ERC20 operation did not succeed');
            }
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
        * @dev Interface of the ERC20 standard as defined in the EIP.
        */
        interface IERC20 {
          /**
            * @dev Returns the amount of tokens in existence.
            */
          function totalSupply() external view returns (uint256);
          /**
            * @dev Returns the amount of tokens owned by `account`.
            */
          function balanceOf(address account) external view returns (uint256);
          /**
            * @dev Moves `amount` tokens from the caller's account to `recipient`.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transfer(address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Returns the remaining number of tokens that `spender` will be
            * allowed to spend on behalf of `owner` through {transferFrom}. This is
            * zero by default.
            *
            * This value changes when {approve} or {transferFrom} are called.
            */
          function allowance(address owner, address spender) external view returns (uint256);
          /**
            * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * IMPORTANT: Beware that changing an allowance with this method brings the risk
            * that someone may use both the old and the new allowance by unfortunate
            * transaction ordering. One possible solution to mitigate this race
            * condition is to first reduce the spender's allowance to 0 and set the
            * desired value afterwards:
            * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
            *
            * Emits an {Approval} event.
            */
          function approve(address spender, uint256 amount) external returns (bool);
          /**
            * @dev Moves `amount` tokens from `sender` to `recipient` using the
            * allowance mechanism. `amount` is then deducted from the caller's
            * allowance.
            *
            * Returns a boolean value indicating whether the operation succeeded.
            *
            * Emits a {Transfer} event.
            */
          function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
          /**
            * @dev Emitted when `value` tokens are moved from one account (`from`) to
            * another (`to`).
            *
            * Note that `value` may be zero.
            */
          event Transfer(address indexed from, address indexed to, uint256 value);
          /**
            * @dev Emitted when the allowance of a `spender` for an `owner` is set by
            * a call to {approve}. `value` is the new allowance.
            */
          event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Roles } from './SM1Roles.sol';
        import { SM1StakedBalances } from './SM1StakedBalances.sol';
        /**
         * @title SM1Admin
         * @author dYdX
         *
         * @dev Admin-only functions.
         */
        abstract contract SM1Admin is
          SM1StakedBalances,
          SM1Roles
        {
          using SafeMath for uint256;
          // ============ External Functions ============
          /**
           * @notice Set the parameters defining the function from timestamp to epoch number.
           *
           *  The formula used is `n = floor((t - b) / a)` where:
           *    - `n` is the epoch number
           *    - `t` is the timestamp (in seconds)
           *    - `b` is a non-negative offset, indicating the start of epoch zero (in seconds)
           *    - `a` is the length of an epoch, a.k.a. the interval (in seconds)
           *
           *  Reverts if epoch zero already started, and the new parameters would change the current epoch.
           *  Reverts if epoch zero has not started, but would have had started under the new parameters.
           *
           * @param  interval  The length `a` of an epoch, in seconds.
           * @param  offset    The offset `b`, i.e. the start of epoch zero, in seconds.
           */
          function setEpochParameters(
            uint256 interval,
            uint256 offset
          )
            external
            onlyRole(EPOCH_PARAMETERS_ROLE)
            nonReentrant
          {
            if (!hasEpochZeroStarted()) {
              require(
                block.timestamp < offset,
                'SM1Admin: Started epoch zero'
              );
              _setEpochParameters(interval, offset);
              return;
            }
            // We must settle the total active balance to ensure the index is recorded at the epoch
            // boundary as needed, before we make any changes to the epoch formula.
            _settleTotalActiveBalance();
            // Update the epoch parameters. Require that the current epoch number is unchanged.
            uint256 originalCurrentEpoch = getCurrentEpoch();
            _setEpochParameters(interval, offset);
            uint256 newCurrentEpoch = getCurrentEpoch();
            require(
              originalCurrentEpoch == newCurrentEpoch,
              'SM1Admin: Changed epochs'
            );
          }
          /**
           * @notice Set the blackout window, during which one cannot request withdrawals of staked funds.
           */
          function setBlackoutWindow(
            uint256 blackoutWindow
          )
            external
            onlyRole(EPOCH_PARAMETERS_ROLE)
            nonReentrant
          {
            _setBlackoutWindow(blackoutWindow);
          }
          /**
           * @notice Set the emission rate of rewards.
           *
           * @param  emissionPerSecond  The new number of rewards tokens given out per second.
           */
          function setRewardsPerSecond(
            uint256 emissionPerSecond
          )
            external
            onlyRole(REWARDS_RATE_ROLE)
            nonReentrant
          {
            uint256 totalStaked = 0;
            if (hasEpochZeroStarted()) {
              // We must settle the total active balance to ensure the index is recorded at the epoch
              // boundary as needed, before we make any changes to the emission rate.
              totalStaked = _settleTotalActiveBalance();
            }
            _setRewardsPerSecond(emissionPerSecond, totalStaked);
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { Math } from '../../../utils/Math.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1Getters
         * @author dYdX
         *
         * @dev Some external getter functions.
         */
        abstract contract SM1Getters is
          SM1Storage
        {
          using SafeMath for uint256;
          // ============ External Functions ============
          /**
           * @notice The parameters specifying the function from timestamp to epoch number.
           *
           * @return The parameters struct with `interval` and `offset` fields.
           */
          function getEpochParameters()
            external
            view
            returns (SM1Types.EpochParameters memory)
          {
            return _EPOCH_PARAMETERS_;
          }
          /**
           * @notice The period of time at the end of each epoch in which withdrawals cannot be requested.
           *
           * @return The blackout window duration, in seconds.
           */
          function getBlackoutWindow()
            external
            view
            returns (uint256)
          {
            return _BLACKOUT_WINDOW_;
          }
          /**
           * @notice Get the domain separator used for EIP-712 signatures.
           *
           * @return The EIP-712 domain separator.
           */
          function getDomainSeparator()
            external
            view
            returns (bytes32)
          {
            return _DOMAIN_SEPARATOR_;
          }
          /**
           * @notice The value of one underlying token, in the units used for staked balances, denominated
           *  as a mutiple of EXCHANGE_RATE_BASE for additional precision.
           *
           *  To convert from an underlying amount to a staked amount, multiply by the exchange rate.
           *
           * @return The exchange rate.
           */
          function getExchangeRate()
            external
            view
            returns (uint256)
          {
            return _EXCHANGE_RATE_;
          }
          /**
           * @notice Get an exchange rate snapshot.
           *
           * @param  index  The index number of the exchange rate snapshot.
           *
           * @return The snapshot struct with `blockNumber` and `value` fields.
           */
          function getExchangeRateSnapshot(
            uint256 index
          )
            external
            view
            returns (SM1Types.Snapshot memory)
          {
            return _EXCHANGE_RATE_SNAPSHOTS_[index];
          }
          /**
           * @notice Get the number of exchange rate snapshots.
           *
           * @return The number of snapshots that have been taken of the exchange rate.
           */
          function getExchangeRateSnapshotCount()
            external
            view
            returns (uint256)
          {
            return _EXCHANGE_RATE_SNAPSHOT_COUNT_;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { SM1Roles } from './SM1Roles.sol';
        import { SM1Staking } from './SM1Staking.sol';
        /**
         * @title SM1Operators
         * @author dYdX
         *
         * @dev Actions which may be called by authorized operators, nominated by the contract owner.
         *
         *  There are two types of operators. These should be smart contracts, which can be used to
         *  provide additional functionality to users:
         *
         *  STAKE_OPERATOR_ROLE:
         *
         *    This operator is allowed to request withdrawals and withdraw funds on behalf of stakers. This
         *    role could be used by a smart contract to provide a staking interface with additional
         *    features, for example, optional lock-up periods that pay out additional rewards (from a
         *    separate rewards pool).
         *
         *  CLAIM_OPERATOR_ROLE:
         *
         *    This operator is allowed to claim rewards on behalf of stakers. This role could be used by a
         *    smart contract to provide an interface for claiming rewards from multiple incentive programs
         *    at once.
         */
        abstract contract SM1Operators is
          SM1Staking,
          SM1Roles
        {
          using SafeMath for uint256;
          // ============ Events ============
          event OperatorStakedFor(
            address indexed staker,
            uint256 amount,
            address operator
          );
          event OperatorWithdrawalRequestedFor(
            address indexed staker,
            uint256 amount,
            address operator
          );
          event OperatorWithdrewStakeFor(
            address indexed staker,
            address recipient,
            uint256 amount,
            address operator
          );
          event OperatorClaimedRewardsFor(
            address indexed staker,
            address recipient,
            uint256 claimedRewards,
            address operator
          );
          // ============ External Functions ============
          /**
           * @notice Request a withdrawal on behalf of a staker.
           *
           *  Reverts if we are currently in the blackout window.
           *
           * @param  staker       The staker whose stake to request a withdrawal for.
           * @param  stakeAmount  The amount of stake to move from the active to the inactive balance.
           */
          function requestWithdrawalFor(
            address staker,
            uint256 stakeAmount
          )
            external
            onlyRole(STAKE_OPERATOR_ROLE)
            nonReentrant
          {
            _requestWithdrawal(staker, stakeAmount);
            emit OperatorWithdrawalRequestedFor(staker, stakeAmount, msg.sender);
          }
          /**
           * @notice Withdraw a staker's stake, and send to the specified recipient.
           *
           * @param  staker       The staker whose stake to withdraw.
           * @param  recipient    The address that should receive the funds.
           * @param  stakeAmount  The amount of stake to withdraw from the staker's inactive balance.
           */
          function withdrawStakeFor(
            address staker,
            address recipient,
            uint256 stakeAmount
          )
            external
            onlyRole(STAKE_OPERATOR_ROLE)
            nonReentrant
          {
            _withdrawStake(staker, recipient, stakeAmount);
            emit OperatorWithdrewStakeFor(staker, recipient, stakeAmount, msg.sender);
          }
          /**
           * @notice Claim rewards on behalf of a staker, and send them to the specified recipient.
           *
           * @param  staker     The staker whose rewards to claim.
           * @param  recipient  The address that should receive the funds.
           *
           * @return The number of rewards tokens claimed.
           */
          function claimRewardsFor(
            address staker,
            address recipient
          )
            external
            onlyRole(CLAIM_OPERATOR_ROLE)
            nonReentrant
            returns (uint256)
          {
            uint256 rewards = _settleAndClaimRewards(staker, recipient); // Emits an event internally.
            emit OperatorClaimedRewardsFor(staker, recipient, rewards, msg.sender);
            return rewards;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeERC20 } from '../../../dependencies/open-zeppelin/SafeERC20.sol';
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../../interfaces/IERC20.sol';
        import { Math } from '../../../utils/Math.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Roles } from './SM1Roles.sol';
        import { SM1Staking } from './SM1Staking.sol';
        /**
         * @title SM1Slashing
         * @author dYdX
         *
         * @dev Provides the slashing function for removing funds from the contract.
         *
         *  SLASHING:
         *
         *   All funds in the contract, active or inactive, are slashable. Slashes are recorded by updating
         *   the exchange rate, and to simplify the technical implementation, we disallow full slashes.
         *   To reduce the possibility of overflow in the exchange rate, we place an upper bound on the
         *   fraction of funds that may be slashed in a single slash.
         *
         *   Warning: Slashing is not possible if the slash would cause the exchange rate to overflow.
         *
         *  REWARDS AND GOVERNANCE POWER ACCOUNTING:
         *
         *   Since all slashes are accounted for by a global exchange rate, slashes do not require any
         *   update to staked balances. The earning of rewards is unaffected by slashes.
         *
         *   Governance power takes slashes into account by using snapshots of the exchange rate inside
         *   the getPowerAtBlock() function. Note that getPowerAtBlock() returns the governance power as of
         *   the end of the specified block.
         */
        abstract contract SM1Slashing is
          SM1Staking,
          SM1Roles
        {
          using SafeERC20 for IERC20;
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice The maximum fraction of funds that may be slashed in a single slash (numerator).
          uint256 public constant MAX_SLASH_NUMERATOR = 95;
          /// @notice The maximum fraction of funds that may be slashed in a single slash (denominator).
          uint256 public constant MAX_SLASH_DENOMINATOR = 100;
          // ============ Events ============
          event Slashed(
            uint256 amount,
            address recipient,
            uint256 newExchangeRate
          );
          // ============ External Functions ============
          /**
           * @notice Slash staked token balances and withdraw those funds to the specified address.
           *
           * @param  requestedSlashAmount  The request slash amount, denominated in the underlying token.
           * @param  recipient             The address to receive the slashed tokens.
           *
           * @return The amount slashed, denominated in the underlying token.
           */
          function slash(
            uint256 requestedSlashAmount,
            address recipient
          )
            external
            onlyRole(SLASHER_ROLE)
            nonReentrant
            returns (uint256)
          {
            uint256 underlyingBalance = STAKED_TOKEN.balanceOf(address(this));
            if (underlyingBalance == 0) {
              return 0;
            }
            // Get the slash amount and remaining amount. Note that remainingAfterSlash is nonzero.
            uint256 maxSlashAmount = underlyingBalance.mul(MAX_SLASH_NUMERATOR).div(MAX_SLASH_DENOMINATOR);
            uint256 slashAmount = Math.min(requestedSlashAmount, maxSlashAmount);
            uint256 remainingAfterSlash = underlyingBalance.sub(slashAmount);
            if (slashAmount == 0) {
              return 0;
            }
            // Update the exchange rate.
            //
            // Warning: Can revert if the max exchange rate is exceeded.
            uint256 newExchangeRate = updateExchangeRate(underlyingBalance, remainingAfterSlash);
            // Transfer the slashed token.
            STAKED_TOKEN.safeTransfer(recipient, slashAmount);
            emit Slashed(slashAmount, recipient, newExchangeRate);
            return slashAmount;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeERC20 } from '../../../dependencies/open-zeppelin/SafeERC20.sol';
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../../interfaces/IERC20.sol';
        import { Math } from '../../../utils/Math.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1ERC20 } from './SM1ERC20.sol';
        import { SM1StakedBalances } from './SM1StakedBalances.sol';
        /**
         * @title SM1Staking
         * @author dYdX
         *
         * @dev External functions for stakers. See SM1StakedBalances for details on staker accounting.
         *
         *  UNDERLYING AND STAKED AMOUNTS:
         *
         *   We distinguish between underlying amounts and stake amounts. An underlying amount is denoted
         *   in the original units of the token being staked. A stake amount is adjusted by the exchange
         *   rate, which can increase due to slashing. Before any slashes have occurred, the exchange rate
         *   is equal to one.
         */
        abstract contract SM1Staking is
          SM1StakedBalances,
          SM1ERC20
        {
          using SafeERC20 for IERC20;
          using SafeMath for uint256;
          // ============ Events ============
          event Staked(
            address indexed staker,
            address spender,
            uint256 underlyingAmount,
            uint256 stakeAmount
          );
          event WithdrawalRequested(
            address indexed staker,
            uint256 stakeAmount
          );
          event WithdrewStake(
            address indexed staker,
            address recipient,
            uint256 underlyingAmount,
            uint256 stakeAmount
          );
          // ============ Constants ============
          IERC20 public immutable STAKED_TOKEN;
          // ============ Constructor ============
          constructor(
            IERC20 stakedToken,
            IERC20 rewardsToken,
            address rewardsTreasury,
            uint256 distributionStart,
            uint256 distributionEnd
          )
            SM1StakedBalances(rewardsToken, rewardsTreasury, distributionStart, distributionEnd)
          {
            STAKED_TOKEN = stakedToken;
          }
          // ============ External Functions ============
          /**
           * @notice Deposit and stake funds. These funds are active and start earning rewards immediately.
           *
           * @param  underlyingAmount  The amount of underlying token to stake.
           */
          function stake(
            uint256 underlyingAmount
          )
            external
            nonReentrant
          {
            _stake(msg.sender, underlyingAmount);
          }
          /**
           * @notice Deposit and stake on behalf of another address.
           *
           * @param  staker            The staker who will receive the stake.
           * @param  underlyingAmount  The amount of underlying token to stake.
           */
          function stakeFor(
            address staker,
            uint256 underlyingAmount
          )
            external
            nonReentrant
          {
            _stake(staker, underlyingAmount);
          }
          /**
           * @notice Request to withdraw funds. Starting in the next epoch, the funds will be “inactive”
           *  and available for withdrawal. Inactive funds do not earn rewards.
           *
           *  Reverts if we are currently in the blackout window.
           *
           * @param  stakeAmount  The amount of stake to move from the active to the inactive balance.
           */
          function requestWithdrawal(
            uint256 stakeAmount
          )
            external
            nonReentrant
          {
            _requestWithdrawal(msg.sender, stakeAmount);
          }
          /**
           * @notice Withdraw the sender's inactive funds, and send to the specified recipient.
           *
           * @param  recipient    The address that should receive the funds.
           * @param  stakeAmount  The amount of stake to withdraw from the sender's inactive balance.
           */
          function withdrawStake(
            address recipient,
            uint256 stakeAmount
          )
            external
            nonReentrant
          {
            _withdrawStake(msg.sender, recipient, stakeAmount);
          }
          /**
           * @notice Withdraw the max available inactive funds, and send to the specified recipient.
           *
           *  This is less gas-efficient than querying the max via eth_call and calling withdrawStake().
           *
           * @param  recipient  The address that should receive the funds.
           *
           * @return The withdrawn amount.
           */
          function withdrawMaxStake(
            address recipient
          )
            external
            nonReentrant
            returns (uint256)
          {
            uint256 stakeAmount = getStakeAvailableToWithdraw(msg.sender);
            _withdrawStake(msg.sender, recipient, stakeAmount);
            return stakeAmount;
          }
          /**
           * @notice Settle and claim all rewards, and send them to the specified recipient.
           *
           *  Call this function with eth_call to query the claimable rewards balance.
           *
           * @param  recipient  The address that should receive the funds.
           *
           * @return The number of rewards tokens claimed.
           */
          function claimRewards(
            address recipient
          )
            external
            nonReentrant
            returns (uint256)
          {
            return _settleAndClaimRewards(msg.sender, recipient); // Emits an event internally.
          }
          // ============ Public Functions ============
          /**
           * @notice Get the amount of stake available for a given staker to withdraw.
           *
           * @param  staker  The address whose balance to check.
           *
           * @return The staker's stake amount that is inactive and available to withdraw.
           */
          function getStakeAvailableToWithdraw(
            address staker
          )
            public
            view
            returns (uint256)
          {
            // Note that the next epoch inactive balance is always at least that of the current epoch.
            return getInactiveBalanceCurrentEpoch(staker);
          }
          // ============ Internal Functions ============
          function _stake(
            address staker,
            uint256 underlyingAmount
          )
            internal
          {
            // Convert using the exchange rate.
            uint256 stakeAmount = stakeAmountFromUnderlyingAmount(underlyingAmount);
            // Update staked balances and delegate snapshots.
            _increaseCurrentAndNextActiveBalance(staker, stakeAmount);
            _moveDelegatesForTransfer(address(0), staker, stakeAmount);
            // Transfer token from the sender.
            STAKED_TOKEN.safeTransferFrom(msg.sender, address(this), underlyingAmount);
            emit Staked(staker, msg.sender, underlyingAmount, stakeAmount);
            emit Transfer(address(0), msg.sender, stakeAmount);
          }
          function _requestWithdrawal(
            address staker,
            uint256 stakeAmount
          )
            internal
          {
            require(
              !inBlackoutWindow(),
              'SM1Staking: Withdraw requests restricted in the blackout window'
            );
            // Get the staker's requestable amount and revert if there is not enough to request withdrawal.
            uint256 requestableBalance = getActiveBalanceNextEpoch(staker);
            require(
              stakeAmount <= requestableBalance,
              'SM1Staking: Withdraw request exceeds next active balance'
            );
            // Move amount from active to inactive in the next epoch.
            _moveNextBalanceActiveToInactive(staker, stakeAmount);
            emit WithdrawalRequested(staker, stakeAmount);
          }
          function _withdrawStake(
            address staker,
            address recipient,
            uint256 stakeAmount
          )
            internal
          {
            // Get staker withdrawable balance and revert if there is not enough to withdraw.
            uint256 withdrawableBalance = getInactiveBalanceCurrentEpoch(staker);
            require(
              stakeAmount <= withdrawableBalance,
              'SM1Staking: Withdraw amount exceeds staker inactive balance'
            );
            // Update staked balances and delegate snapshots.
            _decreaseCurrentAndNextInactiveBalance(staker, stakeAmount);
            _moveDelegatesForTransfer(staker, address(0), stakeAmount);
            // Convert using the exchange rate.
            uint256 underlyingAmount = underlyingAmountFromStakeAmount(stakeAmount);
            // Transfer token to the recipient.
            STAKED_TOKEN.safeTransfer(recipient, underlyingAmount);
            emit Transfer(msg.sender, address(0), stakeAmount);
            emit WithdrewStake(staker, recipient, underlyingAmount, stakeAmount);
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when an
         * operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         */
        library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, 'SafeMath: addition overflow');
            return c;
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, 'SafeMath: subtraction overflow');
          }
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
            return c;
          }
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
              return 0;
            }
            uint256 c = a * b;
            require(c / a == b, 'SafeMath: multiplication overflow');
            return c;
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, 'SafeMath: division by zero');
          }
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
            return c;
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, 'SafeMath: modulo by zero');
          }
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              codehash := extcodehash(account)
            }
            return (codehash != accountHash && codehash != 0x0);
          }
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, 'Address: insufficient balance');
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}('');
            require(success, 'Address: unable to send value, recipient may have reverted');
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        library SM1Types {
          /**
           * @dev The parameters used to convert a timestamp to an epoch number.
           */
          struct EpochParameters {
            uint128 interval;
            uint128 offset;
          }
          /**
           * @dev Snapshot of a value at a specific block, used to track historical governance power.
           */
          struct Snapshot {
            uint256 blockNumber;
            uint256 value;
          }
          /**
           * @dev A balance, possibly with a change scheduled for the next epoch.
           *
           * @param  currentEpoch         The epoch in which the balance was last updated.
           * @param  currentEpochBalance  The balance at epoch `currentEpoch`.
           * @param  nextEpochBalance     The balance at epoch `currentEpoch + 1`.
           */
          struct StoredBalance {
            uint16 currentEpoch;
            uint240 currentEpochBalance;
            uint240 nextEpochBalance;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1Roles
         * @author dYdX
         *
         * @dev Defines roles used in the SafetyModuleV1 contract. The hierarchy of roles and powers
         *  of each role are described below.
         *
         *  Roles:
         *
         *    OWNER_ROLE
         *      | -> May add or remove addresses from any of the roles below.
         *      |
         *      +-- SLASHER_ROLE
         *      |     -> Can slash staked token balances and withdraw those funds.
         *      |
         *      +-- EPOCH_PARAMETERS_ROLE
         *      |     -> May set epoch parameters such as the interval, offset, and blackout window.
         *      |
         *      +-- REWARDS_RATE_ROLE
         *      |     -> May set the emission rate of rewards.
         *      |
         *      +-- CLAIM_OPERATOR_ROLE
         *      |     -> May claim rewards on behalf of a user.
         *      |
         *      +-- STAKE_OPERATOR_ROLE
         *            -> May manipulate user's staked funds (e.g. perform withdrawals on behalf of a user).
         */
        abstract contract SM1Roles is SM1Storage {
          bytes32 public constant OWNER_ROLE = keccak256('OWNER_ROLE');
          bytes32 public constant SLASHER_ROLE = keccak256('SLASHER_ROLE');
          bytes32 public constant EPOCH_PARAMETERS_ROLE = keccak256('EPOCH_PARAMETERS_ROLE');
          bytes32 public constant REWARDS_RATE_ROLE = keccak256('REWARDS_RATE_ROLE');
          bytes32 public constant CLAIM_OPERATOR_ROLE = keccak256('CLAIM_OPERATOR_ROLE');
          bytes32 public constant STAKE_OPERATOR_ROLE = keccak256('STAKE_OPERATOR_ROLE');
          function __SM1Roles_init() internal {
            // Assign roles to the sender.
            //
            // The STAKE_OPERATOR_ROLE and CLAIM_OPERATOR_ROLE roles are not initially assigned.
            // These can be assigned to other smart contracts to provide additional functionality for users.
            _setupRole(OWNER_ROLE, msg.sender);
            _setupRole(SLASHER_ROLE, msg.sender);
            _setupRole(EPOCH_PARAMETERS_ROLE, msg.sender);
            _setupRole(REWARDS_RATE_ROLE, msg.sender);
            // Set OWNER_ROLE as the admin of all roles.
            _setRoleAdmin(OWNER_ROLE, OWNER_ROLE);
            _setRoleAdmin(SLASHER_ROLE, OWNER_ROLE);
            _setRoleAdmin(EPOCH_PARAMETERS_ROLE, OWNER_ROLE);
            _setRoleAdmin(REWARDS_RATE_ROLE, OWNER_ROLE);
            _setRoleAdmin(CLAIM_OPERATOR_ROLE, OWNER_ROLE);
            _setRoleAdmin(STAKE_OPERATOR_ROLE, OWNER_ROLE);
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../../interfaces/IERC20.sol';
        import { SafeCast } from '../lib/SafeCast.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Rewards } from './SM1Rewards.sol';
        /**
         * @title SM1StakedBalances
         * @author dYdX
         *
         * @dev Accounting of staked balances.
         *
         *  NOTE: Functions may revert if epoch zero has not started.
         *
         *  NOTE: All amounts dealt with in this file are denominated in staked units, which because of the
         *   exchange rate, may not correspond one-to-one with the underlying token. See SM1Staking.sol.
         *
         *  STAKED BALANCE ACCOUNTING:
         *
         *   A staked balance is in one of two states:
         *     - active: Earning staking rewards; cannot be withdrawn by staker; may be slashed.
         *     - inactive: Not earning rewards; can be withdrawn by the staker; may be slashed.
         *
         *   A staker may have a combination of active and inactive balances. The following operations
         *   affect staked balances as follows:
         *     - deposit:            Increase active balance.
         *     - request withdrawal: At the end of the current epoch, move some active funds to inactive.
         *     - withdraw:           Decrease inactive balance.
         *     - transfer:           Move some active funds to another staker.
         *
         *   To encode the fact that a balance may be scheduled to change at the end of a certain epoch, we
         *   store each balance as a struct of three fields: currentEpoch, currentEpochBalance, and
         *   nextEpochBalance.
         *
         *  REWARDS ACCOUNTING:
         *
         *   Active funds earn rewards for the period of time that they remain active. This means, after
         *   requesting a withdrawal of some funds, those funds will continue to earn rewards until the end
         *   of the epoch. For example:
         *
         *     epoch: n        n + 1      n + 2      n + 3
         *            |          |          |          |
         *            +----------+----------+----------+-----...
         *               ^ t_0: User makes a deposit.
         *                          ^ t_1: User requests a withdrawal of all funds.
         *                                  ^ t_2: The funds change state from active to inactive.
         *
         *   In the above scenario, the user would earn rewards for the period from t_0 to t_2, varying
         *   with the total staked balance in that period. If the user only request a withdrawal for a part
         *   of their balance, then the remaining balance would continue earning rewards beyond t_2.
         *
         *   User rewards must be settled via SM1Rewards any time a user's active balance changes. Special
         *   attention is paid to the the epoch boundaries, where funds may have transitioned from active
         *   to inactive.
         *
         *  SETTLEMENT DETAILS:
         *
         *   Internally, this module uses the following types of operations on stored balances:
         *     - Load:            Loads a balance, while applying settlement logic internally to get the
         *                        up-to-date result. Returns settlement results without updating state.
         *     - Store:           Stores a balance.
         *     - Load-for-update: Performs a load and applies updates as needed to rewards accounting.
         *                        Since this is state-changing, it must be followed by a store operation.
         *     - Settle:          Performs load-for-update and store operations.
         *
         *   This module is responsible for maintaining the following invariants to ensure rewards are
         *   calculated correctly:
         *     - When an active balance is loaded for update, if a rollover occurs from one epoch to the
         *       next, the rewards index must be settled up to the boundary at which the rollover occurs.
         *     - Because the global rewards index is needed to update the user rewards index, the total
         *       active balance must be settled before any staker balances are settled or loaded for update.
         *     - A staker's balance must be settled before their rewards are settled.
         */
        abstract contract SM1StakedBalances is
          SM1Rewards
        {
          using SafeCast for uint256;
          using SafeMath for uint256;
          // ============ Constructor ============
          constructor(
            IERC20 rewardsToken,
            address rewardsTreasury,
            uint256 distributionStart,
            uint256 distributionEnd
          )
            SM1Rewards(rewardsToken, rewardsTreasury, distributionStart, distributionEnd)
          {}
          // ============ Public Functions ============
          /**
           * @notice Get the current active balance of a staker.
           */
          function getActiveBalanceCurrentEpoch(
            address staker
          )
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            (SM1Types.StoredBalance memory balance, , , ) = _loadActiveBalance(
              _ACTIVE_BALANCES_[staker]
            );
            return uint256(balance.currentEpochBalance);
          }
          /**
           * @notice Get the next epoch active balance of a staker.
           */
          function getActiveBalanceNextEpoch(
            address staker
          )
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            (SM1Types.StoredBalance memory balance, , , ) = _loadActiveBalance(
              _ACTIVE_BALANCES_[staker]
            );
            return uint256(balance.nextEpochBalance);
          }
          /**
           * @notice Get the current total active balance.
           */
          function getTotalActiveBalanceCurrentEpoch()
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            (SM1Types.StoredBalance memory balance, , , ) = _loadActiveBalance(
              _TOTAL_ACTIVE_BALANCE_
            );
            return uint256(balance.currentEpochBalance);
          }
          /**
           * @notice Get the next epoch total active balance.
           */
          function getTotalActiveBalanceNextEpoch()
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            (SM1Types.StoredBalance memory balance, , , ) = _loadActiveBalance(
              _TOTAL_ACTIVE_BALANCE_
            );
            return uint256(balance.nextEpochBalance);
          }
          /**
           * @notice Get the current inactive balance of a staker.
           * @dev The balance is converted via the index to token units.
           */
          function getInactiveBalanceCurrentEpoch(
            address staker
          )
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            SM1Types.StoredBalance memory balance = _loadInactiveBalance(_INACTIVE_BALANCES_[staker]);
            return uint256(balance.currentEpochBalance);
          }
          /**
           * @notice Get the next epoch inactive balance of a staker.
           * @dev The balance is converted via the index to token units.
           */
          function getInactiveBalanceNextEpoch(
            address staker
          )
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            SM1Types.StoredBalance memory balance = _loadInactiveBalance(_INACTIVE_BALANCES_[staker]);
            return uint256(balance.nextEpochBalance);
          }
          /**
           * @notice Get the current total inactive balance.
           */
          function getTotalInactiveBalanceCurrentEpoch()
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            SM1Types.StoredBalance memory balance = _loadInactiveBalance(_TOTAL_INACTIVE_BALANCE_);
            return uint256(balance.currentEpochBalance);
          }
          /**
           * @notice Get the next epoch total inactive balance.
           */
          function getTotalInactiveBalanceNextEpoch()
            public
            view
            returns (uint256)
          {
            if (!hasEpochZeroStarted()) {
              return 0;
            }
            SM1Types.StoredBalance memory balance = _loadInactiveBalance(_TOTAL_INACTIVE_BALANCE_);
            return uint256(balance.nextEpochBalance);
          }
          /**
           * @notice Get the current transferable balance for a user. The user can
           *  only transfer their balance that is not currently inactive or going to be
           *  inactive in the next epoch. Note that this means the user's transferable funds
           *  are their active balance of the next epoch.
           *
           * @param  account  The account to get the transferable balance of.
           *
           * @return The user's transferable balance.
           */
          function getTransferableBalance(
            address account
          )
            public
            view
            returns (uint256)
          {
            return getActiveBalanceNextEpoch(account);
          }
          // ============ Internal Functions ============
          function _increaseCurrentAndNextActiveBalance(
            address staker,
            uint256 amount
          )
            internal
          {
            // Always settle total active balance before settling a staker active balance.
            uint256 oldTotalBalance = _increaseCurrentAndNextBalances(address(0), true, amount);
            uint256 oldUserBalance = _increaseCurrentAndNextBalances(staker, true, amount);
            // When an active balance changes at current timestamp, settle rewards to the current timestamp.
            _settleUserRewardsUpToNow(staker, oldUserBalance, oldTotalBalance);
          }
          function _moveNextBalanceActiveToInactive(
            address staker,
            uint256 amount
          )
            internal
          {
            // Decrease the active balance for the next epoch.
            // Always settle total active balance before settling a staker active balance.
            _decreaseNextBalance(address(0), true, amount);
            _decreaseNextBalance(staker, true, amount);
            // Increase the inactive balance for the next epoch.
            _increaseNextBalance(address(0), false, amount);
            _increaseNextBalance(staker, false, amount);
            // Note that we don't need to settle rewards since the current active balance did not change.
          }
          function _transferCurrentAndNextActiveBalance(
            address sender,
            address recipient,
            uint256 amount
          )
            internal
          {
            // Always settle total active balance before settling a staker active balance.
            uint256 totalBalance = _settleTotalActiveBalance();
            // Move current and next active balances from sender to recipient.
            uint256 oldSenderBalance = _decreaseCurrentAndNextBalances(sender, true, amount);
            uint256 oldRecipientBalance = _increaseCurrentAndNextBalances(recipient, true, amount);
            // When an active balance changes at current timestamp, settle rewards to the current timestamp.
            _settleUserRewardsUpToNow(sender, oldSenderBalance, totalBalance);
            _settleUserRewardsUpToNow(recipient, oldRecipientBalance, totalBalance);
          }
          function _decreaseCurrentAndNextInactiveBalance(
            address staker,
            uint256 amount
          )
            internal
          {
            // Decrease the inactive balance for the next epoch.
            _decreaseCurrentAndNextBalances(address(0), false, amount);
            _decreaseCurrentAndNextBalances(staker, false, amount);
            // Note that we don't settle rewards since active balances are not affected.
          }
          function _settleTotalActiveBalance()
            internal
            returns (uint256)
          {
            return _settleBalance(address(0), true);
          }
          function _settleAndClaimRewards(
            address staker,
            address recipient
          )
            internal
            returns (uint256)
          {
            // Always settle total active balance before settling a staker active balance.
            uint256 totalBalance = _settleTotalActiveBalance();
            // Always settle staker active balance before settling staker rewards.
            uint256 userBalance = _settleBalance(staker, true);
            // Settle rewards balance since we want to claim the full accrued amount.
            _settleUserRewardsUpToNow(staker, userBalance, totalBalance);
            // Claim rewards balance.
            return _claimRewards(staker, recipient);
          }
          // ============ Private Functions ============
          /**
           * @dev Load a balance for update and then store it.
           */
          function _settleBalance(
            address maybeStaker,
            bool isActiveBalance
          )
            private
            returns (uint256)
          {
            SM1Types.StoredBalance storage balancePtr = _getBalancePtr(maybeStaker, isActiveBalance);
            SM1Types.StoredBalance memory balance =
              _loadBalanceForUpdate(balancePtr, maybeStaker, isActiveBalance);
            uint256 currentBalance = uint256(balance.currentEpochBalance);
            _storeBalance(balancePtr, balance);
            return currentBalance;
          }
          /**
           * @dev Settle a balance while applying an increase.
           */
          function _increaseCurrentAndNextBalances(
            address maybeStaker,
            bool isActiveBalance,
            uint256 amount
          )
            private
            returns (uint256)
          {
            SM1Types.StoredBalance storage balancePtr = _getBalancePtr(maybeStaker, isActiveBalance);
            SM1Types.StoredBalance memory balance =
              _loadBalanceForUpdate(balancePtr, maybeStaker, isActiveBalance);
            uint256 originalCurrentBalance = uint256(balance.currentEpochBalance);
            balance.currentEpochBalance = originalCurrentBalance.add(amount).toUint240();
            balance.nextEpochBalance = uint256(balance.nextEpochBalance).add(amount).toUint240();
            _storeBalance(balancePtr, balance);
            return originalCurrentBalance;
          }
          /**
           * @dev Settle a balance while applying a decrease.
           */
          function _decreaseCurrentAndNextBalances(
            address maybeStaker,
            bool isActiveBalance,
            uint256 amount
          )
            private
            returns (uint256)
          {
            SM1Types.StoredBalance storage balancePtr = _getBalancePtr(maybeStaker, isActiveBalance);
            SM1Types.StoredBalance memory balance =
              _loadBalanceForUpdate(balancePtr, maybeStaker, isActiveBalance);
            uint256 originalCurrentBalance = uint256(balance.currentEpochBalance);
            balance.currentEpochBalance = originalCurrentBalance.sub(amount).toUint240();
            balance.nextEpochBalance = uint256(balance.nextEpochBalance).sub(amount).toUint240();
            _storeBalance(balancePtr, balance);
            return originalCurrentBalance;
          }
          /**
           * @dev Settle a balance while applying an increase.
           */
          function _increaseNextBalance(
            address maybeStaker,
            bool isActiveBalance,
            uint256 amount
          )
            private
          {
            SM1Types.StoredBalance storage balancePtr = _getBalancePtr(maybeStaker, isActiveBalance);
            SM1Types.StoredBalance memory balance =
              _loadBalanceForUpdate(balancePtr, maybeStaker, isActiveBalance);
            balance.nextEpochBalance = uint256(balance.nextEpochBalance).add(amount).toUint240();
            _storeBalance(balancePtr, balance);
          }
          /**
           * @dev Settle a balance while applying a decrease.
           */
          function _decreaseNextBalance(
            address maybeStaker,
            bool isActiveBalance,
            uint256 amount
          )
            private
          {
            SM1Types.StoredBalance storage balancePtr = _getBalancePtr(maybeStaker, isActiveBalance);
            SM1Types.StoredBalance memory balance =
              _loadBalanceForUpdate(balancePtr, maybeStaker, isActiveBalance);
            balance.nextEpochBalance = uint256(balance.nextEpochBalance).sub(amount).toUint240();
            _storeBalance(balancePtr, balance);
          }
          function _getBalancePtr(
            address maybeStaker,
            bool isActiveBalance
          )
            private
            view
            returns (SM1Types.StoredBalance storage)
          {
            // Active.
            if (isActiveBalance) {
              if (maybeStaker != address(0)) {
                return _ACTIVE_BALANCES_[maybeStaker];
              }
              return _TOTAL_ACTIVE_BALANCE_;
            }
            // Inactive.
            if (maybeStaker != address(0)) {
              return _INACTIVE_BALANCES_[maybeStaker];
            }
            return _TOTAL_INACTIVE_BALANCE_;
          }
          /**
           * @dev Load a balance for updating.
           *
           *  IMPORTANT: This function may modify state, and so the balance MUST be stored afterwards.
           *    - For active balances:
           *      - If a rollover occurs, rewards are settled up to the epoch boundary.
           *
           * @param  balancePtr       A storage pointer to the balance.
           * @param  maybeStaker      The user address, or address(0) to update total balance.
           * @param  isActiveBalance  Whether the balance is an active balance.
           */
          function _loadBalanceForUpdate(
            SM1Types.StoredBalance storage balancePtr,
            address maybeStaker,
            bool isActiveBalance
          )
            private
            returns (SM1Types.StoredBalance memory)
          {
            // Active balance.
            if (isActiveBalance) {
              (
                SM1Types.StoredBalance memory balance,
                uint256 beforeRolloverEpoch,
                uint256 beforeRolloverBalance,
                bool didRolloverOccur
              ) = _loadActiveBalance(balancePtr);
              if (didRolloverOccur) {
                // Handle the effect of the balance rollover on rewards. We must partially settle the index
                // up to the epoch boundary where the change in balance occurred. We pass in the balance
                // from before the boundary.
                if (maybeStaker == address(0)) {
                  // If it's the total active balance...
                  _settleGlobalIndexUpToEpoch(beforeRolloverBalance, beforeRolloverEpoch);
                } else {
                  // If it's a user active balance...
                  _settleUserRewardsUpToEpoch(maybeStaker, beforeRolloverBalance, beforeRolloverEpoch);
                }
              }
              return balance;
            }
            // Inactive balance.
            return _loadInactiveBalance(balancePtr);
          }
          function _loadActiveBalance(
            SM1Types.StoredBalance storage balancePtr
          )
            private
            view
            returns (
              SM1Types.StoredBalance memory,
              uint256,
              uint256,
              bool
            )
          {
            SM1Types.StoredBalance memory balance = balancePtr;
            // Return these as they may be needed for rewards settlement.
            uint256 beforeRolloverEpoch = uint256(balance.currentEpoch);
            uint256 beforeRolloverBalance = uint256(balance.currentEpochBalance);
            bool didRolloverOccur = false;
            // Roll the balance forward if needed.
            uint256 currentEpoch = getCurrentEpoch();
            if (currentEpoch > uint256(balance.currentEpoch)) {
              didRolloverOccur = balance.currentEpochBalance != balance.nextEpochBalance;
              balance.currentEpoch = currentEpoch.toUint16();
              balance.currentEpochBalance = balance.nextEpochBalance;
            }
            return (balance, beforeRolloverEpoch, beforeRolloverBalance, didRolloverOccur);
          }
          function _loadInactiveBalance(
            SM1Types.StoredBalance storage balancePtr
          )
            private
            view
            returns (SM1Types.StoredBalance memory)
          {
            SM1Types.StoredBalance memory balance = balancePtr;
            // Roll the balance forward if needed.
            uint256 currentEpoch = getCurrentEpoch();
            if (currentEpoch > uint256(balance.currentEpoch)) {
              balance.currentEpoch = currentEpoch.toUint16();
              balance.currentEpochBalance = balance.nextEpochBalance;
            }
            return balance;
          }
          /**
           * @dev Store a balance.
           */
          function _storeBalance(
            SM1Types.StoredBalance storage balancePtr,
            SM1Types.StoredBalance memory balance
          )
            private
          {
            // Note: This should use a single `sstore` when compiler optimizations are enabled.
            balancePtr.currentEpoch = balance.currentEpoch;
            balancePtr.currentEpochBalance = balance.currentEpochBalance;
            balancePtr.nextEpochBalance = balance.nextEpochBalance;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import {
          AccessControlUpgradeable
        } from '../../../dependencies/open-zeppelin/AccessControlUpgradeable.sol';
        import { ReentrancyGuard } from '../../../utils/ReentrancyGuard.sol';
        import { VersionedInitializable } from '../../../utils/VersionedInitializable.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        /**
         * @title SM1Storage
         * @author dYdX
         *
         * @dev Storage contract. Contains or inherits from all contract with storage.
         */
        abstract contract SM1Storage is
          AccessControlUpgradeable,
          ReentrancyGuard,
          VersionedInitializable
        {
          // ============ Epoch Schedule ============
          /// @dev The parameters specifying the function from timestamp to epoch number.
          SM1Types.EpochParameters internal _EPOCH_PARAMETERS_;
          /// @dev The period of time at the end of each epoch in which withdrawals cannot be requested.
          uint256 internal _BLACKOUT_WINDOW_;
          // ============ Staked Token ERC20 ============
          /// @dev Allowances for ERC-20 transfers.
          mapping(address => mapping(address => uint256)) internal _ALLOWANCES_;
          // ============ Governance Power Delegation ============
          /// @dev Domain separator for EIP-712 signatures.
          bytes32 internal _DOMAIN_SEPARATOR_;
          /// @dev Mapping from (owner) => (next valid nonce) for EIP-712 signatures.
          mapping(address => uint256) internal _NONCES_;
          /// @dev Snapshots and delegates for governance voting power.
          mapping(address => mapping(uint256 => SM1Types.Snapshot)) internal _VOTING_SNAPSHOTS_;
          mapping(address => uint256) internal _VOTING_SNAPSHOT_COUNTS_;
          mapping(address => address) internal _VOTING_DELEGATES_;
          /// @dev Snapshots and delegates for governance proposition power.
          mapping(address => mapping(uint256 => SM1Types.Snapshot)) internal _PROPOSITION_SNAPSHOTS_;
          mapping(address => uint256) internal _PROPOSITION_SNAPSHOT_COUNTS_;
          mapping(address => address) internal _PROPOSITION_DELEGATES_;
          // ============ Rewards Accounting ============
          /// @dev The emission rate of rewards.
          uint256 internal _REWARDS_PER_SECOND_;
          /// @dev The cumulative rewards earned per staked token. (Shared storage slot.)
          uint224 internal _GLOBAL_INDEX_;
          /// @dev The timestamp at which the global index was last updated. (Shared storage slot.)
          uint32 internal _GLOBAL_INDEX_TIMESTAMP_;
          /// @dev The value of the global index when the user's staked balance was last updated.
          mapping(address => uint256) internal _USER_INDEXES_;
          /// @dev The user's accrued, unclaimed rewards (as of the last update to the user index).
          mapping(address => uint256) internal _USER_REWARDS_BALANCES_;
          /// @dev The value of the global index at the end of a given epoch.
          mapping(uint256 => uint256) internal _EPOCH_INDEXES_;
          // ============ Staker Accounting ============
          /// @dev The active balance by staker.
          mapping(address => SM1Types.StoredBalance) internal _ACTIVE_BALANCES_;
          /// @dev The total active balance of stakers.
          SM1Types.StoredBalance internal _TOTAL_ACTIVE_BALANCE_;
          /// @dev The inactive balance by staker.
          mapping(address => SM1Types.StoredBalance) internal _INACTIVE_BALANCES_;
          /// @dev The total inactive balance of stakers.
          SM1Types.StoredBalance internal _TOTAL_INACTIVE_BALANCE_;
          // ============ Exchange Rate ============
          /// @dev The value of one underlying token, in the units used for staked balances, denominated
          ///  as a mutiple of EXCHANGE_RATE_BASE for additional precision.
          uint256 internal _EXCHANGE_RATE_;
          /// @dev Historical snapshots of the exchange rate, in each block that it has changed.
          mapping(uint256 => SM1Types.Snapshot) internal _EXCHANGE_RATE_SNAPSHOTS_;
          /// @dev Number of snapshots of the exchange rate.
          uint256 internal _EXCHANGE_RATE_SNAPSHOT_COUNT_;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './Context.sol';
        import './Strings.sol';
        import './ERC165.sol';
        /**
         * @dev External interface of AccessControl declared to support ERC165 detection.
         */
        interface IAccessControlUpgradeable {
          function hasRole(bytes32 role, address account) external view returns (bool);
          function getRoleAdmin(bytes32 role) external view returns (bytes32);
          function grantRole(bytes32 role, address account) external;
          function revokeRole(bytes32 role, address account) external;
          function renounceRole(bytes32 role, address account) external;
        }
        /**
         * @dev Contract module that allows children to implement role-based access
         * control mechanisms. This is a lightweight version that doesn't allow enumerating role
         * members except through off-chain means by accessing the contract event logs. Some
         * applications may benefit from on-chain enumerability, for those cases see
         * {AccessControlEnumerable}.
         *
         * Roles are referred to by their `bytes32` identifier. These should be exposed
         * in the external API and be unique. The best way to achieve this is by
         * using `public constant` hash digests:
         *
         * ```
         * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
         * ```
         *
         * Roles can be used to represent a set of permissions. To restrict access to a
         * function call, use {hasRole}:
         *
         * ```
         * function foo() public {
         *     require(hasRole(MY_ROLE, msg.sender));
         *     ...
         * }
         * ```
         *
         * Roles can be granted and revoked dynamically via the {grantRole} and
         * {revokeRole} functions. Each role has an associated admin role, and only
         * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
         *
         * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
         * that only accounts with this role will be able to grant or revoke other
         * roles. More complex role relationships can be created by using
         * {_setRoleAdmin}.
         *
         * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
         * grant and revoke this role. Extra precautions should be taken to secure
         * accounts that have been granted it.
         */
        abstract contract AccessControlUpgradeable is Context, IAccessControlUpgradeable, ERC165 {
          struct RoleData {
            mapping(address => bool) members;
            bytes32 adminRole;
          }
          mapping(bytes32 => RoleData) private _roles;
          bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;
          /**
           * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
           *
           * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
           * {RoleAdminChanged} not being emitted signaling this.
           *
           * _Available since v3.1._
           */
          event RoleAdminChanged(
            bytes32 indexed role,
            bytes32 indexed previousAdminRole,
            bytes32 indexed newAdminRole
          );
          /**
           * @dev Emitted when `account` is granted `role`.
           *
           * `sender` is the account that originated the contract call, an admin role
           * bearer except when using {_setupRole}.
           */
          event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Emitted when `account` is revoked `role`.
           *
           * `sender` is the account that originated the contract call:
           *   - if using `revokeRole`, it is the admin role bearer
           *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
           */
          event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);
          /**
           * @dev Modifier that checks that an account has a specific role. Reverts
           * with a standardized message including the required role.
           *
           * The format of the revert reason is given by the following regular expression:
           *
           *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
           *
           * _Available since v4.1._
           */
          modifier onlyRole(bytes32 role) {
            _checkRole(role, _msgSender());
            _;
          }
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return
              interfaceId == type(IAccessControlUpgradeable).interfaceId ||
              super.supportsInterface(interfaceId);
          }
          /**
           * @dev Returns `true` if `account` has been granted `role`.
           */
          function hasRole(bytes32 role, address account) public view override returns (bool) {
            return _roles[role].members[account];
          }
          /**
           * @dev Revert with a standard message if `account` is missing `role`.
           *
           * The format of the revert reason is given by the following regular expression:
           *
           *  /^AccessControl: account (0x[0-9a-f]{20}) is missing role (0x[0-9a-f]{32})$/
           */
          function _checkRole(bytes32 role, address account) internal view {
            if (!hasRole(role, account)) {
              revert(
                string(
                  abi.encodePacked(
                    'AccessControl: account ',
                    Strings.toHexString(uint160(account), 20),
                    ' is missing role ',
                    Strings.toHexString(uint256(role), 32)
                  )
                )
              );
            }
          }
          /**
           * @dev Returns the admin role that controls `role`. See {grantRole} and
           * {revokeRole}.
           *
           * To change a role's admin, use {_setRoleAdmin}.
           */
          function getRoleAdmin(bytes32 role) public view override returns (bytes32) {
            return _roles[role].adminRole;
          }
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function grantRole(bytes32 role, address account)
            public
            virtual
            override
            onlyRole(getRoleAdmin(role))
          {
            _grantRole(role, account);
          }
          /**
           * @dev Revokes `role` from `account`.
           *
           * If `account` had been granted `role`, emits a {RoleRevoked} event.
           *
           * Requirements:
           *
           * - the caller must have ``role``'s admin role.
           */
          function revokeRole(bytes32 role, address account)
            public
            virtual
            override
            onlyRole(getRoleAdmin(role))
          {
            _revokeRole(role, account);
          }
          /**
           * @dev Revokes `role` from the calling account.
           *
           * Roles are often managed via {grantRole} and {revokeRole}: this function's
           * purpose is to provide a mechanism for accounts to lose their privileges
           * if they are compromised (such as when a trusted device is misplaced).
           *
           * If the calling account had been granted `role`, emits a {RoleRevoked}
           * event.
           *
           * Requirements:
           *
           * - the caller must be `account`.
           */
          function renounceRole(bytes32 role, address account) public virtual override {
            require(account == _msgSender(), 'AccessControl: can only renounce roles for self');
            _revokeRole(role, account);
          }
          /**
           * @dev Grants `role` to `account`.
           *
           * If `account` had not been already granted `role`, emits a {RoleGranted}
           * event. Note that unlike {grantRole}, this function doesn't perform any
           * checks on the calling account.
           *
           * [WARNING]
           * ====
           * This function should only be called from the constructor when setting
           * up the initial roles for the system.
           *
           * Using this function in any other way is effectively circumventing the admin
           * system imposed by {AccessControl}.
           * ====
           */
          function _setupRole(bytes32 role, address account) internal virtual {
            _grantRole(role, account);
          }
          /**
           * @dev Sets `adminRole` as ``role``'s admin role.
           *
           * Emits a {RoleAdminChanged} event.
           */
          function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
            emit RoleAdminChanged(role, getRoleAdmin(role), adminRole);
            _roles[role].adminRole = adminRole;
          }
          function _grantRole(bytes32 role, address account) private {
            if (!hasRole(role, account)) {
              _roles[role].members[account] = true;
              emit RoleGranted(role, account, _msgSender());
            }
          }
          function _revokeRole(bytes32 role, address account) private {
            if (hasRole(role, account)) {
              _roles[role].members[account] = false;
              emit RoleRevoked(role, account, _msgSender());
            }
          }
          uint256[49] private __gap;
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        /**
         * @title ReentrancyGuard
         * @author dYdX
         *
         * @dev Updated ReentrancyGuard library designed to be used with Proxy Contracts.
         */
        abstract contract ReentrancyGuard {
          uint256 private constant NOT_ENTERED = 1;
          uint256 private constant ENTERED = uint256(int256(-1));
          uint256 private _STATUS_;
          constructor()
            internal
          {
            _STATUS_ = NOT_ENTERED;
          }
          modifier nonReentrant() {
            require(_STATUS_ != ENTERED, 'ReentrancyGuard: reentrant call');
            _STATUS_ = ENTERED;
            _;
            _STATUS_ = NOT_ENTERED;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        /**
         * @title VersionedInitializable
         * @author Aave, inspired by the OpenZeppelin Initializable contract
         *
         * @dev Helper contract to support initializer functions. To use it, replace
         * the constructor with a function that has the `initializer` modifier.
         * WARNING: Unlike constructors, initializer functions must be manually
         * invoked. This applies both to deploying an Initializable contract, as well
         * as extending an Initializable contract via inheritance.
         * WARNING: When used with inheritance, manual care must be taken to not invoke
         * a parent initializer twice, or ensure that all initializers are idempotent,
         * because this is not dealt with automatically as with constructors.
         *
         */
        abstract contract VersionedInitializable {
            /**
           * @dev Indicates that the contract has been initialized.
           */
            uint256 internal lastInitializedRevision = 0;
           /**
           * @dev Modifier to use in the initializer function of a contract.
           */
            modifier initializer() {
                uint256 revision = getRevision();
                require(revision > lastInitializedRevision, "Contract instance has already been initialized");
                lastInitializedRevision = revision;
                _;
            }
            /// @dev returns the revision number of the contract.
            /// Needs to be defined in the inherited class as a constant.
            function getRevision() internal pure virtual returns(uint256);
            // Reserved storage space to allow for layout changes in the future.
            uint256[50] private ______gap;
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
          }
          function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev String operations.
         */
        library Strings {
          bytes16 private constant alphabet = '0123456789abcdef';
          /**
           * @dev Converts a `uint256` to its ASCII `string` decimal representation.
           */
          function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            if (value == 0) {
              return '0';
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
              digits++;
              temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
              digits -= 1;
              buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
              value /= 10;
            }
            return string(buffer);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
           */
          function toHexString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
              return '0x00';
            }
            uint256 temp = value;
            uint256 length = 0;
            while (temp != 0) {
              length++;
              temp >>= 8;
            }
            return toHexString(value, length);
          }
          /**
           * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
           */
          function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = '0';
            buffer[1] = 'x';
            for (uint256 i = 2 * length + 1; i > 1; --i) {
              buffer[i] = alphabet[value & 0xf];
              value >>= 4;
            }
            require(value == 0, 'Strings: hex length insufficient');
            return string(buffer);
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        import './IERC165.sol';
        /**
         * @dev Implementation of the {IERC165} interface.
         *
         * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
         * for the additional interface id that will be supported. For example:
         *
         * ```solidity
         * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
         *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
         * }
         * ```
         *
         * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
         */
        abstract contract ERC165 is IERC165 {
          /**
           * @dev See {IERC165-supportsInterface}.
           */
          function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
          }
        }
        // SPDX-License-Identifier: MIT
        pragma solidity 0.7.5;
        /**
         * @dev Interface of the ERC165 standard, as defined in the
         * https://eips.ethereum.org/EIPS/eip-165[EIP].
         *
         * Implementers can declare support of contract interfaces, which can then be
         * queried by others ({ERC165Checker}).
         *
         * For an implementation, see {ERC165}.
         */
        interface IERC165 {
          /**
           * @dev Returns true if this contract implements the interface defined by
           * `interfaceId`. See the corresponding
           * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
           * to learn more about how these ids are created.
           *
           * This function call must use less than 30 000 gas.
           */
          function supportsInterface(bytes4 interfaceId) external view returns (bool);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        /**
         * @dev Methods for downcasting unsigned integers, reverting on overflow.
         */
        library SafeCast {
          /**
           * @dev Downcast to a uint16, reverting on overflow.
           */
          function toUint16(
            uint256 a
          )
            internal
            pure
            returns (uint16)
          {
            uint16 b = uint16(a);
            require(
              uint256(b) == a,
              'SafeCast: toUint16 overflow'
            );
            return b;
          }
          /**
           * @dev Downcast to a uint32, reverting on overflow.
           */
          function toUint32(
            uint256 a
          )
            internal
            pure
            returns (uint32)
          {
            uint32 b = uint32(a);
            require(
              uint256(b) == a,
              'SafeCast: toUint32 overflow'
            );
            return b;
          }
          /**
           * @dev Downcast to a uint128, reverting on overflow.
           */
          function toUint128(
            uint256 a
          )
            internal
            pure
            returns (uint128)
          {
            uint128 b = uint128(a);
            require(
              uint256(b) == a,
              'SafeCast: toUint128 overflow'
            );
            return b;
          }
          /**
           * @dev Downcast to a uint224, reverting on overflow.
           */
          function toUint224(
            uint256 a
          )
            internal
            pure
            returns (uint224)
          {
            uint224 b = uint224(a);
            require(
              uint256(b) == a,
              'SafeCast: toUint224 overflow'
            );
            return b;
          }
          /**
           * @dev Downcast to a uint240, reverting on overflow.
           */
          function toUint240(
            uint256 a
          )
            internal
            pure
            returns (uint240)
          {
            uint240 b = uint240(a);
            require(
              uint256(b) == a,
              'SafeCast: toUint240 overflow'
            );
            return b;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeERC20 } from '../../../dependencies/open-zeppelin/SafeERC20.sol';
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../../interfaces/IERC20.sol';
        import { Math } from '../../../utils/Math.sol';
        import { SafeCast } from '../lib/SafeCast.sol';
        import { SM1EpochSchedule } from './SM1EpochSchedule.sol';
        /**
         * @title SM1Rewards
         * @author dYdX
         *
         * @dev Manages the distribution of token rewards.
         *
         *  Rewards are distributed continuously. After each second, an account earns rewards `r` according
         *  to the following formula:
         *
         *      r = R * s / S
         *
         *  Where:
         *    - `R` is the rewards distributed globally each second, also called the “emission rate.”
         *    - `s` is the account's staked balance in that second (technically, it is measured at the
         *      end of the second)
         *    - `S` is the sum total of all staked balances in that second (again, measured at the end of
         *      the second)
         *
         *  The parameter `R` can be configured by the contract owner. For every second that elapses,
         *  exactly `R` tokens will accrue to users, save for rounding errors, and with the exception that
         *  while the total staked balance is zero, no tokens will accrue to anyone.
         *
         *  The accounting works as follows: A global index is stored which represents the cumulative
         *  number of rewards tokens earned per staked token since the start of the distribution.
         *  The value of this index increases over time, and there are two factors affecting the rate of
         *  increase:
         *    1) The emission rate (in the numerator)
         *    2) The total number of staked tokens (in the denominator)
         *
         *  Whenever either factor changes, in some timestamp T, we settle the global index up to T by
         *  calculating the increase in the index since the last update using the OLD values of the factors:
         *
         *    indexDelta = timeDelta * emissionPerSecond * INDEX_BASE / totalStaked
         *
         *  Where `INDEX_BASE` is a scaling factor used to allow more precision in the storage of the index.
         *
         *  For each user we store an accrued rewards balance, as well as a user index, which is a cache of
         *  the global index at the time that the user's accrued rewards balance was last updated. Then at
         *  any point in time, a user's claimable rewards are represented by the following:
         *
         *    rewards = _USER_REWARDS_BALANCES_[user] + userStaked * (
         *                settledGlobalIndex - _USER_INDEXES_[user]
         *              ) / INDEX_BASE
         */
        abstract contract SM1Rewards is
          SM1EpochSchedule
        {
          using SafeCast for uint256;
          using SafeERC20 for IERC20;
          using SafeMath for uint256;
          // ============ Constants ============
          /// @dev Additional precision used to represent the global and user index values.
          uint256 private constant INDEX_BASE = 10**18;
          /// @notice The rewards token.
          IERC20 public immutable REWARDS_TOKEN;
          /// @notice Address to pull rewards from. Must have provided an allowance to this contract.
          address public immutable REWARDS_TREASURY;
          /// @notice Start timestamp (inclusive) of the period in which rewards can be earned.
          uint256 public immutable DISTRIBUTION_START;
          /// @notice End timestamp (exclusive) of the period in which rewards can be earned.
          uint256 public immutable DISTRIBUTION_END;
          // ============ Events ============
          event RewardsPerSecondUpdated(
            uint256 emissionPerSecond
          );
          event GlobalIndexUpdated(
            uint256 index
          );
          event UserIndexUpdated(
            address indexed user,
            uint256 index,
            uint256 unclaimedRewards
          );
          event ClaimedRewards(
            address indexed user,
            address recipient,
            uint256 claimedRewards
          );
          // ============ Constructor ============
          constructor(
            IERC20 rewardsToken,
            address rewardsTreasury,
            uint256 distributionStart,
            uint256 distributionEnd
          ) {
            require(
              distributionEnd >= distributionStart,
              'SM1Rewards: Invalid parameters'
            );
            REWARDS_TOKEN = rewardsToken;
            REWARDS_TREASURY = rewardsTreasury;
            DISTRIBUTION_START = distributionStart;
            DISTRIBUTION_END = distributionEnd;
          }
          // ============ External Functions ============
          /**
           * @notice The current emission rate of rewards.
           *
           * @return The number of rewards tokens issued globally each second.
           */
          function getRewardsPerSecond()
            external
            view
            returns (uint256)
          {
            return _REWARDS_PER_SECOND_;
          }
          // ============ Internal Functions ============
          /**
           * @dev Initialize the contract.
           */
          function __SM1Rewards_init()
            internal
          {
            _GLOBAL_INDEX_TIMESTAMP_ = Math.max(block.timestamp, DISTRIBUTION_START).toUint32();
          }
          /**
           * @dev Set the emission rate of rewards.
           *
           *  IMPORTANT: Do not call this function without settling the total staked balance first, to
           *  ensure that the index is settled up to the epoch boundaries.
           *
           * @param  emissionPerSecond  The new number of rewards tokens to give out each second.
           * @param  totalStaked        The total staked balance.
           */
          function _setRewardsPerSecond(
            uint256 emissionPerSecond,
            uint256 totalStaked
          )
            internal
          {
            _settleGlobalIndexUpToNow(totalStaked);
            _REWARDS_PER_SECOND_ = emissionPerSecond;
            emit RewardsPerSecondUpdated(emissionPerSecond);
          }
          /**
           * @dev Claim tokens, sending them to the specified recipient.
           *
           *  Note: In order to claim all accrued rewards, the total and user staked balances must first be
           *  settled before calling this function.
           *
           * @param  user       The user's address.
           * @param  recipient  The address to send rewards to.
           *
           * @return The number of rewards tokens claimed.
           */
          function _claimRewards(
            address user,
            address recipient
          )
            internal
            returns (uint256)
          {
            uint256 accruedRewards = _USER_REWARDS_BALANCES_[user];
            _USER_REWARDS_BALANCES_[user] = 0;
            REWARDS_TOKEN.safeTransferFrom(REWARDS_TREASURY, recipient, accruedRewards);
            emit ClaimedRewards(user, recipient, accruedRewards);
            return accruedRewards;
          }
          /**
           * @dev Settle a user's rewards up to the latest global index as of `block.timestamp`. Triggers a
           *  settlement of the global index up to `block.timestamp`. Should be called with the OLD user
           *  and total balances.
           *
           * @param  user         The user's address.
           * @param  userStaked   Tokens staked by the user during the period since the last user index
           *                      update.
           * @param  totalStaked  Total tokens staked by all users during the period since the last global
           *                      index update.
           *
           * @return The user's accrued rewards, including past unclaimed rewards.
           */
          function _settleUserRewardsUpToNow(
            address user,
            uint256 userStaked,
            uint256 totalStaked
          )
            internal
            returns (uint256)
          {
            uint256 globalIndex = _settleGlobalIndexUpToNow(totalStaked);
            return _settleUserRewardsUpToIndex(user, userStaked, globalIndex);
          }
          /**
           * @dev Settle a user's rewards up to an epoch boundary. Should be used to partially settle a
           *  user's rewards if their balance was known to have changed on that epoch boundary.
           *
           * @param  user         The user's address.
           * @param  userStaked   Tokens staked by the user. Should be accurate for the time period
           *                      since the last update to this user and up to the end of the
           *                      specified epoch.
           * @param  epochNumber  Settle the user's rewards up to the end of this epoch.
           *
           * @return The user's accrued rewards, including past unclaimed rewards, up to the end of the
           *  specified epoch.
           */
          function _settleUserRewardsUpToEpoch(
            address user,
            uint256 userStaked,
            uint256 epochNumber
          )
            internal
            returns (uint256)
          {
            uint256 globalIndex = _EPOCH_INDEXES_[epochNumber];
            return _settleUserRewardsUpToIndex(user, userStaked, globalIndex);
          }
          /**
           * @dev Settle the global index up to the end of the given epoch.
           *
           *  IMPORTANT: This function should only be called under conditions which ensure the following:
           *    - `epochNumber` < the current epoch number
           *    - `_GLOBAL_INDEX_TIMESTAMP_ < settleUpToTimestamp`
           *    - `_EPOCH_INDEXES_[epochNumber] = 0`
           */
          function _settleGlobalIndexUpToEpoch(
            uint256 totalStaked,
            uint256 epochNumber
          )
            internal
            returns (uint256)
          {
            uint256 settleUpToTimestamp = getStartOfEpoch(epochNumber.add(1));
            uint256 globalIndex = _settleGlobalIndexUpToTimestamp(totalStaked, settleUpToTimestamp);
            _EPOCH_INDEXES_[epochNumber] = globalIndex;
            return globalIndex;
          }
          // ============ Private Functions ============
          /**
           * @dev Updates the global index, reflecting cumulative rewards given out per staked token.
           *
           * @param  totalStaked          The total staked balance, which should be constant in the interval
           *                              since the last update to the global index.
           *
           * @return The new global index.
           */
          function _settleGlobalIndexUpToNow(
            uint256 totalStaked
          )
            private
            returns (uint256)
          {
            return _settleGlobalIndexUpToTimestamp(totalStaked, block.timestamp);
          }
          /**
           * @dev Helper function which settles a user's rewards up to a global index. Should be called
           *  any time a user's staked balance changes, with the OLD user and total balances.
           *
           * @param  user            The user's address.
           * @param  userStaked      Tokens staked by the user during the period since the last user index
           *                         update.
           * @param  newGlobalIndex  The new index value to bring the user index up to. MUST NOT be less
           *                         than the user's index.
           *
           * @return The user's accrued rewards, including past unclaimed rewards.
           */
          function _settleUserRewardsUpToIndex(
            address user,
            uint256 userStaked,
            uint256 newGlobalIndex
          )
            private
            returns (uint256)
          {
            uint256 oldAccruedRewards = _USER_REWARDS_BALANCES_[user];
            uint256 oldUserIndex = _USER_INDEXES_[user];
            if (oldUserIndex == newGlobalIndex) {
              return oldAccruedRewards;
            }
            uint256 newAccruedRewards;
            if (userStaked == 0) {
              // Note: Even if the user's staked balance is zero, we still need to update the user index.
              newAccruedRewards = oldAccruedRewards;
            } else {
              // Calculate newly accrued rewards since the last update to the user's index.
              uint256 indexDelta = newGlobalIndex.sub(oldUserIndex);
              uint256 accruedRewardsDelta = userStaked.mul(indexDelta).div(INDEX_BASE);
              newAccruedRewards = oldAccruedRewards.add(accruedRewardsDelta);
              // Update the user's rewards.
              _USER_REWARDS_BALANCES_[user] = newAccruedRewards;
            }
            // Update the user's index.
            _USER_INDEXES_[user] = newGlobalIndex;
            emit UserIndexUpdated(user, newGlobalIndex, newAccruedRewards);
            return newAccruedRewards;
          }
          /**
           * @dev Updates the global index, reflecting cumulative rewards given out per staked token.
           *
           * @param  totalStaked          The total staked balance, which should be constant in the interval
           *                              (_GLOBAL_INDEX_TIMESTAMP_, settleUpToTimestamp).
           * @param  settleUpToTimestamp  The timestamp up to which to settle rewards. It MUST satisfy
           *                              `settleUpToTimestamp <= block.timestamp`.
           *
           * @return The new global index.
           */
          function _settleGlobalIndexUpToTimestamp(
            uint256 totalStaked,
            uint256 settleUpToTimestamp
          )
            private
            returns (uint256)
          {
            uint256 oldGlobalIndex = uint256(_GLOBAL_INDEX_);
            // The goal of this function is to calculate rewards earned since the last global index update.
            // These rewards are earned over the time interval which is the intersection of the intervals
            // [_GLOBAL_INDEX_TIMESTAMP_, settleUpToTimestamp] and [DISTRIBUTION_START, DISTRIBUTION_END].
            //
            // We can simplify a bit based on the assumption:
            //   `_GLOBAL_INDEX_TIMESTAMP_ >= DISTRIBUTION_START`
            //
            // Get the start and end of the time interval under consideration.
            uint256 intervalStart = uint256(_GLOBAL_INDEX_TIMESTAMP_);
            uint256 intervalEnd = Math.min(settleUpToTimestamp, DISTRIBUTION_END);
            // Return early if the interval has length zero (incl. case where intervalEnd < intervalStart).
            if (intervalEnd <= intervalStart) {
              return oldGlobalIndex;
            }
            // Note: If we reach this point, we must update _GLOBAL_INDEX_TIMESTAMP_.
            uint256 emissionPerSecond = _REWARDS_PER_SECOND_;
            if (emissionPerSecond == 0 || totalStaked == 0) {
              // Ensure a log is emitted if the timestamp changed, even if the index does not change.
              _GLOBAL_INDEX_TIMESTAMP_ = intervalEnd.toUint32();
              emit GlobalIndexUpdated(oldGlobalIndex);
              return oldGlobalIndex;
            }
            // Calculate the change in index over the interval.
            uint256 timeDelta = intervalEnd.sub(intervalStart);
            uint256 indexDelta = timeDelta.mul(emissionPerSecond).mul(INDEX_BASE).div(totalStaked);
            // Calculate, update, and return the new global index.
            uint256 newGlobalIndex = oldGlobalIndex.add(indexDelta);
            // Update storage. (Shared storage slot.)
            _GLOBAL_INDEX_TIMESTAMP_ = intervalEnd.toUint32();
            _GLOBAL_INDEX_ = newGlobalIndex.toUint224();
            emit GlobalIndexUpdated(newGlobalIndex);
            return newGlobalIndex;
          }
        }
        // SPDX-License-Identifier: Apache-2.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../dependencies/open-zeppelin/SafeMath.sol';
        /**
         * @title Math
         * @author dYdX
         *
         * @dev Library for non-standard Math functions.
         */
        library Math {
          using SafeMath for uint256;
          // ============ Library Functions ============
          /**
           * @dev Return `ceil(numerator / denominator)`.
           */
          function divRoundUp(
            uint256 numerator,
            uint256 denominator
          )
            internal
            pure
            returns (uint256)
          {
            if (numerator == 0) {
              // SafeMath will check for zero denominator
              return SafeMath.div(0, denominator);
            }
            return numerator.sub(1).div(denominator).add(1);
          }
          /**
           * @dev Returns the minimum between a and b.
           */
          function min(
            uint256 a,
            uint256 b
          )
            internal
            pure
            returns (uint256)
          {
            return a < b ? a : b;
          }
          /**
           * @dev Returns the maximum between a and b.
           */
          function max(
            uint256 a,
            uint256 b
          )
            internal
            pure
            returns (uint256)
          {
            return a > b ? a : b;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { SafeCast } from '../lib/SafeCast.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1EpochSchedule
         * @author dYdX
         *
         * @dev Defines a function from block timestamp to epoch number.
         *
         *  The formula used is `n = floor((t - b) / a)` where:
         *    - `n` is the epoch number
         *    - `t` is the timestamp (in seconds)
         *    - `b` is a non-negative offset, indicating the start of epoch zero (in seconds)
         *    - `a` is the length of an epoch, a.k.a. the interval (in seconds)
         *
         *  Note that by restricting `b` to be non-negative, we limit ourselves to functions in which epoch
         *  zero starts at a non-negative timestamp.
         *
         *  The recommended epoch length and blackout window are 28 and 7 days respectively; however, these
         *  are modifiable by the admin, within the specified bounds.
         */
        abstract contract SM1EpochSchedule is
          SM1Storage
        {
          using SafeCast for uint256;
          using SafeMath for uint256;
          // ============ Events ============
          event EpochParametersChanged(
            SM1Types.EpochParameters epochParameters
          );
          event BlackoutWindowChanged(
            uint256 blackoutWindow
          );
          // ============ Initializer ============
          function __SM1EpochSchedule_init(
            uint256 interval,
            uint256 offset,
            uint256 blackoutWindow
          )
            internal
          {
            require(
              block.timestamp < offset,
              'SM1EpochSchedule: Epoch zero must start after initialization'
            );
            _setBlackoutWindow(blackoutWindow);
            _setEpochParameters(interval, offset);
          }
          // ============ Public Functions ============
          /**
           * @notice Get the epoch at the current block timestamp.
           *
           *  NOTE: Reverts if epoch zero has not started.
           *
           * @return The current epoch number.
           */
          function getCurrentEpoch()
            public
            view
            returns (uint256)
          {
            (uint256 interval, uint256 offsetTimestamp) = _getIntervalAndOffsetTimestamp();
            return offsetTimestamp.div(interval);
          }
          /**
           * @notice Get the time remaining in the current epoch.
           *
           *  NOTE: Reverts if epoch zero has not started.
           *
           * @return The number of seconds until the next epoch.
           */
          function getTimeRemainingInCurrentEpoch()
            public
            view
            returns (uint256)
          {
            (uint256 interval, uint256 offsetTimestamp) = _getIntervalAndOffsetTimestamp();
            uint256 timeElapsedInEpoch = offsetTimestamp.mod(interval);
            return interval.sub(timeElapsedInEpoch);
          }
          /**
           * @notice Given an epoch number, get the start of that epoch. Calculated as `t = (n * a) + b`.
           *
           * @return The timestamp in seconds representing the start of that epoch.
           */
          function getStartOfEpoch(
            uint256 epochNumber
          )
            public
            view
            returns (uint256)
          {
            SM1Types.EpochParameters memory epochParameters = _EPOCH_PARAMETERS_;
            uint256 interval = uint256(epochParameters.interval);
            uint256 offset = uint256(epochParameters.offset);
            return epochNumber.mul(interval).add(offset);
          }
          /**
           * @notice Check whether we are at or past the start of epoch zero.
           *
           * @return Boolean `true` if the current timestamp is at least the start of epoch zero,
           *  otherwise `false`.
           */
          function hasEpochZeroStarted()
            public
            view
            returns (bool)
          {
            SM1Types.EpochParameters memory epochParameters = _EPOCH_PARAMETERS_;
            uint256 offset = uint256(epochParameters.offset);
            return block.timestamp >= offset;
          }
          /**
           * @notice Check whether we are in a blackout window, where withdrawal requests are restricted.
           *  Note that before epoch zero has started, there are no blackout windows.
           *
           * @return Boolean `true` if we are in a blackout window, otherwise `false`.
           */
          function inBlackoutWindow()
            public
            view
            returns (bool)
          {
            return hasEpochZeroStarted() && getTimeRemainingInCurrentEpoch() <= _BLACKOUT_WINDOW_;
          }
          // ============ Internal Functions ============
          function _setEpochParameters(
            uint256 interval,
            uint256 offset
          )
            internal
          {
            SM1Types.EpochParameters memory epochParameters =
              SM1Types.EpochParameters({interval: interval.toUint128(), offset: offset.toUint128()});
            _EPOCH_PARAMETERS_ = epochParameters;
            emit EpochParametersChanged(epochParameters);
          }
          function _setBlackoutWindow(
            uint256 blackoutWindow
          )
            internal
          {
            _BLACKOUT_WINDOW_ = blackoutWindow;
            emit BlackoutWindowChanged(blackoutWindow);
          }
          // ============ Private Functions ============
          /**
           * @dev Helper function to read params from storage and apply offset to the given timestamp.
           *  Recall that the formula for epoch number is `n = (t - b) / a`.
           *
           *  NOTE: Reverts if epoch zero has not started.
           *
           * @return The values `a` and `(t - b)`.
           */
          function _getIntervalAndOffsetTimestamp()
            private
            view
            returns (uint256, uint256)
          {
            SM1Types.EpochParameters memory epochParameters = _EPOCH_PARAMETERS_;
            uint256 interval = uint256(epochParameters.interval);
            uint256 offset = uint256(epochParameters.offset);
            require(
              block.timestamp >= offset,
              'SM1EpochSchedule: Epoch zero has not started'
            );
            uint256 offsetTimestamp = block.timestamp.sub(offset);
            return (interval, offsetTimestamp);
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { IERC20 } from '../../../interfaces/IERC20.sol';
        import { IERC20Detailed } from '../../../interfaces/IERC20Detailed.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1GovernancePowerDelegation } from './SM1GovernancePowerDelegation.sol';
        import { SM1StakedBalances } from './SM1StakedBalances.sol';
        /**
         * @title SM1ERC20
         * @author dYdX
         *
         * @dev ERC20 interface for staked tokens. Implements governance functionality for the tokens.
         *
         *  Also allows a user with an active stake to transfer their staked tokens to another user,
         *  even if they would otherwise be restricted from withdrawing.
         */
        abstract contract SM1ERC20 is
          SM1StakedBalances,
          SM1GovernancePowerDelegation,
          IERC20Detailed
        {
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice EIP-712 typehash for token approval via EIP-2612 permit.
          bytes32 public constant PERMIT_TYPEHASH = keccak256(
            'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
          );
          // ============ External Functions ============
          function name()
            external
            pure
            override
            returns (string memory)
          {
            return 'Staked DYDX';
          }
          function symbol()
            external
            pure
            override
            returns (string memory)
          {
            return 'stkDYDX';
          }
          function decimals()
            external
            pure
            override
            returns (uint8)
          {
            return 18;
          }
          /**
           * @notice Get the total supply of staked balances.
           *
           *  Note that due to the exchange rate, this is different than querying the total balance of
           *  underyling token staked to this contract.
           *
           * @return The sum of all staked balances.
           */
          function totalSupply()
            external
            view
            override
            returns (uint256)
          {
            return getTotalActiveBalanceCurrentEpoch() + getTotalInactiveBalanceCurrentEpoch();
          }
          /**
           * @notice Get a user's staked balance.
           *
           *  Note that due to the exchange rate, one unit of staked balance may not be equivalent to one
           *  unit of the underlying token. Also note that a user's staked balance is different from a
           *  user's transferable balance.
           *
           * @param  account  The account to get the balance of.
           *
           * @return The user's staked balance.
           */
          function balanceOf(
            address account
          )
            public
            view
            override(SM1GovernancePowerDelegation, IERC20)
            returns (uint256)
          {
            return getActiveBalanceCurrentEpoch(account) + getInactiveBalanceCurrentEpoch(account);
          }
          function transfer(
            address recipient,
            uint256 amount
          )
            external
            override
            nonReentrant
            returns (bool)
          {
            _transfer(msg.sender, recipient, amount);
            return true;
          }
          function allowance(
            address owner,
            address spender
          )
            external
            view
            override
            returns (uint256)
          {
            return _ALLOWANCES_[owner][spender];
          }
          function approve(
            address spender,
            uint256 amount
          )
            external
            override
            returns (bool)
          {
            _approve(msg.sender, spender, amount);
            return true;
          }
          function transferFrom(
            address sender,
            address recipient,
            uint256 amount
          )
            external
            override
            nonReentrant
            returns (bool)
          {
            _transfer(sender, recipient, amount);
            _approve(
              sender,
              msg.sender,
              _ALLOWANCES_[sender][msg.sender].sub(amount, 'SM1ERC20: transfer amount exceeds allowance')
            );
            return true;
          }
          function increaseAllowance(
            address spender,
            uint256 addedValue
          )
            external
            returns (bool)
          {
            _approve(msg.sender, spender, _ALLOWANCES_[msg.sender][spender].add(addedValue));
            return true;
          }
          function decreaseAllowance(
            address spender,
            uint256 subtractedValue
          )
            external
            returns (bool)
          {
            _approve(
              msg.sender,
              spender,
              _ALLOWANCES_[msg.sender][spender].sub(
                subtractedValue,
                'SM1ERC20: Decreased allowance below zero'
              )
            );
            return true;
          }
          /**
           * @notice Implements the permit function as specified in EIP-2612.
           *
           * @param  owner     Address of the token owner.
           * @param  spender   Address of the spender.
           * @param  value     Amount of allowance.
           * @param  deadline  Expiration timestamp for the signature.
           * @param  v         Signature param.
           * @param  r         Signature param.
           * @param  s         Signature param.
           */
          function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            external
          {
            require(
              owner != address(0),
              'SM1ERC20: INVALID_OWNER'
            );
            require(
              block.timestamp <= deadline,
              'SM1ERC20: INVALID_EXPIRATION'
            );
            uint256 currentValidNonce = _NONCES_[owner];
            bytes32 digest = keccak256(
              abi.encodePacked(
                '\\x19\\x01',
                _DOMAIN_SEPARATOR_,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
              )
            );
            require(
              owner == ecrecover(digest, v, r, s),
              'SM1ERC20: INVALID_SIGNATURE'
            );
            _NONCES_[owner] = currentValidNonce.add(1);
            _approve(owner, spender, value);
          }
          // ============ Internal Functions ============
          function _transfer(
            address sender,
            address recipient,
            uint256 amount
          )
            internal
          {
            require(
              sender != address(0),
              'SM1ERC20: Transfer from address(0)'
            );
            require(
              recipient != address(0),
              'SM1ERC20: Transfer to address(0)'
            );
            require(
              getTransferableBalance(sender) >= amount,
              'SM1ERC20: Transfer exceeds next epoch active balance'
            );
            // Update staked balances and delegate snapshots.
            _transferCurrentAndNextActiveBalance(sender, recipient, amount);
            _moveDelegatesForTransfer(sender, recipient, amount);
            emit Transfer(sender, recipient, amount);
          }
          function _approve(
            address owner,
            address spender,
            uint256 amount
          )
            internal
          {
            require(
              owner != address(0),
              'SM1ERC20: Approve from address(0)'
            );
            require(
              spender != address(0),
              'SM1ERC20: Approve to address(0)'
            );
            _ALLOWANCES_[owner][spender] = amount;
            emit Approval(owner, spender, amount);
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        import { IERC20 } from './IERC20.sol';
        /**
         * @dev Interface for ERC20 including metadata
         **/
        interface IERC20Detailed is IERC20 {
          function name() external view returns (string memory);
          function symbol() external view returns (string memory);
          function decimals() external view returns (uint8);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import {
          IGovernancePowerDelegationERC20
        } from '../../../interfaces/IGovernancePowerDelegationERC20.sol';
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1ExchangeRate } from './SM1ExchangeRate.sol';
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1GovernancePowerDelegation
         * @author dYdX
         *
         * @dev Provides support for two types of governance powers which are separately delegatable.
         *  Provides functions for delegation and for querying a user's power at a certain block number.
         *
         *  Internally, makes use of staked balances denoted in staked units, but returns underlying token
         *  units from the getPowerAtBlock() and getPowerCurrent() functions.
         *
         *  This is based on, and is designed to match, Aave's implementation, which is used in their
         *  governance token and staked token contracts.
         */
        abstract contract SM1GovernancePowerDelegation is
          SM1ExchangeRate,
          IGovernancePowerDelegationERC20
        {
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice EIP-712 typehash for delegation by signature of a specific governance power type.
          bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256(
            'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)'
          );
          /// @notice EIP-712 typehash for delegation by signature of all governance powers.
          bytes32 public constant DELEGATE_TYPEHASH = keccak256(
            'Delegate(address delegatee,uint256 nonce,uint256 expiry)'
          );
          // ============ External Functions ============
          /**
           * @notice Delegates a specific governance power of the sender to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(
            address delegatee,
            DelegationType delegationType
          )
            external
            override
          {
            _delegateByType(msg.sender, delegatee, delegationType);
          }
          /**
           * @notice Delegates all governance powers of the sender to a delegatee.
           *
           * @param  delegatee  The address to delegate power to.
           */
          function delegate(
            address delegatee
          )
            external
            override
          {
            _delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER);
          }
          /**
           * @dev Delegates specific governance power from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee       The address to delegate votes to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           * @param  nonce           The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry          Expiration timestamp for the signature.
           * @param  v               Signature param.
           * @param  r               Signature param.
           * @param  s               Signature param.
           */
          function delegateByTypeBySig(
            address delegatee,
            DelegationType delegationType,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            external
          {
            bytes32 structHash = keccak256(
              abi.encode(DELEGATE_BY_TYPE_TYPEHASH, delegatee, uint256(delegationType), nonce, expiry)
            );
            bytes32 digest = keccak256(abi.encodePacked('\\x19\\x01', _DOMAIN_SEPARATOR_, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(
              signer != address(0),
              'SM1GovernancePowerDelegation: INVALID_SIGNATURE'
            );
            require(
              nonce == _NONCES_[signer]++,
              'SM1GovernancePowerDelegation: INVALID_NONCE'
            );
            require(
              block.timestamp <= expiry,
              'SM1GovernancePowerDelegation: INVALID_EXPIRATION'
            );
            _delegateByType(signer, delegatee, delegationType);
          }
          /**
           * @dev Delegates both governance powers from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee  The address to delegate votes to.
           * @param  nonce      The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry     Expiration timestamp for the signature.
           * @param  v          Signature param.
           * @param  r          Signature param.
           * @param  s          Signature param.
           */
          function delegateBySig(
            address delegatee,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            external
          {
            bytes32 structHash = keccak256(abi.encode(DELEGATE_TYPEHASH, delegatee, nonce, expiry));
            bytes32 digest = keccak256(abi.encodePacked('\\x19\\x01', _DOMAIN_SEPARATOR_, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(
              signer != address(0),
              'SM1GovernancePowerDelegation: INVALID_SIGNATURE'
            );
            require(
              nonce == _NONCES_[signer]++,
              'SM1GovernancePowerDelegation: INVALID_NONCE'
            );
            require(
              block.timestamp <= expiry,
              'SM1GovernancePowerDelegation: INVALID_EXPIRATION'
            );
            _delegateByType(signer, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(signer, delegatee, DelegationType.PROPOSITION_POWER);
          }
          /**
           * @notice Returns the delegatee of a user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(
            address delegator,
            DelegationType delegationType
          )
            external
            override
            view
            returns (address)
          {
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            return _getDelegatee(delegator, delegates);
          }
          /**
           * @notice Returns the current power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(
            address user,
            DelegationType delegationType
          )
            external
            override
            view
            returns (uint256)
          {
            return getPowerAtBlock(user, block.number, delegationType);
          }
          /**
           * @notice Get the next valid nonce for EIP-712 signatures.
           *
           *  This nonce should be used when signing for any of the following functions:
           *   - permit()
           *   - delegateByTypeBySig()
           *   - delegateBySig()
           */
          function nonces(
            address owner
          )
            external
            view
            returns (uint256)
          {
            return _NONCES_[owner];
          }
          // ============ Public Functions ============
          function balanceOf(
            address account
          )
            public
            view
            virtual
            returns (uint256);
          /**
           * @notice Returns the power of a user at a certain block, denominated in underlying token units.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           *
           * @return The user's governance power of the specified type, in underlying token units.
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            public
            override
            view
            returns (uint256)
          {
            (
              mapping(address => mapping(uint256 => SM1Types.Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotCounts,
              // unused: delegates
            ) = _getDelegationDataByType(delegationType);
            uint256 stakeAmount = _findValueAtBlock(
              snapshots[user],
              snapshotCounts[user],
              blockNumber,
              0
            );
            uint256 exchangeRate = _findValueAtBlock(
              _EXCHANGE_RATE_SNAPSHOTS_,
              _EXCHANGE_RATE_SNAPSHOT_COUNT_,
              blockNumber,
              EXCHANGE_RATE_BASE
            );
            return underlyingAmountFromStakeAmountWithExchangeRate(stakeAmount, exchangeRate);
          }
          // ============ Internal Functions ============
          /**
           * @dev Delegates one specific power to a delegatee.
           *
           * @param  delegator       The user whose power to delegate.
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _delegateByType(
            address delegator,
            address delegatee,
            DelegationType delegationType
          )
            internal
          {
            require(
              delegatee != address(0),
              'SM1GovernancePowerDelegation: INVALID_DELEGATEE'
            );
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
            uint256 delegatorBalance = balanceOf(delegator);
            address previousDelegatee = _getDelegatee(delegator, delegates);
            delegates[delegator] = delegatee;
            _moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType);
            emit DelegateChanged(delegator, delegatee, delegationType);
          }
          /**
           * @dev Update delegate snapshots whenever staked tokens are transfered, minted, or burned.
           *
           * @param  from          The sender.
           * @param  to            The recipient.
           * @param  stakedAmount  The amount being transfered, denominated in staked units.
           */
          function _moveDelegatesForTransfer(
            address from,
            address to,
            uint256 stakedAmount
          )
            internal
          {
            address votingPowerFromDelegatee = _getDelegatee(from, _VOTING_DELEGATES_);
            address votingPowerToDelegatee = _getDelegatee(to, _VOTING_DELEGATES_);
            _moveDelegatesByType(
              votingPowerFromDelegatee,
              votingPowerToDelegatee,
              stakedAmount,
              DelegationType.VOTING_POWER
            );
            address propositionPowerFromDelegatee = _getDelegatee(from, _PROPOSITION_DELEGATES_);
            address propositionPowerToDelegatee = _getDelegatee(to, _PROPOSITION_DELEGATES_);
            _moveDelegatesByType(
              propositionPowerFromDelegatee,
              propositionPowerToDelegatee,
              stakedAmount,
              DelegationType.PROPOSITION_POWER
            );
          }
          /**
           * @dev Moves power from one user to another.
           *
           * @param  from            The user from which delegated power is moved.
           * @param  to              The user that will receive the delegated power.
           * @param  amount          The amount of power to be moved.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _moveDelegatesByType(
            address from,
            address to,
            uint256 amount,
            DelegationType delegationType
          )
            internal
          {
            if (from == to) {
              return;
            }
            (
              mapping(address => mapping(uint256 => SM1Types.Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotCounts,
              // unused: delegates
            ) = _getDelegationDataByType(delegationType);
            if (from != address(0)) {
              mapping(uint256 => SM1Types.Snapshot) storage fromSnapshots = snapshots[from];
              uint256 fromSnapshotCount = snapshotCounts[from];
              uint256 previousBalance = 0;
              if (fromSnapshotCount != 0) {
                previousBalance = fromSnapshots[fromSnapshotCount - 1].value;
              }
              uint256 newBalance = previousBalance.sub(amount);
              snapshotCounts[from] = _writeSnapshot(
                fromSnapshots,
                fromSnapshotCount,
                newBalance
              );
              emit DelegatedPowerChanged(from, newBalance, delegationType);
            }
            if (to != address(0)) {
              mapping(uint256 => SM1Types.Snapshot) storage toSnapshots = snapshots[to];
              uint256 toSnapshotCount = snapshotCounts[to];
              uint256 previousBalance = 0;
              if (toSnapshotCount != 0) {
                previousBalance = toSnapshots[toSnapshotCount - 1].value;
              }
              uint256 newBalance = previousBalance.add(amount);
              snapshotCounts[to] = _writeSnapshot(
                toSnapshots,
                toSnapshotCount,
                newBalance
              );
              emit DelegatedPowerChanged(to, newBalance, delegationType);
            }
          }
          /**
           * @dev Returns delegation data (snapshot, snapshotCount, delegates) by delegation type.
           *
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           *
           * @return The mapping of each user to a mapping of snapshots.
           * @return The mapping of each user to the total number of snapshots for that user.
           * @return The mapping of each user to the user's delegate.
           */
          function _getDelegationDataByType(
            DelegationType delegationType
          )
            internal
            view
            returns (
              mapping(address => mapping(uint256 => SM1Types.Snapshot)) storage,
              mapping(address => uint256) storage,
              mapping(address => address) storage
            )
          {
            if (delegationType == DelegationType.VOTING_POWER) {
              return (
                _VOTING_SNAPSHOTS_,
                _VOTING_SNAPSHOT_COUNTS_,
                _VOTING_DELEGATES_
              );
            } else {
              return (
                _PROPOSITION_SNAPSHOTS_,
                _PROPOSITION_SNAPSHOT_COUNTS_,
                _PROPOSITION_DELEGATES_
              );
            }
          }
          /**
           * @dev Returns the delegatee of a user. If a user never performed any delegation, their
           *  delegated address will be 0x0, in which case we return the user's own address.
           *
           * @param  delegator  The address of the user for which return the delegatee.
           * @param  delegates  The mapping of delegates for a particular type of delegation.
           */
          function _getDelegatee(
            address delegator,
            mapping(address => address) storage delegates
          )
            internal
            view
            returns (address)
          {
            address previousDelegatee = delegates[delegator];
            if (previousDelegatee == address(0)) {
              return delegator;
            }
            return previousDelegatee;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        interface IGovernancePowerDelegationERC20 {
          enum DelegationType {
            VOTING_POWER,
            PROPOSITION_POWER
          }
          /**
           * @dev Emitted when a user delegates governance power to another user.
           *
           * @param  delegator       The delegator.
           * @param  delegatee       The delegatee.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegateChanged(
            address indexed delegator,
            address indexed delegatee,
            DelegationType delegationType
          );
          /**
           * @dev Emitted when an action changes the delegated power of a user.
           *
           * @param  user            The user whose delegated power has changed.
           * @param  amount          The new amount of delegated power for the user.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType);
          /**
           * @dev Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType) external virtual;
          /**
           * @dev Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The user to which the power will be delegated.
           */
          function delegate(address delegatee) external virtual;
          /**
           * @dev Returns the delegatee of an user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            view
            virtual
            returns (address);
          /**
           * @dev Returns the current delegated power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            view
            virtual
            returns (uint256);
          /**
           * @dev Returns the delegated power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            external
            view
            virtual
            returns (uint256);
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SafeMath } from '../../../dependencies/open-zeppelin/SafeMath.sol';
        import { SM1Snapshots } from './SM1Snapshots.sol';
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1ExchangeRate
         * @author dYdX
         *
         * @dev Performs math using the exchange rate, which converts between underlying units of the token
         *  that was staked (e.g. STAKED_TOKEN.balanceOf(account)), and staked units, used by this contract
         *  for all staked balances (e.g. this.balanceOf(account)).
         *
         *  OVERVIEW:
         *
         *   The exchange rate is stored as a multiple of EXCHANGE_RATE_BASE, and represents the number of
         *   staked balance units that each unit of underlying token is worth. Before any slashes have
         *   occurred, the exchange rate is equal to one. The exchange rate can increase with each slash,
         *   indicating that staked balances are becoming less and less valuable, per unit, relative to the
         *   underlying token.
         *
         *  AVOIDING OVERFLOW AND UNDERFLOW:
         *
         *   Staked balances are represented internally as uint240, so the result of an operation returning
         *   a staked balances must return a value less than 2^240. Intermediate values in calcuations are
         *   represented as uint256, so all operations within a calculation must return values under 2^256.
         *
         *   In the functions below operating on the exchange rate, we are strategic in our choice of the
         *   order of multiplication and division operations, in order to avoid both overflow and underflow.
         *
         *   We use the following assumptions and principles to implement this module:
         *     - (ASSUMPTION) An amount denoted in underlying token units is never greater than 10^28.
         *     - If the exchange rate is greater than 10^46, then we may perform division on the exchange
         *         rate before performing multiplication, provided that the denominator is not greater
         *         than 10^28 (to ensure a result with at least 18 decimals of precision). Specifically,
         *         we use EXCHANGE_RATE_MAY_OVERFLOW as the cutoff, which is a number greater than 10^46.
         *     - Since staked balances are stored as uint240, we cap the exchange rate to ensure that a
         *         staked balance can never overflow (using the assumption above).
         */
        abstract contract SM1ExchangeRate is
          SM1Snapshots,
          SM1Storage
        {
          using SafeMath for uint256;
          // ============ Constants ============
          /// @notice The assumed upper bound on the total supply of the staked token.
          uint256 public constant MAX_UNDERLYING_BALANCE = 1e28;
          /// @notice Base unit used to represent the exchange rate, for additional precision.
          uint256 public constant EXCHANGE_RATE_BASE = 1e18;
          /// @notice Cutoff where an exchange rate may overflow after multiplying by an underlying balance.
          /// @dev Approximately 1.2e49
          uint256 public constant EXCHANGE_RATE_MAY_OVERFLOW = (2 ** 256 - 1) / MAX_UNDERLYING_BALANCE;
          /// @notice Cutoff where a stake amount may overflow after multiplying by EXCHANGE_RATE_BASE.
          /// @dev Approximately 1.2e59
          uint256 public constant STAKE_AMOUNT_MAY_OVERFLOW = (2 ** 256 - 1) / EXCHANGE_RATE_BASE;
          /// @notice Max exchange rate.
          /// @dev Approximately 1.8e62
          uint256 public constant MAX_EXCHANGE_RATE = (
            ((2 ** 240 - 1) / MAX_UNDERLYING_BALANCE) * EXCHANGE_RATE_BASE
          );
          // ============ Initializer ============
          function __SM1ExchangeRate_init()
            internal
          {
            _EXCHANGE_RATE_ = EXCHANGE_RATE_BASE;
          }
          function stakeAmountFromUnderlyingAmount(
            uint256 underlyingAmount
          )
            internal
            view
            returns (uint256)
          {
            uint256 exchangeRate = _EXCHANGE_RATE_;
            if (exchangeRate > EXCHANGE_RATE_MAY_OVERFLOW) {
              uint256 exchangeRateUnbased = exchangeRate.div(EXCHANGE_RATE_BASE);
              return underlyingAmount.mul(exchangeRateUnbased);
            } else {
              return underlyingAmount.mul(exchangeRate).div(EXCHANGE_RATE_BASE);
            }
          }
          function underlyingAmountFromStakeAmount(
            uint256 stakeAmount
          )
            internal
            view
            returns (uint256)
          {
            return underlyingAmountFromStakeAmountWithExchangeRate(stakeAmount, _EXCHANGE_RATE_);
          }
          function underlyingAmountFromStakeAmountWithExchangeRate(
            uint256 stakeAmount,
            uint256 exchangeRate
          )
            internal
            pure
            returns (uint256)
          {
            if (stakeAmount > STAKE_AMOUNT_MAY_OVERFLOW) {
              // Note that this case implies that exchangeRate > EXCHANGE_RATE_MAY_OVERFLOW.
              uint256 exchangeRateUnbased = exchangeRate.div(EXCHANGE_RATE_BASE);
              return stakeAmount.div(exchangeRateUnbased);
            } else {
              return stakeAmount.mul(EXCHANGE_RATE_BASE).div(exchangeRate);
            }
          }
          function updateExchangeRate(
            uint256 numerator,
            uint256 denominator
          )
            internal
            returns (uint256)
          {
            uint256 oldExchangeRate = _EXCHANGE_RATE_;
            // Avoid overflow.
            // Note that the numerator and denominator are both denominated in underlying token units.
            uint256 newExchangeRate;
            if (oldExchangeRate > EXCHANGE_RATE_MAY_OVERFLOW) {
              newExchangeRate = oldExchangeRate.div(denominator).mul(numerator);
            } else {
              newExchangeRate = oldExchangeRate.mul(numerator).div(denominator);
            }
            require(
              newExchangeRate <= MAX_EXCHANGE_RATE,
              'SM1ExchangeRate: Max exchange rate exceeded'
            );
            _EXCHANGE_RATE_SNAPSHOT_COUNT_ = _writeSnapshot(
              _EXCHANGE_RATE_SNAPSHOTS_,
              _EXCHANGE_RATE_SNAPSHOT_COUNT_,
              newExchangeRate
            );
            _EXCHANGE_RATE_ = newExchangeRate;
            return newExchangeRate;
          }
        }
        // SPDX-License-Identifier: AGPL-3.0
        pragma solidity 0.7.5;
        pragma abicoder v2;
        import { SM1Types } from '../lib/SM1Types.sol';
        import { SM1Storage } from './SM1Storage.sol';
        /**
         * @title SM1Snapshots
         * @author dYdX
         *
         * @dev Handles storage and retrieval of historical values by block number.
         *
         *  Note that the snapshot stored at a given block number represents the value as of the end of
         *  that block.
         */
        abstract contract SM1Snapshots {
          /**
           * @dev Writes a snapshot of a value at the current block.
           *
           * @param  snapshots      Storage mapping from snapshot index to snapshot struct.
           * @param  snapshotCount  The total number of snapshots in the provided mapping.
           * @param  newValue       The new value to snapshot at the current block.
           *
           * @return The new snapshot count.
           */
          function _writeSnapshot(
            mapping(uint256 => SM1Types.Snapshot) storage snapshots,
            uint256 snapshotCount,
            uint256 newValue
          )
            internal
            returns (uint256)
          {
            uint256 currentBlock = block.number;
            if (
              snapshotCount != 0 &&
              snapshots[snapshotCount - 1].blockNumber == currentBlock
            ) {
              // If there was a previous snapshot for this block, overwrite it.
              snapshots[snapshotCount - 1].value = newValue;
              return snapshotCount;
            } else {
              snapshots[snapshotCount] = SM1Types.Snapshot(currentBlock, newValue);
              return snapshotCount + 1;
            }
          }
          /**
           * @dev Search for the snapshot value at a given block. Uses binary search.
           *
           *  Reverts if `blockNumber` is greater than the current block number.
           *
           * @param  snapshots      Storage mapping from snapshot index to snapshot struct.
           * @param  snapshotCount  The total number of snapshots in the provided mapping.
           * @param  blockNumber    The block number to search for.
           * @param  initialValue   The value to return if `blockNumber` is before the earliest snapshot.
           *
           * @return The snapshot value at the specified block number.
           */
          function _findValueAtBlock(
            mapping(uint256 => SM1Types.Snapshot) storage snapshots,
            uint256 snapshotCount,
            uint256 blockNumber,
            uint256 initialValue
          )
            internal
            view
            returns (uint256)
          {
            require(
              blockNumber <= block.number,
              'SM1Snapshots: INVALID_BLOCK_NUMBER'
            );
            if (snapshotCount == 0) {
              return initialValue;
            }
            // Check earliest snapshot.
            if (blockNumber < snapshots[0].blockNumber) {
              return initialValue;
            }
            // Check latest snapshot.
            if (blockNumber >= snapshots[snapshotCount - 1].blockNumber) {
              return snapshots[snapshotCount - 1].value;
            }
            uint256 lower = 0;
            uint256 upper = snapshotCount - 1;
            while (upper > lower) {
              uint256 center = upper - (upper - lower) / 2; // Ceil, avoiding overflow.
              SM1Types.Snapshot memory snapshot = snapshots[center];
              if (snapshot.blockNumber == blockNumber) {
                return snapshot.value;
              } else if (snapshot.blockNumber < blockNumber) {
                lower = center;
              } else {
                upper = center - 1;
              }
            }
            return snapshots[lower].value;
          }
        }
        

        File 6 of 6: DydxToken
        // SPDX-License-Identifier: AGPL-3.0
        
        // File contracts/dependencies/open-zeppelin/Context.sol
        
        pragma solidity 0.7.5;
        
        /*
         * @dev Provides information about the current execution context, including the
         * sender of the transaction and its data. While these are generally available
         * via msg.sender and msg.data, they should not be accessed in such a direct
         * manner, since when dealing with GSN meta-transactions the account sending and
         * paying for execution may not be the actual sender (as far as an application
         * is concerned).
         *
         * This contract is only required for intermediate, library-like contracts.
         */
        abstract contract Context {
          function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
          }
        
          function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
          }
        }
        
        
        // File contracts/dependencies/open-zeppelin/IERC20.sol
        
        pragma solidity 0.7.5;
        
        /**
         * @dev Interface of the ERC20 standard as defined in the EIP.
         */
        interface IERC20 {
            /**
             * @dev Returns the amount of tokens in existence.
             */
            function totalSupply() external view returns (uint256);
        
            /**
             * @dev Returns the amount of tokens owned by `account`.
             */
            function balanceOf(address account) external view returns (uint256);
        
            /**
             * @dev Moves `amount` tokens from the caller's account to `recipient`.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transfer(address recipient, uint256 amount) external returns (bool);
        
            /**
             * @dev Returns the remaining number of tokens that `spender` will be
             * allowed to spend on behalf of `owner` through {transferFrom}. This is
             * zero by default.
             *
             * This value changes when {approve} or {transferFrom} are called.
             */
            function allowance(address owner, address spender) external view returns (uint256);
        
            /**
             * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * IMPORTANT: Beware that changing an allowance with this method brings the risk
             * that someone may use both the old and the new allowance by unfortunate
             * transaction ordering. One possible solution to mitigate this race
             * condition is to first reduce the spender's allowance to 0 and set the
             * desired value afterwards:
             * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
             *
             * Emits an {Approval} event.
             */
            function approve(address spender, uint256 amount) external returns (bool);
        
            /**
             * @dev Moves `amount` tokens from `sender` to `recipient` using the
             * allowance mechanism. `amount` is then deducted from the caller's
             * allowance.
             *
             * Returns a boolean value indicating whether the operation succeeded.
             *
             * Emits a {Transfer} event.
             */
            function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
        
            /**
             * @dev Emitted when `value` tokens are moved from one account (`from`) to
             * another (`to`).
             *
             * Note that `value` may be zero.
             */
            event Transfer(address indexed from, address indexed to, uint256 value);
        
            /**
             * @dev Emitted when the allowance of a `spender` for an `owner` is set by
             * a call to {approve}. `value` is the new allowance.
             */
            event Approval(address indexed owner, address indexed spender, uint256 value);
        }
        
        
        // File contracts/dependencies/open-zeppelin/SafeMath.sol
        
        pragma solidity 0.7.5;
        
        /**
         * @dev Wrappers over Solidity's arithmetic operations with added overflow
         * checks.
         *
         * Arithmetic operations in Solidity wrap on overflow. This can easily result
         * in bugs, because programmers usually assume that an overflow raises an
         * error, which is the standard behavior in high level programming languages.
         * `SafeMath` restores this intuition by reverting the transaction when an
         * operation overflows.
         *
         * Using this library instead of the unchecked operations eliminates an entire
         * class of bugs, so it's recommended to use it always.
         */
        library SafeMath {
          /**
           * @dev Returns the addition of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `+` operator.
           *
           * Requirements:
           * - Addition cannot overflow.
           */
          function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, 'SafeMath: addition overflow');
        
            return c;
          }
        
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            return sub(a, b, 'SafeMath: subtraction overflow');
          }
        
          /**
           * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
           * overflow (when the result is negative).
           *
           * Counterpart to Solidity's `-` operator.
           *
           * Requirements:
           * - Subtraction cannot overflow.
           */
          function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            uint256 c = a - b;
        
            return c;
          }
        
          /**
           * @dev Returns the multiplication of two unsigned integers, reverting on
           * overflow.
           *
           * Counterpart to Solidity's `*` operator.
           *
           * Requirements:
           * - Multiplication cannot overflow.
           */
          function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) {
              return 0;
            }
        
            uint256 c = a * b;
            require(c / a == b, 'SafeMath: multiplication overflow');
        
            return c;
          }
        
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(uint256 a, uint256 b) internal pure returns (uint256) {
            return div(a, b, 'SafeMath: division by zero');
          }
        
          /**
           * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
           * division by zero. The result is rounded towards zero.
           *
           * Counterpart to Solidity's `/` operator. Note: this function uses a
           * `revert` opcode (which leaves remaining gas untouched) while Solidity
           * uses an invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            // Solidity only automatically asserts when dividing by 0
            require(b > 0, errorMessage);
            uint256 c = a / b;
            // assert(a == b * c + a % b); // There is no case in which this doesn't hold
        
            return c;
          }
        
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            return mod(a, b, 'SafeMath: modulo by zero');
          }
        
          /**
           * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
           * Reverts with custom message when dividing by zero.
           *
           * Counterpart to Solidity's `%` operator. This function uses a `revert`
           * opcode (which leaves remaining gas untouched) while Solidity uses an
           * invalid opcode to revert (consuming all remaining gas).
           *
           * Requirements:
           * - The divisor cannot be zero.
           */
          function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
          ) internal pure returns (uint256) {
            require(b != 0, errorMessage);
            return a % b;
          }
        }
        
        
        // File contracts/dependencies/open-zeppelin/Address.sol
        
        pragma solidity 0.7.5;
        
        /**
         * @dev Collection of functions related to the address type
         */
        library Address {
          /**
           * @dev Returns true if `account` is a contract.
           *
           * [IMPORTANT]
           * ====
           * It is unsafe to assume that an address for which this function returns
           * false is an externally-owned account (EOA) and not a contract.
           *
           * Among others, `isContract` will return false for the following
           * types of addresses:
           *
           *  - an externally-owned account
           *  - a contract in construction
           *  - an address where a contract will be created
           *  - an address where a contract lived, but was destroyed
           * ====
           */
          function isContract(address account) internal view returns (bool) {
            // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
            // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
            // for accounts without code, i.e. `keccak256('')`
            bytes32 codehash;
            bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
            // solhint-disable-next-line no-inline-assembly
            assembly {
              codehash := extcodehash(account)
            }
            return (codehash != accountHash && codehash != 0x0);
          }
        
          /**
           * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
           * `recipient`, forwarding all available gas and reverting on errors.
           *
           * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
           * of certain opcodes, possibly making contracts go over the 2300 gas limit
           * imposed by `transfer`, making them unable to receive funds via
           * `transfer`. {sendValue} removes this limitation.
           *
           * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
           *
           * IMPORTANT: because control is transferred to `recipient`, care must be
           * taken to not create reentrancy vulnerabilities. Consider using
           * {ReentrancyGuard} or the
           * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
           */
          function sendValue(address payable recipient, uint256 amount) internal {
            require(address(this).balance >= amount, 'Address: insufficient balance');
        
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (bool success, ) = recipient.call{value: amount}('');
            require(success, 'Address: unable to send value, recipient may have reverted');
          }
        }
        
        
        // File contracts/dependencies/open-zeppelin/ERC20.sol
        
        pragma solidity ^0.7.5;
        
        
        
        
        /**
         * @dev Implementation of the {IERC20} interface.
         *
         * This implementation is agnostic to the way tokens are created. This means
         * that a supply mechanism has to be added in a derived contract using {_mint}.
         * For a generic mechanism see {ERC20PresetMinterPauser}.
         *
         * TIP: For a detailed writeup see our guide
         * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
         * to implement supply mechanisms].
         *
         * We have followed general OpenZeppelin guidelines: functions revert instead
         * of returning `false` on failure. This behavior is nonetheless conventional
         * and does not conflict with the expectations of ERC20 applications.
         *
         * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
         * This allows applications to reconstruct the allowance for all accounts just
         * by listening to said events. Other implementations of the EIP may not emit
         * these events, as it isn't required by the specification.
         *
         * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
         * functions have been added to mitigate the well-known issues around setting
         * allowances. See {IERC20-approve}.
         */
        contract ERC20 is Context, IERC20 {
            using SafeMath for uint256;
            using Address for address;
        
            mapping (address => uint256) private _balances;
        
            mapping (address => mapping (address => uint256)) private _allowances;
        
            uint256 private _totalSupply;
        
            string internal _name;
            string internal _symbol;
            uint8 private _decimals;
        
            /**
             * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
             * a default value of 18.
             *
             * To select a different value for {decimals}, use {_setupDecimals}.
             *
             * All three of these values are immutable: they can only be set once during
             * construction.
             */
            constructor (string memory name, string memory symbol) public {
                _name = name;
                _symbol = symbol;
                _decimals = 18;
            }
        
            /**
             * @dev Returns the name of the token.
             */
            function name() virtual public view returns (string memory) {
                return _name;
            }
        
            /**
             * @dev Returns the symbol of the token, usually a shorter version of the
             * name.
             */
            function symbol() virtual public view returns (string memory) {
                return _symbol;
            }
        
            /**
             * @dev Returns the number of decimals used to get its user representation.
             * For example, if `decimals` equals `2`, a balance of `505` tokens should
             * be displayed to a user as `5,05` (`505 / 10 ** 2`).
             *
             * Tokens usually opt for a value of 18, imitating the relationship between
             * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
             * called.
             *
             * NOTE: This information is only used for _display_ purposes: it in
             * no way affects any of the arithmetic of the contract, including
             * {IERC20-balanceOf} and {IERC20-transfer}.
             */
            function decimals() virtual public view returns (uint8) {
                return _decimals;
            }
        
            /**
             * @dev See {IERC20-totalSupply}.
             */
            function totalSupply() public view override returns (uint256) {
                return _totalSupply;
            }
        
            /**
             * @dev See {IERC20-balanceOf}.
             */
            function balanceOf(address account) public view override returns (uint256) {
                return _balances[account];
            }
        
            /**
             * @dev See {IERC20-transfer}.
             *
             * Requirements:
             *
             * - `recipient` cannot be the zero address.
             * - the caller must have a balance of at least `amount`.
             */
            function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(_msgSender(), recipient, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-allowance}.
             */
            function allowance(address owner, address spender) public view virtual override returns (uint256) {
                return _allowances[owner][spender];
            }
        
            /**
             * @dev See {IERC20-approve}.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function approve(address spender, uint256 amount) public virtual override returns (bool) {
                _approve(_msgSender(), spender, amount);
                return true;
            }
        
            /**
             * @dev See {IERC20-transferFrom}.
             *
             * Emits an {Approval} event indicating the updated allowance. This is not
             * required by the EIP. See the note at the beginning of {ERC20};
             *
             * Requirements:
             * - `sender` and `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             * - the caller must have allowance for ``sender``'s tokens of at least
             * `amount`.
             */
            function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                _transfer(sender, recipient, amount);
                _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                return true;
            }
        
            /**
             * @dev Atomically increases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             */
            function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                return true;
            }
        
            /**
             * @dev Atomically decreases the allowance granted to `spender` by the caller.
             *
             * This is an alternative to {approve} that can be used as a mitigation for
             * problems described in {IERC20-approve}.
             *
             * Emits an {Approval} event indicating the updated allowance.
             *
             * Requirements:
             *
             * - `spender` cannot be the zero address.
             * - `spender` must have allowance for the caller of at least
             * `subtractedValue`.
             */
            function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                return true;
            }
        
            /**
             * @dev Moves tokens `amount` from `sender` to `recipient`.
             *
             * This is internal function is equivalent to {transfer}, and can be used to
             * e.g. implement automatic token fees, slashing mechanisms, etc.
             *
             * Emits a {Transfer} event.
             *
             * Requirements:
             *
             * - `sender` cannot be the zero address.
             * - `recipient` cannot be the zero address.
             * - `sender` must have a balance of at least `amount`.
             */
            function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                require(sender != address(0), "ERC20: transfer from the zero address");
                require(recipient != address(0), "ERC20: transfer to the zero address");
        
                _beforeTokenTransfer(sender, recipient, amount);
        
                _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                _balances[recipient] = _balances[recipient].add(amount);
                emit Transfer(sender, recipient, amount);
            }
        
            /** @dev Creates `amount` tokens and assigns them to `account`, increasing
             * the total supply.
             *
             * Emits a {Transfer} event with `from` set to the zero address.
             *
             * Requirements
             *
             * - `to` cannot be the zero address.
             */
            function _mint(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: mint to the zero address");
        
                _beforeTokenTransfer(address(0), account, amount);
        
                _totalSupply = _totalSupply.add(amount);
                _balances[account] = _balances[account].add(amount);
                emit Transfer(address(0), account, amount);
            }
        
            /**
             * @dev Destroys `amount` tokens from `account`, reducing the
             * total supply.
             *
             * Emits a {Transfer} event with `to` set to the zero address.
             *
             * Requirements
             *
             * - `account` cannot be the zero address.
             * - `account` must have at least `amount` tokens.
             */
            function _burn(address account, uint256 amount) internal virtual {
                require(account != address(0), "ERC20: burn from the zero address");
        
                _beforeTokenTransfer(account, address(0), amount);
        
                _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                _totalSupply = _totalSupply.sub(amount);
                emit Transfer(account, address(0), amount);
            }
        
            /**
             * @dev Sets `amount` as the allowance of `spender` over the `owner`s tokens.
             *
             * This is internal function is equivalent to `approve`, and can be used to
             * e.g. set automatic allowances for certain subsystems, etc.
             *
             * Emits an {Approval} event.
             *
             * Requirements:
             *
             * - `owner` cannot be the zero address.
             * - `spender` cannot be the zero address.
             */
            function _approve(address owner, address spender, uint256 amount) internal virtual {
                require(owner != address(0), "ERC20: approve from the zero address");
                require(spender != address(0), "ERC20: approve to the zero address");
        
                _allowances[owner][spender] = amount;
                emit Approval(owner, spender, amount);
            }
        
            /**
             * @dev Sets {decimals} to a value other than the default one of 18.
             *
             * WARNING: This function should only be called from the constructor. Most
             * applications that interact with token contracts will not expect
             * {decimals} to ever change, and may work incorrectly if it does.
             */
            function _setupDecimals(uint8 decimals_) internal {
                _decimals = decimals_;
            }
        
            /**
             * @dev Hook that is called before any transfer of tokens. This includes
             * minting and burning.
             *
             * Calling conditions:
             *
             * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
             * will be to transferred to `to`.
             * - when `from` is zero, `amount` tokens will be minted for `to`.
             * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
             * - `from` and `to` are never both zero.
             *
             * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
             */
            function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
        }
        
        
        // File contracts/dependencies/open-zeppelin/Ownable.sol
        
        pragma solidity 0.7.5;
        
        /**
         * @dev Contract module which provides a basic access control mechanism, where
         * there is an account (an owner) that can be granted exclusive access to
         * specific functions.
         *
         * By default, the owner account will be the one that deploys the contract. This
         * can later be changed with {transferOwnership}.
         *
         * This module is used through inheritance. It will make available the modifier
         * `onlyOwner`, which can be applied to your functions to restrict their use to
         * the owner.
         */
        contract Ownable is Context {
          address private _owner;
        
          event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        
          /**
           * @dev Initializes the contract setting the deployer as the initial owner.
           */
          constructor() {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
          }
        
          /**
           * @dev Returns the address of the current owner.
           */
          function owner() public view returns (address) {
            return _owner;
          }
        
          /**
           * @dev Throws if called by any account other than the owner.
           */
          modifier onlyOwner() {
            require(_owner == _msgSender(), 'Ownable: caller is not the owner');
            _;
          }
        
          /**
           * @dev Leaves the contract without owner. It will not be possible to call
           * `onlyOwner` functions anymore. Can only be called by the current owner.
           *
           * NOTE: Renouncing ownership will leave the contract without an owner,
           * thereby removing any functionality that is only available to the owner.
           */
          function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
          }
        
          /**
           * @dev Transfers ownership of the contract to a new account (`newOwner`).
           * Can only be called by the current owner.
           */
          function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), 'Ownable: new owner is the zero address');
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
          }
        }
        
        
        // File contracts/interfaces/IGovernancePowerDelegationERC20.sol
        
        pragma solidity 0.7.5;
        
        interface IGovernancePowerDelegationERC20 {
        
          enum DelegationType {
            VOTING_POWER,
            PROPOSITION_POWER
          }
        
          /**
           * @dev Emitted when a user delegates governance power to another user.
           *
           * @param  delegator       The delegator.
           * @param  delegatee       The delegatee.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegateChanged(
            address indexed delegator,
            address indexed delegatee,
            DelegationType delegationType
          );
        
          /**
           * @dev Emitted when an action changes the delegated power of a user.
           *
           * @param  user            The user whose delegated power has changed.
           * @param  amount          The new amount of delegated power for the user.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          event DelegatedPowerChanged(address indexed user, uint256 amount, DelegationType delegationType);
        
          /**
           * @dev Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(address delegatee, DelegationType delegationType) external virtual;
        
          /**
           * @dev Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The user to which the power will be delegated.
           */
          function delegate(address delegatee) external virtual;
        
          /**
           * @dev Returns the delegatee of an user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(address delegator, DelegationType delegationType)
            external
            view
            virtual
            returns (address);
        
          /**
           * @dev Returns the current delegated power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(address user, DelegationType delegationType)
            external
            view
            virtual
            returns (uint256);
        
          /**
           * @dev Returns the delegated power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            external
            view
            virtual
            returns (uint256);
        }
        
        
        // File contracts/governance/token/GovernancePowerDelegationERC20Mixin.sol
        
        pragma solidity 0.7.5;
        
        
        
        /**
         * @title GovernancePowerDelegationERC20Mixin
         * @author dYdX
         *
         * @dev Provides support for two types of governance powers, both endowed by the governance
         *  token, and separately delegatable. Provides functions for delegation and for querying a user's
         *  power at a certain block number.
         */
        abstract contract GovernancePowerDelegationERC20Mixin is
          ERC20,
          IGovernancePowerDelegationERC20
        {
          using SafeMath for uint256;
        
          // ============ Constants ============
        
          /// @notice EIP-712 typehash for delegation by signature of a specific governance power type.
          bytes32 public constant DELEGATE_BY_TYPE_TYPEHASH = keccak256(
            'DelegateByType(address delegatee,uint256 type,uint256 nonce,uint256 expiry)'
          );
        
          /// @notice EIP-712 typehash for delegation by signature of all governance powers.
          bytes32 public constant DELEGATE_TYPEHASH = keccak256(
            'Delegate(address delegatee,uint256 nonce,uint256 expiry)'
          );
        
          // ============ Structs ============
        
          /// @dev Snapshot of a value on a specific block, used to track voting power for proposals.
          struct Snapshot {
            uint128 blockNumber;
            uint128 value;
          }
        
          // ============ External Functions ============
        
          /**
           * @notice Delegates a specific governance power to a delegatee.
           *
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function delegateByType(
            address delegatee,
            DelegationType delegationType
          )
            external
            override
          {
            _delegateByType(msg.sender, delegatee, delegationType);
          }
        
          /**
           * @notice Delegates all governance powers to a delegatee.
           *
           * @param  delegatee  The address to delegate power to.
           */
          function delegate(
            address delegatee
          )
            external
            override
          {
            _delegateByType(msg.sender, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(msg.sender, delegatee, DelegationType.PROPOSITION_POWER);
          }
        
          /**
           * @notice Returns the delegatee of a user.
           *
           * @param  delegator       The address of the delegator.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           */
          function getDelegateeByType(
            address delegator,
            DelegationType delegationType
          )
            external
            override
            view
            returns (address)
          {
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
        
            return _getDelegatee(delegator, delegates);
          }
        
          /**
           * @notice Returns the current power of a user. The current power is the power delegated
           *  at the time of the last snapshot.
           *
           * @param  user            The user whose power to query.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerCurrent(
            address user,
            DelegationType delegationType
          )
            external
            override
            view
            returns (uint256)
          {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
        
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, block.number);
          }
        
          /**
           * @notice Returns the power of a user at a certain block.
           *
           * @param  user            The user whose power to query.
           * @param  blockNumber     The block number at which to get the user's power.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function getPowerAtBlock(
            address user,
            uint256 blockNumber,
            DelegationType delegationType
          )
            external
            override
            view
            returns (uint256)
          {
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
        
            return _searchByBlockNumber(snapshots, snapshotsCounts, user, blockNumber);
          }
        
          // ============ Internal Functions ============
        
          /**
           * @dev Delegates one specific power to a delegatee.
           *
           * @param  delegator       The user whose power to delegate.
           * @param  delegatee       The address to delegate power to.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _delegateByType(
            address delegator,
            address delegatee,
            DelegationType delegationType
          )
            internal
          {
            require(
              delegatee != address(0),
              'INVALID_DELEGATEE'
            );
        
            (, , mapping(address => address) storage delegates) = _getDelegationDataByType(delegationType);
        
            uint256 delegatorBalance = balanceOf(delegator);
        
            address previousDelegatee = _getDelegatee(delegator, delegates);
        
            delegates[delegator] = delegatee;
        
            _moveDelegatesByType(previousDelegatee, delegatee, delegatorBalance, delegationType);
            emit DelegateChanged(delegator, delegatee, delegationType);
          }
        
          /**
           * @dev Moves power from one user to another.
           *
           * @param  from            The user from which delegated power is moved.
           * @param  to              The user that will receive the delegated power.
           * @param  amount          The amount of power to be moved.
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _moveDelegatesByType(
            address from,
            address to,
            uint256 amount,
            DelegationType delegationType
          )
            internal
          {
            if (from == to) {
              return;
            }
        
            (
              mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
              mapping(address => uint256) storage snapshotsCounts,
              // delegates
            ) = _getDelegationDataByType(delegationType);
        
            if (from != address(0)) {
              uint256 previous = 0;
              uint256 fromSnapshotsCount = snapshotsCounts[from];
        
              if (fromSnapshotsCount != 0) {
                previous = snapshots[from][fromSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(from);
              }
        
              uint256 newAmount = previous.sub(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                from,
                uint128(newAmount)
              );
        
              emit DelegatedPowerChanged(from, newAmount, delegationType);
            }
        
            if (to != address(0)) {
              uint256 previous = 0;
              uint256 toSnapshotsCount = snapshotsCounts[to];
              if (toSnapshotsCount != 0) {
                previous = snapshots[to][toSnapshotsCount - 1].value;
              } else {
                previous = balanceOf(to);
              }
        
              uint256 newAmount = previous.add(amount);
              _writeSnapshot(
                snapshots,
                snapshotsCounts,
                to,
                uint128(newAmount)
              );
        
              emit DelegatedPowerChanged(to, newAmount, delegationType);
            }
          }
        
          /**
           * @dev Searches for a balance snapshot by block number using binary search.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  user             The user for which the snapshot is being searched.
           * @param  blockNumber      The block number being searched.
           */
          function _searchByBlockNumber(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address user,
            uint256 blockNumber
          )
            internal
            view
            returns (uint256)
          {
            require(
              blockNumber <= block.number,
              'INVALID_BLOCK_NUMBER'
            );
        
            uint256 snapshotsCount = snapshotsCounts[user];
        
            if (snapshotsCount == 0) {
              return balanceOf(user);
            }
        
            // First check most recent balance
            if (snapshots[user][snapshotsCount - 1].blockNumber <= blockNumber) {
              return snapshots[user][snapshotsCount - 1].value;
            }
        
            // Next check implicit zero balance
            if (snapshots[user][0].blockNumber > blockNumber) {
              return 0;
            }
        
            uint256 lower = 0;
            uint256 upper = snapshotsCount - 1;
            while (upper > lower) {
              uint256 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
              Snapshot memory snapshot = snapshots[user][center];
              if (snapshot.blockNumber == blockNumber) {
                return snapshot.value;
              } else if (snapshot.blockNumber < blockNumber) {
                lower = center;
              } else {
                upper = center - 1;
              }
            }
            return snapshots[user][lower].value;
          }
        
          /**
           * @dev Returns delegation data (snapshot, snapshotsCount, delegates) by delegation type.
           *
           *  Note: This mixin contract does not itself define any storage, and we require the inheriting
           *  contract to implement this method to provide access to the relevant mappings in storage.
           *  This pattern was implemented by Aave for legacy reasons and we have decided not to change it.
           *
           * @param  delegationType  The type of power (VOTING_POWER, PROPOSITION_POWER).
           */
          function _getDelegationDataByType(
            DelegationType delegationType
          )
            internal
            virtual
            view
            returns (
              mapping(address => mapping(uint256 => Snapshot)) storage, // snapshots
              mapping(address => uint256) storage, // snapshotsCount
              mapping(address => address) storage // delegates
            );
        
          /**
           * @dev Writes a snapshot of a user's token/power balance.
           *
           * @param  snapshots        The mapping of snapshots by user.
           * @param  snapshotsCounts  The mapping of the number of snapshots by user.
           * @param  owner            The user whose power to snapshot.
           * @param  newValue         The new balance to snapshot at the current block.
           */
          function _writeSnapshot(
            mapping(address => mapping(uint256 => Snapshot)) storage snapshots,
            mapping(address => uint256) storage snapshotsCounts,
            address owner,
            uint128 newValue
          )
            internal
          {
            uint128 currentBlock = uint128(block.number);
        
            uint256 ownerSnapshotsCount = snapshotsCounts[owner];
            mapping(uint256 => Snapshot) storage ownerSnapshots = snapshots[owner];
        
            if (
              ownerSnapshotsCount != 0 &&
              ownerSnapshots[ownerSnapshotsCount - 1].blockNumber == currentBlock
            ) {
              // Doing multiple operations in the same block
              ownerSnapshots[ownerSnapshotsCount - 1].value = newValue;
            } else {
              ownerSnapshots[ownerSnapshotsCount] = Snapshot(currentBlock, newValue);
              snapshotsCounts[owner] = ownerSnapshotsCount + 1;
            }
          }
        
          /**
           * @dev Returns the delegatee of a user. If a user never performed any delegation, their
           *  delegated address will be 0x0, in which case we return the user's own address.
           *
           * @param  delegator  The address of the user for which return the delegatee.
           * @param  delegates  The mapping of delegates for a particular type of delegation.
           */
          function _getDelegatee(
            address delegator,
            mapping(address => address) storage delegates
          )
            internal
            view
            returns (address)
          {
            address previousDelegatee = delegates[delegator];
        
            if (previousDelegatee == address(0)) {
              return delegator;
            }
        
            return previousDelegatee;
          }
        }
        
        
        // File contracts/governance/token/DydxToken.sol
        
        pragma solidity 0.7.5;
        
        
        
        
        /**
         * @title DydxToken
         * @author dYdX
         *
         * @notice The dYdX governance token.
         */
        contract DydxToken is
          GovernancePowerDelegationERC20Mixin,
          Ownable
        {
          using SafeMath for uint256;
        
          // ============ Events ============
        
          /**
           * @dev Emitted when an address has been added to or removed from the token transfer allowlist.
           *
           * @param  account    Address that was added to or removed from the token transfer allowlist.
           * @param  isAllowed  True if the address was added to the allowlist, false if removed.
           */
          event TransferAllowlistUpdated(
            address account,
            bool isAllowed
          );
        
          /**
           * @dev Emitted when the transfer restriction timestamp is reassigned.
           *
           * @param  transfersRestrictedBefore  The new timestamp on and after which non-allowlisted
           *                                    transfers may occur.
           */
          event TransfersRestrictedBeforeUpdated(
            uint256 transfersRestrictedBefore
          );
        
          // ============ Constants ============
        
          string internal constant NAME = 'dYdX';
          string internal constant SYMBOL = 'DYDX';
        
          uint256 public constant INITIAL_SUPPLY = 1_000_000_000 ether;
        
          bytes32 public immutable DOMAIN_SEPARATOR;
          bytes public constant EIP712_VERSION = '1';
          bytes32 public constant EIP712_DOMAIN = keccak256(
            'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
          );
          bytes32 public constant PERMIT_TYPEHASH = keccak256(
            'Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)'
          );
        
          /// @notice Minimum time between mints.
          uint256 public constant MINT_MIN_INTERVAL = 365 days;
        
          /// @notice Cap on the percentage of the total supply that can be minted at each mint.
          ///  Denominated in percentage points (units out of 100).
          uint256 public immutable MINT_MAX_PERCENT;
        
          /// @notice The timestamp on and after which the transfer restriction must be lifted.
          uint256 public immutable TRANSFER_RESTRICTION_LIFTED_NO_LATER_THAN;
        
          // ============ Storage ============
        
          /// @dev Mapping from (owner) => (next valid nonce) for EIP-712 signatures.
          mapping(address => uint256) internal _nonces;
        
          mapping(address => mapping(uint256 => Snapshot)) public _votingSnapshots;
          mapping(address => uint256) public _votingSnapshotsCounts;
          mapping(address => address) public _votingDelegates;
        
          mapping(address => mapping(uint256 => Snapshot)) public _propositionPowerSnapshots;
          mapping(address => uint256) public _propositionPowerSnapshotsCounts;
          mapping(address => address) public _propositionPowerDelegates;
        
          /// @notice Snapshots of the token total supply, at each block where the total supply has changed.
          mapping(uint256 => Snapshot) public _totalSupplySnapshots;
        
          /// @notice Number of snapshots of the token total supply.
          uint256 public _totalSupplySnapshotsCount;
        
          /// @notice Allowlist of addresses which may send or receive tokens while transfers are
          ///  otherwise restricted.
          mapping(address => bool) public _tokenTransferAllowlist;
        
          /// @notice The timestamp on and after which minting may occur.
          uint256 public _mintingRestrictedBefore;
        
          /// @notice The timestamp on and after which non-allowlisted transfers may occur.
          uint256 public _transfersRestrictedBefore;
        
          // ============ Constructor ============
        
          /**
           * @notice Constructor.
           *
           * @param  distributor                           The address which will receive the initial supply of tokens.
           * @param  transfersRestrictedBefore             Timestamp, before which transfers are restricted unless the
           *                                               origin or destination address is in the allowlist.
           * @param  transferRestrictionLiftedNoLaterThan  Timestamp, which is the maximum timestamp that transfer
           *                                               restrictions can be extended to.
           * @param  mintingRestrictedBefore               Timestamp, before which minting is not allowed.
           * @param  mintMaxPercent                        Cap on the percentage of the total supply that can be minted at
           *                                               each mint.
           */
          constructor(
            address distributor,
            uint256 transfersRestrictedBefore,
            uint256 transferRestrictionLiftedNoLaterThan,
            uint256 mintingRestrictedBefore,
            uint256 mintMaxPercent
          )
            ERC20(NAME, SYMBOL)
          {
            uint256 chainId;
        
            // solium-disable-next-line
            assembly {
              chainId := chainid()
            }
        
            DOMAIN_SEPARATOR = keccak256(
              abi.encode(
                EIP712_DOMAIN,
                keccak256(bytes(NAME)),
                keccak256(bytes(EIP712_VERSION)),
                chainId,
                address(this)
              )
            );
        
            // Validate and set parameters.
            require(
              transfersRestrictedBefore > block.timestamp,
              'TRANSFERS_RESTRICTED_BEFORE_TOO_EARLY'
            );
            require(
              transfersRestrictedBefore <= transferRestrictionLiftedNoLaterThan,
              'MAX_TRANSFER_RESTRICTION_TOO_EARLY'
            );
            require(
              mintingRestrictedBefore > block.timestamp,
              'MINTING_RESTRICTED_BEFORE_TOO_EARLY'
            );
            _transfersRestrictedBefore = transfersRestrictedBefore;
            TRANSFER_RESTRICTION_LIFTED_NO_LATER_THAN = transferRestrictionLiftedNoLaterThan;
            _mintingRestrictedBefore = mintingRestrictedBefore;
            MINT_MAX_PERCENT = mintMaxPercent;
        
            // Mint the initial supply.
            _mint(distributor, INITIAL_SUPPLY);
        
            emit TransfersRestrictedBeforeUpdated(transfersRestrictedBefore);
          }
        
          // ============ Other Functions ============
        
          /**
           * @notice Adds addresses to the token transfer allowlist. Reverts if any of the addresses
           *  already exist in the allowlist. Only callable by owner.
           *
           * @param  addressesToAdd  Addresses to add to the token transfer allowlist.
           */
          function addToTokenTransferAllowlist(
            address[] calldata addressesToAdd
          )
            external
            onlyOwner
          {
            for (uint256 i = 0; i < addressesToAdd.length; i++) {
              require(
                !_tokenTransferAllowlist[addressesToAdd[i]],
                'ADDRESS_EXISTS_IN_TRANSFER_ALLOWLIST'
              );
              _tokenTransferAllowlist[addressesToAdd[i]] = true;
              emit TransferAllowlistUpdated(addressesToAdd[i], true);
            }
          }
        
          /**
           * @notice Removes addresses from the token transfer allowlist. Reverts if any of the addresses
           *  don't exist in the allowlist. Only callable by owner.
           *
           * @param  addressesToRemove  Addresses to remove from the token transfer allowlist.
           */
          function removeFromTokenTransferAllowlist(
            address[] calldata addressesToRemove
          )
            external
            onlyOwner
          {
            for (uint256 i = 0; i < addressesToRemove.length; i++) {
              require(
                _tokenTransferAllowlist[addressesToRemove[i]],
                'ADDRESS_DOES_NOT_EXIST_IN_TRANSFER_ALLOWLIST'
              );
              _tokenTransferAllowlist[addressesToRemove[i]] = false;
              emit TransferAllowlistUpdated(addressesToRemove[i], false);
            }
          }
        
          /**
           * @notice Updates the transfer restriction. Reverts if the transfer restriction has already passed,
           *  the new transfer restriction is earlier than the previous one, or the new transfer restriction is
           *  after the maximum transfer restriction.
           *
           * @param  transfersRestrictedBefore  The timestamp on and after which non-allowlisted transfers may occur.
           */
          function updateTransfersRestrictedBefore(
            uint256 transfersRestrictedBefore
          )
            external
            onlyOwner
          {
            uint256 previousTransfersRestrictedBefore = _transfersRestrictedBefore;
            require(
              block.timestamp < previousTransfersRestrictedBefore,
              'TRANSFER_RESTRICTION_ENDED'
            );
            require(
              previousTransfersRestrictedBefore <= transfersRestrictedBefore,
              'NEW_TRANSFER_RESTRICTION_TOO_EARLY'
            );
            require(
              transfersRestrictedBefore <= TRANSFER_RESTRICTION_LIFTED_NO_LATER_THAN,
              'AFTER_MAX_TRANSFER_RESTRICTION'
            );
        
            _transfersRestrictedBefore = transfersRestrictedBefore;
        
            emit TransfersRestrictedBeforeUpdated(transfersRestrictedBefore);
          }
        
          /**
           * @notice Mint new tokens. Only callable by owner after the required time period has elapsed.
           *
           * @param  recipient  The address to receive minted tokens.
           * @param  amount     The number of tokens to mint.
           */
          function mint(
            address recipient,
            uint256 amount
          )
            external
            onlyOwner
          {
            require(
              block.timestamp >= _mintingRestrictedBefore,
              'MINT_TOO_EARLY'
            );
            require(
              amount <= totalSupply().mul(MINT_MAX_PERCENT).div(100),
              'MAX_MINT_EXCEEDED'
            );
        
            // Update the next allowed minting time.
            _mintingRestrictedBefore = block.timestamp.add(MINT_MIN_INTERVAL);
        
            // Mint the amount.
            _mint(recipient, amount);
          }
        
          /**
           * @notice Implements the permit function as specified in EIP-2612.
           *
           * @param  owner     Address of the token owner.
           * @param  spender   Address of the spender.
           * @param  value     Amount of allowance.
           * @param  deadline  Expiration timestamp for the signature.
           * @param  v         Signature param.
           * @param  r         Signature param.
           * @param  s         Signature param.
           */
          function permit(
            address owner,
            address spender,
            uint256 value,
            uint256 deadline,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            external
          {
            require(
              owner != address(0),
              'INVALID_OWNER'
            );
            require(
              block.timestamp <= deadline,
              'INVALID_EXPIRATION'
            );
            uint256 currentValidNonce = _nonces[owner];
            bytes32 digest = keccak256(
              abi.encodePacked(
                '\x19\x01',
                DOMAIN_SEPARATOR,
                keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, currentValidNonce, deadline))
              )
            );
        
            require(
              owner == ecrecover(digest, v, r, s),
              'INVALID_SIGNATURE'
            );
            _nonces[owner] = currentValidNonce.add(1);
            _approve(owner, spender, value);
          }
        
          /**
           * @notice Get the next valid nonce for EIP-712 signatures.
           *
           *  This nonce should be used when signing for any of the following functions:
           *   - permit()
           *   - delegateByTypeBySig()
           *   - delegateBySig()
           */
          function nonces(
            address owner
          )
            external
            view
            returns (uint256)
          {
            return _nonces[owner];
          }
        
          function transfer(
            address recipient,
            uint256 amount
          )
            public
            override
            returns (bool)
          {
            _requireTransferAllowed(_msgSender(), recipient);
            return super.transfer(recipient, amount);
          }
        
          function transferFrom(
            address sender,
            address recipient,
            uint256 amount
          )
            public
            override
            returns (bool)
          {
            _requireTransferAllowed(sender, recipient);
            return super.transferFrom(sender, recipient, amount);
          }
        
          /**
           * @dev Override _mint() to write a snapshot whenever the total supply changes.
           *
           *  These snapshots are intended to be used by the governance strategy.
           *
           *  Note that the ERC20 _burn() function is never used. If desired, an official burn mechanism
           *  could be implemented external to this contract, and accounted for in the governance strategy.
           */
          function _mint(
            address account,
            uint256 amount
          )
            internal
            override
          {
            super._mint(account, amount);
        
            uint256 snapshotsCount = _totalSupplySnapshotsCount;
            uint128 currentBlock = uint128(block.number);
            uint128 newValue = uint128(totalSupply());
        
            // Note: There is no special case for the total supply being updated multiple times in the same
            // block. That should never occur.
            _totalSupplySnapshots[snapshotsCount] = Snapshot(currentBlock, newValue);
            _totalSupplySnapshotsCount = snapshotsCount.add(1);
          }
        
          function _requireTransferAllowed(
            address sender,
            address recipient
          )
            view
            internal
          {
            // Compare against the constant `TRANSFER_RESTRICTION_LIFTED_NO_LATER_THAN` first
            // to avoid additional gas costs from reading from storage.
            if (
              block.timestamp < TRANSFER_RESTRICTION_LIFTED_NO_LATER_THAN &&
              block.timestamp < _transfersRestrictedBefore
            ) {
              // While transfers are restricted, a transfer is permitted if either the sender or the
              // recipient is on the allowlist.
              require(
                _tokenTransferAllowlist[sender] || _tokenTransferAllowlist[recipient],
                'NON_ALLOWLIST_TRANSFERS_DISABLED'
              );
            }
          }
        
          /**
           * @dev Writes a snapshot before any transfer operation, including: _transfer, _mint and _burn.
           *  - On _transfer, it writes snapshots for both 'from' and 'to'.
           *  - On _mint, only for `to`.
           *  - On _burn, only for `from`.
           *
           * @param  from    The sender.
           * @param  to      The recipient.
           * @param  amount  The amount being transfered.
           */
          function _beforeTokenTransfer(
            address from,
            address to,
            uint256 amount
          )
            internal
            override
          {
            address votingFromDelegatee = _getDelegatee(from, _votingDelegates);
            address votingToDelegatee = _getDelegatee(to, _votingDelegates);
        
            _moveDelegatesByType(
              votingFromDelegatee,
              votingToDelegatee,
              amount,
              DelegationType.VOTING_POWER
            );
        
            address propPowerFromDelegatee = _getDelegatee(from, _propositionPowerDelegates);
            address propPowerToDelegatee = _getDelegatee(to, _propositionPowerDelegates);
        
            _moveDelegatesByType(
              propPowerFromDelegatee,
              propPowerToDelegatee,
              amount,
              DelegationType.PROPOSITION_POWER
            );
          }
        
          function _getDelegationDataByType(
            DelegationType delegationType
          )
            internal
            override
            view
            returns (
              mapping(address => mapping(uint256 => Snapshot)) storage, // snapshots
              mapping(address => uint256) storage, // snapshots count
              mapping(address => address) storage // delegatees list
            )
          {
            if (delegationType == DelegationType.VOTING_POWER) {
              return (_votingSnapshots, _votingSnapshotsCounts, _votingDelegates);
            } else {
              return (
                _propositionPowerSnapshots,
                _propositionPowerSnapshotsCounts,
                _propositionPowerDelegates
              );
            }
          }
        
          /**
           * @dev Delegates specific governance power from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee       The address to delegate votes to.
           * @param  delegationType  The type of delegation (VOTING_POWER, PROPOSITION_POWER).
           * @param  nonce           The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry          Expiration timestamp for the signature.
           * @param  v               Signature param.
           * @param  r               Signature param.
           * @param  s               Signature param.
           */
          function delegateByTypeBySig(
            address delegatee,
            DelegationType delegationType,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            public
          {
            bytes32 structHash = keccak256(
              abi.encode(DELEGATE_BY_TYPE_TYPEHASH, delegatee, uint256(delegationType), nonce, expiry)
            );
            bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(
              signer != address(0),
              'INVALID_SIGNATURE'
            );
            require(
              nonce == _nonces[signer]++,
              'INVALID_NONCE'
            );
            require(
              block.timestamp <= expiry,
              'INVALID_EXPIRATION'
            );
            _delegateByType(signer, delegatee, delegationType);
          }
        
          /**
           * @dev Delegates both governance powers from signer to `delegatee` using an EIP-712 signature.
           *
           * @param  delegatee  The address to delegate votes to.
           * @param  nonce      The signer's nonce for EIP-712 signatures on this contract.
           * @param  expiry     Expiration timestamp for the signature.
           * @param  v          Signature param.
           * @param  r          Signature param.
           * @param  s          Signature param.
           */
          function delegateBySig(
            address delegatee,
            uint256 nonce,
            uint256 expiry,
            uint8 v,
            bytes32 r,
            bytes32 s
          )
            public
          {
            bytes32 structHash = keccak256(abi.encode(DELEGATE_TYPEHASH, delegatee, nonce, expiry));
            bytes32 digest = keccak256(abi.encodePacked('\x19\x01', DOMAIN_SEPARATOR, structHash));
            address signer = ecrecover(digest, v, r, s);
            require(
              signer != address(0),
              'INVALID_SIGNATURE'
            );
            require(
              nonce == _nonces[signer]++,
              'INVALID_NONCE'
            );
            require(
              block.timestamp <= expiry,
              'INVALID_EXPIRATION'
            );
            _delegateByType(signer, delegatee, DelegationType.VOTING_POWER);
            _delegateByType(signer, delegatee, DelegationType.PROPOSITION_POWER);
          }
        }