creation_sourcecode: {{
    "language": "Solidity",
    "sources": {
      "@helix-foundation/currency-dev/contracts/clone/CloneFactory.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/*\nThe MIT License (MIT)\n\nCopyright (c) 2018 Murray Software, LLC.\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be included\nin all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\nOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n*/\n/* solhint-disable */\n\n// See the EIP-1167: http://eips.ethereum.org/EIPS/eip-1167 and\n// clone-factory: https://github.com/optionality/clone-factory for details.\n\nabstract contract CloneFactory {\n    function createClone(address target) internal returns (address result) {\n        bytes20 targetBytes = bytes20(target);\n        assembly {\n            let clone := mload(0x40)\n            mstore(\n                clone,\n                0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000\n            )\n            mstore(add(clone, 0x14), targetBytes)\n            mstore(\n                add(clone, 0x28),\n                0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000\n            )\n            result := create(0, clone, 0x37)\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/DelegatePermit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// Heavily inspired by:\n// OpenZeppelin Contracts v4.4.1 (token/Delegate/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol\";\n\n/**\n * @dev Abstract contract including helper functions to allow delegation by signature using\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {_verifyDelegatePermit} internal method, verifies a signature specifying permission to receive delegation power\n *\n */\nabstract contract DelegatePermit is EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private constant _DELEGATE_TYPEHASH =\n        keccak256(\n            \"Delegate(address delegator,address delegatee,uint256 nonce,uint256 deadline)\"\n        );\n\n    /**\n     * @notice Verify that the given delegate signature is valid, throws if not\n     * @param delegator The address delegating\n     * @param delegatee The address being delegated to\n     * @param deadline The deadling of the delegation after which it will be invalid\n     * @param v The v part of the signature\n     * @param r The r part of the signature\n     * @param s The s part of the signature\n     */\n    function _verifyDelegatePermit(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        require(\n            block.timestamp <= deadline,\n            \"DelegatePermit: expired deadline\"\n        );\n        require(delegator != address(0), \"invalid delegator\");\n\n        bytes32 structHash = keccak256(\n            abi.encode(\n                _DELEGATE_TYPEHASH,\n                delegator,\n                delegatee,\n                _useDelegationNonce(delegator),\n                deadline\n            )\n        );\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == delegator, \"DelegatePermit: invalid signature\");\n    }\n\n    /**\n     * @notice get the current nonce for the given address\n     * @param owner The address to get nonce for\n     * @return the current nonce of `owner`\n     */\n    function delegationNonce(address owner) public view returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useDelegationNonce(address owner)\n        private\n        returns (uint256 current)\n    {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/ECO.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./InflationCheckpoints.sol\";\nimport \"../governance/monetary/CurrencyGovernance.sol\";\nimport \"../governance/IGeneration.sol\";\n\n/** @title An ERC20 token interface to the Eco currency system.\n */\ncontract ECO is InflationCheckpoints {\n    /** Fired when a proposal with a new inflation multiplier is selected and passed.\n     * Used to calculate new values for the rebased token.\n     */\n    event NewInflationMultiplier(uint256 inflationMultiplier);\n\n    /* Current generation of the balance store. */\n    uint256 public currentGeneration;\n\n    // the address of the contract for initial distribution\n    address public immutable distributor;\n\n    uint256 public immutable initialSupply;\n\n    constructor(\n        Policy _policy,\n        address _distributor,\n        uint256 _initialSupply,\n        address _initialPauser\n    ) InflationCheckpoints(_policy, \"ECO\", \"ECO\", _initialPauser) {\n        distributor = _distributor;\n        initialSupply = _initialSupply;\n    }\n\n    function initialize(address _self)\n        public\n        virtual\n        override\n        onlyConstruction\n    {\n        super.initialize(_self);\n        pauser = ERC20Pausable(_self).pauser();\n        _mint(distributor, initialSupply);\n    }\n\n    function mint(address _to, uint256 _value) external {\n        require(\n            msg.sender == policyFor(ID_CURRENCY_TIMER) ||\n                msg.sender == policyFor(ID_ECOX) ||\n                msg.sender == policyFor(ID_FAUCET),\n            \"Caller not authorized to mint tokens\"\n        );\n\n        _mint(_to, _value);\n    }\n\n    function burn(address _from, uint256 _value) external {\n        require(\n            msg.sender == _from || msg.sender == policyFor(ID_CURRENCY_TIMER),\n            \"Caller not authorized to burn tokens\"\n        );\n\n        _burn(_from, _value);\n    }\n\n    function notifyGenerationIncrease() public virtual override {\n        uint256 _old = currentGeneration;\n        uint256 _new = IGeneration(policyFor(ID_TIMED_POLICIES)).generation();\n        require(_new != _old, \"Generation has not increased\");\n\n        // update currentGeneration\n        currentGeneration = _new;\n\n        CurrencyGovernance bg = CurrencyGovernance(\n            policyFor(ID_CURRENCY_GOVERNANCE)\n        );\n\n        if (address(bg) != address(0)) {\n            if (\n                uint8(bg.currentStage()) <\n                uint8(CurrencyGovernance.Stage.Compute)\n            ) {\n                bg.updateStage();\n            }\n            if (\n                uint8(bg.currentStage()) ==\n                uint8(CurrencyGovernance.Stage.Compute)\n            ) {\n                bg.compute();\n            }\n            address winner = bg.winner();\n            if (winner != address(0)) {\n                uint256 _inflationMultiplier;\n                (, , , , _inflationMultiplier, ) = bg.proposals(winner);\n                emit NewInflationMultiplier(_inflationMultiplier);\n\n                // updates the inflation value\n                uint256 _newInflationMultiplier = (_linearInflationCheckpoints[\n                    _linearInflationCheckpoints.length - 1\n                ].value * _inflationMultiplier) / INITIAL_INFLATION_MULTIPLIER;\n                _writeCheckpoint(\n                    _linearInflationCheckpoints,\n                    _replace,\n                    _newInflationMultiplier\n                );\n            }\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/ECOx.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"./IECO.sol\";\nimport \"../policy/PolicedUtils.sol\";\nimport \"./ERC20Pausable.sol\";\n\n/** @title An ERC20 token interface for ECOx\n *\n * Contains the conversion mechanism for turning ECOx into ECO.\n */\ncontract ECOx is ERC20Pausable, PolicedUtils {\n    // bits of precision used in the exponentiation approximation\n    uint8 public constant PRECISION_BITS = 100;\n\n    uint256 public immutable initialSupply;\n\n    // the address of the contract for initial distribution\n    address public immutable distributor;\n\n    // the address of the ECO token contract\n    IECO public immutable ecoToken;\n\n    constructor(\n        Policy _policy,\n        address _distributor,\n        uint256 _initialSupply,\n        IECO _ecoAddr,\n        address _initialPauser\n    )\n        ERC20Pausable(\"ECOx\", \"ECOx\", address(_policy), _initialPauser)\n        PolicedUtils(_policy)\n    {\n        require(_initialSupply > 0, \"initial supply not properly set\");\n        require(\n            address(_ecoAddr) != address(0),\n            \"Do not set the ECO address as the zero address\"\n        );\n\n        initialSupply = _initialSupply;\n        distributor = _distributor;\n        ecoToken = _ecoAddr;\n    }\n\n    function initialize(address _self)\n        public\n        virtual\n        override\n        onlyConstruction\n    {\n        super.initialize(_self);\n        pauser = ERC20Pausable(_self).pauser();\n        _mint(distributor, initialSupply);\n    }\n\n    function ecoValueOf(uint256 _ecoXValue) public view returns (uint256) {\n        uint256 _ecoSupply = ecoToken.totalSupply();\n\n        return computeValue(_ecoXValue, _ecoSupply);\n    }\n\n    function valueAt(uint256 _ecoXValue, uint256 _blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        uint256 _ecoSupplyAt = ecoToken.totalSupplyAt(_blockNumber);\n\n        return computeValue(_ecoXValue, _ecoSupplyAt);\n    }\n\n    function computeValue(uint256 _ecoXValue, uint256 _ecoSupply)\n        internal\n        view\n        returns (uint256)\n    {\n        uint256 _preciseRatio = safeLeftShift(_ecoXValue, PRECISION_BITS) /\n            initialSupply;\n\n        return\n            (generalExp(_preciseRatio, PRECISION_BITS) * _ecoSupply) >>\n            PRECISION_BITS;\n    }\n\n    function safeLeftShift(uint256 value, uint8 shift)\n        internal\n        pure\n        returns (uint256)\n    {\n        uint256 _result = value << shift;\n        require(\n            _result >> shift == value,\n            \"value too large, shift out of bounds\"\n        );\n        return _result;\n    }\n\n    /**\n     * @dev this function can be auto-generated by the script 'PrintFunctionGeneralExp.py'.\n     * it approximates \"e ^ x\" via maclaurin summation: \"(x^0)/0! + (x^1)/1! + ... + (x^n)/n!\".\n     * it returns \"e ^ (x / 2 ^ precision) * 2 ^ precision\", that is, the result is upshifted for accuracy.\n     * the global \"maxExpArray\" maps each \"precision\" to \"((maximumExponent + 1) << (MAX_PRECISION - precision)) - 1\".\n     * the maximum permitted value for \"x\" is therefore given by \"maxExpArray[precision] >> (MAX_PRECISION - precision)\".\n     */\n    function generalExp(uint256 _x, uint8 _precision)\n        internal\n        pure\n        returns (uint256)\n    {\n        uint256 xi = _x;\n        uint256 res = 0;\n\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!)\n\n        return res / 0x688589cc0e9505e2f2fee5580000000 + _x; // divide by 33! and then add x^1 / 1! + x^0 / 0!\n    }\n\n    function exchange(uint256 _ecoXValue) external {\n        uint256 eco = ecoValueOf(_ecoXValue);\n\n        _burn(msg.sender, _ecoXValue);\n\n        ecoToken.mint(msg.sender, eco);\n    }\n\n    function mint(address _to, uint256 _value) external {\n        require(\n            msg.sender == policyFor(ID_FAUCET),\n            \"Caller not authorized to mint tokens\"\n        );\n\n        _mint(_to, _value);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/StringPacker.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./ERC20Permit.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface.\n *\n * This comment taken from the openzeppelin source contract.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see our guide\n * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How\n * to implement supply mechanisms].\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\n// internal _name and _symbol are stored immutable as bytes32 and unpacked via StringPacker\ncontract ERC20 is ERC20Permit {\n    mapping(address => uint256) internal _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 internal _totalSupply;\n\n    bytes32 internal immutable _name;\n    bytes32 internal immutable _symbol;\n\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n\n    /**\n     * @dev Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) ERC20Permit(name_) {\n        _name = StringPacker.pack(name_);\n        _symbol = StringPacker.pack(symbol_);\n    }\n\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        return StringPacker.unpack(_name);\n    }\n\n    /**\n     * @dev Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        return StringPacker.unpack(_symbol);\n    }\n\n    /**\n     * @dev Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * @dev See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * @dev See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(address recipient, uint256 amount)\n        public\n        virtual\n        returns (bool)\n    {\n        _transfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-allowance}.\n     */\n    function allowance(address owner, address spender)\n        public\n        view\n        virtual\n        returns (uint256)\n    {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * @dev See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(address spender, uint256 amount)\n        public\n        virtual\n        returns (bool)\n    {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    /**\n     * @dev See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * Requirements:\n     *\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``sender``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) public virtual returns (bool) {\n        _transfer(sender, recipient, amount);\n\n        uint256 currentAllowance = _allowances[sender][msg.sender];\n        require(\n            currentAllowance >= amount,\n            \"ERC20: transfer amount exceeds allowance\"\n        );\n        unchecked {\n            _approve(sender, msg.sender, currentAllowance - amount);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(address spender, uint256 addedValue)\n        public\n        virtual\n        returns (bool)\n    {\n        _approve(\n            msg.sender,\n            spender,\n            _allowances[msg.sender][spender] + addedValue\n        );\n        return true;\n    }\n\n    /**\n     * @dev Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue)\n        public\n        virtual\n        returns (bool)\n    {\n        uint256 currentAllowance = _allowances[msg.sender][spender];\n        require(\n            currentAllowance >= subtractedValue,\n            \"ERC20: decreased allowance below zero\"\n        );\n        unchecked {\n            _approve(msg.sender, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * @dev Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address sender,\n        address recipient,\n        uint256 originalAmount\n    ) internal virtual {\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        uint256 amount = _beforeTokenTransfer(\n            sender,\n            recipient,\n            originalAmount\n        );\n\n        uint256 senderBalance = _balances[sender];\n        require(\n            senderBalance >= amount,\n            \"ERC20: transfer amount exceeds balance\"\n        );\n        unchecked {\n            _balances[sender] = senderBalance - amount;\n        }\n        _balances[recipient] += amount;\n\n        emit Transfer(sender, recipient, originalAmount);\n\n        _afterTokenTransfer(sender, recipient, amount);\n    }\n\n    /** @dev Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(address account, uint256 originalAmount)\n        internal\n        virtual\n        returns (uint256)\n    {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        uint256 amount = _beforeTokenTransfer(\n            address(0),\n            account,\n            originalAmount\n        );\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, originalAmount);\n\n        _afterTokenTransfer(address(0), account, amount);\n\n        return amount;\n    }\n\n    /**\n     * @dev Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(address account, uint256 originalAmount)\n        internal\n        virtual\n        returns (uint256)\n    {\n        uint256 amount = _beforeTokenTransfer(\n            account,\n            address(0),\n            originalAmount\n        );\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), originalAmount);\n\n        _afterTokenTransfer(account, address(0), amount);\n\n        return amount;\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual override {\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address, // from\n        address, // to\n        uint256 amount\n    ) internal virtual returns (uint256) {\n        return amount;\n    }\n\n    /**\n     * @dev Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/ERC20Pausable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/security/Pausable.sol\";\nimport \"./ERC20.sol\";\n\n/**\n * @dev Implementation of the {IERC20} interface with pausability\n * When paused by the pauser admin, transfers revert.\n */\ncontract ERC20Pausable is ERC20, Pausable {\n    address public immutable roleAdmin;\n\n    // initially no-one should have the pauser role\n    // it can be granted and revoked by the admin policy\n    address public pauser;\n\n    /**\n     * @notice event indicating the pauser was updated\n     * @param pauser The new pauser\n     */\n    event PauserAssignment(address indexed pauser);\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        address _roleAdmin,\n        address _initialPauser\n    ) ERC20(name, symbol) {\n        require(\n            address(_roleAdmin) != address(0),\n            \"Unrecoverable: do not set the _roleAdmin as the zero address\"\n        );\n        roleAdmin = _roleAdmin;\n        pauser = _initialPauser;\n        emit PauserAssignment(_initialPauser);\n    }\n\n    modifier onlyAdmin() {\n        require(msg.sender == roleAdmin, \"ERC20Pausable: not admin\");\n        _;\n    }\n\n    modifier onlyPauser() {\n        require(msg.sender == pauser, \"ERC20Pausable: not pauser\");\n        _;\n    }\n\n    /**\n     * @dev Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * If the token is not paused, it will pass through the amount\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override whenNotPaused returns (uint256) {\n        return amount;\n    }\n\n    /**\n     * @notice pauses transfers of this token\n     * @dev only callable by the pauser\n     */\n    function pause() external onlyPauser {\n        _pause();\n    }\n\n    /**\n     * @notice unpauses transfers of this token\n     * @dev only callable by the pauser\n     */\n    function unpause() external onlyPauser {\n        _unpause();\n    }\n\n    /**\n     * @notice set the given address as the pauser\n     * @param _pauser The address that can pause this token\n     * @dev only the roleAdmin can call this function\n     */\n    function setPauser(address _pauser) public onlyAdmin {\n        require(_pauser != pauser, \"ERC20Pausable: must change pauser\");\n        pauser = _pauser;\n        emit PauserAssignment(_pauser);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/ERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// Heavily inspired by:\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol\";\n\n/**\n * @dev Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is IERC20Permit, EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private immutable _PERMIT_TYPEHASH =\n        keccak256(\n            \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n        );\n\n    /**\n     * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"1\"`.\n     *\n     * It's a good idea to use the same `name` that is defined as the ERC20 token name.\n     */\n    constructor(string memory name) EIP712(name, \"1\") {\n        //empty block in order to pass parameters to the parent EIP712 constructor\n    }\n\n    /**\n     * @dev See {IERC20Permit-permit}.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(\n            abi.encode(\n                _PERMIT_TYPEHASH,\n                owner,\n                spender,\n                value,\n                _useNonce(owner),\n                deadline\n            )\n        );\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * @dev See {IERC20Permit-nonces}.\n     */\n    function nonces(address owner)\n        public\n        view\n        virtual\n        override\n        returns (uint256)\n    {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * @dev \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(address owner)\n        internal\n        virtual\n        returns (uint256 current)\n    {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual;\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/IECO.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../governance/IGenerationIncrease.sol\";\n\ninterface IECO is IERC20, IGenerationIncrease {\n    /**\n     * Only available to CurrencyTimer and ECOx\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * Only available to token holders and CurrencyTimer\n     */\n    function burn(address from, uint256 amount) external;\n\n    /**\n     * Returns the currentGeneration\n     */\n    function currentGeneration() external view returns (uint256);\n\n    /**\n     * Returns final votes of an address at the end of a blockNumber\n     */\n    function getPastVotes(address owner, uint256 blockNumber)\n        external\n        view\n        returns (uint256);\n\n    /**\n     * Returns the inflation multiplier value checkpointed on or before the blockNumber\n     */\n    function getPastLinearInflation(uint256 blockNumber)\n        external\n        view\n        returns (uint256);\n\n    /**\n     * Returns the final total supply at the end of the given block number\n     */\n    function totalSupplyAt(uint256 blockNumber) external view returns (uint256);\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/InflationCheckpoints.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"../currency/VoteCheckpoints.sol\";\nimport \"../governance/IGenerationIncrease.sol\";\nimport \"../policy/PolicedUtils.sol\";\n\n/** @title InflationCheckpoints\n * This implements a generational store with snapshotted balances. Balances\n * are lazy-evaluated, but are effectively all atomically snapshotted when\n * the generation changes.\n */\nabstract contract InflationCheckpoints is\n    VoteCheckpoints,\n    PolicedUtils,\n    IGenerationIncrease\n{\n    uint256 public constant INITIAL_INFLATION_MULTIPLIER = 1e18;\n\n    Checkpoint[] internal _linearInflationCheckpoints;\n\n    // to be used to record the transfer amounts after _beforeTokenTransfer\n    // these values are the base (unchanging) values the currency is stored in\n    event BaseValueTransfer(\n        address indexed from,\n        address indexed to,\n        uint256 value\n    );\n\n    /** Construct a new instance.\n     *\n     * Note that it is always necessary to call reAuthorize on the balance store\n     * after it is first constructed to populate the authorized interface\n     * contracts cache. These calls are separated to allow the authorized\n     * contracts to be configured/deployed after the balance store contract.\n     */\n    constructor(\n        Policy _policy,\n        string memory _name,\n        string memory _symbol,\n        address _initialPauser\n    )\n        VoteCheckpoints(_name, _symbol, address(_policy), _initialPauser)\n        PolicedUtils(_policy)\n    {\n        _writeCheckpoint(\n            _linearInflationCheckpoints,\n            _replace,\n            INITIAL_INFLATION_MULTIPLIER\n        );\n    }\n\n    function initialize(address _self)\n        public\n        virtual\n        override\n        onlyConstruction\n    {\n        super.initialize(_self);\n        _writeCheckpoint(\n            _linearInflationCheckpoints,\n            _replace,\n            INITIAL_INFLATION_MULTIPLIER\n        );\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override returns (uint256) {\n        amount = super._beforeTokenTransfer(from, to, amount);\n        uint256 gonsAmount = amount *\n            _checkpointsLookup(_linearInflationCheckpoints, block.number);\n\n        emit BaseValueTransfer(from, to, gonsAmount);\n\n        return gonsAmount;\n    }\n\n    function getPastLinearInflation(uint256 blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        require(\n            blockNumber <= block.number,\n            \"InflationCheckpoints: cannot check future block\"\n        );\n        return _checkpointsLookup(_linearInflationCheckpoints, blockNumber);\n    }\n\n    /** Access function to determine the token balance held by some address.\n     */\n    function balanceOf(address _owner) public view override returns (uint256) {\n        uint256 _linearInflation = _checkpointsLookup(\n            _linearInflationCheckpoints,\n            block.number\n        );\n        return _balances[_owner] / _linearInflation;\n    }\n\n    /** Returns the total (inflation corrected) token supply\n     */\n    function totalSupply() public view override returns (uint256) {\n        uint256 _linearInflation = _checkpointsLookup(\n            _linearInflationCheckpoints,\n            block.number\n        );\n        return _totalSupply / _linearInflation;\n    }\n\n    /** Returns the total (inflation corrected) token supply at a specified block number\n     */\n    function totalSupplyAt(uint256 _blockNumber)\n        public\n        view\n        override\n        returns (uint256)\n    {\n        uint256 _linearInflation = getPastLinearInflation(_blockNumber);\n\n        return getPastTotalSupply(_blockNumber) / _linearInflation;\n    }\n\n    /** Return historical voting balance (includes delegation) at given block number.\n     *\n     * If the latest block number for the account is before the requested\n     * block then the most recent known balance is returned. Otherwise the\n     * exact block number requested is returned.\n     *\n     * @param _owner The account to check the balance of.\n     * @param _blockNumber The block number to check the balance at the start\n     *                        of. Must be less than or equal to the present\n     *                        block number.\n     */\n    function getPastVotes(address _owner, uint256 _blockNumber)\n        public\n        view\n        override\n        returns (uint256)\n    {\n        uint256 _linearInflation = getPastLinearInflation(_blockNumber);\n\n        return getPastVotingGons(_owner, _blockNumber) / _linearInflation;\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/currency/VoteCheckpoints.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ERC20Pausable.sol\";\nimport \"./DelegatePermit.sol\";\n\n/**\n * @dev Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to 2^224^ - 1, while COMP is limited to 2^96^ - 1.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotingGons} and {getPastVotingGons}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. The downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n * Enabling self-delegation can easily be done by overriding the {delegates} function. Keep in mind however that this\n * will significantly increase the base gas cost of transfers.\n *\n * _Available since v4.2._\n */\nabstract contract VoteCheckpoints is ERC20Pausable, DelegatePermit {\n    // structure for saving past voting balances, accounting for delegation\n    struct Checkpoint {\n        uint32 fromBlock;\n        uint224 value;\n    }\n\n    // the mapping from an address to each address that it delegates to, then mapped to the amount delegated\n    mapping(address => mapping(address => uint256)) internal _delegates;\n\n    // a mapping that aggregates the total delegated amounts in the mapping above\n    mapping(address => uint256) internal _delegatedTotals;\n\n    /** a mapping that tracks the primaryDelegates of each user\n     *\n     * Primary delegates can only be chosen using delegate() which sends the full balance\n     * The exist to maintain the functionality that recieving tokens gives those votes to the delegate\n     */\n    mapping(address => address) internal _primaryDelegates;\n\n    // mapping that tracks if an address is willing to be delegated to\n    mapping(address => bool) public delegationToAddressEnabled;\n\n    // mapping that tracks if an address is unable to delegate\n    mapping(address => bool) public delegationFromAddressDisabled;\n\n    // mapping to the ordered arrays of voting checkpoints for each address\n    mapping(address => Checkpoint[]) public checkpoints;\n\n    // the checkpoints to track the token total supply\n    Checkpoint[] private _totalSupplyCheckpoints;\n\n    /**\n     * @dev Emitted when a delegatee is delegated new votes.\n     */\n    event DelegatedVotes(\n        address indexed delegator,\n        address indexed delegatee,\n        uint256 amount\n    );\n\n    /**\n     * @dev Emitted when a token transfer or delegate change results in changes to an account's voting power.\n     */\n    event UpdatedVotes(address indexed voter, uint256 newVotes);\n\n    /**\n     * @dev Emitted when an account denotes a primary delegate.\n     */\n    event NewPrimaryDelegate(\n        address indexed delegator,\n        address indexed primaryDelegate\n    );\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        address admin,\n        address _initialPauser\n    ) ERC20Pausable(_name, _symbol, admin, _initialPauser) {\n        // call to super constructor\n    }\n\n    /** Returns the total (inflation corrected) token supply at a specified block number\n     */\n    function totalSupplyAt(uint256 _blockNumber)\n        public\n        view\n        virtual\n        returns (uint256)\n    {\n        return getPastTotalSupply(_blockNumber);\n    }\n\n    /** Return historical voting balance (includes delegation) at given block number.\n     *\n     * If the latest block number for the account is before the requested\n     * block then the most recent known balance is returned. Otherwise the\n     * exact block number requested is returned.\n     *\n     * @param _owner The account to check the balance of.\n     * @param _blockNumber The block number to check the balance at the start\n     *                        of. Must be less than or equal to the present\n     *                        block number.\n     */\n    function getPastVotes(address _owner, uint256 _blockNumber)\n        public\n        view\n        virtual\n        returns (uint256)\n    {\n        return getPastVotingGons(_owner, _blockNumber);\n    }\n\n    /**\n     * @dev Get number of checkpoints for `account`.\n     */\n    function numCheckpoints(address account)\n        public\n        view\n        virtual\n        returns (uint32)\n    {\n        uint256 _numCheckpoints = checkpoints[account].length;\n        require(\n            _numCheckpoints <= type(uint32).max,\n            \"number of checkpoints cannot be casted safely\"\n        );\n        return uint32(_numCheckpoints);\n    }\n\n    /**\n     * @dev Set yourself as willing to recieve delegates.\n     */\n    function enableDelegationTo() public {\n        require(\n            isOwnDelegate(msg.sender),\n            \"Cannot enable delegation if you have outstanding delegation\"\n        );\n\n        delegationToAddressEnabled[msg.sender] = true;\n        delegationFromAddressDisabled[msg.sender] = true;\n    }\n\n    /**\n     * @dev Set yourself as no longer recieving delegates.\n     */\n    function disableDelegationTo() public {\n        delegationToAddressEnabled[msg.sender] = false;\n    }\n\n    /**\n     * @dev Set yourself as being able to delegate again.\n     * also disables delegating to you\n     * NOTE: the condition for this is not easy and cannot be unilaterally achieved\n     */\n    function reenableDelegating() public {\n        delegationToAddressEnabled[msg.sender] = false;\n\n        require(\n            _balances[msg.sender] == getVotingGons(msg.sender) &&\n                isOwnDelegate(msg.sender),\n            \"Cannot re-enable delegating if you have outstanding delegations to you\"\n        );\n\n        delegationFromAddressDisabled[msg.sender] = false;\n    }\n\n    /**\n     * @dev Returns true if the user has no amount of their balance delegated, otherwise false.\n     */\n    function isOwnDelegate(address account) public view returns (bool) {\n        return _delegatedTotals[account] == 0;\n    }\n\n    /**\n     * @dev Get the primary address `account` is currently delegating to. Defaults to the account address itself if none specified.\n     * The primary delegate is the one that is delegated any new funds the address recieves.\n     */\n    function getPrimaryDelegate(address account)\n        public\n        view\n        virtual\n        returns (address)\n    {\n        address _voter = _primaryDelegates[account];\n        return _voter == address(0) ? account : _voter;\n    }\n\n    /**\n     * sets the primaryDelegate and emits an event to track it\n     */\n    function _setPrimaryDelegate(address delegator, address delegatee)\n        internal\n    {\n        _primaryDelegates[delegator] = delegatee;\n\n        emit NewPrimaryDelegate(\n            delegator,\n            delegatee == address(0) ? delegator : delegatee\n        );\n    }\n\n    /**\n     * @dev Gets the current votes balance in gons for `account`\n     */\n    function getVotingGons(address account) public view returns (uint256) {\n        Checkpoint[] memory accountCheckpoints = checkpoints[account];\n        uint256 pos = accountCheckpoints.length;\n        return pos == 0 ? 0 : accountCheckpoints[pos - 1].value;\n    }\n\n    /**\n     * @dev Retrieve the number of votes in gons for `account` at the end of `blockNumber`.\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     */\n    function getPastVotingGons(address account, uint256 blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        require(\n            blockNumber < block.number,\n            \"VoteCheckpoints: block not yet mined\"\n        );\n        return _checkpointsLookup(checkpoints[account], blockNumber);\n    }\n\n    /**\n     * @dev Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n     * It is NOT the sum of all the delegated votes!\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     */\n    function getPastTotalSupply(uint256 blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        require(\n            blockNumber < block.number,\n            \"VoteCheckpoints: block not yet mined\"\n        );\n        return _checkpointsLookup(_totalSupplyCheckpoints, blockNumber);\n    }\n\n    /**\n     * @dev Lookup a value in a list of (sorted) checkpoints.\n     */\n    function _checkpointsLookup(Checkpoint[] storage ckpts, uint256 blockNumber)\n        internal\n        view\n        returns (uint256)\n    {\n        // This function runs a binary search to look for the last checkpoint taken before `blockNumber`.\n        //\n        // During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n        // With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n        // - If the middle checkpoint is after `blockNumber`, the next iteration looks in [low, mid)\n        // - If the middle checkpoint is before or equal to `blockNumber`, the next iteration looks in [mid+1, high)\n        // Once it reaches a single value (when low == high), it has found the right checkpoint at the index high-1, if not\n        // out of bounds (in which case it's looking too far in the past and the result is 0).\n        // Note that if the latest checkpoint available is exactly for `blockNumber`, it will end up with an index that is\n        // past the end of the array, so this technically doesn't find a checkpoint after `blockNumber`, but the result is\n        // the same.\n\n        uint256 ckptsLength = ckpts.length;\n        if (ckptsLength == 0) return 0;\n        Checkpoint memory lastCkpt = ckpts[ckptsLength - 1];\n        if (blockNumber >= lastCkpt.fromBlock) return lastCkpt.value;\n\n        uint256 high = ckptsLength;\n        uint256 low = 0;\n\n        while (low < high) {\n            uint256 mid = low + ((high - low) >> 1);\n            if (ckpts[mid].fromBlock > blockNumber) {\n                high = mid;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        return high == 0 ? 0 : ckpts[high - 1].value;\n    }\n\n    /**\n     * @dev Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"Must have an undelegated amount available to cover delegation\" if you do\n     */\n    function delegate(address delegatee) public {\n        require(\n            delegatee != msg.sender,\n            \"Use undelegate instead of delegating to yourself\"\n        );\n\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"Primary delegates must enable delegation\"\n        );\n\n        if (!isOwnDelegate(msg.sender)) {\n            undelegateFromAddress(getPrimaryDelegate(msg.sender));\n        }\n\n        uint256 _amount = _balances[msg.sender];\n        _delegate(msg.sender, delegatee, _amount);\n        _setPrimaryDelegate(msg.sender, delegatee);\n    }\n\n    /**\n     * @dev Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"Must have an undelegated amount available to cover delegation\" if you do\n     */\n    function delegateBySig(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public {\n        require(delegator != delegatee, \"Do not delegate to yourself\");\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"Primary delegates must enable delegation\"\n        );\n\n        if (!isOwnDelegate(delegator)) {\n            _undelegateFromAddress(delegator, getPrimaryDelegate(delegator));\n        }\n\n        _verifyDelegatePermit(delegator, delegatee, deadline, v, r, s);\n\n        uint256 _amount = _balances[delegator];\n        _delegate(delegator, delegatee, _amount);\n        _setPrimaryDelegate(delegator, delegatee);\n    }\n\n    /**\n     * @dev Delegate an `amount` of votes from the sender to `delegatee`.\n     */\n    function delegateAmount(address delegatee, uint256 amount) public {\n        require(delegatee != msg.sender, \"Do not delegate to yourself\");\n\n        _delegate(msg.sender, delegatee, amount);\n    }\n\n    /**\n     * @dev Change delegation for `delegator` to `delegatee`.\n     *\n     * Emits events {NewDelegatedAmount} and {UpdatedVotes}.\n     */\n    function _delegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        require(\n            amount <= _balances[delegator] - _delegatedTotals[delegator],\n            \"Must have an undelegated amount available to cover delegation\"\n        );\n\n        require(\n            !delegationFromAddressDisabled[delegator],\n            \"Cannot delegate if you have enabled primary delegation to yourself and/or have outstanding delegates\"\n        );\n\n        emit DelegatedVotes(delegator, delegatee, amount);\n\n        _delegates[delegator][delegatee] += amount;\n        _delegatedTotals[delegator] += amount;\n\n        _moveVotingPower(delegator, delegatee, amount);\n    }\n\n    /**\n     * @dev Undelegate all votes from the sender's primary delegate.\n     */\n    function undelegate() public {\n        address _primaryDelegate = getPrimaryDelegate(msg.sender);\n        require(\n            _primaryDelegate != msg.sender,\n            \"Must specifiy address without a Primary Delegate\"\n        );\n        undelegateFromAddress(_primaryDelegate);\n    }\n\n    /**\n     * @dev Undelegate votes from the `delegatee` back to the sender.\n     */\n    function undelegateFromAddress(address delegatee) public {\n        _undelegateFromAddress(msg.sender, delegatee);\n    }\n\n    /**\n     * @dev Undelegate votes from the `delegatee` back to the delegator.\n     */\n    function _undelegateFromAddress(address delegator, address delegatee)\n        internal\n    {\n        uint256 _amount = _delegates[delegator][delegatee];\n        _undelegate(delegator, delegatee, _amount);\n        if (delegatee == getPrimaryDelegate(delegator)) {\n            _setPrimaryDelegate(delegator, address(0));\n        }\n    }\n\n    /**\n     * @dev Undelegate a specific amount of votes from the `delegatee` back to the sender.\n     */\n    function undelegateAmountFromAddress(address delegatee, uint256 amount)\n        public\n    {\n        require(\n            _delegates[msg.sender][delegatee] >= amount,\n            \"amount not available to undelegate\"\n        );\n        require(\n            msg.sender == getPrimaryDelegate(msg.sender),\n            \"undelegating amounts is only available for partial delegators\"\n        );\n        _undelegate(msg.sender, delegatee, amount);\n    }\n\n    function _undelegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        _delegatedTotals[delegator] -= amount;\n        _delegates[delegator][delegatee] -= amount;\n\n        _moveVotingPower(delegatee, delegator, amount);\n    }\n\n    /**\n     * @dev Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n     */\n    function _maxSupply() internal view virtual returns (uint224) {\n        return type(uint224).max;\n    }\n\n    /**\n     * @dev Snapshots the totalSupply after it has been increased.\n     */\n    function _mint(address account, uint256 amount)\n        internal\n        virtual\n        override\n        returns (uint256)\n    {\n        amount = super._mint(account, amount);\n        require(\n            totalSupply() <= _maxSupply(),\n            \"VoteCheckpoints: total supply risks overflowing votes\"\n        );\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n        return amount;\n    }\n\n    /**\n     * @dev Snapshots the totalSupply after it has been decreased.\n     */\n    function _burn(address account, uint256 amount)\n        internal\n        virtual\n        override\n        returns (uint256)\n    {\n        amount = super._burn(account, amount);\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n        return amount;\n    }\n\n    /**\n     * @dev Move voting power when tokens are transferred.\n     *\n     * Emits a {UpdatedVotes} event.\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        if (from == to) {\n            // self transfers require no change in delegation and can be the source of exploits\n            return;\n        }\n\n        // if the address has delegated, they might be transfering tokens allotted to someone else\n        if (!isOwnDelegate(from)) {\n            uint256 _undelegatedAmount = _balances[from] +\n                amount -\n                _delegatedTotals[from];\n\n            // check to see if tokens must be undelegated to transefer\n            if (_undelegatedAmount < amount) {\n                address _sourcePrimaryDelegate = getPrimaryDelegate(from);\n                uint256 _sourcePrimaryDelegatement = _delegates[from][\n                    _sourcePrimaryDelegate\n                ];\n\n                require(\n                    amount <= _undelegatedAmount + _sourcePrimaryDelegatement,\n                    \"Delegation too complicated to transfer. Undelegate and simplify before trying again\"\n                );\n\n                _undelegate(\n                    from,\n                    _sourcePrimaryDelegate,\n                    amount - _undelegatedAmount\n                );\n            }\n        }\n\n        address _destPrimaryDelegate = _primaryDelegates[to];\n        // saving gas by manually doing isOwnDelegate since this function already needs to read the data for this conditional\n        if (_destPrimaryDelegate != address(0)) {\n            _delegates[to][_destPrimaryDelegate] += amount;\n            _delegatedTotals[to] += amount;\n            _moveVotingPower(from, _destPrimaryDelegate, amount);\n        } else {\n            _moveVotingPower(from, to, amount);\n        }\n    }\n\n    function _moveVotingPower(\n        address src,\n        address dst,\n        uint256 amount\n    ) private {\n        if (src != dst && amount > 0) {\n            if (src != address(0)) {\n                uint256 newWeight = _writeCheckpoint(\n                    checkpoints[src],\n                    _subtract,\n                    amount\n                );\n                emit UpdatedVotes(src, newWeight);\n            }\n\n            if (dst != address(0)) {\n                uint256 newWeight = _writeCheckpoint(\n                    checkpoints[dst],\n                    _add,\n                    amount\n                );\n                emit UpdatedVotes(dst, newWeight);\n            }\n        }\n    }\n\n    // returns the newly written value in the checkpoint\n    function _writeCheckpoint(\n        Checkpoint[] storage ckpts,\n        function(uint256, uint256) view returns (uint256) op,\n        uint256 delta\n    ) internal returns (uint256) {\n        require(\n            delta <= type(uint224).max,\n            \"newWeight cannot be casted safely\"\n        );\n        require(\n            block.number <= type(uint32).max,\n            \"block number cannot be casted safely\"\n        );\n\n        uint256 pos = ckpts.length;\n\n        /* if there are no checkpoints, just write the value\n         * This part assumes that an account would never exist with a balance but without checkpoints.\n         * This function cannot be called directly, so there's no malicious way to exploit this. If this\n         * is somehow called with op = _subtract, it will revert as that action is nonsensical.\n         */\n        if (pos == 0) {\n            ckpts.push(\n                Checkpoint({\n                    fromBlock: uint32(block.number),\n                    value: uint224(op(0, delta))\n                })\n            );\n            return delta;\n        }\n\n        // else, iterate on the existing checkpoints as per usual\n        Checkpoint storage newestCkpt = ckpts[pos - 1];\n\n        uint256 oldWeight = newestCkpt.value;\n        uint256 newWeight = op(oldWeight, delta);\n\n        require(\n            newWeight <= type(uint224).max,\n            \"newWeight cannot be casted safely\"\n        );\n\n        if (newestCkpt.fromBlock == block.number) {\n            newestCkpt.value = uint224(newWeight);\n        } else {\n            ckpts.push(\n                Checkpoint({\n                    fromBlock: uint32(block.number),\n                    value: uint224(newWeight)\n                })\n            );\n        }\n        return newWeight;\n    }\n\n    function _add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function _subtract(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    function _replace(uint256, uint256 b) internal pure returns (uint256) {\n        return b;\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/community/ECOxStaking.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../currency/VoteCheckpoints.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../IGeneration.sol\";\n\n/** @title ECOxStaking\n *\n */\ncontract ECOxStaking is VoteCheckpoints, PolicedUtils {\n    /** The Deposit event indicates that ECOx has been locked up, credited\n     * to a particular address in a particular amount.\n     *\n     * @param source The address that a deposit certificate has been issued to.\n     * @param amount The amount of ECOx tokens deposited.\n     */\n    event Deposit(address indexed source, uint256 amount);\n\n    /** The Withdrawal event indicates that a withdrawal has been made to a particular\n     * address in a particular amount.\n     *\n     * @param destination The address that has made a withdrawal.\n     * @param amount The amount in basic unit of 10^{-18} ECOx (weicoX) tokens withdrawn.\n     */\n    event Withdrawal(address indexed destination, uint256 amount);\n\n    // the ECOx contract address\n    IERC20 public immutable ecoXToken;\n\n    constructor(Policy _policy, IERC20 _ecoXAddr)\n        // Note that the policy has the ability to pause transfers\n        // through ERC20Pausable, although transfers are paused by default\n        // therefore the pauser is unset\n        VoteCheckpoints(\"Staked ECOx\", \"sECOx\", address(_policy), address(0))\n        PolicedUtils(_policy)\n    {\n        require(\n            address(_ecoXAddr) != address(0),\n            \"Critical: do not set the _ecoXAddr as the zero address\"\n        );\n        ecoXToken = _ecoXAddr;\n    }\n\n    function deposit(uint256 _amount) external {\n        address _source = msg.sender;\n\n        require(\n            ecoXToken.transferFrom(_source, address(this), _amount),\n            \"Transfer failed\"\n        );\n\n        _mint(_source, _amount);\n\n        emit Deposit(_source, _amount);\n    }\n\n    function withdraw(uint256 _amount) external {\n        address _destination = msg.sender;\n\n        // do this first to ensure that any undelegations in this function are caught\n        _burn(_destination, _amount);\n\n        require(ecoXToken.transfer(_destination, _amount), \"Transfer Failed\");\n\n        emit Withdrawal(_destination, _amount);\n    }\n\n    function votingECOx(address _voter, uint256 _blockNumber)\n        external\n        view\n        returns (uint256)\n    {\n        return getPastVotingGons(_voter, _blockNumber);\n    }\n\n    function totalVotingECOx(uint256 _blockNumber)\n        external\n        view\n        returns (uint256)\n    {\n        return getPastTotalSupply(_blockNumber);\n    }\n\n    function transfer(address, uint256) public pure override returns (bool) {\n        revert(\"sECOx is non-transferrable\");\n    }\n\n    function transferFrom(\n        address,\n        address,\n        uint256\n    ) public pure override returns (bool) {\n        revert(\"sECOx is non-transferrable\");\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/community/PolicyProposals.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policy.sol\";\nimport \"../../currency/IECO.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"./proposals/Proposal.sol\";\nimport \"./PolicyVotes.sol\";\nimport \"../TimedPolicies.sol\";\nimport \"./VotingPower.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/** @title PolicyProposals\n * `PolicyProposals` oversees the proposals phase of the policy decision\n * process. Proposals can be submitted by anyone willing to put forth funds, and\n * submitted proposals can be supported by anyone\n *\n * First, during the proposals portion of the proposals phase, proposals can be\n * submitted (for a fee). This is parallelized with a signal voting process where\n * support can be distributed and redistributed to proposals after they are submitted.\n *\n * A proposal that makes it to support above 30% of the total possible support ends this\n * phase and starts a vote.\n */\ncontract PolicyProposals is VotingPower, TimeUtils {\n    /** The data tracked for a proposal in the process.\n     */\n    struct PropData {\n        // the returnable data\n        PropMetadata metadata;\n        // A record of which addresses have already staked in support of the proposal\n        mapping(address => bool) staked;\n    }\n\n    /** The submitted data for a proposal submitted to the process.\n     */\n    struct PropMetadata {\n        /* The address of the proposing account.\n         */\n        address proposer;\n        /* The address of the proposal contract.\n         */\n        Proposal proposal;\n        /* The amount of tokens staked in support of this proposal.\n         */\n        uint256 totalStake;\n        /* Flag to mark if a pause caused the fee to be waived.\n         */\n        bool feeWaived;\n    }\n\n    /** The set of proposals under consideration.\n     * maps from addresses of proposals to structs containing with info and\n     * the staking data (structs defined above)\n     */\n    mapping(Proposal => PropData) public proposals;\n\n    /** The total number of proposals made.\n     */\n    uint256 public totalProposals;\n\n    /** The duration of the proposal portion of the proposal phase.\n     */\n    uint256 public constant PROPOSAL_TIME = 9 days + 16 hours;\n\n    /** Whether or not a winning proposal has been selected\n     */\n    bool public proposalSelected;\n\n    /** Selected proposal awaiting configuration before voting\n     */\n    Proposal public proposalToConfigure;\n\n    /** The minimum cost to register a proposal.\n     */\n    uint256 public constant COST_REGISTER = 10000e18;\n\n    /** The amount refunded if a proposal does not get selected.\n     */\n    uint256 public constant REFUND_IF_LOST = 5000e18;\n\n    /** The percentage of total voting power required to push to a vote.\n     */\n    uint256 public constant SUPPORT_THRESHOLD = 15;\n\n    /** The divisor for the above constant, tracks the digits of precision.\n     */\n    uint256 public constant SUPPORT_THRESHOLD_DIVISOR = 100;\n\n    /** The total voting value against which to compare for the threshold\n     * This is a fixed digit number with 2 decimal digits\n     * see SUPPORT_THRESHOLD_DIVISOR variable\n     */\n    uint256 public totalVotingThreshold;\n\n    /** The time at which the proposal portion of the proposals phase ends.\n     */\n    uint256 public proposalEnds;\n\n    /** The block number of the balance stores to use for staking in\n     * support of a proposal.\n     */\n    uint256 public blockNumber;\n\n    /** The address of the `PolicyVotes` contract, to be cloned for the voting\n     * phase.\n     */\n    PolicyVotes public policyVotesImpl;\n\n    /** An event indicating a proposal has been proposed\n     *\n     * @param proposer The address that submitted the Proposal\n     * @param proposalAddress The address of the Proposal contract instance that was added\n     */\n    event Register(address indexed proposer, Proposal indexed proposalAddress);\n\n    /** An event indicating that proposal have been supported by stake.\n     *\n     * @param supporter The address submitting their support for the proposal\n     * @param proposalAddress The address of the Proposal contract instance that was supported\n     */\n    event Support(address indexed supporter, Proposal indexed proposalAddress);\n\n    /** An event indicating that support has been removed from a proposal.\n     *\n     * @param unsupporter The address removing their support for the proposal\n     * @param proposalAddress The address of the Proposal contract instance that was unsupported\n     */\n    event Unsupport(\n        address indexed unsupporter,\n        Proposal indexed proposalAddress\n    );\n\n    /** An event indicating a proposal has reached its support threshold\n     *\n     * @param proposalAddress The address of the Proposal contract instance that reached the threshold.\n     */\n    event SupportThresholdReached(Proposal indexed proposalAddress);\n\n    /** An event indicating that a proposal has been accepted for voting\n     *\n     * @param contractAddress The address of the PolicyVotes contract instance.\n     */\n    event VoteStart(PolicyVotes indexed contractAddress);\n\n    /** An event indicating that proposal fee was partially refunded.\n     *\n     * @param proposer The address of the proposee which was refunded\n     * @param proposalAddress The address of the Proposal instance that was refunded\n     */\n    event ProposalRefund(\n        address indexed proposer,\n        Proposal indexed proposalAddress\n    );\n\n    /** Construct a new PolicyProposals instance using the provided supervising\n     * policy (root) and supporting contracts.\n     *\n     * @param _policy The address of the root policy contract.\n     * @param _policyvotes The address of the contract that will be cloned to\n     *                     oversee the voting phase.\n     * @param _ecoAddr The address of the ECO token contract.\n     */\n    constructor(\n        Policy _policy,\n        PolicyVotes _policyvotes,\n        ECO _ecoAddr\n    ) VotingPower(_policy, _ecoAddr) {\n        require(\n            address(_policyvotes) != address(0),\n            \"Unrecoverable: do not set the _policyvotes as the zero address\"\n        );\n        policyVotesImpl = _policyvotes;\n    }\n\n    /** Initialize the storage context using parameters copied from the original\n     * contract (provided as _self).\n     *\n     * Can only be called once, during proxy initialization.\n     *\n     * @param _self The original contract address.\n     */\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n\n        // implementation addresses are left as mutable for easier governance\n        policyVotesImpl = PolicyProposals(_self).policyVotesImpl();\n        TimedPolicies timedPolicies = TimedPolicies(\n            policyFor(ID_TIMED_POLICIES)\n        );\n        proposalEnds =\n            timedPolicies.generationEnd() -\n            MIN_GENERATION_DURATION +\n            PROPOSAL_TIME;\n        blockNumber = block.number;\n    }\n\n    /** Submit a proposal.\n     *\n     * You must approve the policy proposals contract to withdraw the required\n     * fee from your account before calling this.\n     *\n     * Can only be called during the proposals portion of the proposals phase.\n     * Each proposal may only be submitted once.\n     *\n     * @param _prop The address of the proposal to submit.\n     */\n    function registerProposal(Proposal _prop) external {\n        require(\n            address(_prop) != address(0),\n            \"The proposal address can't be 0\"\n        );\n\n        require(\n            getTime() < proposalEnds && !proposalSelected,\n            \"Proposals may no longer be registered because the registration period has ended\"\n        );\n\n        PropMetadata storage _p = proposals[_prop].metadata;\n\n        require(\n            address(_p.proposal) == address(0),\n            \"A proposal may only be registered once\"\n        );\n\n        _p.proposal = _prop;\n        _p.proposer = msg.sender;\n\n        totalProposals++;\n\n        // if eco token is paused, the proposal fee can't be and isn't collected\n        if (!ecoToken.paused()) {\n            require(\n                ecoToken.transferFrom(msg.sender, address(this), COST_REGISTER),\n                \"The token cost of registration must be approved to transfer prior to calling registerProposal\"\n            );\n        } else {\n            _p.feeWaived = true;\n        }\n\n        emit Register(msg.sender, _prop);\n\n        // check if totalVotingThreshold still needs to be precomputed\n        if (totalVotingThreshold == 0) {\n            totalVotingThreshold =\n                totalVotingPower(blockNumber) *\n                SUPPORT_THRESHOLD;\n        }\n    }\n\n    /** Stake in support of an existing proposal.\n     *\n     * Can only be called during the staking portion of the proposals phase.\n     *\n     * Your voting strength is added to the supporting stake of the proposal.\n     *\n     * @param _prop The proposal to support.\n     */\n    function support(Proposal _prop) external {\n        require(\n            policyFor(ID_POLICY_PROPOSALS) == address(this),\n            \"Proposal contract no longer active\"\n        );\n        require(!proposalSelected, \"A proposal has already been selected\");\n        require(\n            getTime() < proposalEnds,\n            \"Proposals may no longer be supported because the registration period has ended\"\n        );\n\n        PropData storage _p = proposals[_prop];\n        PropMetadata storage _pMeta = _p.metadata;\n\n        require(\n            address(_pMeta.proposal) != address(0),\n            \"The supported proposal is not registered\"\n        );\n        require(\n            !_p.staked[msg.sender],\n            \"You may not stake in support of a proposal twice\"\n        );\n\n        uint256 _amount = votingPower(msg.sender, blockNumber);\n\n        require(\n            _amount > 0,\n            \"In order to support a proposal you must stake a non-zero amount of tokens\"\n        );\n\n        uint256 _totalStake = _pMeta.totalStake + _amount;\n\n        _pMeta.totalStake = _totalStake;\n        _p.staked[msg.sender] = true;\n\n        emit Support(msg.sender, _prop);\n\n        if (_totalStake * SUPPORT_THRESHOLD_DIVISOR > totalVotingThreshold) {\n            emit SupportThresholdReached(_prop);\n            proposalSelected = true;\n            proposalToConfigure = _prop;\n        }\n    }\n\n    function unsupport(Proposal _prop) external {\n        require(\n            policyFor(ID_POLICY_PROPOSALS) == address(this),\n            \"Proposal contract no longer active\"\n        );\n        require(!proposalSelected, \"A proposal has already been selected\");\n        require(\n            getTime() < proposalEnds,\n            \"Proposals may no longer be supported because the registration period has ended\"\n        );\n\n        PropData storage _p = proposals[_prop];\n\n        require(_p.staked[msg.sender], \"You have not staked this proposal\");\n\n        uint256 _amount = votingPower(msg.sender, blockNumber);\n        _p.metadata.totalStake -= _amount;\n        _p.staked[msg.sender] = false;\n\n        emit Unsupport(msg.sender, _prop);\n    }\n\n    function deployProposalVoting() external {\n        require(proposalSelected, \"no proposal has been selected\");\n        Proposal _proposalToConfigure = proposalToConfigure;\n        require(\n            address(_proposalToConfigure) != address(0),\n            \"voting has already been deployed\"\n        );\n        address _proposer = proposals[_proposalToConfigure].metadata.proposer;\n\n        delete proposalToConfigure;\n        delete proposals[_proposalToConfigure];\n        totalProposals--;\n\n        PolicyVotes pv = PolicyVotes(policyVotesImpl.clone());\n        pv.configure(\n            _proposalToConfigure,\n            _proposer,\n            blockNumber,\n            totalECOxSnapshot,\n            excludedVotingPower\n        );\n        policy.setPolicy(ID_POLICY_VOTES, address(pv), ID_POLICY_PROPOSALS);\n\n        emit VoteStart(pv);\n    }\n\n    /** Refund the fee for a proposal that was not selected.\n     *\n     * Returns a partial refund only, does not work on proposals that are\n     * on the ballot for the voting phase, and can only be called after voting\n     * been deployed or when the period is over and no vote was selected.\n     *\n     * @param _prop The proposal to issue a refund for.\n     */\n    function refund(Proposal _prop) external {\n        require(\n            (proposalSelected && address(proposalToConfigure) == address(0)) ||\n                getTime() > proposalEnds,\n            \"Refunds may not be distributed until the period is over or voting has started\"\n        );\n\n        require(\n            address(_prop) != address(0),\n            \"The proposal address can't be 0\"\n        );\n\n        PropMetadata storage _p = proposals[_prop].metadata;\n\n        require(\n            _p.proposal == _prop,\n            \"The provided proposal address is not valid\"\n        );\n\n        address receiver = _p.proposer;\n        bool _feePaid = !_p.feeWaived;\n\n        delete proposals[_prop];\n        totalProposals--;\n\n        // if fee was waived, still delete the proposal, but do not refund\n        if (_feePaid) {\n            require(\n                ecoToken.transfer(receiver, REFUND_IF_LOST),\n                \"Transfer Failed\"\n            );\n            emit ProposalRefund(receiver, _prop);\n        }\n    }\n\n    /** Reclaim tokens after end time\n     * only callable if all proposals are refunded\n     */\n    function destruct() external {\n        require(\n            proposalSelected || getTime() > proposalEnds,\n            \"The destruct operation can only be performed when the period is over\"\n        );\n\n        require(totalProposals == 0, \"Must refund all missed proposals first\");\n\n        policy.removeSelf(ID_POLICY_PROPOSALS);\n\n        require(\n            ecoToken.transfer(\n                address(policy),\n                ecoToken.balanceOf(address(this))\n            ),\n            \"Transfer Failed\"\n        );\n    }\n\n    // configure the total voting power for the vote thresholds\n    function configure(uint256 _totalECOxSnapshot, uint256 _excludedVotingPower)\n        external\n    {\n        require(\n            totalECOxSnapshot == 0,\n            \"This instance has already been configured\"\n        );\n        require(_totalECOxSnapshot != 0, \"Invalid value for ECOx voting power\");\n\n        totalECOxSnapshot = _totalECOxSnapshot;\n        excludedVotingPower = _excludedVotingPower;\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/community/PolicyVotes.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policy.sol\";\nimport \"./proposals/Proposal.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"./VotingPower.sol\";\nimport \"../../currency/ECO.sol\";\nimport \"../../currency/ECOx.sol\";\n\n/** @title PolicyVotes\n * This implements the voting and implementation phases of the policy decision process.\n * Open stake based voting is used for the voting phase.\n */\ncontract PolicyVotes is VotingPower, TimeUtils {\n    /** The proposal being voted on */\n    Proposal public proposal;\n\n    /* The proposer of the proposal being voted on */\n    address public proposer;\n\n    /** The stake an the yes votes of an address on a proposal\n     */\n    struct VotePartial {\n        uint256 stake;\n        uint256 yesVotes;\n    }\n\n    /** The voting power that a user has based on their stake and\n     *  the portion that they have voted yes with\n     */\n    mapping(address => VotePartial) public votePartials;\n\n    /** Total currency staked in all ongoing votes in basic unit of 10^{-18} ECO (weico).\n     */\n    uint256 public totalStake;\n\n    /** Total revealed positive stake in basic unit of 10^{-18} ECO (weico).\n     */\n    uint256 public yesStake;\n\n    /** The length of the commit portion of the voting phase.\n     */\n    uint256 public constant VOTE_TIME = 3 days;\n\n    /** The delay on a plurality win\n     */\n    uint256 public constant ENACTION_DELAY = 1 days;\n\n    /** The timestamp at which the commit portion of the voting phase ends.\n     */\n    uint256 public voteEnds;\n\n    /** Vote result */\n    enum Result {\n        Accepted,\n        Rejected,\n        Failed\n    }\n\n    /** Event emitted when the vote outcome is known.\n     */\n    event VoteCompletion(Result indexed result);\n\n    /** Event emitted when a vote is submitted.\n     * simple votes have the address's voting power as votesYes or votesNo, depending on the vote\n     * split votes show the split and votesYes + votesNo might be less than the address's voting power\n     */\n    event PolicyVote(address indexed voter, uint256 votesYes, uint256 votesNo);\n\n    /** The store block number to use when checking account balances for staking.\n     */\n    uint256 public blockNumber;\n\n    /** This constructor just passes the call to the super constructor\n     */\n    // solhint-disable-next-line no-empty-blocks\n    constructor(Policy _policy, ECO _ecoAddr) VotingPower(_policy, _ecoAddr) {}\n\n    /** Submit your yes/no support\n     *\n     * Shows whether or not your voting power supports or does not support the vote\n     *\n     * Note Not voting is not equivalent to voting no. Percentage of voted support,\n     * not percentage of total voting power is used to determine the win.\n     *\n     * @param _vote The vote for the proposal\n     */\n    function vote(bool _vote) external {\n        require(\n            getTime() < voteEnds,\n            \"Votes can only be recorded during the voting period\"\n        );\n\n        uint256 _amount = votingPower(msg.sender, blockNumber);\n\n        require(\n            _amount > 0,\n            \"Voters must have held tokens before this voting cycle\"\n        );\n\n        VotePartial storage vpower = votePartials[msg.sender];\n        uint256 _oldStake = vpower.stake;\n        uint256 _oldYesVotes = vpower.yesVotes;\n        bool _prevVote = _oldYesVotes != 0;\n\n        if (_oldStake != 0) {\n            require(\n                _prevVote != _vote ||\n                    _oldStake != _amount ||\n                    (_vote && (_oldYesVotes != _amount)),\n                \"Your vote has already been recorded\"\n            );\n\n            if (_prevVote) {\n                yesStake -= _oldYesVotes;\n                vpower.yesVotes = 0;\n            }\n        }\n\n        vpower.stake = _amount;\n        totalStake = totalStake + _amount - _oldStake;\n\n        if (_vote) {\n            yesStake += _amount;\n            vpower.yesVotes = _amount;\n\n            emit PolicyVote(msg.sender, _amount, 0);\n        } else {\n            emit PolicyVote(msg.sender, 0, _amount);\n        }\n    }\n\n    /** Submit a mixed vote of yes/no support\n     *\n     * Useful for contracts that wish to vote for an agregate of users\n     *\n     * Note As not voting is not equivalent to voting no it matters recording the no votes\n     * The total amount of votes in favor is relevant for early enaction and the total percentage\n     * of voting power that voted is necessary for determining a winner.\n     *\n     * Note As this is designed for contracts, the onus is on the contract designer to correctly\n     * understand and take responsibility for its input parameters. The only check is to stop\n     * someone from voting with more power than they have.\n     *\n     * @param _votesYes The amount of votes in favor of the proposal\n     * @param _votesNo The amount of votes against the proposal\n     */\n    function voteSplit(uint256 _votesYes, uint256 _votesNo) external {\n        require(\n            getTime() < voteEnds,\n            \"Votes can only be recorded during the voting period\"\n        );\n\n        uint256 _amount = votingPower(msg.sender, blockNumber);\n\n        require(\n            _amount > 0,\n            \"Voters must have held tokens before this voting cycle\"\n        );\n\n        uint256 _totalVotes = _votesYes + _votesNo;\n\n        require(\n            _amount >= _totalVotes,\n            \"Your voting power is less than submitted yes + no votes\"\n        );\n\n        VotePartial storage vpower = votePartials[msg.sender];\n        uint256 _oldStake = vpower.stake;\n        uint256 _oldYesVotes = vpower.yesVotes;\n\n        if (_oldYesVotes > 0) {\n            yesStake -= _oldYesVotes;\n        }\n\n        vpower.yesVotes = _votesYes;\n        yesStake += _votesYes;\n\n        vpower.stake = _totalVotes;\n        totalStake = totalStake + _totalVotes - _oldStake;\n\n        emit PolicyVote(msg.sender, _votesYes, _votesNo);\n    }\n\n    /** Initialize a cloned/proxied copy of this contract.\n     *\n     * @param _self The original contract, to provide access to storage data.\n     */\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n    }\n\n    /** Configure the proposals that are part of this voting cycle and start\n     * the lockup period.\n     *\n     * This also fixes the end times of each subsequent phase.\n     *\n     * This can only be called once, and should be called atomically with\n     * instantiation.\n     *\n     * @param _proposal The proposal to vote on.\n     */\n    function configure(\n        Proposal _proposal,\n        address _proposer,\n        uint256 _cutoffBlockNumber,\n        uint256 _totalECOxSnapshot,\n        uint256 _excludedVotingPower\n    ) external {\n        require(voteEnds == 0, \"This instance has already been configured\");\n\n        voteEnds = getTime() + VOTE_TIME;\n        blockNumber = _cutoffBlockNumber;\n        totalECOxSnapshot = _totalECOxSnapshot;\n        excludedVotingPower = _excludedVotingPower;\n\n        proposal = _proposal;\n        proposer = _proposer;\n    }\n\n    /** Execute the proposal if it has enough support.\n     *\n     * Can only be called after the voting and the delay phase,\n     * or after the point that at least 50% of the total voting power\n     * has voted in favor of the proposal.\n     *\n     * If the proposal has been accepted, it will be enacted by\n     * calling the `enacted` functions using `delegatecall`\n     * from the root policy.\n     */\n    function execute() external {\n        uint256 _total = totalVotingPower(blockNumber);\n\n        Result _res;\n\n        if (2 * yesStake < _total) {\n            require(\n                getTime() > voteEnds + ENACTION_DELAY,\n                \"Majority support required for early enaction\"\n            );\n        }\n\n        require(\n            policyFor(ID_POLICY_VOTES) == address(this),\n            \"This contract no longer has authorization to enact the vote\"\n        );\n\n        if (totalStake == 0) {\n            // Nobody voted\n            _res = Result.Failed;\n        } else if (2 * yesStake < totalStake) {\n            // Not enough yes votes\n            _res = Result.Rejected;\n        } else {\n            // Vote passed\n            _res = Result.Accepted;\n\n            //Enact the policy\n            policy.internalCommand(address(proposal), ID_POLICY_VOTES);\n        }\n\n        emit VoteCompletion(_res);\n        policy.removeSelf(ID_POLICY_VOTES);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/community/proposals/Proposal.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/** @title Proposal\n * Interface specification for proposals. Any proposal submitted in the\n * policy decision process must implement this interface.\n */\ninterface Proposal {\n    /** The name of the proposal.\n     *\n     * This should be relatively unique and descriptive.\n     */\n    function name() external view returns (string memory);\n\n    /** A longer description of what this proposal achieves.\n     */\n    function description() external view returns (string memory);\n\n    /** A URL where voters can go to see the case in favour of this proposal,\n     * and learn more about it.\n     */\n    function url() external view returns (string memory);\n\n    /** Called to enact the proposal.\n     *\n     * This will be called from the root policy contract using delegatecall,\n     * with the direct proposal address passed in as _self so that storage\n     * data can be accessed if needed.\n     *\n     * @param _self The address of the proposal contract.\n     */\n    function enacted(address _self) external;\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/community/VotingPower.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../monetary/Lockup.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../currency/ECO.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"./ECOxStaking.sol\";\n\n/** @title VotingPower\n * Compute voting power for user\n */\ncontract VotingPower is PolicedUtils {\n    // ECOx voting power is snapshotted when the contract is cloned\n    uint256 public totalECOxSnapshot;\n\n    // voting power to exclude from totalVotingPower\n    uint256 public excludedVotingPower;\n\n    // the ECO contract address\n    ECO public immutable ecoToken;\n\n    constructor(Policy _policy, ECO _ecoAddr) PolicedUtils(_policy) {\n        require(\n            address(_ecoAddr) != address(0),\n            \"Unrecoverable: do not set the _ecoAddr as the zero address\"\n        );\n        ecoToken = _ecoAddr;\n    }\n\n    function totalVotingPower(uint256 _blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        uint256 _supply = ecoToken.totalSupplyAt(_blockNumber);\n\n        return _supply + 10 * totalECOxSnapshot - excludedVotingPower;\n    }\n\n    function votingPower(address _who, uint256 _blockNumber)\n        public\n        view\n        returns (uint256)\n    {\n        uint256 _power = ecoToken.getPastVotes(_who, _blockNumber);\n        uint256 _powerx = getXStaking().votingECOx(_who, _blockNumber);\n        // ECOx has 10x the voting power of ECO per unit\n        return _power + 10 * _powerx;\n    }\n\n    function getXStaking() internal view returns (ECOxStaking) {\n        return ECOxStaking(policyFor(ID_ECOXSTAKING));\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/CurrencyTimer.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../policy/PolicedUtils.sol\";\nimport \"../policy/Policy.sol\";\nimport \"./community/PolicyProposals.sol\";\nimport \"./monetary/CurrencyGovernance.sol\";\nimport \"../utils/TimeUtils.sol\";\nimport \"./IGenerationIncrease.sol\";\nimport \"./IGeneration.sol\";\nimport \"./monetary/Lockup.sol\";\nimport \"./monetary/RandomInflation.sol\";\nimport \"../currency/ECO.sol\";\n\n/** @title TimedPolicies\n * Oversees the time-based recurring processes that allow governance of the\n * Eco currency.\n */\ncontract CurrencyTimer is PolicedUtils, IGenerationIncrease {\n    /** The on-chain address for the currency voting contract. This contract is\n     * cloned for each new currency vote.\n     */\n    CurrencyGovernance public bordaImpl;\n\n    RandomInflation public inflationImpl;\n    Lockup public lockupImpl;\n\n    // the ECO contract address\n    ECO public immutable ecoToken;\n\n    /* Current generation of the balance store. */\n    uint256 public currentGeneration;\n\n    mapping(uint256 => Lockup) public lockups;\n    mapping(address => bool) public isLockup;\n\n    mapping(uint256 => RandomInflation) public randomInflations;\n\n    event NewInflation(\n        RandomInflation indexed addr,\n        uint256 indexed generation\n    );\n    event NewLockup(Lockup indexed addr, uint256 indexed generation);\n    event NewCurrencyGovernance(\n        CurrencyGovernance indexed addr,\n        uint256 indexed generation\n    );\n\n    constructor(\n        Policy _policy,\n        CurrencyGovernance _borda,\n        RandomInflation _inflation,\n        Lockup _lockup,\n        ECO _ecoAddr\n    ) PolicedUtils(_policy) {\n        require(\n            address(_borda) != address(0),\n            \"Critical: do not set the _borda as the zero address\"\n        );\n        require(\n            address(_inflation) != address(0),\n            \"Critical: do not set the _inflation as the zero address\"\n        );\n        require(\n            address(_lockup) != address(0),\n            \"Critical: do not set the _lockup as the zero address\"\n        );\n        require(\n            address(_ecoAddr) != address(0),\n            \"Critical: do not set the _ecoAddr as the zero address\"\n        );\n        bordaImpl = _borda;\n        inflationImpl = _inflation;\n        lockupImpl = _lockup;\n        ecoToken = _ecoAddr;\n    }\n\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n\n        // all of these values are better left mutable to allow for easier governance\n        bordaImpl = CurrencyTimer(_self).bordaImpl();\n        inflationImpl = CurrencyTimer(_self).inflationImpl();\n        lockupImpl = CurrencyTimer(_self).lockupImpl();\n    }\n\n    function notifyGenerationIncrease() external override {\n        uint256 _old = currentGeneration;\n        uint256 _new = IGeneration(policyFor(ID_TIMED_POLICIES)).generation();\n        require(_new != _old, \"Generation has not increased\");\n\n        currentGeneration = _new;\n\n        CurrencyGovernance bg = CurrencyGovernance(\n            policyFor(ID_CURRENCY_GOVERNANCE)\n        );\n\n        uint256 _numberOfRecipients = 0;\n        uint256 _randomInflationReward = 0;\n        uint256 _lockupDuration = 0;\n        uint256 _lockupInterest = 0;\n\n        if (address(bg) != address(0)) {\n            if (uint8(bg.currentStage()) < 3) {\n                bg.updateStage();\n            }\n            if (uint8(bg.currentStage()) == 3) {\n                bg.compute();\n            }\n            address winner = bg.winner();\n            if (winner != address(0)) {\n                (\n                    _numberOfRecipients,\n                    _randomInflationReward,\n                    _lockupDuration,\n                    _lockupInterest,\n                    ,\n\n                ) = bg.proposals(winner);\n            }\n        }\n\n        {\n            CurrencyGovernance _clone = CurrencyGovernance(bordaImpl.clone());\n            policy.setPolicy(\n                ID_CURRENCY_GOVERNANCE,\n                address(_clone),\n                ID_CURRENCY_TIMER\n            );\n            emit NewCurrencyGovernance(_clone, _new);\n        }\n\n        if (_numberOfRecipients > 0 && _randomInflationReward > 0) {\n            // new inflation contract\n            RandomInflation _clone = RandomInflation(inflationImpl.clone());\n            ecoToken.mint(\n                address(_clone),\n                _numberOfRecipients * _randomInflationReward\n            );\n            _clone.startInflation(_numberOfRecipients, _randomInflationReward);\n            emit NewInflation(_clone, _old);\n            randomInflations[_old] = _clone;\n        }\n\n        if (_lockupDuration > 0 && _lockupInterest > 0) {\n            Lockup _clone = Lockup(\n                lockupImpl.clone(_lockupDuration, _lockupInterest)\n            );\n            emit NewLockup(_clone, _old);\n            lockups[_old] = _clone;\n            isLockup[address(_clone)] = true;\n        }\n    }\n\n    function lockupWithdrawal(\n        address _withdrawer,\n        uint256 _amount,\n        bool _penalty\n    ) external {\n        require(isLockup[msg.sender], \"Not authorized to call this function\");\n\n        if (_penalty) {\n            ecoToken.burn(_withdrawer, _amount);\n        } else {\n            ecoToken.mint(_withdrawer, _amount);\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/IGeneration.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IGeneration {\n    // generations index from 1000, see GENERATION_START in PolicedUtils.sol\n    // @return uint256 generation number\n    function generation() external view returns (uint256);\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/IGenerationIncrease.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IGenerationIncrease {\n    /**\n     * This function is called by the TimedPolicies to update this contract on a generation increase.\n     * Its presence on a contract implies that the contract's identifier is in the notificationHashes\n     * array on the TimedPolicies contract.\n     */\n    function notifyGenerationIncrease() external;\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/monetary/CurrencyGovernance.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/security/Pausable.sol\";\nimport \"./TrustedNodes.sol\";\nimport \"../../policy/Policy.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../currency/IECO.sol\";\nimport \"./RandomInflation.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"../../VDF/VDFVerifier.sol\";\n\n/** @title Inflation/Deflation Process\n *\n * This contract oversees the voting on the currency inflation/deflation process.\n * Trusted nodes vote on a policy that is implemented the following generation\n * to manage the relative price of Eco tokens.\n */\ncontract CurrencyGovernance is PolicedUtils, TimeUtils, Pausable {\n    enum Stage {\n        Propose,\n        Commit,\n        Reveal,\n        Compute,\n        Finished\n    }\n\n    // tracks the progress of the contract\n    Stage public currentStage;\n\n    // data structure for monetary policy proposals\n    struct GovernanceProposal {\n        // random inflation recipients\n        uint256 numberOfRecipients;\n        // amount of weico recieved by each random inflation recipient\n        uint256 randomInflationReward;\n        // duration in seconds\n        uint256 lockupDuration;\n        // lockup interest as a 9 digit fixed point number\n        uint256 lockupInterest;\n        // multiplier for linear inflation as an 18 digit fixed point number\n        uint256 inflationMultiplier;\n        // to store a link to more information\n        string description;\n    }\n\n    struct Vote {\n        // the proposal being voted for\n        address proposal;\n        // the score of this proposal within the ballot, min recorded score is one\n        // to get a score of zero, an item must be unscored\n        uint256 score;\n    }\n\n    // timescales\n    uint256 public constant PROPOSAL_TIME = 10 days;\n    uint256 public constant VOTING_TIME = 3 days;\n    uint256 public constant REVEAL_TIME = 1 days;\n\n    // timestamps for the above periods\n    uint256 public proposalEnds;\n    uint256 public votingEnds;\n    uint256 public revealEnds;\n\n    uint256 public constant IDEMPOTENT_INFLATION_MULTIPLIER = 1e18;\n\n    // max length of description field\n    uint256 public constant MAX_DATA = 160;\n\n    // mapping of proposing trustee addresses to their submitted proposals\n    mapping(address => GovernanceProposal) public proposals;\n    // mapping of trustee addresses to their hash commits for voting\n    mapping(address => bytes32) public commitments;\n    // mapping of proposals (indexed by the submitting trustee) to their voting score, accumulated during reveal\n    mapping(address => uint256) public score;\n\n    // used to track the leading proposal during the vote totalling\n    address public leader;\n    // used to denote the winning proposal when the vote is finalized\n    address public winner;\n\n    // address that can pause currency governance\n    address public pauser;\n\n    // emitted when a proposal is submitted to track the values\n    event ProposalCreation(\n        address indexed trusteeAddress,\n        uint256 _numberOfRecipients,\n        uint256 _randomInflationReward,\n        uint256 _lockupDuration,\n        uint256 _lockupInterest,\n        uint256 _inflationMultiplier,\n        string _description\n    );\n\n    // emitted when a trustee retracts their proposal\n    event ProposalRetraction(address indexed trustee);\n\n    /** Fired when the voting stage begins.\n     * Triggered by updateStage().\n     */\n    event VoteStart();\n\n    /** Fired when a trustee casts a vote.\n     */\n    event VoteCast(address indexed trustee);\n\n    /** Fired when the reveal stage begins.\n     * Triggered by updateStage().\n     */\n    event RevealStart();\n\n    /** Fired when a vote is revealed, to create a voting history for all\n     * participants. Records the voter, as well as all of the parameters of\n     * the vote cast.\n     */\n    event VoteReveal(address indexed voter, Vote[] votes);\n\n    /** Fired when vote results are computed, creating a permanent record of\n     * vote outcomes.\n     */\n    event VoteResult(address indexed winner);\n\n    /**\n     * @notice event indicating the pauser was updated\n     * @param pauser The new pauser\n     */\n    event PauserAssignment(address indexed pauser);\n\n    modifier onlyPauser() {\n        require(msg.sender == pauser, \"CurrencyGovernance: not pauser\");\n        _;\n    }\n\n    modifier atStage(Stage _stage) {\n        updateStage();\n        require(\n            currentStage == _stage,\n            \"This call is not allowed at this stage\"\n        );\n        _;\n    }\n\n    function updateStage() public {\n        uint256 time = getTime();\n        if (currentStage == Stage.Propose && time >= proposalEnds) {\n            currentStage = Stage.Commit;\n            emit VoteStart();\n        }\n        if (currentStage == Stage.Commit && time >= votingEnds) {\n            currentStage = Stage.Reveal;\n            emit RevealStart();\n        }\n        if (currentStage == Stage.Reveal && time >= revealEnds) {\n            currentStage = Stage.Compute;\n        }\n    }\n\n    constructor(Policy _policy, address _initialPauser) PolicedUtils(_policy) {\n        pauser = _initialPauser;\n        emit PauserAssignment(_initialPauser);\n    }\n\n    /** Restrict access to trusted nodes only.\n     */\n    modifier onlyTrusted() {\n        require(\n            getTrustedNodes().isTrusted(msg.sender),\n            \"Only trusted nodes can call this method\"\n        );\n        _;\n    }\n\n    function propose(\n        uint256 _numberOfRecipients,\n        uint256 _randomInflationReward,\n        uint256 _lockupDuration,\n        uint256 _lockupInterest,\n        uint256 _inflationMultiplier,\n        string calldata _description\n    ) external onlyTrusted atStage(Stage.Propose) {\n        require(\n            _inflationMultiplier > 0,\n            \"Inflation multiplier cannot be zero\"\n        );\n        require(\n            // didn't choose this number for any particular reason\n            uint256(bytes(_description).length) <= MAX_DATA,\n            \"Description is too long\"\n        );\n\n        GovernanceProposal storage p = proposals[msg.sender];\n        p.numberOfRecipients = _numberOfRecipients;\n        p.randomInflationReward = _randomInflationReward;\n        p.lockupDuration = _lockupDuration;\n        p.lockupInterest = _lockupInterest;\n        p.inflationMultiplier = _inflationMultiplier;\n        p.description = _description;\n\n        emit ProposalCreation(\n            msg.sender,\n            _numberOfRecipients,\n            _randomInflationReward,\n            _lockupDuration,\n            _lockupInterest,\n            _inflationMultiplier,\n            _description\n        );\n    }\n\n    function unpropose() external atStage(Stage.Propose) {\n        require(\n            proposals[msg.sender].inflationMultiplier != 0,\n            \"You do not have a proposal to retract\"\n        );\n        delete proposals[msg.sender];\n        emit ProposalRetraction(msg.sender);\n    }\n\n    function commit(bytes32 _commitment)\n        external\n        onlyTrusted\n        atStage(Stage.Commit)\n    {\n        commitments[msg.sender] = _commitment;\n        emit VoteCast(msg.sender);\n    }\n\n    function reveal(bytes32 _seed, Vote[] calldata _votes)\n        external\n        atStage(Stage.Reveal)\n    {\n        uint256 numVotes = _votes.length;\n        require(numVotes > 0, \"Invalid vote, cannot vote empty\");\n        require(\n            commitments[msg.sender] != bytes32(0),\n            \"Invalid vote, no unrevealed commitment exists\"\n        );\n        require(\n            keccak256(abi.encode(_seed, msg.sender, _votes)) ==\n                commitments[msg.sender],\n            \"Invalid vote, commitment mismatch\"\n        );\n\n        delete commitments[msg.sender];\n\n        // remove the trustee's default vote\n        score[address(0)] -= 1;\n\n        // use memory vars to store and track the changes of the leader\n        address priorLeader = leader;\n        address leaderTracker = priorLeader;\n        uint256 leaderRankTracker = 0;\n\n        /**\n         * by setting this to 1, the code can skip checking _score != 0\n         */\n        uint256 scoreDuplicateCheck = 1;\n\n        for (uint256 i = 0; i < numVotes; ++i) {\n            Vote memory v = _votes[i];\n            address _proposal = v.proposal;\n            uint256 _score = v.score;\n\n            require(\n                proposals[_proposal].inflationMultiplier > 0,\n                \"Invalid vote, missing proposal\"\n            );\n            require(\n                i == 0 || _votes[i - 1].proposal < _proposal,\n                \"Invalid vote, proposals not in increasing order\"\n            );\n            require(\n                _score <= numVotes,\n                \"Invalid vote, proposal score out of bounds\"\n            );\n            require(\n                scoreDuplicateCheck & (1 << _score) == 0,\n                \"Invalid vote, duplicate score\"\n            );\n\n            scoreDuplicateCheck += 1 << _score;\n\n            score[_proposal] += _score;\n            if (score[_proposal] > score[leaderTracker]) {\n                leaderTracker = _proposal;\n                leaderRankTracker = _score;\n            } else if (score[_proposal] == score[leaderTracker]) {\n                if (_score > leaderRankTracker) {\n                    leaderTracker = _proposal;\n                    leaderRankTracker = _score;\n                }\n            }\n        }\n\n        // only changes the leader if the new leader is of greater score\n        if (\n            leaderTracker != priorLeader &&\n            score[leaderTracker] > score[priorLeader]\n        ) {\n            leader = leaderTracker;\n        }\n\n        // record the trustee's vote for compensation purposes\n        getTrustedNodes().recordVote(msg.sender);\n\n        emit VoteReveal(msg.sender, _votes);\n    }\n\n    function compute() external atStage(Stage.Compute) {\n        // if paused then the default policy automatically wins\n        if (!paused()) {\n            winner = leader;\n        }\n\n        currentStage = Stage.Finished;\n\n        emit VoteResult(winner);\n    }\n\n    /** Initialize the storage context using parameters copied from the\n     * original contract (provided as _self).\n     *\n     * Can only be called once, during proxy initialization.\n     *\n     * @param _self The original contract address.\n     */\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n        TimedPolicies timedPolicies = TimedPolicies(\n            policyFor(ID_TIMED_POLICIES)\n        );\n        proposalEnds =\n            timedPolicies.generationEnd() -\n            MIN_GENERATION_DURATION +\n            PROPOSAL_TIME;\n        votingEnds = proposalEnds + VOTING_TIME;\n        revealEnds = votingEnds + REVEAL_TIME;\n\n        // should not emit an event\n        pauser = CurrencyGovernance(_self).pauser();\n\n        GovernanceProposal storage p = proposals[address(0)];\n        p.inflationMultiplier = IDEMPOTENT_INFLATION_MULTIPLIER;\n\n        // sets the default votes for the default proposal\n        score[address(0)] = getTrustedNodes().numTrustees();\n    }\n\n    function getTrustedNodes() private view returns (TrustedNodes) {\n        return TrustedNodes(policyFor(ID_TRUSTED_NODES));\n    }\n\n    /**\n     * @notice set the given address as the pauser\n     * @param _pauser The address that can pause this token\n     * @dev only the roleAdmin can call this function\n     */\n    function setPauser(address _pauser) public onlyPolicy {\n        pauser = _pauser;\n        emit PauserAssignment(_pauser);\n    }\n\n    /**\n     * @notice pauses transfers of this token\n     * @dev only callable by the pauser\n     */\n    function pause() external onlyPauser {\n        _pause();\n    }\n\n    /**\n     * @notice unpauses transfers of this token\n     * @dev only callable by the pauser\n     */\n    function unpause() external onlyPauser {\n        _unpause();\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/monetary/InflationRootHashProposal.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../policy/Policy.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"../../currency/IECO.sol\";\nimport \"../monetary/RandomInflation.sol\";\n\n/** @title Inflation Root Hash Proposal\n * This implements a root hash proposal contract to\n * establish a merkle tree representing accounts and balances\n *\n * Merkle Tree serves as a way to fairly establish which addresses can claim the random inflation reward\n */\ncontract InflationRootHashProposal is PolicedUtils, TimeUtils {\n    enum ChallengeStatus {\n        Empty,\n        Pending,\n        Resolved\n    }\n\n    enum RootHashStatus {\n        Uninitialized,\n        Pending,\n        Rejected,\n        Accepted\n    }\n\n    struct ChallengeResponse {\n        address account;\n        uint256 balance;\n        uint256 sum;\n    }\n\n    struct InflationChallenge {\n        bool initialized;\n        uint256 challengeEnds;\n        uint256 amountOfRequests;\n        mapping(uint256 => ChallengeStatus) challengeStatus;\n    }\n\n    struct RootHashProposal {\n        bool initialized;\n        bytes32 rootHash;\n        uint256 totalSum;\n        uint256 amountOfAccounts;\n        uint256 lastLiveChallenge;\n        uint256 amountPendingChallenges;\n        uint256 totalChallenges;\n        uint256 stakedAmount;\n        uint256 newChallengerSubmissionEnds;\n        RootHashStatus status;\n        mapping(address => InflationChallenge) challenges;\n        mapping(uint256 => ChallengeResponse) challengeResponses;\n        mapping(address => bool) claimed;\n    }\n\n    // the ECO token contract address\n    IECO public immutable ecoToken;\n\n    /** The root hash accepted for current generation, set as a final result */\n    bytes32 public acceptedRootHash;\n\n    /** The total cumulative sum of the accepted root hash proposal */\n    uint256 public acceptedTotalSum;\n\n    /** The total number of accounts in the merkle tree of the accepted root hash proposal */\n    uint256 public acceptedAmountOfAccounts;\n\n    /** proposer to proposal data structure. Stores all evaluated proposals */\n    mapping(address => RootHashProposal) public rootHashProposals;\n\n    /** Challenger charged with CHALLENGE_FEE ECO every time they challenge proposal */\n    uint256 public constant CHALLENGE_FEE = 1000e18;\n\n    /** Root hash proposer charged with PROPOSER_FEE ECO for the root hash submission */\n    uint256 public constant PROPOSER_FEE = 100000e18;\n\n    /** Initial amount of time given to challengers to submit challenges to new proposal */\n    uint256 public constant CHALLENGING_TIME = 1 days;\n\n    /** Amount of time given to challengers to contest a challenges to a proposal */\n    uint256 public constant CONTESTING_TIME = 1 hours;\n\n    /** The time period to collect fees after the root hash was accepted.\n     */\n    uint256 public constant FEE_COLLECTION_TIME = 180 days;\n\n    /** The blacklisted address for the Uni v2 AMM pool */\n    address public constant POOL_ADDRESS =\n        0x09bC52B9EB7387ede639Fc10Ce5Fa01CBCBf2b17;\n\n    /** The first blacklisted address for Eco Associaton */\n    address public constant ECO_ASSOCIATION1 =\n        0x98830c37Aa6aBDaE028Bea5c587852c569092d71;\n\n    /** The second blacklisted address for Eco Associaton */\n    address public constant ECO_ASSOCIATION2 =\n        0x99f98ea4A883DB4692Fa317070F4ad2dC94b05CE;\n\n    /** The blacklisted address for Eco Inc. */\n    address public constant ECO_INC =\n        0xA201d3C815AC9D4d8830fb3dE2b490B5b0069ACa;\n\n    /** The timestamp at which the fee collection phase ends and contract might be destructed.\n     */\n    uint256 public feeCollectionEnds;\n\n    /** merkle tree verified against balances at block number\n     */\n    uint256 public blockNumber;\n\n    /* Event to be emitted whenever a new root hash proposal submitted to the contract.\n     */\n    event RootHashPost(\n        address indexed proposer,\n        bytes32 indexed proposedRootHash,\n        uint256 totalSum,\n        uint256 amountOfAccounts\n    );\n\n    /* Event to be emitted whenever a new challenge to root hash submitted to the contract.\n     */\n    event RootHashChallengeIndexRequest(\n        address indexed proposer,\n        address challenger,\n        uint256 indexed index\n    );\n\n    /* Event to be emitted whenever proposer successfully responded to a challenge\n     */\n    event ChallengeSuccessResponse(\n        address indexed proposer,\n        address challenger,\n        address account,\n        uint256 balance,\n        uint256 sum,\n        uint256 indexed index\n    );\n\n    /* Event to be emitted whenever a root hash proposal rejected.\n     */\n    event RootHashRejection(address indexed proposer);\n\n    /* Event to be emitted whenever a missing account claim succeeded. Root hash is rejected.\n     */\n    event ChallengeMissingAccountSuccess(\n        address indexed proposer,\n        address challenger,\n        address missingAccount,\n        uint256 indexed index\n    );\n\n    /* Event to be emitted whenever a root hash proposal accepted.\n     */\n    event RootHashAcceptance(\n        address indexed proposer,\n        uint256 totalSum,\n        uint256 amountOfAccounts\n    );\n\n    /* Event to be emitted whenever the configuration for the inflation root hash proposal contract is set\n     */\n    event ConfigureBlock(uint256 _blockNumber);\n\n    modifier hashIsNotAcceptedYet() {\n        require(\n            acceptedRootHash == 0,\n            \"The root hash accepted, no more actions allowed\"\n        );\n        _;\n    }\n\n    constructor(Policy _policy, IECO _ecoAddr) PolicedUtils(_policy) {\n        require(\n            address(_ecoAddr) != address(0),\n            \"do not set the _ecoAddr as the zero address\"\n        );\n        ecoToken = IECO(_ecoAddr);\n    }\n\n    /** @notice Configure the inflation root hash proposal contract\n     *  which is part of the random inflation mechanism\n     *\n     * @param _blockNumber block number to verify accounts balances against\n     */\n    function configure(uint256 _blockNumber) external {\n        require(blockNumber == 0, \"This instance has already been configured\");\n\n        blockNumber = _blockNumber;\n        emit ConfigureBlock(_blockNumber);\n    }\n\n    /** @notice Allows to propose new root hash\n     *  which is part of the random inflation mechanism\n     *\n     * @param _proposedRootHash a root hash of the merkle tree describing all the accounts\n     * @param _totalSum total cumulative sum of all the balances in the merkle tree\n     * @param _amountOfAccounts total amount of accounts in the tree\n     */\n    function proposeRootHash(\n        bytes32 _proposedRootHash,\n        uint256 _totalSum,\n        uint256 _amountOfAccounts\n    ) external hashIsNotAcceptedYet {\n        require(_proposedRootHash != bytes32(0), \"Root hash cannot be zero\");\n        require(_totalSum > 0, \"Total sum cannot be zero\");\n        require(\n            _amountOfAccounts > 0,\n            \"Hash must consist of at least 1 account\"\n        );\n\n        RootHashProposal storage proposal = rootHashProposals[msg.sender];\n\n        require(!proposal.initialized, \"Root hash already proposed\");\n\n        proposal.initialized = true;\n        proposal.status = RootHashStatus.Pending;\n        proposal.rootHash = _proposedRootHash;\n        proposal.totalSum = _totalSum;\n        proposal.amountOfAccounts = _amountOfAccounts;\n        proposal.newChallengerSubmissionEnds = getTime() + CHALLENGING_TIME;\n\n        emit RootHashPost(\n            msg.sender,\n            _proposedRootHash,\n            _totalSum,\n            _amountOfAccounts\n        );\n\n        chargeFee(msg.sender, msg.sender, PROPOSER_FEE);\n    }\n\n    /** @notice Allows to challenge previously proposed root hash.\n     *  Challenge requires proposer of the root hash submit proof of the account for requested index\n     *\n     *  @param _proposer  the roothash proposer address\n     *  @param _index    index in the merkle tree of the account being challenged\n     */\n    function challengeRootHashRequestAccount(address _proposer, uint256 _index)\n        external\n        hashIsNotAcceptedYet\n    {\n        requireValidChallengeConstraints(_proposer, msg.sender);\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n        require(\n            proposal.amountOfAccounts > _index,\n            \"may only request an index within the tree\"\n        );\n\n        InflationChallenge storage challenge = proposal.challenges[msg.sender];\n\n        if (!challenge.initialized) {\n            challenge.initialized = true;\n            challenge.challengeEnds = getTime() + CHALLENGING_TIME;\n            challenge.challengeStatus[_index] = ChallengeStatus.Pending;\n        } else {\n            require(\n                challenge.challengeStatus[_index] == ChallengeStatus.Empty,\n                \"Index already challenged\"\n            );\n            challenge.challengeStatus[_index] = ChallengeStatus.Pending;\n        }\n        emit RootHashChallengeIndexRequest(_proposer, msg.sender, _index);\n        updateCounters(_proposer, msg.sender);\n\n        chargeFee(msg.sender, _proposer, CHALLENGE_FEE);\n    }\n\n    /** @notice A special challenge, the challenger can claim that an account is missing\n     *\n     * @param _proposer         the roothash proposer address\n     * @param _index        index in the merkle tree of the account being challenged\n     * @param _account      address of the missing account\n     */\n    function claimMissingAccount(\n        address _proposer,\n        uint256 _index,\n        address _account\n    ) external hashIsNotAcceptedYet {\n        requireValidChallengeConstraints(_proposer, msg.sender);\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n        require(\n            proposal.amountOfAccounts >= _index,\n            \"missing account position must be to the left of the submitted index\"\n        );\n\n        InflationChallenge storage challenge = proposal.challenges[msg.sender];\n\n        require(\n            ecoToken.getPastVotes(_account, blockNumber) > 0,\n            \"Missing account does not exist\"\n        );\n        require(\n            _account != address(0),\n            \"The zero address not allowed in Merkle tree\"\n        );\n        require(\n            _account != address(policy),\n            \"The policy address not allowed in Merkle tree\"\n        );\n        require(\n            _account != POOL_ADDRESS,\n            \"The pool address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_ASSOCIATION1,\n            \"The association address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_ASSOCIATION2,\n            \"The association address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_INC,\n            \"The eco inc address not allowed in Merkle tree\"\n        );\n\n        require(challenge.initialized, \"Submit Index Request first\");\n\n        if (_index != 0) {\n            require(\n                challenge.challengeStatus[_index - 1] ==\n                    ChallengeStatus.Resolved,\n                \"Left _index is not resolved\"\n            );\n            require(\n                proposal.challengeResponses[_index - 1].account < _account,\n                \"Missing account claim failed\"\n            );\n        }\n        if (_index != proposal.amountOfAccounts) {\n            require(\n                challenge.challengeStatus[_index] == ChallengeStatus.Resolved,\n                \"Right _index is not resolved\"\n            );\n            require(\n                _account < proposal.challengeResponses[_index].account,\n                \"Missing account claim failed\"\n            );\n        }\n\n        challenge.amountOfRequests += 1;\n\n        emit ChallengeMissingAccountSuccess(\n            _proposer,\n            msg.sender,\n            _account,\n            _index\n        );\n        rejectRootHash(_proposer);\n    }\n\n    /** @notice Allows to proposer of the root hash respond to a challenge of specific index with proof details\n     *\n     *  @param _challenger       address of the submitter of the challenge\n     *  @param _proof            the “other nodes” in the merkle tree.\n     *  @param _account          address of an account of challenged index in the tree\n     *  @param _claimedBalance   balance of an account of challenged index in the tree\n     *  @param _sum              cumulative sum of an account of challenged index in the tree\n     *  @param _index            index in the merkle tree being answered\n     */\n    function respondToChallenge(\n        address _challenger,\n        bytes32[] calldata _proof,\n        address _account,\n        uint256 _claimedBalance,\n        uint256 _sum,\n        uint256 _index\n    ) external hashIsNotAcceptedYet {\n        require(\n            _claimedBalance > 0,\n            \"Accounts with zero balance not allowed in Merkle tree\"\n        );\n        require(\n            _account != address(0),\n            \"The zero address not allowed in Merkle tree\"\n        );\n        require(\n            _account != address(policy),\n            \"The policy address not allowed in Merkle tree\"\n        );\n        require(\n            _account != POOL_ADDRESS,\n            \"The pool address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_ASSOCIATION1,\n            \"The association address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_ASSOCIATION2,\n            \"The association address not allowed in Merkle tree\"\n        );\n        require(\n            _account != ECO_INC,\n            \"The eco inc address not allowed in Merkle tree\"\n        );\n\n        RootHashProposal storage proposal = rootHashProposals[msg.sender];\n        InflationChallenge storage challenge = proposal.challenges[_challenger];\n        uint256 challengeEnds = challenge.challengeEnds;\n\n        require(\n            getTime() < challengeEnds,\n            \"Timeframe to respond to a challenge is over\"\n        );\n\n        require(\n            challenge.challengeStatus[_index] == ChallengeStatus.Pending,\n            \"There is no pending challenge for this index\"\n        );\n\n        /* Since the merkle tree includes the index as the hash, it's impossible to give isomorphic answers,\n         * so any attempt to answer with a different value than what was used before will fail the merkle check,\n         * hence this doesn't care if it rewrites previous answer */\n        ChallengeResponse storage indexChallenge = proposal.challengeResponses[\n            _index\n        ];\n        indexChallenge.account = _account;\n        indexChallenge.balance = _claimedBalance;\n        indexChallenge.sum = _sum;\n\n        require(\n            ecoToken.getPastVotes(_account, blockNumber) == _claimedBalance,\n            \"Challenge response failed account balance check\"\n        );\n\n        require(\n            verifyMerkleProof(\n                _proof,\n                proposal.rootHash,\n                keccak256(\n                    abi.encodePacked(_account, _claimedBalance, _sum, _index)\n                ),\n                _index,\n                proposal.amountOfAccounts\n            ),\n            \"Challenge response failed merkle tree verification check\"\n        );\n\n        // Ensure first account starts at 0 cumulative sum\n        if (_index == 0) {\n            require(_sum == 0, \"cumulative sum does not starts from 0\");\n        } else {\n            ChallengeResponse storage leftNeighborChallenge = proposal\n                .challengeResponses[_index - 1];\n            if (leftNeighborChallenge.balance != 0) {\n                // Is left neighbor queried, and is it valid?\n                require(\n                    leftNeighborChallenge.sum + leftNeighborChallenge.balance ==\n                        _sum,\n                    \"Left neighbor sum verification failed\"\n                );\n                require(\n                    leftNeighborChallenge.account < _account,\n                    \"Left neighbor order verification failed\"\n                );\n            }\n        }\n\n        // Ensure final account matches total sum\n        if (_index == proposal.amountOfAccounts - 1) {\n            require(\n                proposal.totalSum == _sum + _claimedBalance,\n                \"cumulative sum does not match total sum\"\n            );\n        } else {\n            ChallengeResponse storage rightNeighborChallenge = proposal\n                .challengeResponses[_index + 1];\n            // Is right neighbor queried, and is it valid?\n            if (rightNeighborChallenge.balance != 0) {\n                require(\n                    _sum + _claimedBalance == rightNeighborChallenge.sum,\n                    \"Right neighbor sum verification failed\"\n                );\n                require(\n                    _account < rightNeighborChallenge.account,\n                    \"Right neighbor order verification failed\"\n                );\n            }\n        }\n\n        emit ChallengeSuccessResponse(\n            msg.sender,\n            _challenger,\n            _account,\n            _claimedBalance,\n            _sum,\n            _index\n        );\n\n        challenge.challengeStatus[_index] = ChallengeStatus.Resolved;\n        proposal.amountPendingChallenges -= 1;\n        challengeEnds += CONTESTING_TIME;\n        challenge.challengeEnds = challengeEnds;\n\n        if (proposal.lastLiveChallenge < challengeEnds) {\n            proposal.lastLiveChallenge = challengeEnds;\n        }\n    }\n\n    /** @notice Checks root hash proposal. If time is out and there is unanswered challenges proposal is rejected. If time to submit\n     *  new challenges is over and there is no unanswered challenges, root hash is accepted.\n     *\n     *  @param _proposer the roothash proposer address\n     *\n     */\n    function checkRootHashStatus(address _proposer) external {\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n        require(proposal.initialized, \"No such proposal\");\n\n        if (\n            acceptedRootHash == 0 &&\n            getTime() > proposal.newChallengerSubmissionEnds &&\n            getTime() > proposal.lastLiveChallenge\n        ) {\n            if (proposal.amountPendingChallenges == 0) {\n                acceptRootHash(_proposer);\n            } else {\n                rejectRootHash(_proposer);\n            }\n        }\n\n        if (\n            acceptedRootHash != 0 && proposal.status == RootHashStatus.Pending\n        ) {\n            rejectRootHash(_proposer);\n        }\n    }\n\n    /** @notice Verifies that the account specified is associated with the provided cumulative sum in the approved\n     * Merkle tree for the current generation.\n     *\n     *  @param _who     address of the account attempting to claim\n     *  @param _proof   the “other nodes” in the merkle tree.\n     *  @param _sum     cumulative sum of a claiming account\n     *  @param _index   index of the account\n     */\n    function verifyClaimSubmission(\n        address _who,\n        bytes32[] calldata _proof,\n        uint256 _sum,\n        uint256 _index\n    ) external view returns (bool) {\n        require(\n            acceptedRootHash != 0,\n            \"Can't claim before root hash established\"\n        );\n        uint256 balance = ecoToken.getPastVotes(_who, blockNumber);\n        return\n            verifyMerkleProof(\n                _proof,\n                acceptedRootHash,\n                keccak256(abi.encodePacked(_who, balance, _sum, _index)),\n                _index,\n                acceptedAmountOfAccounts\n            );\n    }\n\n    /** @notice Allows to claim fee paid as part of challenge or proposal submissions\n     *\n     *  @param _who        fee recipient\n     *  @param _proposer   the roothash proposer address\n     */\n    function claimFeeFor(address _who, address _proposer) public {\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n        require(proposal.initialized, \"No such proposal\");\n        require(\n            proposal.status != RootHashStatus.Pending,\n            \"Cannot claimFee on pending proposal\"\n        );\n\n        require(!proposal.claimed[_who], \"fee already claimed\");\n\n        InflationChallenge storage challenge = proposal.challenges[_who];\n\n        if (_who == _proposer) {\n            require(\n                proposal.status == RootHashStatus.Accepted ||\n                    (proposal.status == RootHashStatus.Rejected &&\n                        proposal.rootHash == acceptedRootHash &&\n                        proposal.totalSum == acceptedTotalSum &&\n                        proposal.amountOfAccounts == acceptedAmountOfAccounts),\n                \"proposer can't claim fee on not accepted hash\"\n            );\n            require(\n                ecoToken.transfer(_who, proposal.stakedAmount),\n                \"Transfer Failed\"\n            );\n        } else {\n            require(\n                challenge.initialized &&\n                    proposal.status == RootHashStatus.Rejected,\n                \"challenger may claim fee on rejected proposal only\"\n            );\n            uint256 amount = challenge.amountOfRequests * CHALLENGE_FEE;\n            amount =\n                amount +\n                (proposal.stakedAmount *\n                    proposal.challenges[msg.sender].amountOfRequests) /\n                proposal.totalChallenges;\n            require(ecoToken.transfer(_who, amount), \"Transfer Failed\");\n        }\n        proposal.claimed[_who] = true;\n    }\n\n    /** @notice Allows to claim fee paid as part of challenge or proposal submissions\n     *          on behalf of the caller (`msg.sender`).\n     *\n     *  @param _proposer   the roothash proposer address\n     *\n     */\n    function claimFee(address _proposer) external {\n        claimFeeFor(msg.sender, _proposer);\n    }\n\n    /** @notice Reclaims tokens on the inflation root hash proposal contract.\n     *\n     */\n    function destruct() external {\n        require(\n            feeCollectionEnds != 0 && getTime() > feeCollectionEnds,\n            \"contract might be destructed after fee collection period is over\"\n        );\n        require(\n            ecoToken.transfer(\n                address(policy),\n                ecoToken.balanceOf(address(this))\n            ),\n            \"Transfer Failed\"\n        );\n    }\n\n    /** @notice updates root hash proposal data structure to mark it rejected\n     */\n    function rejectRootHash(address _proposer) internal {\n        rootHashProposals[_proposer].status = RootHashStatus.Rejected;\n        emit RootHashRejection(_proposer);\n    }\n\n    /** @notice updates root hash proposal data structure  and contract state variables\n     *  to mark root hash is accepted\n     */\n    function acceptRootHash(address _proposer) internal {\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n\n        proposal.status = RootHashStatus.Accepted;\n        acceptedRootHash = proposal.rootHash;\n        acceptedTotalSum = proposal.totalSum;\n        acceptedAmountOfAccounts = proposal.amountOfAccounts;\n        feeCollectionEnds = getTime() + FEE_COLLECTION_TIME;\n        emit RootHashAcceptance(\n            _proposer,\n            proposal.totalSum,\n            proposal.amountOfAccounts\n        );\n    }\n\n    /**\n     * @dev Returns true if a `_leaf` can be proved to be a part of a Merkle tree\n     * defined by `_root`. For this, a `_proof` must be provided, containing\n     * sibling hashes on the branch from the _leaf to the _root of the tree. Each\n     * pair of leaves and each pair of pre-images are assumed to be sorted.\n     * (c) https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/MerkleProof.sol\n     */\n    function verifyMerkleProof(\n        bytes32[] memory _proof,\n        bytes32 _root,\n        bytes32 _leaf,\n        uint256 _index,\n        uint256 _numAccounts\n    ) internal pure returns (bool) {\n        // ensure that the proof conforms to the minimum possible tree height\n        // and also that the number of accounts is small enough to fit in the claimed tree\n        if (\n            1 << (_proof.length - 1) >= _numAccounts ||\n            1 << (_proof.length) < _numAccounts\n        ) {\n            return false;\n        }\n\n        bytes32 computedHash = _leaf;\n\n        // checks for validity of proof elements and tree ordering\n        for (uint256 i = 0; i < _proof.length; i++) {\n            bytes32 proofElement = _proof[i];\n            if ((_index >> i) & 1 == 1) {\n                // Hash(current element of the _proof + current computed hash)\n                computedHash = keccak256(\n                    abi.encodePacked(proofElement, computedHash)\n                );\n            } else {\n                // Hash(current computed hash + current element of the _proof)\n                computedHash = keccak256(\n                    abi.encodePacked(computedHash, proofElement)\n                );\n            }\n        }\n\n        if (computedHash != _root) {\n            return false;\n        }\n\n        // xor to separate matching and non-matching elements of the bitmaps\n        uint256 branchBitMap = _index ^ (_numAccounts - 1);\n\n        // verifies that unused tree nodes are reperesnted by bytes32(0)\n        for (uint256 i = _proof.length; i > 0; i--) {\n            // check if this is traversing the right edge of the filled tree\n            // _numAccounts indexes from 1 but _index does so from zero\n            if ((branchBitMap >> (i - 1)) & 1 == 0) {\n                // see if the index is in a left branch requiring a zero valued right branch\n                if ((_index >> (i - 1)) & 1 == 0) {\n                    if (_proof[i - 1] != bytes32(0)) {\n                        return false;\n                    }\n                }\n            } else {\n                // the index is now in the middle of the tree, cannot check further\n                break;\n            }\n        }\n\n        // Check if the computed hash (_root) is equal to the provided _root\n        return true;\n    }\n\n    /** @notice increment counter that's used to track amount of open challenges and the timelines\n     */\n    function updateCounters(address _proposer, address _challenger) internal {\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n        InflationChallenge storage challenge = proposal.challenges[_challenger];\n        uint256 challengeEnds = challenge.challengeEnds + CONTESTING_TIME;\n\n        proposal.totalChallenges += 1;\n        proposal.amountPendingChallenges += 1;\n        challenge.amountOfRequests += 1;\n\n        challenge.challengeEnds = challengeEnds;\n\n        if (proposal.lastLiveChallenge < challengeEnds) {\n            proposal.lastLiveChallenge = challengeEnds;\n        }\n    }\n\n    /** @notice charge sender with a fee while updating tracking stake counter\n     */\n    function chargeFee(\n        address _submitter,\n        address _proposer,\n        uint256 _fee\n    ) internal {\n        require(\n            ecoToken.transferFrom(_submitter, address(this), _fee),\n            \"Transfer Failed\"\n        );\n        rootHashProposals[_proposer].stakedAmount += _fee;\n    }\n\n    function requireValidChallengeConstraints(\n        address _proposer,\n        address _challenger\n    ) internal view {\n        RootHashProposal storage proposal = rootHashProposals[_proposer];\n\n        require(\n            _proposer != _challenger,\n            \"Root hash proposer can't challenge its own submission\"\n        );\n        require(\n            proposal.rootHash != bytes32(0),\n            \"There is no such hash proposal\"\n        );\n        require(\n            proposal.status == RootHashStatus.Pending,\n            \"The proposal is resolved\"\n        );\n        uint256 requestsByChallenger = proposal\n            .challenges[_challenger]\n            .amountOfRequests;\n        if (requestsByChallenger > 2) {\n            /* math explanation x - number of request, N - amount of accounts, log base 2\n              condition  -- x < 2 * log( N ) + 2\n                            2 ^ x < 2 ^ (2 * log( N ) + 2)\n                            2 ^ (x - 2) < (2 ^ log( N )) ^ 2\n                            2 ^ (x - 2) < N ^ 2\n            */\n\n            require(\n                1 << (requestsByChallenger - 2) <=\n                    (proposal.amountOfAccounts)**2,\n                \"Challenger reached maximum amount of allowed challenges\"\n            );\n        }\n        InflationChallenge storage challenge = proposal.challenges[_challenger];\n        if (!challenge.initialized) {\n            require(\n                getTime() < proposal.newChallengerSubmissionEnds,\n                \"Time to submit new challenges is over\"\n            );\n        } else {\n            require(\n                getTime() < challenge.challengeEnds,\n                \"Time to submit additional challenges is over\"\n            );\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/monetary/Lockup.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../CurrencyTimer.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"../IGeneration.sol\";\nimport \"../../currency/ECO.sol\";\n\n/** @title Lockup\n * This provides deposit certificate functionality for the purpose of countering\n * inflationary effects.\n *\n * The contract instance is cloned by the CurrencyTimer contract when a vote outcome\n * mandates the issuance of deposit certificates. It has no special privileges.\n *\n * Deposits can be made and interest will be paid out to those who make\n * deposits. Deposit principal is accessable before the interested period\n * but for a penalty of not retrieving your gained interest as well as an\n * additional penalty of that same amount.\n */\ncontract Lockup is PolicedUtils, TimeUtils {\n    // data structure for deposits made per address\n    struct DepositRecord {\n        /** The amount deposited in the underlying representation of the token\n         * This allows deposit amounts to account for linear inflation during lockup\n         */\n        uint256 gonsDepositAmount;\n        /** The amount of ECO to reward a successful withdrawal\n         * Also equal to the penalty for withdrawing early\n         * Calculated upon deposit\n         */\n        uint256 ecoDepositReward;\n        /** Address the lockup has delegated the deposited funds to\n         * Either the depositor or their primary delegate at time of deposit\n         */\n        address delegate;\n    }\n\n    // the ECO token address\n    ECO public immutable ecoToken;\n\n    // the CurrencyTimer address\n    CurrencyTimer public immutable currencyTimer;\n\n    // length in seconds that deposited funds must be locked up for a reward\n    uint256 public duration;\n\n    // timestamp for when the Lockup is no longer recieving deposits\n    uint256 public depositWindowEnd;\n\n    // length of the deposit window\n    uint256 public constant DEPOSIT_WINDOW = 2 days;\n\n    /** The fraction of payout gained on successful withdrawal\n     * Also the fraction for the penality for withdrawing early.\n     * A 9 digit fixed point decimal representation\n     */\n    uint256 public interest;\n\n    // denotes the number of decimals of fixed point math for interest\n    uint256 public constant INTEREST_DIVISOR = 1e9;\n\n    // mapping from depositing addresses to data on their deposit\n    mapping(address => DepositRecord) public deposits;\n\n    /** The Deposit event indicates that a deposit certificate has been sold\n     * to a particular address in a particular amount.\n     *\n     * @param to The address that a deposit certificate has been issued to.\n     * @param amount The amount in basic unit of 10^{-18} ECO (weico) at time of deposit.\n     */\n    event Deposit(address indexed to, uint256 amount);\n\n    /** The Withdrawal event indicates that a withdrawal has been made,\n     * and records the account that was credited, the amount it was credited\n     * with.\n     *\n     * @param to The address that has made a withdrawal.\n     * @param amount The amount in basic unit of 10^{-18} ECO (weico) withdrawn.\n     */\n    event Withdrawal(address indexed to, uint256 amount);\n\n    constructor(\n        Policy _policy,\n        ECO _ecoAddr,\n        CurrencyTimer _timerAddr\n    ) PolicedUtils(_policy) {\n        require(\n            address(_ecoAddr) != address(0),\n            \"do not set the _ecoAddr as the zero address\"\n        );\n        require(\n            address(_timerAddr) != address(0),\n            \"do not set the _timerAddr as the zero address\"\n        );\n        ecoToken = _ecoAddr;\n        currencyTimer = _timerAddr;\n    }\n\n    function deposit(uint256 _amount) external {\n        internalDeposit(_amount, msg.sender, msg.sender);\n    }\n\n    function depositFor(uint256 _amount, address _benefactor) external {\n        internalDeposit(_amount, msg.sender, _benefactor);\n    }\n\n    function withdraw() external {\n        doWithdrawal(msg.sender, true);\n    }\n\n    function withdrawFor(address _who) external {\n        doWithdrawal(_who, false);\n    }\n\n    function clone(uint256 _duration, uint256 _interest)\n        external\n        returns (Lockup)\n    {\n        require(\n            implementation() == address(this),\n            \"This method cannot be called on clones\"\n        );\n        require(_duration > 0, \"duration should not be zero\");\n        require(_interest > 0, \"interest should not be zero\");\n        Lockup _clone = Lockup(createClone(address(this)));\n        _clone.initialize(address(this), _duration, _interest);\n        return _clone;\n    }\n\n    function initialize(\n        address _self,\n        uint256 _duration,\n        uint256 _interest\n    ) external onlyConstruction {\n        super.initialize(_self);\n        duration = _duration;\n        interest = _interest;\n        depositWindowEnd = getTime() + DEPOSIT_WINDOW;\n    }\n\n    function doWithdrawal(address _owner, bool _allowEarly) internal {\n        DepositRecord storage _deposit = deposits[_owner];\n\n        uint256 _gonsAmount = _deposit.gonsDepositAmount;\n\n        require(\n            _gonsAmount > 0,\n            \"Withdrawals can only be made for accounts with valid deposits\"\n        );\n\n        bool early = getTime() < depositWindowEnd + duration;\n\n        require(_allowEarly || !early, \"Only depositor may withdraw early\");\n\n        uint256 _inflationMult = ecoToken.getPastLinearInflation(block.number);\n        uint256 _amount = _gonsAmount / _inflationMult;\n        uint256 _rawDelta = _deposit.ecoDepositReward;\n        uint256 _delta = _amount > _rawDelta ? _rawDelta : _amount;\n\n        _deposit.gonsDepositAmount = 0;\n        _deposit.ecoDepositReward = 0;\n\n        ecoToken.undelegateAmountFromAddress(_deposit.delegate, _gonsAmount);\n        require(ecoToken.transfer(_owner, _amount), \"Transfer Failed\");\n        currencyTimer.lockupWithdrawal(_owner, _delta, early);\n\n        if (early) {\n            emit Withdrawal(_owner, _amount - _delta);\n        } else {\n            emit Withdrawal(_owner, _amount + _delta);\n        }\n    }\n\n    function internalDeposit(\n        uint256 _amount,\n        address _payer,\n        address _who\n    ) private {\n        require(\n            getTime() < depositWindowEnd,\n            \"Deposits can only be made during sale window\"\n        );\n\n        require(\n            ecoToken.transferFrom(_payer, address(this), _amount),\n            \"Transfer Failed\"\n        );\n\n        address _primaryDelegate = ecoToken.getPrimaryDelegate(_who);\n        uint256 _inflationMult = ecoToken.getPastLinearInflation(block.number);\n        uint256 _gonsAmount = _amount * _inflationMult;\n\n        DepositRecord storage _deposit = deposits[_who];\n        uint256 depositGons = _deposit.gonsDepositAmount;\n        address depositDelegate = _deposit.delegate;\n\n        if (depositGons > 0 && _primaryDelegate != depositDelegate) {\n            ecoToken.undelegateAmountFromAddress(depositDelegate, depositGons);\n            ecoToken.delegateAmount(\n                _primaryDelegate,\n                _gonsAmount + depositGons\n            );\n        } else {\n            ecoToken.delegateAmount(_primaryDelegate, _gonsAmount);\n        }\n\n        _deposit.ecoDepositReward += (_amount * interest) / INTEREST_DIVISOR;\n        _deposit.gonsDepositAmount += _gonsAmount;\n        _deposit.delegate = _primaryDelegate;\n\n        emit Deposit(_who, _amount);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/monetary/RandomInflation.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policy.sol\";\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../currency/ECO.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"../../VDF/VDFVerifier.sol\";\nimport \"./InflationRootHashProposal.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\n/** @title RandomInflation\n *\n * This contract oversees the currency random inflation process and is spawned\n * on demand by the CurrencyTimer.\n */\ncontract RandomInflation is PolicedUtils, TimeUtils {\n    /** The time period over which inflation reward is spread to prevent\n     *  flooding by spreading out the new tokens.\n     */\n    uint256 public constant CLAIM_PERIOD = 28 days;\n\n    /** The bound on how much more than the uint256 previous blockhash can a submitted prime be\n     */\n    uint256 public constant PRIME_BOUND = 1000;\n\n    /** The number of checks to determine the prime seed to start the VDF\n     */\n    uint256 public constant MILLER_RABIN_ROUNDS = 25;\n\n    /** The per-participant reward amount in basic unit of 10^{-18} ECO (weico) selected by the voting process.\n     */\n    uint256 public reward;\n\n    /** The computed number of reward recipients (inflation/reward) in basic unit of 10^{-18} ECO (weico).\n     */\n    uint256 public numRecipients;\n\n    /** The block number to use as the reference point when checking if an account holds currency.\n     */\n    uint256 public blockNumber;\n\n    /** The initial value used for VDF to compute random seed. This is set by a\n     * call to `commitEntropyVDFSeed()` after the vote results are computed.\n     */\n    uint256 public entropyVDFSeed;\n\n    /** The random seed used to determine the inflation reward recipients.\n     */\n    bytes32 public seed;\n\n    /** Difficulty of VDF for random process. This is left mutable for easier governance */\n    uint256 public randomVDFDifficulty;\n\n    /** Timestamp to start claim period from */\n    uint256 public claimPeriodStarts;\n\n    /** A mapping recording which claim numbers have been claimed.\n     */\n    mapping(uint256 => uint256) public claimed;\n\n    // the max bits that can be stored in a uint256 number\n    uint256 public constant BITMAP_MAXIMUM = 256;\n\n    // A counter of outstanding unclaimed rewards\n    uint256 public unclaimedRewards;\n\n    /** The base VDFVerifier implementation */\n    /** The VDF is used to set the random seed for inflation */\n    VDFVerifier public vdfVerifier;\n\n    /** The base InflationRootHashProposal implementation */\n    /** The inflation root hash proposal that's used to verify inflation claims */\n    InflationRootHashProposal public inflationRootHashProposal;\n\n    // the ECO token address\n    ECO public immutable ecoToken;\n\n    /** A mapping of primals asssociated to the block they were commited in\n     */\n    mapping(uint256 => uint256) public primals;\n\n    /** Emitted when inflation starts.\n     */\n    event InflationStart(\n        VDFVerifier indexed vdfVerifier,\n        InflationRootHashProposal indexed inflationRootHashProposal,\n        uint256 claimPeriodStarts\n    );\n\n    /** Fired when a user claims their reward */\n    event Claim(address indexed who, uint256 sequence);\n\n    /** Emitted when the VDF seed used to provide entropy has been committed to the contract.\n     */\n    event EntropyVDFSeedCommit(uint256 seed);\n\n    /** Emitted when the entropy seed is revealed by provable VDF computation.\n     */\n    event EntropySeedReveal(bytes32 seed);\n\n    constructor(\n        Policy _policy,\n        VDFVerifier _vdfVerifierImpl,\n        uint256 _randomDifficulty,\n        InflationRootHashProposal _inflationRootHashProposalImpl,\n        ECO _ecoAddr\n    ) PolicedUtils(_policy) {\n        require(\n            address(_vdfVerifierImpl) != address(0),\n            \"do not set the _vdfVerifierImpl as the zero address\"\n        );\n        require(\n            _randomDifficulty > 0,\n            \"do not set the _randomDifficulty to zero\"\n        );\n        require(\n            address(_inflationRootHashProposalImpl) != address(0),\n            \"do not set the _inflationRootHashProposalImpl as the zero address\"\n        );\n        require(\n            address(_ecoAddr) != address(0),\n            \"do not set the _ecoAddr as the zero address\"\n        );\n        vdfVerifier = _vdfVerifierImpl;\n        randomVDFDifficulty = _randomDifficulty;\n        inflationRootHashProposal = _inflationRootHashProposalImpl;\n        ecoToken = _ecoAddr;\n    }\n\n    /** Clean up the inflation contract.\n     *\n     * Can only be called after all rewards\n     * have been claimed.\n     */\n    function destruct() external {\n        require(\n            seed != 0 || getTime() > claimPeriodStarts + CLAIM_PERIOD,\n            \"Entropy not set, wait until end of full claim period to abort\"\n        );\n\n        // consider putting a long scale timeout to allow for late stage aborts\n        // unclaimedRewards is guaranteed to be set before the seed\n        require(\n            seed == 0 || unclaimedRewards == 0,\n            \"All rewards must be claimed prior to destruct\"\n        );\n\n        require(\n            ecoToken.transfer(\n                address(policy),\n                ecoToken.balanceOf(address(this))\n            ),\n            \"Transfer Failed\"\n        );\n    }\n\n    /** Initialize the storage context using parameters copied from the\n     * original contract (provided as _self).\n     *\n     * Can only be called once, during proxy initialization.\n     *\n     * @param _self The original contract address.\n     */\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n        blockNumber = block.number - 1;\n\n        vdfVerifier = VDFVerifier(RandomInflation(_self).vdfVerifier().clone());\n        randomVDFDifficulty = RandomInflation(_self).randomVDFDifficulty();\n\n        inflationRootHashProposal = InflationRootHashProposal(\n            RandomInflation(_self).inflationRootHashProposal().clone()\n        );\n        inflationRootHashProposal.configure(blockNumber);\n    }\n\n    /** Commit to a VDF seed for inflation distribution entropy.\n     *\n     * Can only be called after results are computed and the registration\n     * period has ended. The VDF seed can only be set once, and must be computed and\n     * set in the previous block.\n     *\n     * @param _primal the primal to use, must have been committed to in a previous block\n     */\n    function commitEntropyVDFSeed(uint256 _primal) external {\n        require(entropyVDFSeed == 0, \"The VDF seed has already been set\");\n        uint256 _primalCommitBlock = primals[_primal];\n        require(\n            _primalCommitBlock > 0 && _primalCommitBlock < block.number,\n            \"primal block invalid\"\n        );\n        require(\n            vdfVerifier.isProbablePrime(_primal, MILLER_RABIN_ROUNDS),\n            \"input failed primality test\"\n        );\n\n        entropyVDFSeed = _primal;\n\n        emit EntropyVDFSeedCommit(entropyVDFSeed);\n    }\n\n    /** Sets a primal in storage associated to the commiting block\n     * A user first adds a primal to the contract, then they can test\n     * its primality in a subsequent block\n     *\n     * @param _primal uint256 the prime number to commit for the block\n     */\n    function setPrimal(uint256 _primal) external {\n        uint256 _bhash = uint256(blockhash(block.number - 1));\n        require(\n            _primal > _bhash && _primal - _bhash < PRIME_BOUND,\n            \"suggested prime is out of bounds\"\n        );\n\n        primals[_primal] = block.number;\n    }\n\n    /** Starts the inflation payout period. Validates that the contract is sufficiently\n     * capitalized with Eco to meet the inflation demand. Can only be called once, ie by CurrencyTimer\n     *\n     * @param _numRecipients the number of recipients that will get rewards\n     * @param _reward the amount of ECO to be given as reward to each recipient\n     */\n    function startInflation(uint256 _numRecipients, uint256 _reward) external {\n        require(\n            _numRecipients > 0 && _reward > 0,\n            \"Contract must have rewards\"\n        );\n        require(\n            ecoToken.balanceOf(address(this)) >= _numRecipients * _reward,\n            \"The contract must have a token balance at least the total rewards\"\n        );\n        require(numRecipients == 0, \"The sale can only be started once\");\n\n        /* This sets the amount of recipients to be iterated through later, it is important\n        this number stay reasonable from gas consumption standpoint */\n        numRecipients = _numRecipients;\n        unclaimedRewards = _numRecipients;\n        reward = _reward;\n        claimPeriodStarts = getTime();\n        emit InflationStart(\n            vdfVerifier,\n            inflationRootHashProposal,\n            claimPeriodStarts\n        );\n    }\n\n    /** Submit a solution for VDF for randomness.\n     *\n     * @param _y The computed VDF output. Must be proven with the VDF\n     *           verification contract.\n     */\n    function submitEntropyVDF(bytes calldata _y) external {\n        require(entropyVDFSeed != 0, \"Initial seed must be set\");\n        require(seed == bytes32(0), \"Can only submit once\");\n\n        require(\n            vdfVerifier.isVerified(entropyVDFSeed, randomVDFDifficulty, _y),\n            \"The VDF output value must be verified by the VDF verification contract\"\n        );\n\n        seed = keccak256(_y);\n\n        emit EntropySeedReveal(seed);\n    }\n\n    /** Claim an inflation reward on behalf of some address.\n     *\n     * The reward is sent directly to the address that has claim to the reward, but the\n     * gas cost is paid by the caller.\n     *\n     * For example, an exchange might stake using funds deposited into its\n     * contract.\n     *\n     * @param _who The address to claim a reward on behalf of.\n     * @param _sequence The reward sequence number to determine if the address\n     *                  gets paid.\n     * @param _proof the “other nodes” in the Merkle tree\n     * @param _sum cumulative sum of all account ECO votes before this node\n     * @param _index the index of the `who` address in the Merkle tree\n     */\n    function claimFor(\n        address _who,\n        uint256 _sequence,\n        bytes32[] memory _proof,\n        uint256 _sum,\n        uint256 _index\n    ) public {\n        require(seed != bytes32(0), \"Must prove VDF before claims can be paid\");\n        require(\n            _sequence < numRecipients,\n            \"The provided sequence number must be within the set of recipients\"\n        );\n        require(\n            getTime() >\n                claimPeriodStarts + (_sequence * CLAIM_PERIOD) / numRecipients,\n            \"A claim can only be made after enough time has passed\"\n        );\n        require(\n            claimed[_sequence / BITMAP_MAXIMUM] &\n                (1 << (_sequence % BITMAP_MAXIMUM)) ==\n                0,\n            \"A claim can only be made if it has not already been made\"\n        );\n\n        require(\n            inflationRootHashProposal.acceptedRootHash() != 0,\n            \"A claim can only be made after root hash for this generation was accepted\"\n        );\n\n        require(\n            inflationRootHashProposal.verifyClaimSubmission(\n                _who,\n                _proof,\n                _sum,\n                _index\n            ),\n            \"A claim submission failed root hash verification\"\n        );\n\n        claimed[_sequence / BITMAP_MAXIMUM] +=\n            1 <<\n            (_sequence % BITMAP_MAXIMUM);\n        unclaimedRewards--;\n\n        uint256 claimable = uint256(\n            keccak256(abi.encodePacked(seed, _sequence))\n        ) % inflationRootHashProposal.acceptedTotalSum();\n\n        require(\n            claimable < ecoToken.getPastVotes(_who, blockNumber) + _sum,\n            \"The provided address cannot claim this reward\"\n        );\n        require(\n            claimable >= _sum,\n            \"The provided address cannot claim this reward\"\n        );\n\n        require(ecoToken.transfer(_who, reward), \"Transfer Failed\");\n\n        emit Claim(_who, _sequence);\n    }\n\n    /** Claim an inflation reward for yourself.\n     *\n     * You need to know your claim number's place in the order.\n     *\n     * @param _sequence Your claim number's place in the order.\n     */\n    function claim(\n        uint256 _sequence,\n        bytes32[] calldata _proof,\n        uint256 _sum,\n        uint256 _index\n    ) external {\n        claimFor(msg.sender, _sequence, _proof, _sum, _index);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/monetary/TrustedNodes.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/PolicedUtils.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"../TimedPolicies.sol\";\nimport \"../IGeneration.sol\";\nimport \"../../utils/TimeUtils.sol\";\n\n/** @title TrustedNodes\n *\n * A registry of trusted nodes. Trusted nodes are able to vote during\n * inflation/deflation votes, and can only be added or removed using policy\n * proposals.\n *\n */\ncontract TrustedNodes is PolicedUtils, TimeUtils {\n    uint256 public constant GENERATIONS_PER_YEAR = 26;\n\n    uint256 public yearEnd;\n\n    uint256 public yearStartGen;\n\n    address public hoard;\n\n    /** Tracks the current trustee cohort\n     * each trustee election cycle corresponds to a new trustee cohort.\n     */\n\n    struct Cohort {\n        /** The list of trusted nodes in the cohort*/\n        address[] trustedNodes;\n        /** @dev address of trusted node to index in trustedNodes */\n        mapping(address => uint256) trusteeNumbers;\n    }\n\n    /** cohort number */\n    uint256 public cohort;\n\n    /** cohort number to cohort */\n    mapping(uint256 => Cohort) internal cohorts;\n\n    /** Represents the number of votes for which the trustee can claim rewards.\n    Increments each time the trustee votes, set to zero upon redemption */\n    mapping(address => uint256) public votingRecord;\n\n    // last year's voting record\n    mapping(address => uint256) public lastYearVotingRecord;\n\n    // completely vested\n    mapping(address => uint256) public fullyVestedRewards;\n\n    /** reward earned per completed and revealed vote */\n    uint256 public voteReward;\n\n    // unallocated rewards to be sent to hoard upon the end of the year term\n    uint256 public unallocatedRewardsCount;\n\n    /** Event emitted when a node added to a list of trusted nodes.\n     */\n    event TrustedNodeAddition(address indexed node, uint256 cohort);\n\n    /** Event emitted when a node removed from a list of trusted nodes\n     */\n    event TrustedNodeRemoval(address indexed node, uint256 cohort);\n\n    /** Event emitted when voting rewards are redeemed */\n    event VotingRewardRedemption(address indexed recipient, uint256 amount);\n\n    // Event emitted on annualUpdate and newCohort to request funding to the contract\n    event FundingRequest(uint256 amount);\n\n    // information for the new trustee rewards term\n    event RewardsTrackingUpdate(\n        uint256 nextUpdateTimestamp,\n        uint256 newRewardsCount\n    );\n\n    /** Creates a new trusted node registry, populated with some initial nodes.\n     */\n    constructor(\n        Policy _policy,\n        address[] memory _initialTrustedNodes,\n        uint256 _voteReward\n    ) PolicedUtils(_policy) {\n        voteReward = _voteReward;\n        uint256 trusteeCount = _initialTrustedNodes.length;\n        hoard = address(_policy);\n\n        for (uint256 i = 0; i < trusteeCount; ++i) {\n            address node = _initialTrustedNodes[i];\n            _trust(node);\n        }\n    }\n\n    /** Initialize the storage context using parameters copied from the\n     * original contract (provided as _self).\n     *\n     * Can only be called once, during proxy initialization.\n     *\n     * @param _self The original contract address.\n     */\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n        // vote reward is left as mutable for easier governance\n        voteReward = TrustedNodes(_self).voteReward();\n        hoard = TrustedNodes(_self).hoard();\n        yearStartGen = GENERATION_START + 1;\n        yearEnd = getTime() + GENERATIONS_PER_YEAR * MIN_GENERATION_DURATION;\n\n        uint256 _numTrustees = TrustedNodes(_self).numTrustees();\n\n        unallocatedRewardsCount = _numTrustees * GENERATIONS_PER_YEAR;\n        uint256 _cohort = TrustedNodes(_self).cohort();\n        address[] memory trustees = TrustedNodes(_self)\n            .getTrustedNodesFromCohort(_cohort);\n\n        for (uint256 i = 0; i < _numTrustees; ++i) {\n            _trust(trustees[i]);\n        }\n    }\n\n    function getTrustedNodesFromCohort(uint256 _cohort)\n        public\n        view\n        returns (address[] memory)\n    {\n        return cohorts[_cohort].trustedNodes;\n    }\n\n    /** Grant trust to a node.\n     *\n     * The node is pushed to trustedNodes array.\n     *\n     * @param _node The node to start trusting.\n     */\n    function trust(address _node) external onlyPolicy {\n        _trust(_node);\n    }\n\n    /** Stop trusting a node.\n     *\n     * Node to distrust swaped to be a last element in the trustedNodes, then deleted\n     *\n     * @param _node The node to stop trusting.\n     */\n    function distrust(address _node) external onlyPolicy {\n        Cohort storage currentCohort = cohorts[cohort];\n        uint256 trusteeNumber = currentCohort.trusteeNumbers[_node];\n        require(trusteeNumber > 0, \"Node already not trusted\");\n\n        uint256 lastIndex = currentCohort.trustedNodes.length - 1;\n\n        delete currentCohort.trusteeNumbers[_node];\n\n        uint256 trusteeIndex = trusteeNumber - 1;\n        if (trusteeIndex != lastIndex) {\n            address lastNode = currentCohort.trustedNodes[lastIndex];\n\n            currentCohort.trustedNodes[trusteeIndex] = lastNode;\n            currentCohort.trusteeNumbers[lastNode] = trusteeNumber;\n        }\n\n        currentCohort.trustedNodes.pop();\n        emit TrustedNodeRemoval(_node, cohort);\n    }\n\n    /** Incements the counter when the trustee reveals their vote\n     * only callable by the CurrencyGovernance contract\n     */\n    function recordVote(address _who) external {\n        require(\n            msg.sender == policyFor(ID_CURRENCY_GOVERNANCE),\n            \"Must be the monetary policy contract to call\"\n        );\n\n        votingRecord[_who]++;\n\n        if (unallocatedRewardsCount > 0) {\n            unallocatedRewardsCount--;\n        }\n    }\n\n    /** The calling trustee can redeem any rewards from the previous generation\n     *  that they have earned for participating in that generation's voting.\n     */\n    function redeemVoteRewards() external {\n        // rewards from last year\n        uint256 yearGenerationCount = IGeneration(policyFor(ID_TIMED_POLICIES))\n            .generation() - yearStartGen;\n\n        uint256 record = lastYearVotingRecord[msg.sender];\n        uint256 vested = fullyVestedRewards[msg.sender];\n        require(record + vested > 0, \"No vested rewards to redeem\");\n        uint256 rewardsToRedeem = (\n            record > yearGenerationCount ? yearGenerationCount : record\n        );\n        lastYearVotingRecord[msg.sender] = record - rewardsToRedeem;\n\n        // fully vested rewards if they exist\n        if (vested > 0) {\n            rewardsToRedeem += vested;\n            fullyVestedRewards[msg.sender] = 0;\n        }\n\n        uint256 reward = rewardsToRedeem * voteReward;\n\n        require(\n            ECOx(policyFor(ID_ECOX)).transfer(msg.sender, reward),\n            \"Transfer Failed\"\n        );\n\n        emit VotingRewardRedemption(msg.sender, reward);\n    }\n\n    /** Return the number of entries in trustedNodes array.\n     */\n    function numTrustees() external view returns (uint256) {\n        return cohorts[cohort].trustedNodes.length;\n    }\n\n    /** Helper function for adding a node to the trusted set.\n     *\n     * @param _node The node to add to the trusted set.\n     */\n    function _trust(address _node) private {\n        uint256 _cohort = cohort;\n        Cohort storage currentCohort = cohorts[_cohort];\n        require(\n            currentCohort.trusteeNumbers[_node] == 0,\n            \"Node is already trusted\"\n        );\n        // trustee number of new node is len(trustedNodes) + 1, since there can't be a trustee with trusteeNumber = 0\n        currentCohort.trusteeNumbers[_node] =\n            currentCohort.trustedNodes.length +\n            1;\n        currentCohort.trustedNodes.push(_node);\n        emit TrustedNodeAddition(_node, _cohort);\n    }\n\n    /** Checks if a node address is trusted in the current cohort\n     */\n    function isTrusted(address _node) public view returns (bool) {\n        return cohorts[cohort].trusteeNumbers[_node] > 0;\n    }\n\n    /** Function for adding a new cohort of trustees\n     * used for implementing the results of a trustee election\n     */\n    function newCohort(address[] memory _newCohort) external onlyPolicy {\n        uint256 trustees = cohorts[cohort].trustedNodes.length;\n        if (_newCohort.length > trustees) {\n            emit FundingRequest(\n                voteReward *\n                    GENERATIONS_PER_YEAR *\n                    (_newCohort.length - trustees)\n            );\n        }\n\n        cohort++;\n\n        for (uint256 i = 0; i < _newCohort.length; ++i) {\n            _trust(_newCohort[i]);\n        }\n    }\n\n    /** Updates the trustee rewards that they have earned for the year\n     * and then sends the unallocated reward to the hoard.\n     */\n    function annualUpdate() external {\n        require(\n            getTime() > yearEnd,\n            \"cannot call this until the current year term has ended\"\n        );\n        address[] memory trustees = cohorts[cohort].trustedNodes;\n        for (uint256 i = 0; i < trustees.length; ++i) {\n            address trustee = trustees[i];\n            fullyVestedRewards[trustee] += lastYearVotingRecord[trustee];\n            lastYearVotingRecord[trustee] = votingRecord[trustee];\n            votingRecord[trustee] = 0;\n        }\n\n        uint256 reward = unallocatedRewardsCount * voteReward;\n        unallocatedRewardsCount =\n            cohorts[cohort].trustedNodes.length *\n            GENERATIONS_PER_YEAR;\n        yearEnd = getTime() + GENERATIONS_PER_YEAR * MIN_GENERATION_DURATION;\n        yearStartGen = IGeneration(policyFor(ID_TIMED_POLICIES)).generation();\n\n        ECOx ecoX = ECOx(policyFor(ID_ECOX));\n\n        require(ecoX.transfer(hoard, reward), \"Transfer Failed\");\n\n        emit FundingRequest(unallocatedRewardsCount * voteReward);\n        emit VotingRewardRedemption(hoard, reward);\n        emit RewardsTrackingUpdate(yearEnd, unallocatedRewardsCount);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/governance/TimedPolicies.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../policy/PolicedUtils.sol\";\nimport \"../policy/Policy.sol\";\nimport \"../utils/TimeUtils.sol\";\nimport \"./IGenerationIncrease.sol\";\nimport \"./IGeneration.sol\";\nimport \"./community/PolicyProposals.sol\";\nimport \"../currency/ECO.sol\";\nimport \"../currency/ECOx.sol\";\n\n/** @title TimedPolicies\n * Oversees the time-based recurring processes that allow governance of the\n * Eco currency.\n */\ncontract TimedPolicies is PolicedUtils, TimeUtils, IGeneration {\n    // Stores the current generation\n    uint256 public override generation;\n    // Stores when the generation ends\n    uint256 public generationEnd;\n    // Stores all contracts that need a function called on generation increase\n    // Order matters here if there are any cross contract dependencies on the\n    // actions taking on generation increase.\n    bytes32[] public notificationHashes;\n\n    /** The on-chain address for the policy proposal process contract. The\n     * contract is cloned for every policy decision process.\n     */\n    PolicyProposals public policyProposalImpl;\n\n    /**\n     * An event indicating that a new generation has started.\n     *\n     * @param generation The generation number for the new generation.\n     */\n    event NewGeneration(uint256 indexed generation);\n\n    /** An event indicating that a policy decision process has started. The\n     * address included indicates where on chain the relevant contract can be\n     * found. This event is emitted by `startPolicyProposals` to indicate that\n     * a new decision process has started, and to help track historical vote\n     * contracts.\n     *\n     * @param contractAddress The address of the PolicyProposals contract.\n     */\n    event PolicyDecisionStart(address contractAddress);\n\n    constructor(\n        Policy _policy,\n        PolicyProposals _policyproposal,\n        bytes32[] memory _notificationHashes\n    ) PolicedUtils(_policy) {\n        require(\n            address(_policyproposal) != address(0),\n            \"Unrecoverable: do not set the _policyproposal as the zero address\"\n        );\n        require(\n            _notificationHashes.length > 0,\n            \"Unrecoverable: must set _notificationHashes\"\n        );\n        policyProposalImpl = _policyproposal;\n        generation = GENERATION_START;\n        notificationHashes = _notificationHashes;\n    }\n\n    function initialize(address _self) public override onlyConstruction {\n        super.initialize(_self);\n        // implementations are left mutable for easier governance\n        policyProposalImpl = TimedPolicies(_self).policyProposalImpl();\n\n        generation = TimedPolicies(_self).generation();\n        notificationHashes = TimedPolicies(_self).getNotificationHashes();\n        generationEnd = getTime(); // generation is incremented immediately\n    }\n\n    function getNotificationHashes() public view returns (bytes32[] memory) {\n        return notificationHashes;\n    }\n\n    /**\n     * This function kicks off a new generation\n     * The process of a new generation is a bit of a chain reaction of creating contracts\n     * This function only directly clones and configures the PolicyProposals contract\n     * Everything else is notified via the notificationHashes array\n     * At launch this contains the ECO contract and the CurrencyGovernance contract\n     * however the structure is extensible to other contracts if needed.\n     */\n    function incrementGeneration() external {\n        require(\n            getTime() >= generationEnd,\n            \"Cannot update the generation counter so soon\"\n        );\n        uint256 currTime = getTime();\n        while (generationEnd <= currTime) {\n            generationEnd += MIN_GENERATION_DURATION;\n        }\n        generation++;\n\n        CurrencyGovernance bg = CurrencyGovernance(\n            policyFor(ID_CURRENCY_GOVERNANCE)\n        );\n\n        uint256 _numberOfRecipients;\n        uint256 _randomInflationReward;\n\n        if (address(bg) != address(0)) {\n            address winner = bg.winner();\n            if (winner != address(0)) {\n                (_numberOfRecipients, _randomInflationReward, , , , ) = bg\n                    .proposals(winner);\n            }\n        }\n\n        uint256 mintedOnGenerationIncrease = _numberOfRecipients *\n            _randomInflationReward;\n\n        // snapshot the ECOx total\n        uint256 totalx = ECOx(policyFor(ID_ECOX)).totalSupply();\n\n        PolicyProposals _proposals = PolicyProposals(\n            policyProposalImpl.clone()\n        );\n\n        /**\n         * totalx not allowed to be passed through as zero as a safeguard to if ECOx is\n         * completely burned without first removing this part of the system\n         */\n        _proposals.configure(\n            totalx == 0 ? 1 : totalx,\n            mintedOnGenerationIncrease\n        );\n\n        policy.setPolicy(\n            ID_POLICY_PROPOSALS,\n            address(_proposals),\n            ID_TIMED_POLICIES\n        );\n\n        uint256 notificationHashesLength = notificationHashes.length;\n        for (uint256 i = 0; i < notificationHashesLength; ++i) {\n            IGenerationIncrease notified = IGenerationIncrease(\n                policy.policyFor(notificationHashes[i])\n            );\n            if (address(notified) != address(0)) {\n                notified.notifyGenerationIncrease();\n            }\n        }\n\n        emit PolicyDecisionStart(address(_proposals));\n        emit NewGeneration(generation);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/policy/ERC1820Client.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol\";\n\n/** @title Utilities for interfacing with ERC1820\n */\nabstract contract ERC1820Client {\n    IERC1820Registry internal constant ERC1820REGISTRY =\n        IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24);\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/policy/Policed.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/introspection/IERC1820Implementer.sol\";\nimport \"../proxy/ForwardTarget.sol\";\nimport \"./Policy.sol\";\n\n/** @title Policed Contracts\n *\n * A policed contract is any contract managed by a policy.\n */\nabstract contract Policed is ForwardTarget, IERC1820Implementer, ERC1820Client {\n    bytes32 internal constant ERC1820_ACCEPT_MAGIC =\n        keccak256(\"ERC1820_ACCEPT_MAGIC\");\n\n    /** The address of the root policy instance overseeing this instance.\n     *\n     * This address can be used for ERC1820 lookup of other components, ERC1820\n     * lookup of role policies, and interaction with the policy hierarchy.\n     */\n    Policy public immutable policy;\n\n    /** Restrict method access to the root policy instance only.\n     */\n    modifier onlyPolicy() {\n        require(\n            msg.sender == address(policy),\n            \"Only the policy contract may call this method\"\n        );\n        _;\n    }\n\n    constructor(Policy _policy) {\n        require(\n            address(_policy) != address(0),\n            \"Unrecoverable: do not set the policy as the zero address\"\n        );\n        policy = _policy;\n        ERC1820REGISTRY.setManager(address(this), address(_policy));\n    }\n\n    /** ERC1820 permissioning interface\n     *\n     * @param _addr The address of the contract this might act on behalf of.\n     */\n    function canImplementInterfaceForAddress(bytes32, address _addr)\n        external\n        view\n        virtual\n        override\n        returns (bytes32)\n    {\n        require(\n            _addr == address(policy),\n            \"This contract only implements interfaces for the policy contract\"\n        );\n        return ERC1820_ACCEPT_MAGIC;\n    }\n\n    /** Initialize the contract (replaces constructor)\n     *\n     * Policed contracts are often the targets of proxies, and therefore need a\n     * mechanism to initialize internal state when adopted by a new proxy. This\n     * replaces the constructor.\n     *\n     * @param _self The address of the original contract deployment (as opposed\n     *              to the address of the proxy contract, which takes the place\n     *              of `this`).\n     */\n    function initialize(address _self)\n        public\n        virtual\n        override\n        onlyConstruction\n    {\n        super.initialize(_self);\n        ERC1820REGISTRY.setManager(address(this), address(policy));\n    }\n\n    /** Execute code as indicated by the managing policy contract\n     *\n     * Governance allows the managing policy contract to execute arbitrary code in this\n     * contract's context by allowing it to specify an implementation address and\n     * some message data, and then using delegatecall to execute the code at the\n     * implementation address, passing in the message data, all within the protocol's\n     * address space.\n     *\n     * @param _delegate The address of the contract to delegate execution to.\n     * @param _data The call message/data to execute on.\n     */\n    function policyCommand(address _delegate, bytes memory _data)\n        public\n        onlyPolicy\n    {\n        // solhint-disable-next-line no-inline-assembly\n        assembly {\n            /* Call the address indicated by _delegate passing the data in _data\n             * as the call message using delegatecall. This allows the calling\n             * of arbitrary functions on _delegate (by encoding the call message\n             * into _data) in the context of the current contract's storage.\n             */\n            let result := delegatecall(\n                gas(),\n                _delegate,\n                add(_data, 0x20),\n                mload(_data),\n                0,\n                0\n            )\n            /* Collect up the return data from delegatecall and prepare it for\n             * returning to the caller of policyCommand.\n             */\n            let size := returndatasize()\n            returndatacopy(0x0, 0, size)\n            /* If the delegated call reverted then revert here too. Otherwise\n             * forward the return data prepared above.\n             */\n            switch result\n            case 0 {\n                revert(0x0, size)\n            }\n            default {\n                return(0x0, size)\n            }\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/policy/PolicedUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol\";\n\nimport \"../clone/CloneFactory.sol\";\nimport \"./Policed.sol\";\nimport \"./ERC1820Client.sol\";\n\n/** @title Utility providing helpers for policed contracts\n *\n * See documentation for Policed to understand what a policed contract is.\n */\nabstract contract PolicedUtils is Policed, CloneFactory {\n    bytes32 internal constant ID_FAUCET = keccak256(\"Faucet\");\n    bytes32 internal constant ID_ECO = keccak256(\"ECO\");\n    bytes32 internal constant ID_ECOX = keccak256(\"ECOx\");\n    bytes32 internal constant ID_TIMED_POLICIES = keccak256(\"TimedPolicies\");\n    bytes32 internal constant ID_TRUSTED_NODES = keccak256(\"TrustedNodes\");\n    bytes32 internal constant ID_POLICY_PROPOSALS =\n        keccak256(\"PolicyProposals\");\n    bytes32 internal constant ID_POLICY_VOTES = keccak256(\"PolicyVotes\");\n    bytes32 internal constant ID_CURRENCY_GOVERNANCE =\n        keccak256(\"CurrencyGovernance\");\n    bytes32 internal constant ID_CURRENCY_TIMER = keccak256(\"CurrencyTimer\");\n    bytes32 internal constant ID_ECOXSTAKING = keccak256(\"ECOxStaking\");\n\n    // The minimum time of a generation.\n    uint256 public constant MIN_GENERATION_DURATION = 14 days;\n    // The initial generation\n    uint256 public constant GENERATION_START = 1000;\n\n    address internal expectedInterfaceSet;\n\n    constructor(Policy _policy) Policed(_policy) {}\n\n    /** ERC1820 permissioning interface\n     *\n     * @param _addr The address of the contract this might act on behalf of.\n     */\n    function canImplementInterfaceForAddress(bytes32, address _addr)\n        external\n        view\n        override\n        returns (bytes32)\n    {\n        require(\n            _addr == address(policy) || _addr == expectedInterfaceSet,\n            \"Only the policy or interface contract can set the interface\"\n        );\n        return ERC1820_ACCEPT_MAGIC;\n    }\n\n    /** Set the expected interface set\n     */\n    function setExpectedInterfaceSet(address _addr) public onlyPolicy {\n        expectedInterfaceSet = _addr;\n    }\n\n    /** Create a clone of this contract\n     *\n     * Creates a clone of this contract by instantiating a proxy at a new\n     * address and initializing it based on the current contract. Uses\n     * optionality.io's CloneFactory functionality.\n     *\n     * This is used to save gas cost during deployments. Rather than including\n     * the full contract code in every contract that might instantiate it, it\n     * can be deployed once and the location it was deployed can be referred to for\n     * cloning. The calls to clone() create instances as needed without\n     * increasing the code size of the instantiating contract.\n     */\n    function clone() public virtual returns (address) {\n        require(\n            implementation() == address(this),\n            \"This method cannot be called on clones\"\n        );\n        address _clone = createClone(address(this));\n        PolicedUtils(_clone).initialize(address(this));\n        return _clone;\n    }\n\n    /** Find the policy contract for a particular identifier.\n     *\n     * This is intended as a helper function for contracts that are managed by\n     * a policy framework. A typical use case is checking if the address calling\n     * a function is the authorized policy for a particular action.\n     *\n     * eg:\n     * ```\n     * function doSomethingPrivileged() public {\n     *   require(\n     *     msg.sender == policyFor(keccak256(\"PolicyForDoingPrivilegedThing\")),\n     *     \"Only the privileged contract may call this\"\n     *     );\n     * }\n     * ```\n     */\n    function policyFor(bytes32 _id) internal view returns (address) {\n        return ERC1820REGISTRY.getInterfaceImplementer(address(policy), _id);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/policy/Policy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol\";\nimport \"../proxy/ForwardTarget.sol\";\nimport \"./ERC1820Client.sol\";\n\n/** @title The policy contract that oversees other contracts\n *\n * Policy contracts provide a mechanism for building pluggable (after deploy)\n * governance systems for other contracts.\n */\ncontract Policy is ForwardTarget, ERC1820Client {\n    mapping(bytes32 => bool) public setters;\n\n    modifier onlySetter(bytes32 _identifier) {\n        require(\n            setters[_identifier],\n            \"Identifier hash is not authorized for this action\"\n        );\n\n        require(\n            ERC1820REGISTRY.getInterfaceImplementer(\n                address(this),\n                _identifier\n            ) == msg.sender,\n            \"Caller is not the authorized address for identifier\"\n        );\n\n        _;\n    }\n\n    /** Remove the specified role from the contract calling this function.\n     * This is for cleanup only, so if another contract has taken the\n     * role, this does nothing.\n     *\n     * @param _interfaceIdentifierHash The interface identifier to remove from\n     *                                 the registry.\n     */\n    function removeSelf(bytes32 _interfaceIdentifierHash) external {\n        address old = ERC1820REGISTRY.getInterfaceImplementer(\n            address(this),\n            _interfaceIdentifierHash\n        );\n\n        if (old == msg.sender) {\n            ERC1820REGISTRY.setInterfaceImplementer(\n                address(this),\n                _interfaceIdentifierHash,\n                address(0)\n            );\n        }\n    }\n\n    /** Find the policy contract for a particular identifier.\n     *\n     * @param _interfaceIdentifierHash The hash of the interface identifier\n     *                                 look up.\n     */\n    function policyFor(bytes32 _interfaceIdentifierHash)\n        public\n        view\n        returns (address)\n    {\n        return\n            ERC1820REGISTRY.getInterfaceImplementer(\n                address(this),\n                _interfaceIdentifierHash\n            );\n    }\n\n    /** Set the policy label for a contract\n     *\n     * @param _key The label to apply to the contract.\n     *\n     * @param _implementer The contract to assume the label.\n     */\n    function setPolicy(\n        bytes32 _key,\n        address _implementer,\n        bytes32 _authKey\n    ) public onlySetter(_authKey) {\n        ERC1820REGISTRY.setInterfaceImplementer(\n            address(this),\n            _key,\n            _implementer\n        );\n    }\n\n    /** Enact the code of one of the governance contracts.\n     *\n     * @param _delegate The contract code to delegate execution to.\n     */\n    function internalCommand(address _delegate, bytes32 _authKey)\n        public\n        onlySetter(_authKey)\n    {\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool _success, ) = _delegate.delegatecall(\n            abi.encodeWithSignature(\"enacted(address)\", _delegate)\n        );\n        require(_success, \"Command failed during delegatecall\");\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/proxy/ForwardTarget.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* solhint-disable no-inline-assembly */\n\n/** @title Target for ForwardProxy and EcoInitializable */\nabstract contract ForwardTarget {\n    // Must match definition in ForwardProxy\n    // keccak256(\"com.eco.ForwardProxy.target\")\n    uint256 private constant IMPLEMENTATION_SLOT =\n        0xf86c915dad5894faca0dfa067c58fdf4307406d255ed0a65db394f82b77f53d4;\n\n    modifier onlyConstruction() {\n        require(\n            implementation() == address(0),\n            \"Can only be called during initialization\"\n        );\n        _;\n    }\n\n    constructor() {\n        setImplementation(address(this));\n    }\n\n    /** @notice Storage initialization of cloned contract\n     *\n     * This is used to initialize the storage of the forwarded contract, and\n     * should (typically) copy or repeat any work that would normally be\n     * done in the constructor of the proxied contract.\n     *\n     * Implementations of ForwardTarget should override this function,\n     * and chain to super.initialize(_self).\n     *\n     * @param _self The address of the original contract instance (the one being\n     *              forwarded to).\n     */\n    function initialize(address _self) public virtual onlyConstruction {\n        address _implAddress = address(ForwardTarget(_self).implementation());\n        require(\n            _implAddress != address(0),\n            \"initialization failure: nothing to implement\"\n        );\n        setImplementation(_implAddress);\n    }\n\n    /** Get the address of the proxy target contract.\n     */\n    function implementation() public view returns (address _impl) {\n        assembly {\n            _impl := sload(IMPLEMENTATION_SLOT)\n        }\n    }\n\n    /** @notice Set new implementation */\n    function setImplementation(address _impl) internal {\n        require(implementation() != _impl, \"Implementation already matching\");\n        assembly {\n            sstore(IMPLEMENTATION_SLOT, _impl)\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/test/ImplementationUpdatingTarget.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../proxy/ForwardTarget.sol\";\n\n/** @title ImplementationUpdatingTarget\n *\n * This is a ForwardTarget that allows updates to the implementation reference\n * to test what happens when trying to set to the current value.\n */\ncontract ImplementationUpdatingTarget is ForwardTarget {\n    /** Try updating the implementation reference to a new address.\n     */\n    function updateImplementation(address _newImplementation) public {\n        setImplementation(_newImplementation);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/utils/StringPacker.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nlibrary StringPacker {\n    // takes a string of 31 or less characters and converts it to bytes32\n    function pack(string memory unpacked)\n        internal\n        pure\n        returns (bytes32 packed)\n    {\n        // do not use this function in a lossy way, it will not work\n        // only strings with 31 or less characters are stored in memory packed with their length value\n        require(bytes(unpacked).length < 32);\n        // shift the memory pointer to pack the length of the string into the high byte\n        // by assigning this to the return value, the type of bytes32 means that, when returning,\n        // the pointer continues to read into the string data\n        assembly {\n            packed := mload(add(unpacked, 31))\n        }\n    }\n\n    // takes a bytes32 packed in the format above and unpacks it into a string\n    function unpack(bytes32 packed)\n        internal\n        pure\n        returns (string memory unpacked)\n    {\n        // get the high byte which stores the length of the string when unpacked\n        uint256 len = uint256(packed >> 248);\n        // ensure that the length of the unpacked string doesn't read beyond the input value\n        require(len < 32);\n        // initialize the return value with the length\n        unpacked = string(new bytes(len));\n        // shift the pointer so that the length will be at the bottom of the word to match string encoding\n        // then store the packed value\n        assembly {\n            // Potentially writes into unallocated memory as the length in the packed form will trail off the end\n            // This is fine as there are no other relevant memory values to overwrite\n            mstore(add(unpacked, 31), packed)\n        }\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/utils/TimeUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/** @title TimeUtils\n * Utility class for time, allowing easy unit testing.\n */\nabstract contract TimeUtils {\n    /** Determine the current time as perceived by the policy timing contract.\n     *\n     * Used extensively in testing, but also useful in production for\n     * determining what processes can currently be run.\n     */\n    function getTime() internal view returns (uint256) {\n        // solhint-disable-next-line not-rely-on-time\n        return block.timestamp;\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/VDF/BigNumber.sol": {
        "content": "pragma solidity ^0.8.0;\n\n/*\nMIT License\n\nCopyright (c) 2017 zcoinofficial\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n*/\n\n// Originated from https://github.com/zcoinofficial/solidity-BigNumber\n\n// SPDX-License-Identifier: MIT\n\n// solhint-disable no-inline-assembly, no-empty-blocks, function-max-lines\n\n/**\n * @title Big integer math library\n */\nlibrary BigNumber {\n    /*\n     * BigNumber is defined as a struct named 'Instance' to avoid naming conflicts.\n     * DO NOT ALLOW INSTANTIATING THIS DIRECTLY - use the 'from' functions defined below.\n     * Hoping in future Solidity will allow visibility modifiers on structs.\n     */\n\n    // @notice store bytes in word-size (32 byte) chunks\n    struct Instance {\n        bytes32[] value;\n    }\n\n    /**\n     * @notice Create a new Bignumber instance from byte array\n     * @dev    If the caller subsequently clears or modifies the input _value, it will corrupt the BigNumber value.\n     * @param _value Number stored in big endian bytes\n     * @return instance of BigNumber\n     */\n    function from(bytes memory _value) internal view returns (Instance memory) {\n        uint256 length = _value.length;\n        if (length == 0) {\n            // Zero\n            return Instance(new bytes32[](0));\n        }\n        uint256 numSlots = (length + 31) >> 5;\n        Instance memory _instance = Instance(new bytes32[](numSlots));\n\n        // ensure there aren't any leading zero words\n        // this is not the zeroOffset yet, this is the modulo of the length\n        uint256 zeroOffset = length & 0x1f;\n        bytes32 word;\n        if (zeroOffset == 0) {\n            assembly {\n                // load the first word from _value\n                word := mload(add(_value, 0x20))\n            }\n            require(\n                word != 0,\n                \"High-word must be set when input is bytes32-aligned\"\n            );\n        } else {\n            // calculate zeroOffset\n            zeroOffset = 32 - zeroOffset;\n            assembly {\n                // load the first word from _value\n                word := shr(mul(0x8, zeroOffset), mload(add(_value, 0x20)))\n            }\n            require(\n                word != 0,\n                \"High-word must be set when input is bytes32-aligned\"\n            );\n        }\n\n        assembly {\n            /*\n            Call precompiled contract to copy data\n            gas cost is 15 + 3/word\n            there is no packing for structs in memory, so this just loads the slot for _instance\n            shift 32 bytes to skip the length value of each reference type\n            shift an additional 32 - offset bits on the result to naturally create the offset\n            */\n            if iszero(\n                staticcall(\n                    add(0x0f, mul(0x03, numSlots)),\n                    0x04,\n                    add(_value, 0x20),\n                    length,\n                    add(mload(_instance), add(0x20, zeroOffset)),\n                    length\n                )\n            ) {\n                revert(0, 0)\n            }\n        }\n\n        return _instance;\n    }\n\n    /**\n     * @notice Create a new BigNumber instance from uint256\n     * @param _value Number stored in uint256\n     * @return instance of BigNumber\n     */\n    function from(uint256 _value)\n        internal\n        pure\n        returns (Instance memory instance)\n    {\n        if (_value != 0x0) {\n            instance = Instance(new bytes32[](1));\n            instance.value[0] = bytes32(_value);\n        }\n    }\n\n    /**\n     * @notice Convert instance to padded byte array\n     * @param _instance BigNumber instance to convert\n     * @param _size Desired size of byte array\n     * @return result byte array\n     */\n    function asBytes(Instance memory _instance, uint256 _size)\n        internal\n        view\n        returns (bytes memory)\n    {\n        uint256 length = _instance.value.length;\n        require(_size & 0x1f == 0x0, \"Size must be multiple of 0x20\");\n\n        uint256 _byteLength = length << 5;\n        require(_size >= _byteLength, \"Number too large to represent\");\n\n        uint256 zeroOffset = _size - _byteLength;\n        bytes memory result = new bytes(_size);\n\n        assembly {\n            /*\n            Call precompiled contract to copy data\n            gas cost is 15 + 3/word\n            there is no packing for structs in memory, so this just loads the slot for _instance\n            shift 32 bytes to skip the length value of each reference type\n            shift an additional zeroOffset bits on the result to naturally create the offset\n            */\n            if iszero(\n                staticcall(\n                    add(0x0f, mul(0x03, length)),\n                    0x04,\n                    add(mload(_instance), 0x20),\n                    _byteLength,\n                    add(result, add(0x20, zeroOffset)),\n                    _byteLength\n                )\n            ) {\n                revert(0, 0)\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * @notice Convert instance to minimal byte array\n     * @param _instance BigNumber instance to convert\n     * @return result byte array\n     */\n    function asBytes(Instance memory _instance)\n        internal\n        view\n        returns (bytes memory)\n    {\n        uint256 _length = _instance.value.length;\n        if (_length == 0) {\n            return new bytes(0);\n        }\n\n        bytes32 firstWord = _instance.value[0];\n        uint256 zeroOffset = 0;\n        if (firstWord >> 128 == 0) {\n            firstWord <<= 128;\n            zeroOffset += 16;\n        }\n        if (firstWord >> 192 == 0) {\n            firstWord <<= 64;\n            zeroOffset += 8;\n        }\n        if (firstWord >> 224 == 0) {\n            firstWord <<= 32;\n            zeroOffset += 4;\n        }\n        if (firstWord >> 240 == 0) {\n            firstWord <<= 16;\n            zeroOffset += 2;\n        }\n        if (firstWord >> 248 == 0) {\n            zeroOffset += 1;\n        }\n\n        uint256 _byteLength = (_length << 5) - zeroOffset;\n\n        bytes memory result = new bytes(_byteLength);\n\n        assembly {\n            /*\n            Call precompiled contract to copy data\n            gas cost is 15 + 3/word\n            there is no packing for structs in memory, so this just loads the slot for _instance\n            shift 32 bytes to skip the length value of each reference type\n            shift an additional 32 + zeroOffset bits on the result to naturally create the offset\n            */\n            if iszero(\n                staticcall(\n                    add(0x0f, mul(0x03, _length)),\n                    0x04,\n                    add(mload(_instance), add(0x20, zeroOffset)),\n                    _byteLength,\n                    add(result, 0x20),\n                    _byteLength\n                )\n            ) {\n                revert(0, 0)\n            }\n        }\n\n        return result;\n    }\n\n    /**\n     * @notice Obtain length (in bytes) of BigNumber instance\n     * This will be rounded up to nearest multiple of 0x20 bytes\n     *\n     * @param _instance BigNumber instance\n     * @return Size (in bytes) of BigNumber instance\n     */\n    function byteLength(Instance memory _instance)\n        internal\n        pure\n        returns (uint256)\n    {\n        return _instance.value.length << 5;\n    }\n\n    /**\n     * @notice Obtain minimal length (in bytes) of BigNumber instance\n     *\n     * @param _instance BigNumber instance\n     * @return Size (in bytes) of minimal BigNumber instance\n     */\n    function minimalByteLength(Instance memory _instance)\n        internal\n        pure\n        returns (uint256)\n    {\n        uint256 _byteLength = byteLength(_instance);\n\n        if (_byteLength == 0) {\n            return 0;\n        }\n\n        bytes32 firstWord = _instance.value[0];\n        uint256 zeroOffset = 0;\n        if (firstWord >> 128 == 0) {\n            firstWord <<= 128;\n            zeroOffset += 16;\n        }\n        if (firstWord >> 192 == 0) {\n            firstWord <<= 64;\n            zeroOffset += 8;\n        }\n        if (firstWord >> 224 == 0) {\n            firstWord <<= 32;\n            zeroOffset += 4;\n        }\n        if (firstWord >> 240 == 0) {\n            firstWord <<= 16;\n            zeroOffset += 2;\n        }\n        if (firstWord >> 248 == 0) {\n            zeroOffset += 1;\n        }\n\n        return _byteLength - zeroOffset;\n    }\n\n    /**\n     * @notice Perform modular exponentiation of BigNumber instance\n     * @param _base Base number\n     * @param _exponent Exponent\n     * @param _modulus Modulus\n     * @return result (_base ^ _exponent) % _modulus\n     */\n    function modexp(\n        Instance memory _base,\n        Instance memory _exponent,\n        Instance memory _modulus\n    ) internal view returns (Instance memory result) {\n        result.value = innerModExp(\n            _base.value,\n            _exponent.value,\n            _modulus.value\n        );\n    }\n\n    /**\n     * @notice Perform modular multiplication of BigNumber instances\n     * @param _a number\n     * @param _b number\n     * @param _modulus Modulus\n     * @return (_a * _b) % _modulus\n     */\n    function modmul(\n        Instance memory _a,\n        Instance memory _b,\n        Instance memory _modulus\n    ) internal view returns (Instance memory) {\n        return modulo(multiply(_a, _b), _modulus);\n    }\n\n    /**\n     * @notice Compare two BigNumber instances for equality\n     * @param _a number\n     * @param _b number\n     * @return -1 if (_a<_b), 1 if (_a>_b) and 0 if (_a==_b)\n     */\n    function cmp(Instance memory _a, Instance memory _b)\n        internal\n        pure\n        returns (int256)\n    {\n        uint256 aLength = _a.value.length;\n        uint256 bLength = _b.value.length;\n        if (aLength > bLength) return 0x1;\n        if (bLength > aLength) return -0x1;\n\n        bytes32 aWord;\n        bytes32 bWord;\n\n        for (uint256 i = 0; i < _a.value.length; i++) {\n            aWord = _a.value[i];\n            bWord = _b.value[i];\n\n            if (aWord > bWord) {\n                return 1;\n            }\n            if (bWord > aWord) {\n                return -1;\n            }\n        }\n\n        return 0;\n    }\n\n    /**\n     * @notice Add two BigNumber instances\n     * Not used outside the library itself\n     */\n    function privateAdd(Instance memory _a, Instance memory _b)\n        internal\n        pure\n        returns (Instance memory instance)\n    {\n        uint256 aLength = _a.value.length;\n        uint256 bLength = _b.value.length;\n        if (aLength == 0) return _b;\n        if (bLength == 0) return _a;\n\n        if (aLength >= bLength) {\n            instance.value = innerAdd(_a.value, _b.value);\n        } else {\n            instance.value = innerAdd(_b.value, _a.value);\n        }\n    }\n\n    /**\n     * @dev max + min\n     */\n    function innerAdd(bytes32[] memory _max, bytes32[] memory _min)\n        private\n        pure\n        returns (bytes32[] memory result)\n    {\n        assembly {\n            // Get the highest available block of memory\n            let result_start := mload(0x40)\n\n            // uint256 max (all bits set; inverse of 0)\n            let uint_max := not(0x0)\n\n            let carry := 0x0\n\n            // load lengths of inputs\n            let max_len := shl(5, mload(_max))\n            let min_len := shl(5, mload(_min))\n\n            // point to last word of each byte array.\n            let max_ptr := add(_max, max_len)\n            let min_ptr := add(_min, min_len)\n\n            // set result_ptr end.\n            let result_ptr := add(add(result_start, 0x20), max_len)\n\n            // while 'min' words are still available\n            // for(int i=0; i<min_length; i+=0x20)\n            for {\n                let i := 0x0\n            } lt(i, min_len) {\n                i := add(i, 0x20)\n            } {\n                // get next word for 'max'\n                let max_val := mload(max_ptr)\n                // get next word for 'min'\n                let min_val := mload(min_ptr)\n\n                // check if this needs to carry over to a new word\n                // sum of both words that this is adding\n                let min_max := add(min_val, max_val)\n                // plus the carry amount if there is one\n                let min_max_carry := add(min_max, carry)\n                // store result\n                mstore(result_ptr, min_max_carry)\n                // carry again if this has overflowed\n                carry := or(lt(min_max, min_val), lt(min_max_carry, carry))\n                // point to next 'min' word\n                min_ptr := sub(min_ptr, 0x20)\n\n                // point to next 'result' word\n                result_ptr := sub(result_ptr, 0x20)\n                // point to next 'max' word\n                max_ptr := sub(max_ptr, 0x20)\n            }\n\n            // remainder after 'min' words are complete.\n            // for(int i=min_length; i<max_length; i+=0x20)\n            for {\n                let i := min_len\n            } lt(i, max_len) {\n                i := add(i, 0x20)\n            } {\n                // get next word for 'max'\n                let max_val := mload(max_ptr)\n\n                // result_word = max_word+carry\n                let max_carry := add(max_val, carry)\n                mstore(result_ptr, max_carry)\n                // finds whether or not to set the carry bit for the next iteration.\n                carry := lt(max_carry, carry)\n\n                // point to next 'result' word\n                result_ptr := sub(result_ptr, 0x20)\n                // point to next 'max' word\n                max_ptr := sub(max_ptr, 0x20)\n            }\n\n            // store the carry bit\n            mstore(result_ptr, carry)\n            // move result ptr up by a slot if no carry\n            result := add(result_start, sub(0x20, shl(0x5, carry)))\n\n            // store length of result. The function is finished with the byte array.\n            mstore(result, add(shr(5, max_len), carry))\n\n            // Update freemem pointer to point to new end of memory.\n            mstore(0x40, add(result, add(shl(5, mload(result)), 0x20)))\n        }\n    }\n\n    /**\n     * @notice Return absolute difference between two instances\n     * Not used outside the library itself\n     */\n    function absdiff(Instance memory _a, Instance memory _b)\n        internal\n        pure\n        returns (Instance memory instance)\n    {\n        int256 compare = cmp(_a, _b);\n\n        if (compare == 1) {\n            instance.value = innerDiff(_a.value, _b.value);\n        } else if (compare == -0x1) {\n            instance.value = innerDiff(_b.value, _a.value);\n        }\n    }\n\n    /**\n     * @dev max - min\n     */\n    function innerDiff(bytes32[] memory _max, bytes32[] memory _min)\n        private\n        pure\n        returns (bytes32[] memory result)\n    {\n        uint256 carry = 0x0;\n        assembly {\n            // Get the highest available block of memory\n            let result_start := mload(0x40)\n\n            // uint256 max. (all bits set; inverse of 0)\n            let uint_max := not(0x0)\n\n            // load lengths of inputs\n            let max_len := shl(5, mload(_max))\n            let min_len := shl(5, mload(_min))\n\n            //go to end of arrays\n            let max_ptr := add(_max, max_len)\n            let min_ptr := add(_min, min_len)\n\n            //point to least significant result word.\n            let result_ptr := add(result_start, max_len)\n            // save memory_end to update free memory pointer at the end.\n            let memory_end := add(result_ptr, 0x20)\n\n            // while 'min' words are still available.\n            // for(int i=0; i<min_len; i+=0x20)\n            for {\n                let i := 0x0\n            } lt(i, min_len) {\n                i := add(i, 0x20)\n            } {\n                // get next word for 'max'\n                let max_val := mload(max_ptr)\n                // get next word for 'min'\n                let min_val := mload(min_ptr)\n\n                // result_word = (max_word-min_word)-carry\n                // find whether or not to set the carry bit for the next iteration.\n                let max_min := sub(max_val, min_val)\n                let max_min_carry := sub(max_min, carry)\n                mstore(result_ptr, max_min_carry)\n                carry := or(gt(max_min, max_val), gt(max_min_carry, max_min))\n\n                // point to next 'result' word\n                min_ptr := sub(min_ptr, 0x20)\n                // point to next 'result' word\n                result_ptr := sub(result_ptr, 0x20)\n                // point to next 'max' word\n                max_ptr := sub(max_ptr, 0x20)\n            }\n\n            // remainder after 'min' words are complete.\n            // for(int i=min_len; i<max_len; i+=0x20)\n            for {\n                let i := min_len\n            } lt(i, max_len) {\n                i := add(i, 0x20)\n            } {\n                // get next word for 'max'\n                let max_val := mload(max_ptr)\n\n                // result_word = max_word-carry\n                let max_carry := sub(max_val, carry)\n                mstore(result_ptr, max_carry)\n                carry := gt(max_carry, max_val)\n\n                // point to next 'result' word\n                result_ptr := sub(result_ptr, 0x20)\n                // point to next 'max' word\n                max_ptr := sub(max_ptr, 0x20)\n            }\n\n            // the following code removes any leading words containing all zeroes in the result.\n            let shift := 0x20\n            for {\n\n            } iszero(mload(add(result_ptr, shift))) {\n\n            } {\n                shift := add(shift, 0x20)\n            }\n\n            shift := sub(shift, 0x20)\n            if gt(shift, 0x0) {\n                // for(result_ptr+=0x20;; result==0x0; result_ptr+=0x20)\n                // push up the start pointer for the result..\n                result_start := add(result_start, shift)\n                // and subtract a word (0x20 bytes) from the result length.\n                max_len := sub(max_len, shift)\n            }\n\n            // point 'result' bytes value to the correct address in memory\n            result := result_start\n\n            // store length of result. The function is finished with the byte array.\n            mstore(result, shr(5, max_len))\n\n            // Update freemem pointer.\n            mstore(0x40, memory_end)\n        }\n\n        return (result);\n    }\n\n    /**\n     * @notice Multiply two instances\n     * @param _a number\n     * @param _b number\n     * @return res _a * _b\n     */\n    function multiply(Instance memory _a, Instance memory _b)\n        internal\n        view\n        returns (Instance memory res)\n    {\n        res = opAndSquare(_a, _b, true);\n\n        if (cmp(_a, _b) != 0x0) {\n            // diffSquared = (a-b)^2\n            Instance memory diffSquared = opAndSquare(_a, _b, false);\n\n            // res = add_and_square - diffSquared\n            // diffSquared can never be greater than res\n            // so it is safe to use innerDiff directly instead of absdiff\n            res.value = innerDiff(res.value, diffSquared.value);\n        }\n        res = privateRightShift(res);\n        return res;\n    }\n\n    /**\n     * @dev take two instances, add or diff them, then square the result\n     */\n    function opAndSquare(\n        Instance memory _a,\n        Instance memory _b,\n        bool _add\n    ) private view returns (Instance memory res) {\n        Instance memory two = from(0x2);\n\n        bytes memory _modulus;\n\n        res = _add ? privateAdd(_a, _b) : absdiff(_a, _b);\n        uint256 modIndex = (res.value.length << 6) + 0x1;\n\n        _modulus = new bytes(1);\n        assembly {\n            //store length of modulus\n            mstore(_modulus, modIndex)\n            //set first modulus word\n            mstore(\n                add(_modulus, 0x20),\n                0xf000000000000000000000000000000000000000000000000000000000000000\n            )\n            //update freemem pointer to be modulus index + length\n            // mstore(0x40, add(_modulus, add(modIndex, 0x20)))\n        }\n\n        Instance memory modulus;\n        modulus = from(_modulus);\n\n        res = modexp(res, two, modulus);\n    }\n\n    /**\n     * @dev a % mod\n     */\n    function modulo(Instance memory _a, Instance memory _mod)\n        private\n        view\n        returns (Instance memory res)\n    {\n        Instance memory one = from(1);\n        res = modexp(_a, one, _mod);\n    }\n\n    /**\n     * @dev Use the precompile to perform _base ^ _exp % _mod\n     */\n    function innerModExp(\n        bytes32[] memory _base,\n        bytes32[] memory _exp,\n        bytes32[] memory _mod\n    ) private view returns (bytes32[] memory ret) {\n        assembly {\n            let bl := shl(5, mload(_base))\n            let el := shl(5, mload(_exp))\n            let ml := shl(5, mload(_mod))\n\n            // Free memory pointer is always stored at 0x40\n            let freemem := mload(0x40)\n\n            // arg[0] = base.length @ +0\n            mstore(freemem, bl)\n\n            // arg[1] = exp.length @ + 0x20\n            mstore(add(freemem, 0x20), el)\n\n            // arg[2] = mod.length @ + 0x40\n            mstore(add(freemem, 0x40), ml)\n\n            // arg[3] = base.bits @ + 0x60\n            // Use identity built-in (contract 0x4) as a cheap memcpy\n            let success := staticcall(\n                450,\n                0x4,\n                add(_base, 0x20),\n                bl,\n                add(freemem, 0x60),\n                bl\n            )\n\n            // arg[4] = exp.bits @ +0x60+base.length\n            let argBufferSize := add(0x60, bl)\n            success := and(\n                success,\n                staticcall(\n                    450,\n                    0x4,\n                    add(_exp, 0x20),\n                    el,\n                    add(freemem, argBufferSize),\n                    el\n                )\n            )\n\n            // arg[5] = mod.bits @ +0x60+base.length+exp.length\n            argBufferSize := add(argBufferSize, el)\n            success := and(\n                success,\n                staticcall(\n                    0x1C2,\n                    0x4,\n                    add(_mod, 0x20),\n                    ml,\n                    add(freemem, argBufferSize),\n                    ml\n                )\n            )\n\n            // Total argBufferSize of input = 0x60+base.length+exp.length+mod.length\n            argBufferSize := add(argBufferSize, ml)\n            // Invoke contract 0x5, put return value right after mod.length, @ +0x60\n            success := and(\n                success,\n                staticcall(\n                    sub(gas(), 0x546),\n                    0x5,\n                    freemem,\n                    argBufferSize,\n                    add(0x60, freemem),\n                    ml\n                )\n            )\n\n            if iszero(success) {\n                revert(0x0, 0x0)\n            } // fail where there isn't enough gas to make the call\n\n            let length := ml\n            let result_ptr := add(0x60, freemem)\n\n            // the following code removes any leading words containing all zeroes in the result.\n            let shift := 0x0\n            for {\n\n            } and(gt(length, shift), iszero(mload(add(result_ptr, shift)))) {\n\n            } {\n                shift := add(shift, 0x20)\n            }\n\n            if gt(shift, 0x0) {\n                // push up the start pointer for the result..\n                result_ptr := add(result_ptr, shift)\n                // and subtract a the words from the result length.\n                length := sub(length, shift)\n            }\n\n            ret := sub(result_ptr, 0x20)\n            mstore(ret, shr(5, length))\n\n            // point to the location of the return value (length, bits)\n            // assuming mod length is multiple of 0x20, return value is already in the right format.\n            // Otherwise, the offset needs to be adjusted.\n            // ret := add(0x40,freemem)\n            // deallocate freemem pointer\n            mstore(0x40, add(add(0x60, freemem), ml))\n        }\n        return ret;\n    }\n\n    /**\n     * @dev Right shift instance 'dividend' by 'value' bits.\n     * This clobbers the passed _dividend\n     */\n    function privateRightShift(Instance memory _dividend)\n        internal\n        pure\n        returns (Instance memory)\n    {\n        bytes32[] memory result;\n        uint256 wordShifted;\n        uint256 maskShift = 0xfe;\n        uint256 precedingWord;\n        uint256 resultPtr;\n        uint256 length = _dividend.value.length << 5;\n\n        require(length <= 1024, \"Length must be less than 8192 bits\");\n\n        assembly {\n            resultPtr := add(mload(_dividend), length)\n        }\n\n        for (int256 i = int256(length) - 0x20; i >= 0x0; i -= 0x20) {\n            // for each word:\n            assembly {\n                // get next word\n                wordShifted := mload(resultPtr)\n                // if i==0x0:\n                switch iszero(i)\n                case 0x1 {\n                    // handles msword: no precedingWord needed.\n                    precedingWord := 0x0\n                }\n                default {\n                    // else get precedingWord.\n                    precedingWord := mload(sub(resultPtr, 0x20))\n                }\n            }\n            // right shift current by value\n            wordShifted >>= 0x2;\n            // left shift next significant word by maskShift\n            precedingWord <<= maskShift;\n            assembly {\n                // store OR'd precedingWord and shifted value in-place\n                mstore(resultPtr, or(wordShifted, precedingWord))\n            }\n            // point to next value.\n            resultPtr -= 0x20;\n        }\n\n        assembly {\n            // the following code removes a leading word if any containing all zeroes in the result.\n            resultPtr := add(resultPtr, 0x20)\n\n            if and(gt(length, 0x0), iszero(mload(resultPtr))) {\n                // push up the start pointer for the result..\n                resultPtr := add(resultPtr, 0x20)\n                // and subtract a word (0x20 bytes) from the result length.\n                length := sub(length, 0x20)\n            }\n\n            result := sub(resultPtr, 0x20)\n            mstore(result, shr(5, length))\n        }\n\n        return Instance(result);\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/VDF/IsPrime.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/** @title Probable prime tester with Miller-Rabin\n */\ncontract IsPrime {\n    /* Compute modular exponentiation using the modexp precompile contract\n     * See https://github.com/ethereum/EIPs/blob/master/EIPS/eip-198.md\n     */\n    function expmod(\n        uint256 _x,\n        uint256 _e,\n        uint256 _n\n    ) private view returns (uint256 r) {\n        assembly {\n            let p := mload(0x40) // Load free memory pointer\n            mstore(p, 0x20) // Store length of x (256 bit)\n            mstore(add(p, 0x20), 0x20) // Store length of e (256 bit)\n            mstore(add(p, 0x40), 0x20) // Store length of N (256 bit)\n            mstore(add(p, 0x60), _x) // Store x\n            mstore(add(p, 0x80), _e) // Store e\n            mstore(add(p, 0xa0), _n) // Store n\n\n            // Call precompiled modexp contract, input and output at p\n            if iszero(staticcall(gas(), 0x05, p, 0xc0, p, 0x20)) {\n                // revert if failed\n                revert(0, 0)\n            }\n            // Load output (256 bit)\n            r := mload(p)\n        }\n    }\n\n    /** @notice Test if number is probable prime\n     * Probability of false positive is (1/4)**_k\n     * @param _n Number to be tested for primality\n     * @param _k Number of iterations\n     */\n    function isProbablePrime(uint256 _n, uint256 _k)\n        public\n        view\n        returns (bool)\n    {\n        if (_n == 2 || _n == 3 || _n == 5) {\n            return true;\n        }\n        if (_n == 1 || (_n & 1 == 0)) {\n            return false;\n        }\n\n        uint256 s = 0;\n        uint256 _n3 = _n - 3;\n        uint256 _n1 = _n - 1;\n        uint256 d = _n1;\n\n        //calculate the trailing zeros on the binary representation of the number\n        if (d << 128 == 0) {\n            d >>= 128;\n            s += 128;\n        }\n        if (d << 192 == 0) {\n            d >>= 64;\n            s += 64;\n        }\n        if (d << 224 == 0) {\n            d >>= 32;\n            s += 32;\n        }\n        if (d << 240 == 0) {\n            d >>= 16;\n            s += 16;\n        }\n        if (d << 248 == 0) {\n            d >>= 8;\n            s += 8;\n        }\n        if (d << 252 == 0) {\n            d >>= 4;\n            s += 4;\n        }\n        if (d << 254 == 0) {\n            d >>= 2;\n            s += 2;\n        }\n        if (d << 255 == 0) {\n            d >>= 1;\n            s += 1;\n        }\n\n        bytes32 prevBlockHash = blockhash(block.number - 1);\n\n        for (uint256 i = 0; i < _k; ++i) {\n            bytes32 hash = keccak256(abi.encode(prevBlockHash, i));\n            uint256 a = (uint256(hash) % _n3) + 2;\n            uint256 x = expmod(a, d, _n);\n            if (x != 1 && x != _n1) {\n                uint256 j;\n                for (j = 0; j < s; ++j) {\n                    x = mulmod(x, x, _n);\n                    if (x == _n1) {\n                        break;\n                    }\n                }\n                if (j == s) {\n                    return false;\n                }\n            }\n        }\n\n        return true;\n    }\n}\n"
      },
      "@helix-foundation/currency-dev/contracts/VDF/VDFVerifier.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./BigNumber.sol\";\nimport \"./IsPrime.sol\";\nimport \"../policy/PolicedUtils.sol\";\n\n/** @title On-the-chain verification for RSA 2K VDF\n */\ncontract VDFVerifier is PolicedUtils, IsPrime {\n    using BigNumber for BigNumber.Instance;\n\n    /* 2048-bit modulus from RSA-2048 challenge\n     * https://en.wikipedia.org/wiki/RSA_Factoring_Challenge\n     * The security assumptions rely on RSA challenge rules:\n     * No attacker knows or can obtain the factorization\n     * Factorization wasn't recorded on generation of the number.\n     */\n\n    bytes public constant N =\n        hex\"c7970ceedcc3b0754490201a7aa613cd73911081c790f5f1a8726f463550bb5b7ff0db8e1ea1189ec72f93d1650011bd721aeeacc2acde32a04107f0648c2813a31f5b0b7765ff8b44b4b6ffc93384b646eb09c7cf5e8592d40ea33c80039f35b4f14a04b51f7bfd781be4d1673164ba8eb991c2c4d730bbbe35f592bdef524af7e8daefd26c66fc02c479af89d64d373f442709439de66ceb955f3ea37d5159f6135809f85334b5cb1813addc80cd05609f10ac6a95ad65872c909525bdad32bc729592642920f24c61dc5b3c3b7923e56b16a4d9d373d8721f24a3fc0f1b3131f55615172866bccc30f95054c824e733a5eb6817f7bc16399d48c6361cc7e5\";\n    uint256 public constant MIN_BYTES = 64;\n\n    /* The State is a data structure that tracks progress of a logical single verification session\n     * from a single verifier. Once verification is complete,\n     * state is removed, and (if succesfully verified) replaced by a entry\n     * in verified\n     */\n    struct State {\n        uint256 progress; // progress: 1 .. t-1\n        uint256 t;\n        uint256 x;\n        bytes32 concatHash;\n        BigNumber.Instance y;\n        BigNumber.Instance xi;\n        BigNumber.Instance yi;\n    }\n\n    // Mapping from verifier to state\n    mapping(address => State) private state;\n\n    /** @notice Mapping from keccak256(t, x) to keccak256(y)\n     */\n    mapping(bytes32 => bytes32) public verified;\n\n    /* Event to be emitted when verification is complete.\n     */\n    event SuccessfulVerification(uint256 x, uint256 t, bytes y);\n\n    /**\n     * @notice Construct the contract with global parameters.\n     */\n    // solhint-disable-next-line no-empty-blocks\n    constructor(Policy _policy) PolicedUtils(_policy) {\n        // uses PolicedUtils constructor\n    }\n\n    /**\n     * @notice Start the verification process\n     * This starts the submission of a proof that (x^(2^(2^t+1)))==y\n     * @notice The caller should have already set the prime number, _x, to use in the random inflation\n     * contract.\n     */\n    function start(\n        uint256 _x,\n        uint256 _t,\n        bytes calldata _ybytes\n    ) external {\n        require(\n            verified[keccak256(abi.encode(_t, _x))] == bytes32(0),\n            \"this _x, _t combination has already been verified\"\n        );\n\n        require(_t >= 2, \"t must be at least 2\");\n\n        require(_x > 1, \"The commitment (x) must be > 1\");\n\n        BigNumber.Instance memory n = BigNumber.from(N);\n        BigNumber.Instance memory x = BigNumber.from(_x);\n        BigNumber.Instance memory y = BigNumber.from(_ybytes);\n        BigNumber.Instance memory x2 = BigNumber.multiply(x, x);\n\n        require(\n            y.minimalByteLength() >= MIN_BYTES,\n            \"The secret (y) must be at least 64 bytes long\"\n        );\n        require(BigNumber.cmp(y, n) == -1, \"y must be less than N\");\n\n        State storage currentState = state[msg.sender];\n\n        currentState.progress = 1; // reset the contract\n        currentState.t = _t;\n\n        currentState.x = _x;\n        currentState.y = y;\n\n        currentState.xi = x2; // the time-lock-puzzle is for x2 = x^2; x2 is a QR mod n\n        currentState.yi = y;\n        currentState.concatHash = keccak256(\n            abi.encodePacked(_x, y.asBytes(n.byteLength()))\n        );\n    }\n\n    /**\n     * @notice Submit next step of proof\n     * To be continuously called with progress = 1 ... t-1 and corresponding u, inclusively.\n     * progress input parameter indicates the expected value of progress after the successful processing of this step.\n     *\n     * So, it starts with s.progress == 0 and call with progress=1, ... t-1. Once you set s.progress = t-1, this has\n     * completed the verification successfully.\n     *\n     * In other words, the input is effectively (i, U_sqrt[i]).\n     */\n    function update(bytes calldata _ubytes) external {\n        State storage s = state[msg.sender]; // saves gas\n\n        require(s.progress > 0, \"process has not yet been started\");\n\n        BigNumber.Instance memory n = BigNumber.from(N); // save in memory\n        BigNumber.Instance memory one = BigNumber.from(1);\n        BigNumber.Instance memory two = BigNumber.from(2);\n\n        BigNumber.Instance memory u = BigNumber.from(_ubytes);\n        BigNumber.Instance memory u2 = BigNumber.modexp(u, two, n); // u2 = u^2 mod n\n\n        require(BigNumber.cmp(u, one) == 1, \"u must be greater than 1\");\n        require(BigNumber.cmp(u, n) == -1, \"u must be less than N\");\n        require(BigNumber.cmp(u2, one) == 1, \"u*u must be greater than 1\");\n\n        uint256 nlen = n.byteLength();\n\n        uint256 nextProgress = s.progress;\n\n        BigNumber.Instance memory r = BigNumber.from(\n            uint256(\n                keccak256(\n                    abi.encodePacked(\n                        s.concatHash,\n                        u.asBytes(nlen),\n                        nextProgress\n                    )\n                )\n            )\n        );\n\n        nextProgress++;\n\n        BigNumber.Instance memory xi = BigNumber.modmul(\n            BigNumber.modexp(s.xi, r, n),\n            u2,\n            n\n        ); // xi^r * u^2\n        BigNumber.Instance memory yi = BigNumber.modmul(\n            BigNumber.modexp(u2, r, n),\n            s.yi,\n            n\n        ); // u^2*r * y\n\n        if (nextProgress != s.t) {\n            // Intermediate step\n            s.xi = xi;\n            s.yi = yi;\n\n            s.progress = nextProgress; // this becomes t-1 for the last step\n        } else {\n            // Final step. Finalize calculations.\n            xi = xi.modexp(BigNumber.from(4), n); // xi^4. Must match yi\n\n            require(\n                BigNumber.cmp(xi, yi) == 0,\n                \"Verification failed in the last step\"\n            );\n\n            // Success! Fall through\n\n            verified[keccak256(abi.encode(s.t, s.x))] = keccak256(\n                s.y.asBytes(nlen)\n            );\n\n            emit SuccessfulVerification(s.x, s.t, s.y.asBytes());\n            delete (state[msg.sender]);\n        }\n    }\n\n    /**\n     * @notice Return verified state\n     * @return true iff (x^(2^(2^t+1)))==y has been proven\n     */\n    function isVerified(\n        uint256 _x,\n        uint256 _t,\n        bytes calldata _ybytes\n    ) external view returns (bool) {\n        BigNumber.Instance memory y = BigNumber.from(_ybytes);\n        uint256 nlen = N.length;\n        return\n            verified[keccak256(abi.encode(_t, _x))] ==\n            keccak256(y.asBytes(nlen));\n    }\n}\n"
      },
      "@openzeppelin/contracts/security/Pausable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../utils/Context.sol\";\n\n/**\n * @dev Contract module which allows children to implement an emergency stop\n * mechanism that can be triggered by an authorized account.\n *\n * This module is used through inheritance. It will make available the\n * modifiers `whenNotPaused` and `whenPaused`, which can be applied to\n * the functions of your contract. Note that they will not be pausable by\n * simply including this module, only once the modifiers are put in place.\n */\nabstract contract Pausable is Context {\n    /**\n     * @dev Emitted when the pause is triggered by `account`.\n     */\n    event Paused(address account);\n\n    /**\n     * @dev Emitted when the pause is lifted by `account`.\n     */\n    event Unpaused(address account);\n\n    bool private _paused;\n\n    /**\n     * @dev Initializes the contract in unpaused state.\n     */\n    constructor() {\n        _paused = false;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is not paused.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    modifier whenNotPaused() {\n        _requireNotPaused();\n        _;\n    }\n\n    /**\n     * @dev Modifier to make a function callable only when the contract is paused.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    modifier whenPaused() {\n        _requirePaused();\n        _;\n    }\n\n    /**\n     * @dev Returns true if the contract is paused, and false otherwise.\n     */\n    function paused() public view virtual returns (bool) {\n        return _paused;\n    }\n\n    /**\n     * @dev Throws if the contract is paused.\n     */\n    function _requireNotPaused() internal view virtual {\n        require(!paused(), \"Pausable: paused\");\n    }\n\n    /**\n     * @dev Throws if the contract is not paused.\n     */\n    function _requirePaused() internal view virtual {\n        require(paused(), \"Pausable: not paused\");\n    }\n\n    /**\n     * @dev Triggers stopped state.\n     *\n     * Requirements:\n     *\n     * - The contract must not be paused.\n     */\n    function _pause() internal virtual whenNotPaused {\n        _paused = true;\n        emit Paused(_msgSender());\n    }\n\n    /**\n     * @dev Returns to normal state.\n     *\n     * Requirements:\n     *\n     * - The contract must be paused.\n     */\n    function _unpause() internal virtual whenPaused {\n        _paused = false;\n        emit Unpaused(_msgSender());\n    }\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n */\ninterface IERC20Permit {\n    /**\n     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,\n     * given ``owner``'s signed approval.\n     *\n     * IMPORTANT: The same issues {IERC20-approve} has related to transaction\n     * ordering also apply here.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `deadline` must be a timestamp in the future.\n     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`\n     * over the EIP712-formatted function arguments.\n     * - the signature must use ``owner``'s current nonce (see {nonces}).\n     *\n     * For more information on the signature format, see the\n     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP\n     * section].\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * @dev Returns the current nonce for `owner`. This value must be\n     * included whenever a signature is generated for {permit}.\n     *\n     * Every successful call to {permit} increases ``owner``'s nonce by one. This\n     * prevents a signature from being used multiple times.\n     */\n    function nonces(address owner) external view returns (uint256);\n\n    /**\n     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC20.sol\";\n\n/**\n * @dev Interface for the optional metadata functions from the ERC20 standard.\n *\n * _Available since v4.1._\n */\ninterface IERC20Metadata is IERC20 {\n    /**\n     * @dev Returns the name of the token.\n     */\n    function name() external view returns (string memory);\n\n    /**\n     * @dev Returns the symbol of the token.\n     */\n    function symbol() external view returns (string memory);\n\n    /**\n     * @dev Returns the decimals places of the token.\n     */\n    function decimals() external view returns (uint8);\n}\n"
      },
      "@openzeppelin/contracts/token/ERC20/IERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC20 standard as defined in the EIP.\n */\ninterface IERC20 {\n    /**\n     * @dev Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * @dev Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n\n    /**\n     * @dev Returns the amount of tokens in existence.\n     */\n    function totalSupply() external view returns (uint256);\n\n    /**\n     * @dev Returns the amount of tokens owned by `account`.\n     */\n    function balanceOf(address account) external view returns (uint256);\n\n    /**\n     * @dev Moves `amount` tokens from the caller's account to `to`.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transfer(address to, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Returns the remaining number of tokens that `spender` will be\n     * allowed to spend on behalf of `owner` through {transferFrom}. This is\n     * zero by default.\n     *\n     * This value changes when {approve} or {transferFrom} are called.\n     */\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    /**\n     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * IMPORTANT: Beware that changing an allowance with this method brings the risk\n     * that someone may use both the old and the new allowance by unfortunate\n     * transaction ordering. One possible solution to mitigate this race\n     * condition is to first reduce the spender's allowance to 0 and set the\n     * desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     *\n     * Emits an {Approval} event.\n     */\n    function approve(address spender, uint256 amount) external returns (bool);\n\n    /**\n     * @dev Moves `amount` tokens from `from` to `to` using the\n     * allowance mechanism. `amount` is then deducted from the caller's\n     * allowance.\n     *\n     * Returns a boolean value indicating whether the operation succeeded.\n     *\n     * Emits a {Transfer} event.\n     */\n    function transferFrom(\n        address from,\n        address to,\n        uint256 amount\n    ) external returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/Context.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract Context {\n    function _msgSender() internal view virtual returns (address) {\n        return msg.sender;\n    }\n\n    function _msgData() internal view virtual returns (bytes calldata) {\n        return msg.data;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Counters.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Counters.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title Counters\n * @author Matt Condon (@shrugs)\n * @dev Provides counters that can only be incremented, decremented or reset. This can be used e.g. to track the number\n * of elements in a mapping, issuing ERC721 ids, or counting request ids.\n *\n * Include with `using Counters for Counters.Counter;`\n */\nlibrary Counters {\n    struct Counter {\n        // This variable should never be directly accessed by users of the library: interactions must be restricted to\n        // the library's function. As of Solidity v0.5.2, this cannot be enforced, though there is a proposal to add\n        // this feature: see https://github.com/ethereum/solidity/issues/4637\n        uint256 _value; // default: 0\n    }\n\n    function current(Counter storage counter) internal view returns (uint256) {\n        return counter._value;\n    }\n\n    function increment(Counter storage counter) internal {\n        unchecked {\n            counter._value += 1;\n        }\n    }\n\n    function decrement(Counter storage counter) internal {\n        uint256 value = counter._value;\n        require(value > 0, \"Counter: decrement overflow\");\n        unchecked {\n            counter._value = value - 1;\n        }\n    }\n\n    function reset(Counter storage counter) internal {\n        counter._value = 0;\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/draft-EIP712.sol)\n\npragma solidity ^0.8.0;\n\n// EIP-712 is Final as of 2022-08-11. This file is deprecated.\n\nimport \"./EIP712.sol\";\n"
      },
      "@openzeppelin/contracts/utils/cryptography/ECDSA.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/ECDSA.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../Strings.sol\";\n\n/**\n * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.\n *\n * These functions can be used to verify that a message was signed by the holder\n * of the private keys of a given address.\n */\nlibrary ECDSA {\n    enum RecoverError {\n        NoError,\n        InvalidSignature,\n        InvalidSignatureLength,\n        InvalidSignatureS,\n        InvalidSignatureV // Deprecated in v4.8\n    }\n\n    function _throwError(RecoverError error) private pure {\n        if (error == RecoverError.NoError) {\n            return; // no error: do nothing\n        } else if (error == RecoverError.InvalidSignature) {\n            revert(\"ECDSA: invalid signature\");\n        } else if (error == RecoverError.InvalidSignatureLength) {\n            revert(\"ECDSA: invalid signature length\");\n        } else if (error == RecoverError.InvalidSignatureS) {\n            revert(\"ECDSA: invalid signature 's' value\");\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature` or error string. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     *\n     * Documentation for signature generation:\n     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]\n     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {\n        if (signature.length == 65) {\n            bytes32 r;\n            bytes32 s;\n            uint8 v;\n            // ecrecover takes the signature parameters, and the only way to get them\n            // currently is to use assembly.\n            /// @solidity memory-safe-assembly\n            assembly {\n                r := mload(add(signature, 0x20))\n                s := mload(add(signature, 0x40))\n                v := byte(0, mload(add(signature, 0x60)))\n            }\n            return tryRecover(hash, v, r, s);\n        } else {\n            return (address(0), RecoverError.InvalidSignatureLength);\n        }\n    }\n\n    /**\n     * @dev Returns the address that signed a hashed message (`hash`) with\n     * `signature`. This address can then be used for verification purposes.\n     *\n     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:\n     * this function rejects them by requiring the `s` value to be in the lower\n     * half order, and the `v` value to be either 27 or 28.\n     *\n     * IMPORTANT: `hash` _must_ be the result of a hash operation for the\n     * verification to be secure: it is possible to craft signatures that\n     * recover to arbitrary addresses for non-hashed data. A safe way to ensure\n     * this is by receiving a hash of the original message (which may otherwise\n     * be too long), and then calling {toEthSignedMessageHash} on it.\n     */\n    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, signature);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.\n     *\n     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address, RecoverError) {\n        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);\n        uint8 v = uint8((uint256(vs) >> 255) + 27);\n        return tryRecover(hash, v, r, s);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.\n     *\n     * _Available since v4.2._\n     */\n    function recover(\n        bytes32 hash,\n        bytes32 r,\n        bytes32 vs\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, r, vs);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     *\n     * _Available since v4.3._\n     */\n    function tryRecover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address, RecoverError) {\n        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature\n        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines\n        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most\n        // signatures from current libraries generate a unique signature with an s-value in the lower half order.\n        //\n        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value\n        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or\n        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept\n        // these malleable signatures as well.\n        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\n            return (address(0), RecoverError.InvalidSignatureS);\n        }\n\n        // If the signature is valid (and not malleable), return the signer address\n        address signer = ecrecover(hash, v, r, s);\n        if (signer == address(0)) {\n            return (address(0), RecoverError.InvalidSignature);\n        }\n\n        return (signer, RecoverError.NoError);\n    }\n\n    /**\n     * @dev Overload of {ECDSA-recover} that receives the `v`,\n     * `r` and `s` signature fields separately.\n     */\n    function recover(\n        bytes32 hash,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal pure returns (address) {\n        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);\n        _throwError(error);\n        return recovered;\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from a `hash`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {\n        // 32 is the length in bytes of hash,\n        // enforced by the type signature above\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", hash));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Message, created from `s`. This\n     * produces hash corresponding to the one signed with the\n     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]\n     * JSON-RPC method as part of EIP-191.\n     *\n     * See {recover}.\n     */\n    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n\", Strings.toString(s.length), s));\n    }\n\n    /**\n     * @dev Returns an Ethereum Signed Typed Data, created from a\n     * `domainSeparator` and a `structHash`. This produces hash corresponding\n     * to the one signed with the\n     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]\n     * JSON-RPC method as part of EIP-712.\n     *\n     * See {recover}.\n     */\n    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {\n        return keccak256(abi.encodePacked(\"\\x19\\x01\", domainSeparator, structHash));\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/cryptography/EIP712.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/cryptography/EIP712.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./ECDSA.sol\";\n\n/**\n * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.\n *\n * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,\n * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding\n * they need in their contracts using a combination of `abi.encode` and `keccak256`.\n *\n * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding\n * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA\n * ({_hashTypedDataV4}).\n *\n * The implementation of the domain separator was designed to be as efficient as possible while still properly updating\n * the chain id to protect against replay attacks on an eventual fork of the chain.\n *\n * NOTE: This contract implements the version of the encoding known as \"v4\", as implemented by the JSON RPC method\n * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].\n *\n * _Available since v3.4._\n */\nabstract contract EIP712 {\n    /* solhint-disable var-name-mixedcase */\n    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to\n    // invalidate the cached domain separator if the chain id changes.\n    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;\n    uint256 private immutable _CACHED_CHAIN_ID;\n    address private immutable _CACHED_THIS;\n\n    bytes32 private immutable _HASHED_NAME;\n    bytes32 private immutable _HASHED_VERSION;\n    bytes32 private immutable _TYPE_HASH;\n\n    /* solhint-enable var-name-mixedcase */\n\n    /**\n     * @dev Initializes the domain separator and parameter caches.\n     *\n     * The meaning of `name` and `version` is specified in\n     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:\n     *\n     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.\n     * - `version`: the current major version of the signing domain.\n     *\n     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart\n     * contract upgrade].\n     */\n    constructor(string memory name, string memory version) {\n        bytes32 hashedName = keccak256(bytes(name));\n        bytes32 hashedVersion = keccak256(bytes(version));\n        bytes32 typeHash = keccak256(\n            \"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"\n        );\n        _HASHED_NAME = hashedName;\n        _HASHED_VERSION = hashedVersion;\n        _CACHED_CHAIN_ID = block.chainid;\n        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);\n        _CACHED_THIS = address(this);\n        _TYPE_HASH = typeHash;\n    }\n\n    /**\n     * @dev Returns the domain separator for the current chain.\n     */\n    function _domainSeparatorV4() internal view returns (bytes32) {\n        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {\n            return _CACHED_DOMAIN_SEPARATOR;\n        } else {\n            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);\n        }\n    }\n\n    function _buildDomainSeparator(\n        bytes32 typeHash,\n        bytes32 nameHash,\n        bytes32 versionHash\n    ) private view returns (bytes32) {\n        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));\n    }\n\n    /**\n     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this\n     * function returns the hash of the fully encoded EIP712 message for this domain.\n     *\n     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:\n     *\n     * ```solidity\n     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(\n     *     keccak256(\"Mail(address to,string contents)\"),\n     *     mailTo,\n     *     keccak256(bytes(mailContents))\n     * )));\n     * address signer = ECDSA.recover(digest, signature);\n     * ```\n     */\n    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {\n        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC1820Implementer.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC1820Implementer.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface for an ERC1820 implementer, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820#interface-implementation-erc1820implementerinterface[EIP].\n * Used by contracts that will be registered as implementers in the\n * {IERC1820Registry}.\n */\ninterface IERC1820Implementer {\n    /**\n     * @dev Returns a special value (`ERC1820_ACCEPT_MAGIC`) if this contract\n     * implements `interfaceHash` for `account`.\n     *\n     * See {IERC1820Registry-setInterfaceImplementer}.\n     */\n    function canImplementInterfaceForAddress(bytes32 interfaceHash, address account) external view returns (bytes32);\n}\n"
      },
      "@openzeppelin/contracts/utils/introspection/IERC1820Registry.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/introspection/IERC1820Registry.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the global ERC1820 Registry, as defined in the\n * https://eips.ethereum.org/EIPS/eip-1820[EIP]. Accounts may register\n * implementers for interfaces in this registry, as well as query support.\n *\n * Implementers may be shared by multiple accounts, and can also implement more\n * than a single interface for each account. Contracts can implement interfaces\n * for themselves, but externally-owned accounts (EOA) must delegate this to a\n * contract.\n *\n * {IERC165} interfaces can also be queried via the registry.\n *\n * For an in-depth explanation and source code analysis, see the EIP text.\n */\ninterface IERC1820Registry {\n    event InterfaceImplementerSet(address indexed account, bytes32 indexed interfaceHash, address indexed implementer);\n\n    event ManagerChanged(address indexed account, address indexed newManager);\n\n    /**\n     * @dev Sets `newManager` as the manager for `account`. A manager of an\n     * account is able to set interface implementers for it.\n     *\n     * By default, each account is its own manager. Passing a value of `0x0` in\n     * `newManager` will reset the manager to this initial state.\n     *\n     * Emits a {ManagerChanged} event.\n     *\n     * Requirements:\n     *\n     * - the caller must be the current manager for `account`.\n     */\n    function setManager(address account, address newManager) external;\n\n    /**\n     * @dev Returns the manager for `account`.\n     *\n     * See {setManager}.\n     */\n    function getManager(address account) external view returns (address);\n\n    /**\n     * @dev Sets the `implementer` contract as ``account``'s implementer for\n     * `interfaceHash`.\n     *\n     * `account` being the zero address is an alias for the caller's address.\n     * The zero address can also be used in `implementer` to remove an old one.\n     *\n     * See {interfaceHash} to learn how these are created.\n     *\n     * Emits an {InterfaceImplementerSet} event.\n     *\n     * Requirements:\n     *\n     * - the caller must be the current manager for `account`.\n     * - `interfaceHash` must not be an {IERC165} interface id (i.e. it must not\n     * end in 28 zeroes).\n     * - `implementer` must implement {IERC1820Implementer} and return true when\n     * queried for support, unless `implementer` is the caller. See\n     * {IERC1820Implementer-canImplementInterfaceForAddress}.\n     */\n    function setInterfaceImplementer(\n        address account,\n        bytes32 _interfaceHash,\n        address implementer\n    ) external;\n\n    /**\n     * @dev Returns the implementer of `interfaceHash` for `account`. If no such\n     * implementer is registered, returns the zero address.\n     *\n     * If `interfaceHash` is an {IERC165} interface id (i.e. it ends with 28\n     * zeroes), `account` will be queried for support of it.\n     *\n     * `account` being the zero address is an alias for the caller's address.\n     */\n    function getInterfaceImplementer(address account, bytes32 _interfaceHash) external view returns (address);\n\n    /**\n     * @dev Returns the interface hash for an `interfaceName`, as defined in the\n     * corresponding\n     * https://eips.ethereum.org/EIPS/eip-1820#interface-name[section of the EIP].\n     */\n    function interfaceHash(string calldata interfaceName) external pure returns (bytes32);\n\n    /**\n     * @notice Updates the cache with whether the contract implements an ERC165 interface or not.\n     * @param account Address of the contract for which to update the cache.\n     * @param interfaceId ERC165 interface for which to update the cache.\n     */\n    function updateERC165Cache(address account, bytes4 interfaceId) external;\n\n    /**\n     * @notice Checks whether a contract implements an ERC165 interface or not.\n     * If the result is not cached a direct lookup on the contract address is performed.\n     * If the result is not cached or the cached value is out-of-date, the cache MUST be updated manually by calling\n     * {updateERC165Cache} with the contract address.\n     * @param account Address of the contract to check.\n     * @param interfaceId ERC165 interface to check.\n     * @return True if `account` implements `interfaceId`, false otherwise.\n     */\n    function implementsERC165Interface(address account, bytes4 interfaceId) external view returns (bool);\n\n    /**\n     * @notice Checks whether a contract implements an ERC165 interface or not without using or updating the cache.\n     * @param account Address of the contract to check.\n     * @param interfaceId ERC165 interface to check.\n     * @return True if `account` implements `interfaceId`, false otherwise.\n     */\n    function implementsERC165InterfaceNoCache(address account, bytes4 interfaceId) external view returns (bool);\n}\n"
      },
      "@openzeppelin/contracts/utils/math/Math.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/Math.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Standard math utilities missing in the Solidity language.\n */\nlibrary Math {\n    enum Rounding {\n        Down, // Toward negative infinity\n        Up, // Toward infinity\n        Zero // Toward zero\n    }\n\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a > b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a < b ? a : b;\n    }\n\n    /**\n     * @dev Returns the average of two numbers. The result is rounded towards\n     * zero.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow.\n        return (a & b) + (a ^ b) / 2;\n    }\n\n    /**\n     * @dev Returns the ceiling of the division of two numbers.\n     *\n     * This differs from standard division with `/` in that it rounds up instead\n     * of rounding down.\n     */\n    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b - 1) / b can overflow on addition, so we distribute.\n        return a == 0 ? 0 : (a - 1) / b + 1;\n    }\n\n    /**\n     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0\n     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)\n     * with further edits by Uniswap Labs also under MIT license.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator\n    ) internal pure returns (uint256 result) {\n        unchecked {\n            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use\n            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256\n            // variables such that product = prod1 * 2^256 + prod0.\n            uint256 prod0; // Least significant 256 bits of the product\n            uint256 prod1; // Most significant 256 bits of the product\n            assembly {\n                let mm := mulmod(x, y, not(0))\n                prod0 := mul(x, y)\n                prod1 := sub(sub(mm, prod0), lt(mm, prod0))\n            }\n\n            // Handle non-overflow cases, 256 by 256 division.\n            if (prod1 == 0) {\n                return prod0 / denominator;\n            }\n\n            // Make sure the result is less than 2^256. Also prevents denominator == 0.\n            require(denominator > prod1);\n\n            ///////////////////////////////////////////////\n            // 512 by 256 division.\n            ///////////////////////////////////////////////\n\n            // Make division exact by subtracting the remainder from [prod1 prod0].\n            uint256 remainder;\n            assembly {\n                // Compute remainder using mulmod.\n                remainder := mulmod(x, y, denominator)\n\n                // Subtract 256 bit number from 512 bit number.\n                prod1 := sub(prod1, gt(remainder, prod0))\n                prod0 := sub(prod0, remainder)\n            }\n\n            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.\n            // See https://cs.stackexchange.com/q/138556/92363.\n\n            // Does not overflow because the denominator cannot be zero at this stage in the function.\n            uint256 twos = denominator & (~denominator + 1);\n            assembly {\n                // Divide denominator by twos.\n                denominator := div(denominator, twos)\n\n                // Divide [prod1 prod0] by twos.\n                prod0 := div(prod0, twos)\n\n                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.\n                twos := add(div(sub(0, twos), twos), 1)\n            }\n\n            // Shift in bits from prod1 into prod0.\n            prod0 |= prod1 * twos;\n\n            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such\n            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for\n            // four bits. That is, denominator * inv = 1 mod 2^4.\n            uint256 inverse = (3 * denominator) ^ 2;\n\n            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works\n            // in modular arithmetic, doubling the correct bits in each step.\n            inverse *= 2 - denominator * inverse; // inverse mod 2^8\n            inverse *= 2 - denominator * inverse; // inverse mod 2^16\n            inverse *= 2 - denominator * inverse; // inverse mod 2^32\n            inverse *= 2 - denominator * inverse; // inverse mod 2^64\n            inverse *= 2 - denominator * inverse; // inverse mod 2^128\n            inverse *= 2 - denominator * inverse; // inverse mod 2^256\n\n            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.\n            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is\n            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1\n            // is no longer required.\n            result = prod0 * inverse;\n            return result;\n        }\n    }\n\n    /**\n     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.\n     */\n    function mulDiv(\n        uint256 x,\n        uint256 y,\n        uint256 denominator,\n        Rounding rounding\n    ) internal pure returns (uint256) {\n        uint256 result = mulDiv(x, y, denominator);\n        if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {\n            result += 1;\n        }\n        return result;\n    }\n\n    /**\n     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.\n     *\n     * Inspired by Henry S. Warren, Jr.'s \"Hacker's Delight\" (Chapter 11).\n     */\n    function sqrt(uint256 a) internal pure returns (uint256) {\n        if (a == 0) {\n            return 0;\n        }\n\n        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.\n        //\n        // We know that the \"msb\" (most significant bit) of our target number `a` is a power of 2 such that we have\n        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.\n        //\n        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`\n        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`\n        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`\n        //\n        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.\n        uint256 result = 1 << (log2(a) >> 1);\n\n        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,\n        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at\n        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision\n        // into the expected uint128 result.\n        unchecked {\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            result = (result + a / result) >> 1;\n            return min(result, a / result);\n        }\n    }\n\n    /**\n     * @notice Calculates sqrt(a), following the selected rounding direction.\n     */\n    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = sqrt(a);\n            return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 2, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 128;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 64;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 32;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 16;\n            }\n            if (value >> 8 > 0) {\n                value >>= 8;\n                result += 8;\n            }\n            if (value >> 4 > 0) {\n                value >>= 4;\n                result += 4;\n            }\n            if (value >> 2 > 0) {\n                value >>= 2;\n                result += 2;\n            }\n            if (value >> 1 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log2(value);\n            return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 10, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >= 10**64) {\n                value /= 10**64;\n                result += 64;\n            }\n            if (value >= 10**32) {\n                value /= 10**32;\n                result += 32;\n            }\n            if (value >= 10**16) {\n                value /= 10**16;\n                result += 16;\n            }\n            if (value >= 10**8) {\n                value /= 10**8;\n                result += 8;\n            }\n            if (value >= 10**4) {\n                value /= 10**4;\n                result += 4;\n            }\n            if (value >= 10**2) {\n                value /= 10**2;\n                result += 2;\n            }\n            if (value >= 10**1) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log10(value);\n            return result + (rounding == Rounding.Up && 10**result < value ? 1 : 0);\n        }\n    }\n\n    /**\n     * @dev Return the log in base 256, rounded down, of a positive value.\n     * Returns 0 if given 0.\n     *\n     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.\n     */\n    function log256(uint256 value) internal pure returns (uint256) {\n        uint256 result = 0;\n        unchecked {\n            if (value >> 128 > 0) {\n                value >>= 128;\n                result += 16;\n            }\n            if (value >> 64 > 0) {\n                value >>= 64;\n                result += 8;\n            }\n            if (value >> 32 > 0) {\n                value >>= 32;\n                result += 4;\n            }\n            if (value >> 16 > 0) {\n                value >>= 16;\n                result += 2;\n            }\n            if (value >> 8 > 0) {\n                result += 1;\n            }\n        }\n        return result;\n    }\n\n    /**\n     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.\n     * Returns 0 if given 0.\n     */\n    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {\n        unchecked {\n            uint256 result = log256(value);\n            return result + (rounding == Rounding.Up && 1 << (result * 8) < value ? 1 : 0);\n        }\n    }\n}\n"
      },
      "@openzeppelin/contracts/utils/Strings.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.8.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./math/Math.sol\";\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n    bytes16 private constant _SYMBOLS = \"0123456789abcdef\";\n    uint8 private constant _ADDRESS_LENGTH = 20;\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n     */\n    function toString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            uint256 length = Math.log10(value) + 1;\n            string memory buffer = new string(length);\n            uint256 ptr;\n            /// @solidity memory-safe-assembly\n            assembly {\n                ptr := add(buffer, add(32, length))\n            }\n            while (true) {\n                ptr--;\n                /// @solidity memory-safe-assembly\n                assembly {\n                    mstore8(ptr, byte(mod(value, 10), _SYMBOLS))\n                }\n                value /= 10;\n                if (value == 0) break;\n            }\n            return buffer;\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n     */\n    function toHexString(uint256 value) internal pure returns (string memory) {\n        unchecked {\n            return toHexString(value, Math.log256(value) + 1);\n        }\n    }\n\n    /**\n     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n     */\n    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n        bytes memory buffer = new bytes(2 * length + 2);\n        buffer[0] = \"0\";\n        buffer[1] = \"x\";\n        for (uint256 i = 2 * length + 1; i > 1; --i) {\n            buffer[i] = _SYMBOLS[value & 0xf];\n            value >>= 4;\n        }\n        require(value == 0, \"Strings: hex length insufficient\");\n        return string(buffer);\n    }\n\n    /**\n     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n     */\n    function toHexString(address addr) internal pure returns (string memory) {\n        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n    }\n}\n"
      },
      "contracts/currency/DelegatePermit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// Heavily inspired by:\n// OpenZeppelin Contracts v4.4.1 (token/Delegate/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/EIP712.sol\";\n\n/**\n * Abstract contract including helper functions to allow delegation by signature using\n * [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612).\n *\n * Adds the `{_verifyDelegatePermit}` internal method, verifies a signature specifying permission to receive delegation power\n *\n */\nabstract contract DelegatePermit is EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private constant _DELEGATE_TYPEHASH =\n        keccak256(\n            \"Delegate(address delegator,address delegatee,uint256 nonce,uint256 deadline)\"\n        );\n\n    /**\n     * Verify that the given delegate signature is valid, throws if not\n     * @param delegator The address delegating\n     * @param delegatee The address being delegated to\n     * @param deadline The deadling of the delegation after which it will be invalid\n     * @param v The v part of the signature\n     * @param r The r part of the signature\n     * @param s The s part of the signature\n     */\n    function _verifyDelegatePermit(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) internal {\n        require(\n            block.timestamp <= deadline,\n            \"DelegatePermit: expired deadline\"\n        );\n        require(delegator != address(0), \"invalid delegator\");\n\n        bytes32 structHash = keccak256(\n            abi.encode(\n                _DELEGATE_TYPEHASH,\n                delegator,\n                delegatee,\n                _useDelegationNonce(delegator),\n                deadline\n            )\n        );\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == delegator, \"DelegatePermit: invalid signature\");\n    }\n\n    /**\n     * get the current nonce for the given address\n     * @param owner The address to get nonce for\n     * @return nonce current nonce of `owner`\n     */\n    function delegationNonce(\n        address owner\n    ) public view returns (uint256 nonce) {\n        nonce = _nonces[owner].current();\n        return nonce;\n    }\n\n    /**\n     * \"Consume a nonce\": return the current value and increment.\n     *\n     * Available since v4.1.\n     * @param owner The address to consume a nonce for\n     * @return current incremented nonce of `owner`\n     */\n    function _useDelegationNonce(\n        address owner\n    ) private returns (uint256 current) {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n        return current;\n    }\n}\n"
      },
      "contracts/currency/ECO.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./InflationSnapshots.sol\";\nimport \"../governance/monetary/CurrencyGovernance.sol\";\n\n/**\n * @title An ERC20 token interface to the Eco currency system.\n */\ncontract ECO is InflationSnapshots {\n    //////////////////////////////////////////////\n    //////////////////// VARS ////////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * Mapping storing contracts able to rebase the token\n     */\n    mapping(address => bool) public rebasers;\n    /**\n     * Mapping storing contracts able to rebase the token\n     */\n    mapping(address => bool) public snapshotters;\n\n    //////////////////////////////////////////////\n    /////////////////// ERRORS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * error for when an address tries to rebase without permission\n     */\n    error OnlyRebasers();\n\n    /**\n     * error for when an address tries to snapshot without permission\n     */\n    error OnlySnapshotters();\n\n    //////////////////////////////////////////////\n    /////////////////// EVENTS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * emits when the rebasers permissions are changed\n     * @param actor denotes the new address whose permissions are being updated\n     * @param newPermission denotes the new ability of the actor address (true for can rebase, false for cannot)\n     */\n    event UpdatedRebasers(address actor, bool newPermission);\n\n    /**\n     * emits when the snapshotters permissions are changed\n     * @param actor denotes the new address whose permissions are being updated\n     * @param newPermission denotes the new ability of the actor address (true for can snapshot, false for cannot)\n     */\n    event UpdatedSnapshotters(address actor, bool newPermission);\n\n    //////////////////////////////////////////////\n    ////////////////// MODIFIERS /////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * Modifier for checking if the sender is a rebaser\n     */\n    modifier onlyRebaserRole() {\n        if (!rebasers[msg.sender]) {\n            revert OnlyRebasers();\n        }\n        _;\n    }\n\n    /**\n     * Modifier for checking if the sender is a snapshotter\n     */\n    modifier onlySnapshotterRole() {\n        if (!snapshotters[msg.sender]) {\n            revert OnlySnapshotters();\n        }\n        _;\n    }\n\n    //////////////////////////////////////////////\n    ///////////////// CONSTRUCTOR ////////////////\n    //////////////////////////////////////////////\n\n    constructor(\n        Policy _policy,\n        address _initialPauser\n    ) InflationSnapshots(_policy, \"ECO\", \"ECO\", _initialPauser) {}\n\n    //////////////////////////////////////////////\n    ///////////////// INITIALIZER ////////////////\n    //////////////////////////////////////////////\n\n    function initialize(\n        address _self\n    ) public virtual override onlyConstruction {\n        super.initialize(_self);\n        pauser = ERC20Pausable(_self).pauser();\n    }\n\n    //////////////////////////////////////////////\n    ////////////////// FUNCTIONS /////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * Rebase the currency using an inflation multiplier\n     * @param _inflationMultiplier the multipler used to rebase the currency\n     */\n    function rebase(uint256 _inflationMultiplier) public onlyRebaserRole {\n        _rebase(_inflationMultiplier);\n    }\n\n    /**\n     * Creates a new snapshot\n     */\n    function snapshot() public onlySnapshotterRole {\n        _snapshot();\n    }\n\n    /**\n     * change the rebasing permissions for an address\n     * only callable by tokenRoleAdmin\n     * @param _key the address to change permissions for\n     * @param _value the new permission. true = can rebase, false = cannot rebase\n     */\n    function updateRebasers(address _key, bool _value) public onlyPolicy {\n        rebasers[_key] = _value;\n        emit UpdatedRebasers(_key, _value);\n    }\n\n    /**\n     * change the rebasing permissions for an address\n     * only callable by tokenRoleAdmin\n     * @param _key the address to change permissions for\n     * @param _value the new permission. true = can snapshot, false = cannot snapshot\n     */\n    function updateSnapshotters(address _key, bool _value) public onlyPolicy {\n        snapshotters[_key] = _value;\n        emit UpdatedSnapshotters(_key, _value);\n    }\n}\n"
      },
      "contracts/currency/ECOx.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"./IECO.sol\";\nimport \"./TotalSupplySnapshots.sol\";\n\n/**\n * @title An ERC20 token interface for ECOx\n *\n */\ncontract ECOx is TotalSupplySnapshots {\n    //////////////////////////////////////////////\n    //////////////////// VARS ////////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * @dev Mapping storing contracts able to rebase the token\n     */\n    mapping(address => bool) public snapshotters;\n\n    //////////////////////////////////////////////\n    /////////////////// ERRORS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * error for when transfer returns false\n     * used by contracts that import this contract\n     */\n    error TransferFailed();\n\n    /**\n     * error for when an address tries to snapshot without permission\n     */\n    error OnlySnapshotters();\n\n    //////////////////////////////////////////////\n    /////////////////// EVENTS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * emits when the snapshotters permissions are changed\n     * @param actor denotes the new address whose permissions are being updated\n     * @param newPermission denotes the new ability of the actor address (true for can snapshot, false for cannot)\n     */\n    event UpdatedSnapshotters(address actor, bool newPermission);\n\n    //////////////////////////////////////////////\n    ////////////////// MODIFIERS /////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * @dev Modifier for checking if the sender is a snapshotter\n     */\n    modifier onlySnapshotterRole() {\n        if (!snapshotters[msg.sender]) {\n            revert OnlySnapshotters();\n        }\n        _;\n    }\n\n    constructor(\n        Policy _policy,\n        address _pauser\n    ) TotalSupplySnapshots(_policy, \"ECOx\", \"ECOx\", _pauser) {}\n\n    function initialize(\n        address _self\n    ) public virtual override onlyConstruction {\n        super.initialize(_self);\n        pauser = ERC20Pausable(_self).pauser();\n    }\n\n    function snapshot() public onlySnapshotterRole {\n        _snapshot();\n    }\n\n    /**\n     * @dev change the rebasing permissions for an address\n     * only callable by tokenRoleAdmin\n     * @param _key the address to change permissions for\n     * @param _value the new permission. true = can snapshot, false = cannot snapshot\n     */\n    function updateSnapshotters(address _key, bool _value) public onlyPolicy {\n        snapshotters[_key] = _value;\n        emit UpdatedSnapshotters(_key, _value);\n    }\n}\n"
      },
      "contracts/currency/ECOxExchange.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"./ECO.sol\";\nimport \"../policy/Policed.sol\";\nimport \"./ECOx.sol\";\n\n/**\n * @title EcoX Exchange Contract\n * @notice Exchange for ECOx to ECO\n */\ncontract ECOxExchange is Policed {\n    /**\n     * bits of precision used in the exponentiation approximation\n     */\n    uint8 public constant PRECISION_BITS = 100;\n\n    /**\n     * initial supply of ECOx at deployment\n     */\n    uint256 public immutable initialSupply;\n\n    /**\n     * ECOx token contract\n     */\n    ECOx public immutable ecox;\n\n    /**\n     * ECO token contract\n     */\n    ECO public immutable eco;\n\n    /**\n     * constructor\n     * @param policy policy address\n     * @param _ECOx ECOx address\n     * @param _eco ECO address\n     * @param _initialSupply initial supply of ECOx\n     */\n    constructor(\n        Policy policy,\n        ECOx _ECOx,\n        ECO _eco,\n        uint256 _initialSupply\n    ) Policed(policy) {\n        ecox = _ECOx;\n        eco = _eco;\n        initialSupply = _initialSupply;\n    }\n\n    /**\n     * Calculates the value of ECOx by multiplying value by supply\n     * @param _ecoXValue the value of ECOx\n     * @return ecoValue the value of ECOx multiplied by total supply\n     */\n    function ecoValueOf(\n        uint256 _ecoXValue\n    ) public view returns (uint256 ecoValue) {\n        uint256 _ecoSupply = eco.totalSupply();\n        ecoValue = computeValue(_ecoXValue, _ecoSupply);\n        return ecoValue;\n    }\n\n    /**\n     * Calculates the value of ECOx at the total supply snapshot\n     * @param _ecoXValue the value of ECOx\n     * @return ecoValue the value of ECOx multiplied by the total supply at the time of snapshot\n     */\n    function valueAt(\n        uint256 _ecoXValue\n    ) public view returns (uint256 ecoValue) {\n        uint256 _ecoSupplyAt = eco.totalSupplySnapshot();\n        ecoValue = computeValue(_ecoXValue, _ecoSupplyAt);\n        return ecoValue;\n    }\n\n    /**\n     * Exchange ECOx for ECO by burning ECOx and minting ECO\n     * @param _ecoXValue the value of ECOx tokens to burn\n     * the output amount will always be at or greater than the expected amount by the caller, relative to the total ECO supply, as ECOx is never minted\n     * unless the user miscalculates the output value, there is no need to check that output value is at least what's expected\n     */\n    function exchange(uint256 _ecoXValue) external {\n        uint256 ecoAmount = ecoValueOf(_ecoXValue);\n        ecox.burn(msg.sender, _ecoXValue);\n        eco.mint(msg.sender, ecoAmount);\n    }\n\n    /**\n     * Computes the value of ECO from the ECOx value and the ECO supply\n     * @param _ecoXValue the value of ECOx\n     * @param _ecoSupply the supply of ECO\n     * @return ecoValue the value of ECO\n     */\n    function computeValue(\n        uint256 _ecoXValue,\n        uint256 _ecoSupply\n    ) internal view returns (uint256 ecoValue) {\n        uint256 _preciseRatio = safeLeftShift(_ecoXValue, PRECISION_BITS) /\n            initialSupply;\n\n        ecoValue =\n            (generalExp(_preciseRatio, PRECISION_BITS) * _ecoSupply) >>\n            PRECISION_BITS;\n        return ecoValue;\n    }\n\n    /**\n     * Safe Left Shift\n     * @param value the value to shift\n     * @param shift the amount to shift the value by\n     * @return shiftedAmount the shifted amount\n     */\n    function safeLeftShift(\n        uint256 value,\n        uint8 shift\n    ) internal pure returns (uint256 shiftedAmount) {\n        shiftedAmount = value << shift;\n        require(\n            shiftedAmount >> shift == value,\n            \"value too large, shift out of bounds\"\n        );\n        return shiftedAmount;\n    }\n\n    /**\n     * this function can be auto-generated by the script [PrintFunctionGeneralExp.py](https://github.com/barakman/solidity-math-utils/blob/master/project/emulation/AutoGenerate/PrintFunctionGeneralExp.py).\n     *\n     * it approximates `e ^ x` via maclaurin summation: `(x^0)/0! + (x^1)/1! + ... + (x^n)/n!`.\n     *\n     * it returns `e ^ (x / 2 ^ precision) * 2 ^ precision`, that is, the result is upshifted for accuracy.\n     *\n     * @param _x input value\n     * @param _precision precision\n     * @return result `e ^ (x / 2 ^ precision) * 2 ^ precision`, that is, the result is upshifted for accuracy.\n     */\n    function generalExp(\n        uint256 _x,\n        uint8 _precision\n    ) internal pure returns (uint256 result) {\n        uint256 xi = _x;\n        uint256 res = 0;\n\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x3442c4e6074a82f1797f72ac0000000; // add x^02 * (33! / 02!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x116b96f757c380fb287fd0e40000000; // add x^03 * (33! / 03!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x045ae5bdd5f0e03eca1ff4390000000; // add x^04 * (33! / 04!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00defabf91302cd95b9ffda50000000; // add x^05 * (33! / 05!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x002529ca9832b22439efff9b8000000; // add x^06 * (33! / 06!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00054f1cf12bd04e516b6da88000000; // add x^07 * (33! / 07!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000a9e39e257a09ca2d6db51000000; // add x^08 * (33! / 08!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000012e066e7b839fa050c309000000; // add x^09 * (33! / 09!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000001e33d7d926c329a1ad1a800000; // add x^10 * (33! / 10!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000002bee513bdb4a6b19b5f800000; // add x^11 * (33! / 11!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000003a9316fa79b88eccf2a00000; // add x^12 * (33! / 12!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000048177ebe1fa812375200000; // add x^13 * (33! / 13!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000005263fe90242dcbacf00000; // add x^14 * (33! / 14!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000057e22099c030d94100000; // add x^15 * (33! / 15!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000057e22099c030d9410000; // add x^16 * (33! / 16!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000052b6b54569976310000; // add x^17 * (33! / 17!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000004985f67696bf748000; // add x^18 * (33! / 18!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000003dea12ea99e498000; // add x^19 * (33! / 19!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000031880f2214b6e000; // add x^20 * (33! / 20!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000025bcff56eb36000; // add x^21 * (33! / 21!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000001b722e10ab1000; // add x^22 * (33! / 22!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000001317c70077000; // add x^23 * (33! / 23!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000cba84aafa00; // add x^24 * (33! / 24!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000082573a0a00; // add x^25 * (33! / 25!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000005035ad900; // add x^26 * (33! / 26!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x000000000000000000000002f881b00; // add x^27 * (33! / 27!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000001b29340; // add x^28 * (33! / 28!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x00000000000000000000000000efc40; // add x^29 * (33! / 29!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000007fe0; // add x^30 * (33! / 30!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000420; // add x^31 * (33! / 31!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000021; // add x^32 * (33! / 32!)\n        xi = (xi * _x) >> _precision;\n        res += xi * 0x0000000000000000000000000000001; // add x^33 * (33! / 33!)\n\n        result = res / 0x688589cc0e9505e2f2fee5580000000 + _x; // divide by 33! and then add x^1 / 1! (the x^0 term omitted because we subtract 1 right after)\n        return result;\n    }\n}\n"
      },
      "contracts/currency/ERC20.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"../utils/StringPacker.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol\";\nimport \"./ERC20Permit.sol\";\n\n/**\n * Implementation of the {IERC20} interface.\n *\n * This comment taken from the openzeppelin source contract.\n *\n * This implementation is agnostic to the way tokens are created. This means\n * that a supply mechanism has to be added in a derived contract using {_mint}.\n * For a generic mechanism see {ERC20PresetMinterPauser}.\n *\n * TIP: For a detailed writeup see open zeppelin guide\n * [How to implement supply mechanisms](https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226).\n *\n * We have followed general OpenZeppelin Contracts guidelines: functions revert\n * instead returning `false` on failure. This behavior is nonetheless\n * conventional and does not conflict with the expectations of ERC20\n * applications.\n *\n * Additionally, an {Approval} event is emitted on calls to {transferFrom}.\n * This allows applications to reconstruct the allowance for all accounts just\n * by listening to said events. Other implementations of the EIP may not emit\n * these events, as it isn't required by the specification.\n *\n * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}\n * functions have been added to mitigate the well-known issues around setting\n * allowances. See {IERC20-approve}.\n */\n// internal _name and _symbol are stored immutable as bytes32 and unpacked via StringPacker\ncontract ERC20 is ERC20Permit {\n    mapping(address => uint256) internal _balances;\n\n    mapping(address => mapping(address => uint256)) private _allowances;\n\n    uint256 internal _totalSupply;\n\n    bytes32 internal immutable _name;\n    bytes32 internal immutable _symbol;\n\n    /**\n     * Emitted when `value` tokens are moved from one account (`from`) to\n     * another (`to`).\n     *\n     * Note that `value` may be zero.\n     */\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    /**\n     * Emitted when the allowance of a `spender` for an `owner` is set by\n     * a call to {approve}. `value` is the new allowance.\n     */\n    event Approval(\n        address indexed owner,\n        address indexed spender,\n        uint256 value\n    );\n\n    /**\n     * Sets the values for {name} and {symbol}.\n     *\n     * The default value of {decimals} is 18. To select a different value for\n     * {decimals} you should overload it.\n     *\n     * All two of these values are immutable: they can only be set once during\n     * construction.\n     */\n    constructor(string memory name_, string memory symbol_) ERC20Permit(name_) {\n        _name = StringPacker.pack(name_);\n        _symbol = StringPacker.pack(symbol_);\n    }\n\n    /**\n     * Returns the name of the token.\n     */\n    function name() public view virtual returns (string memory) {\n        return StringPacker.unpack(_name);\n    }\n\n    /**\n     * Returns the symbol of the token, usually a shorter version of the\n     * name.\n     */\n    function symbol() public view virtual returns (string memory) {\n        return StringPacker.unpack(_symbol);\n    }\n\n    /**\n     * Returns the number of decimals used to get its user representation.\n     * For example, if `decimals` equals `2`, a balance of `505` tokens should\n     * be displayed to a user as `5.05` (`505 / 10 ** 2`).\n     *\n     * Tokens usually opt for a value of 18, imitating the relationship between\n     * Ether and Wei. This is the value {ERC20} uses, unless this function is\n     * overridden;\n     *\n     * NOTE: This information is only used for _display_ purposes: it in\n     * no way affects any of the arithmetic of the contract, including\n     * {IERC20-balanceOf} and {IERC20-transfer}.\n     */\n    function decimals() public view virtual returns (uint8) {\n        return 18;\n    }\n\n    /**\n     * See {IERC20-totalSupply}.\n     */\n    function totalSupply() public view virtual returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * See {IERC20-balanceOf}.\n     */\n    function balanceOf(address account) public view virtual returns (uint256) {\n        return _balances[account];\n    }\n\n    /**\n     * See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function transfer(\n        address recipient,\n        uint256 amount\n    ) public virtual returns (bool) {\n        _transfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /**\n     * See {IERC20-allowance}.\n     */\n    function allowance(\n        address owner,\n        address spender\n    ) public view virtual returns (uint256) {\n        return _allowances[owner][spender];\n    }\n\n    /**\n     * See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function approve(\n        address spender,\n        uint256 amount\n    ) public virtual returns (bool) {\n        _approve(msg.sender, spender, amount);\n        return true;\n    }\n\n    /**\n     * See {IERC20-transferFrom}.\n     *\n     * Emits an {Approval} event indicating the updated allowance. This is not\n     * required by the EIP. See the note at the beginning of {ERC20}.\n     *\n     * Requirements:\n     *\n     * - `sender` and `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     * - the caller must have allowance for ``sender``'s tokens of at least\n     * `amount`.\n     */\n    function transferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) public virtual returns (bool) {\n        _transfer(sender, recipient, amount);\n\n        uint256 currentAllowance = _allowances[sender][msg.sender];\n        require(\n            currentAllowance >= amount,\n            \"ERC20: transfer amount exceeds allowance\"\n        );\n        unchecked {\n            _approve(sender, msg.sender, currentAllowance - amount);\n        }\n\n        return true;\n    }\n\n    /**\n     * Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function increaseAllowance(\n        address spender,\n        uint256 addedValue\n    ) public virtual returns (bool) {\n        _approve(\n            msg.sender,\n            spender,\n            _allowances[msg.sender][spender] + addedValue\n        );\n        return true;\n    }\n\n    /**\n     * Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function decreaseAllowance(\n        address spender,\n        uint256 subtractedValue\n    ) public virtual returns (bool) {\n        uint256 currentAllowance = _allowances[msg.sender][spender];\n        require(\n            currentAllowance >= subtractedValue,\n            \"ERC20: decreased allowance below zero\"\n        );\n        unchecked {\n            _approve(msg.sender, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _transfer(\n        address sender,\n        address recipient,\n        uint256 originalAmount\n    ) internal virtual {\n        require(recipient != address(0), \"ERC20: transfer to the zero address\");\n\n        uint256 amount = _beforeTokenTransfer(\n            sender,\n            recipient,\n            originalAmount\n        );\n\n        uint256 senderBalance = _balances[sender];\n        require(\n            senderBalance >= amount,\n            \"ERC20: transfer amount exceeds balance\"\n        );\n        unchecked {\n            _balances[sender] = senderBalance - amount;\n        }\n        _balances[recipient] += amount;\n\n        emit Transfer(sender, recipient, originalAmount);\n\n        _afterTokenTransfer(sender, recipient, amount);\n    }\n\n    /** Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _mint(\n        address account,\n        uint256 originalAmount\n    ) internal virtual returns (uint256) {\n        require(account != address(0), \"ERC20: mint to the zero address\");\n\n        uint256 amount = _beforeTokenTransfer(\n            address(0),\n            account,\n            originalAmount\n        );\n\n        _totalSupply += amount;\n        _balances[account] += amount;\n        emit Transfer(address(0), account, originalAmount);\n\n        _afterTokenTransfer(address(0), account, amount);\n\n        return amount;\n    }\n\n    /**\n     * Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _burn(\n        address account,\n        uint256 originalAmount\n    ) internal virtual returns (uint256) {\n        uint256 amount = _beforeTokenTransfer(\n            account,\n            address(0),\n            originalAmount\n        );\n\n        uint256 accountBalance = _balances[account];\n        require(accountBalance >= amount, \"ERC20: burn amount exceeds balance\");\n        unchecked {\n            _balances[account] = accountBalance - amount;\n        }\n        _totalSupply -= amount;\n\n        emit Transfer(account, address(0), originalAmount);\n\n        _afterTokenTransfer(account, address(0), amount);\n\n        return amount;\n    }\n\n    /**\n     * Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual override {\n        require(spender != address(0), \"ERC20: approve to the zero address\");\n\n        _allowances[owner][spender] = amount;\n        emit Approval(owner, spender, amount);\n    }\n\n    /**\n     * Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _beforeTokenTransfer(\n        address, // from\n        address, // to\n        uint256 amount\n    ) internal virtual returns (uint256) {\n        return amount;\n    }\n\n    /**\n     * Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     *\n     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual {}\n}\n"
      },
      "contracts/currency/ERC20Delegated.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ERC20Pausable.sol\";\nimport \"./DelegatePermit.sol\";\nimport \"./TotalSupplySnapshots.sol\";\n\n/**\n * This contract tracks delegations of an ERC20 token by tokenizing the delegations\n * It assumes a companion token that is transferred to denote changes in votes brought\n * on by both transfers (via _afterTokenTransfer hooks) and delegations.\n * The secondary token creates allowances whenever it delegates to allow for reclaiming the voting power later\n *\n * Voting power can be queried through the public accessor {voteBalanceOf}. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}.\n * Delegates need to disable their own ability to delegate to enable others to delegate to them.\n *\n * Raw delegations can be done in partial amounts via {delegateAmount}. This is intended for contracts which can run\n * their own internal ledger of delegations and will prevent you from transferring the delegated funds until you undelegate.\n */\nabstract contract ERC20Delegated is TotalSupplySnapshots, DelegatePermit {\n    // this checks who has opted in to voting\n    mapping(address => bool) public voter;\n\n    // this balance tracks the amount of votes an address has for snapshot purposes\n    mapping(address => uint256) internal _voteBalances;\n\n    // allowances are created to allow for undelegation and to track delegated amounts\n    mapping(address => mapping(address => uint256)) private _voteAllowances;\n\n    // total allowances helps track if an account is delegated\n    // its value is equivalent to agregating across the middle value of the previous mapping\n    mapping(address => uint256) private _totalVoteAllowances;\n\n    /** a mapping that tracks the primaryDelegates of each user\n     *\n     * Primary delegates can only be chosen using delegate() which sends the full balance\n     * The exist to maintain the functionality that recieving tokens gives those votes to the delegate\n     */\n    mapping(address => address) internal _primaryDelegates;\n\n    // mapping that tracks if an address is willing to be delegated to\n    mapping(address => bool) public delegationToAddressEnabled;\n\n    // mapping that tracks if an address is unable to delegate\n    mapping(address => bool) public delegationFromAddressDisabled;\n\n    /**\n     * Emitted when a delegatee is delegated new votes.\n     */\n    event DelegatedVotes(\n        address indexed delegator,\n        address indexed delegatee,\n        uint256 amount\n    );\n\n    /**\n     * Emitted when a token transfer or delegate change results a transfer of voting power.\n     */\n    event VoteTransfer(\n        address indexed sendingVoter,\n        address indexed recievingVoter,\n        uint256 votes\n    );\n\n    /**\n     * Emitted when an account denotes a primary delegate.\n     */\n    event NewPrimaryDelegate(\n        address indexed delegator,\n        address indexed primaryDelegate\n    );\n\n    constructor(\n        Policy _policy,\n        string memory _name,\n        string memory _symbol,\n        address _initialPauser\n    ) TotalSupplySnapshots(_policy, _name, _symbol, _initialPauser) {\n        // call to super constructor\n    }\n\n    function enableVoting() public {\n        require(!voter[msg.sender], \"ERC20Delegated: voting already enabled\");\n\n        voter[msg.sender] = true; // this must be set before the mint to make sure voting power is given\n        _voteMint(msg.sender, _balances[msg.sender]);\n    }\n\n    /**\n     * Set yourself as willing to recieve delegates.\n     */\n    function enableDelegationTo() public {\n        require(\n            isOwnDelegate(msg.sender),\n            \"ERC20Delegated: cannot enable delegation if you have outstanding delegation\"\n        );\n\n        require(\n            voter[msg.sender],\n            \"ERC20Delegated: enable voting before enabling being a delegate\"\n        );\n\n        delegationToAddressEnabled[msg.sender] = true;\n        delegationFromAddressDisabled[msg.sender] = true;\n    }\n\n    /**\n     * Set yourself as no longer recieving delegates.\n     */\n    function disableDelegationTo() public {\n        delegationToAddressEnabled[msg.sender] = false;\n    }\n\n    /**\n     * Set yourself as being able to delegate again.\n     * also disables delegating to you\n     */\n    function reenableDelegating() public {\n        delegationToAddressEnabled[msg.sender] = false;\n\n        require(\n            _balances[msg.sender] == _voteBalances[msg.sender] &&\n                isOwnDelegate(msg.sender),\n            \"ERC20Delegated: cannot re-enable delegating if you have outstanding delegations\"\n        );\n\n        delegationFromAddressDisabled[msg.sender] = false;\n    }\n\n    /**\n     * Returns true if the user has no amount of their balance delegated, otherwise false.\n     */\n    function isOwnDelegate(address account) public view returns (bool) {\n        return\n            _totalVoteAllowances[account] == 0 &&\n            _primaryDelegates[account] == address(0);\n    }\n\n    /**\n     * Get the primary address `account` is currently delegating to. Defaults to the account address itself if none specified.\n     * The primary delegate is the one that is delegated any new funds the address recieves.\n     * @param account the address whose primary delegate is being fetched\n     */\n    function getPrimaryDelegate(\n        address account\n    ) public view virtual returns (address) {\n        address _voter = _primaryDelegates[account];\n        return _voter == address(0) ? account : _voter;\n    }\n\n    /**\n     * sets the primaryDelegate and emits an event to track it\n     */\n    function _setPrimaryDelegate(\n        address delegator,\n        address delegatee\n    ) internal {\n        _primaryDelegates[delegator] = delegatee;\n\n        emit NewPrimaryDelegate(\n            delegator,\n            delegatee == address(0) ? delegator : delegatee\n        );\n    }\n\n    /**\n     * Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"ERC20Delegated: must have an undelegated amount available to cover delegation\" if you do\n     * @param delegatee the address being delegated to\n     */\n    function delegate(address delegatee) public {\n        require(\n            delegatee != msg.sender,\n            \"ERC20Delegated: use undelegate instead of delegating to yourself\"\n        );\n\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"ERC20Delegated: a primary delegate must enable delegation\"\n        );\n\n        if (!isOwnDelegate(msg.sender)) {\n            undelegateFromAddress(getPrimaryDelegate(msg.sender));\n        }\n\n        uint256 _amount = _balances[msg.sender];\n        _delegate(msg.sender, delegatee, _amount);\n        _setPrimaryDelegate(msg.sender, delegatee);\n    }\n\n    /**\n     * Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"ERC20Delegated: must have an undelegated amount available to cover delegation\" if you do\n     * @param delegator the address delegating votes\n     * @param delegatee the address being delegated to\n     * @param deadline the time at which the signature expires\n     * @param v signature value\n     * @param r signature value\n     * @param s signature value\n     */\n    function delegateBySig(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public {\n        require(\n            delegator != delegatee,\n            \"ERC20Delegated: use undelegate instead of delegating to yourself\"\n        );\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"ERC20Delegated: a primary delegate must enable delegation\"\n        );\n\n        if (!isOwnDelegate(delegator)) {\n            _undelegateFromAddress(delegator, getPrimaryDelegate(delegator));\n        }\n\n        _verifyDelegatePermit(delegator, delegatee, deadline, v, r, s);\n\n        uint256 _amount = _balances[delegator];\n        _delegate(delegator, delegatee, _amount);\n        _setPrimaryDelegate(delegator, delegatee);\n    }\n\n    /**\n     * Delegate an `amount` of votes from the sender to `delegatee`.\n     */\n    function delegateAmount(address delegatee, uint256 amount) public {\n        require(\n            delegatee != msg.sender,\n            \"ERC20Delegated: use undelegate instead of delegating to yourself\"\n        );\n        require(\n            delegatee != address(0),\n            \"ERC20Delegated: cannot delegate to the zero address\"\n        );\n\n        _delegate(msg.sender, delegatee, amount);\n    }\n\n    /**\n     * Change delegation for `delegator` to `delegatee`.\n     *\n     * Emits events {NewDelegatedAmount} and {VoteTransfer}.\n     */\n    function _delegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        require(\n            voter[delegator],\n            \"ERC20Delegated: must be a voter to delegate\"\n        );\n\n        // more strict that the transfer requirement\n        require(\n            amount <= _balances[delegator] - _totalVoteAllowances[delegator],\n            \"ERC20Delegated: must have an undelegated amount available to cover delegation\"\n        );\n\n        require(\n            !delegationFromAddressDisabled[delegator],\n            \"ERC20Delegated: cannot delegate if you have enabled primary delegation to yourself and/or have outstanding delegates\"\n        );\n\n        emit DelegatedVotes(delegator, delegatee, amount);\n\n        _voteTransfer(delegator, delegatee, amount);\n        // create allowance to reclaim token\n        _increaseVoteAllowance(delegatee, delegator, amount);\n        // track owed votes\n        _totalVoteAllowances[delegator] += amount;\n    }\n\n    /**\n     * Undelegate all votes from the sender's primary delegate.\n     */\n    function undelegate() public {\n        address _primaryDelegate = getPrimaryDelegate(msg.sender);\n        require(\n            _primaryDelegate != msg.sender,\n            \"ERC20Delegated: must specifiy undelegate address when not using a Primary Delegate\"\n        );\n        undelegateFromAddress(_primaryDelegate);\n    }\n\n    /**\n     * Undelegate votes from the `delegatee` back to the sender.\n     */\n    function undelegateFromAddress(address delegatee) public {\n        _undelegateFromAddress(msg.sender, delegatee);\n    }\n\n    /**\n     * A primary delegated individual can revoke delegations of unwanted delegators\n     * Useful for allowing yourself to call reenableDelegating after calling disableDelegationTo\n     * @param delegator the address whose delegation is being revoked\n     */\n    function revokeDelegation(address delegator) public {\n        address _primaryDelegate = getPrimaryDelegate(delegator);\n        require(\n            (delegator != msg.sender) && (_primaryDelegate == msg.sender),\n            \"ERC20Delegated: can only revoke delegations to yourself\"\n        );\n        _undelegateFromAddress(delegator, msg.sender);\n    }\n\n    /**\n     * Undelegate votes from the `delegatee` back to the delegator.\n     */\n    function _undelegateFromAddress(\n        address delegator,\n        address delegatee\n    ) internal {\n        uint256 _amount = voteAllowance(delegatee, delegator);\n        _undelegate(delegator, delegatee, _amount);\n        if (delegatee == getPrimaryDelegate(delegator)) {\n            _setPrimaryDelegate(delegator, address(0));\n        }\n    }\n\n    /**\n     * Undelegate a specific amount of votes from the `delegatee` back to the sender.\n     * @param delegatee the address being undelegated to\n     * @param amount the amount of tokens being undelegated\n     */\n    function undelegateAmountFromAddress(\n        address delegatee,\n        uint256 amount\n    ) public {\n        require(\n            voteAllowance(delegatee, msg.sender) >= amount,\n            \"ERC20Delegated: amount not available to undelegate\"\n        );\n        require(\n            msg.sender == getPrimaryDelegate(msg.sender),\n            \"ERC20Delegated: undelegating amounts is only available for partial delegators\"\n        );\n        _undelegate(msg.sender, delegatee, amount);\n    }\n\n    function _undelegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        _totalVoteAllowances[delegator] -= amount;\n        _voteTransferFrom(delegatee, delegator, amount);\n    }\n\n    /**\n     * Move voting power when tokens are transferred.\n     *\n     * Emits a {VoteTransfer} event.\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        if (from == to) {\n            // self transfers require no change in delegation and can be the source of exploits\n            return;\n        }\n\n        bool fromVoter = voter[from];\n\n        // if the address has delegated, they might be transfering tokens allotted to someone else\n        if (fromVoter && !isOwnDelegate(from)) {\n            address _sourcePrimaryDelegate = _primaryDelegates[from]; // cheaper than getPrimaryDelegate because we do the check to own delegate already\n            if (_sourcePrimaryDelegate == address(0)) {\n                // this combined with !isOwnDelegate(from) guarantees a partial delegate situation\n                uint256 _undelegatedAmount = _balances[from] + // need to check if the transfer can be covered\n                    amount -\n                    _totalVoteAllowances[from];\n                require(\n                    _undelegatedAmount >= amount, // can't undelegate in a partial delegate situation\n                    \"ERC20Delegated: delegation too complicated to transfer. Undelegate and simplify before trying again\"\n                );\n            } else {\n                // the combination of !isOwnDelegate(from) and _sourcePrimaryDelegate != address(0) means that we're in a primary delegate situation where all funds are delegated\n                // this means that we already know that amount < _sourcePrimaryDelegatement since _sourcePrimaryDelegatement == senderBalance\n                _undelegate(from, _sourcePrimaryDelegate, amount);\n            }\n        }\n\n        if (voter[to]) {\n            address _voteDestination = to;\n            address _destPrimaryDelegate = _primaryDelegates[to];\n            // saving gas by manually doing a form of isOwnDelegate since this function already needs to read the data for this conditional\n            if (_destPrimaryDelegate != address(0)) {\n                _increaseVoteAllowance(_destPrimaryDelegate, to, amount);\n                _totalVoteAllowances[to] += amount;\n                _voteDestination = _destPrimaryDelegate;\n            }\n\n            if (fromVoter) {\n                _voteTransfer(from, _voteDestination, amount);\n            } else {\n                _voteMint(_voteDestination, amount);\n            }\n        } else {\n            if (fromVoter) {\n                _voteBurn(from, amount);\n            }\n        }\n    }\n\n    /**\n     * See {IERC20-balanceOf}.\n     * @param account the address whose vote balance is being checked\n     */\n    function voteBalanceOf(\n        address account\n    ) public view virtual returns (uint256) {\n        return _voteBalances[account];\n    }\n\n    /**\n     * See {IERC20-transfer}.\n     *\n     * Requirements:\n     *\n     * - `recipient` cannot be the zero address.\n     * - the caller must have a balance of at least `amount`.\n     */\n    function voteTransfer(\n        address recipient,\n        uint256 amount\n    ) internal virtual returns (bool) {\n        _voteTransfer(msg.sender, recipient, amount);\n        return true;\n    }\n\n    /**\n     * See {IERC20-allowance}.\n     */\n    function voteAllowance(\n        address owner,\n        address spender\n    ) internal view virtual returns (uint256) {\n        return _voteAllowances[owner][spender];\n    }\n\n    /**\n     * See {IERC20-approve}.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function voteApprove(\n        address spender,\n        uint256 amount\n    ) internal virtual returns (bool) {\n        _voteApprove(msg.sender, spender, amount);\n        return true;\n    }\n\n    /**\n     * not the same as ERC20 transferFrom\n     * is instead more restrictive, only allows for transfers where the recipient owns the allowance\n     */\n    function _voteTransferFrom(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal virtual returns (bool) {\n        _voteTransfer(sender, recipient, amount);\n\n        uint256 currentAllowance = _voteAllowances[sender][recipient];\n        require(\n            currentAllowance >= amount,\n            \"ERC20Delegated: vote transfer amount exceeds allowance\"\n        );\n        unchecked {\n            _voteApprove(sender, recipient, currentAllowance - amount);\n        }\n\n        return true;\n    }\n\n    /**\n     * Moves `amount` of tokens from `sender` to `recipient`.\n     *\n     * This internal function is equivalent to {transfer}, and can be used to\n     * e.g. implement automatic token fees, slashing mechanisms, etc.\n     *\n     * Emits a {Transfer} event.\n     *\n     * Requirements:\n     *\n     * - `sender` cannot be the zero address.\n     * - `recipient` cannot be the zero address.\n     * - `sender` must have a balance of at least `amount`.\n     */\n    function _voteTransfer(\n        address sender,\n        address recipient,\n        uint256 amount\n    ) internal virtual {\n        _beforeVoteTokenTransfer(sender, recipient, amount);\n\n        if (sender != address(0)) {\n            uint256 senderBalance = _voteBalances[sender];\n            require(\n                senderBalance >= amount,\n                \"ERC20Delegated: vote transfer amount exceeds balance\"\n            );\n            unchecked {\n                _voteBalances[sender] = senderBalance - amount;\n            }\n        }\n\n        if (recipient != address(0)) {\n            _voteBalances[recipient] += amount;\n        }\n\n        emit VoteTransfer(sender, recipient, amount);\n\n        _afterVoteTokenTransfer(sender, recipient, amount);\n    }\n\n    /** Creates `amount` tokens and assigns them to `account`, increasing\n     * the total supply.\n     *\n     * Emits a {Transfer} event with `from` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     */\n    function _voteMint(\n        address account,\n        uint256 amount\n    ) internal virtual returns (uint256) {\n        require(\n            account != address(0),\n            \"ERC20Delegated: vote mint to the zero address\"\n        );\n\n        _beforeVoteTokenTransfer(address(0), account, amount);\n\n        _voteBalances[account] += amount;\n        emit VoteTransfer(address(0), account, amount);\n\n        _afterVoteTokenTransfer(address(0), account, amount);\n\n        return amount;\n    }\n\n    /**\n     * Destroys `amount` tokens from `account`, reducing the\n     * total supply.\n     *\n     * Emits a {Transfer} event with `to` set to the zero address.\n     *\n     * Requirements:\n     *\n     * - `account` cannot be the zero address.\n     * - `account` must have at least `amount` tokens.\n     */\n    function _voteBurn(\n        address account,\n        uint256 amount\n    ) internal virtual returns (uint256) {\n        _beforeVoteTokenTransfer(account, address(0), amount);\n\n        uint256 accountBalance = _voteBalances[account];\n        require(\n            accountBalance >= amount,\n            \"ERC20Delegated: vote burn amount exceeds balance\"\n        );\n        unchecked {\n            _voteBalances[account] = accountBalance - amount;\n        }\n\n        emit VoteTransfer(account, address(0), amount);\n\n        _afterVoteTokenTransfer(account, address(0), amount);\n\n        return amount;\n    }\n\n    /**\n     * Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _voteApprove(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual {\n        require(\n            spender != address(0),\n            \"ERC20Delegate: approve votes to the zero address\"\n        );\n\n        _voteAllowances[owner][spender] = amount;\n    }\n\n    /**\n     * Atomically increases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     */\n    function _increaseVoteAllowance(\n        address owner,\n        address spender,\n        uint256 addedValue\n    ) internal virtual returns (bool) {\n        _voteApprove(\n            owner,\n            spender,\n            _voteAllowances[owner][spender] + addedValue\n        );\n        return true;\n    }\n\n    /**\n     * Atomically decreases the allowance granted to `spender` by the caller.\n     *\n     * This is an alternative to {approve} that can be used as a mitigation for\n     * problems described in {IERC20-approve}.\n     *\n     * Emits an {Approval} event indicating the updated allowance.\n     *\n     * Requirements:\n     *\n     * - `spender` cannot be the zero address.\n     * - `spender` must have allowance for the caller of at least\n     * `subtractedValue`.\n     */\n    function _decreaseVoteAllowance(\n        address owner,\n        address spender,\n        uint256 subtractedValue\n    ) internal virtual returns (bool) {\n        uint256 currentAllowance = _voteAllowances[owner][spender];\n        require(\n            currentAllowance >= subtractedValue,\n            \"ERC20Delegated: decreased vote allowance below zero\"\n        );\n        unchecked {\n            _voteApprove(owner, spender, currentAllowance - subtractedValue);\n        }\n\n        return true;\n    }\n\n    /**\n     * Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * will be transferred to `to`.\n     * - when `from` is zero, `amount` tokens will be minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.\n     * - `from` and `to` are never both zero.\n     */\n    function _beforeVoteTokenTransfer(\n        address, // from\n        address, // to\n        uint256 amount\n    ) internal virtual {}\n\n    /**\n     * Hook that is called after any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * Calling conditions:\n     *\n     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens\n     * has been transferred to `to`.\n     * - when `from` is zero, `amount` tokens have been minted for `to`.\n     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.\n     * - `from` and `to` are never both zero.\n     */\n    function _afterVoteTokenTransfer(\n        address, // from\n        address, // to\n        uint256 amount\n    ) internal virtual {}\n\n    // protecting future upgradeability\n    uint256[50] private __gapERC20Delegated;\n}\n"
      },
      "contracts/currency/ERC20MintAndBurn.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"../policy/PolicedUpgradeable.sol\";\nimport \"./ERC20Pausable.sol\";\n\n/**\n * @title An ERC20 token interface for ECOx\n *\n */\ncontract ERC20MintAndBurn is ERC20Pausable, PolicedUpgradeable {\n    // storage gap covers all of ECO contract's old delegation functionality (no ECOx storage to be gapped)\n    uint256[10] private __gapMintAndBurn;\n    // additional useable gap for future upgradeability\n    uint256[50] private __gapMintAndBurn2;\n    //////////////////////////////////////////////\n    //////////////////// VARS ////////////////////\n    //////////////////////////////////////////////\n    /**\n     * Mapping storing contracts able to mint tokens\n     */\n    mapping(address => bool) public minters;\n\n    /**\n     * Mapping storing contracts able to burn tokens\n     */\n    mapping(address => bool) public burners;\n\n    //////////////////////////////////////////////\n    /////////////////// ERRORS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * error for when an address tries to mint tokens without permission\n     */\n    error OnlyMinters();\n\n    /**\n     * error for when an address tries to burn tokens without permission\n     */\n    error OnlyBurners();\n\n    //////////////////////////////////////////////\n    /////////////////// EVENTS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * emits when the minters permissions are changed\n     * @param actor denotes the new address whose permissions are being updated\n     * @param newPermission denotes the new ability of the actor address (true for can mint, false for cannot)\n     */\n    event UpdatedMinters(address actor, bool newPermission);\n\n    /**\n     * emits when the burners permissions are changed\n     * @param actor denotes the new address whose permissions are being updated\n     * @param newPermission denotes the new ability of the actor address (true for can burn, false for cannot)\n     */\n    event UpdatedBurners(address actor, bool newPermission);\n\n    //////////////////////////////////////////////\n    ////////////////// MODIFIERS /////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * Modifier for checking if the sender is a minter\n     */\n    modifier onlyMinterRole() {\n        if (!minters[msg.sender]) {\n            revert OnlyMinters();\n        }\n        _;\n    }\n\n    /**\n     * Modifier for checking if the sender is allowed to burn\n     * both burners and the message sender can burn\n     * @param _from the address burning tokens\n     */\n    modifier onlyBurnerRoleOrSelf(address _from) {\n        if (_from != msg.sender && !burners[msg.sender]) {\n            revert OnlyBurners();\n        }\n        _;\n    }\n\n    constructor(\n        Policy policy,\n        string memory name,\n        string memory ticker,\n        address pauser\n    ) Policed(policy) ERC20Pausable(name, ticker, address(policy), pauser) {}\n\n    /**\n     * change the minting permissions for an address\n     * only callable by tokenRoleAdmin\n     * @param _key the address to change permissions for\n     * @param _value the new permission. true = can mint, false = cannot mint\n     */\n    function updateMinters(address _key, bool _value) public onlyPolicy {\n        minters[_key] = _value;\n        emit UpdatedMinters(_key, _value);\n    }\n\n    /**\n     * change the burning permissions for an address\n     * only callable by tokenRoleAdmin\n     * @param _key the address to change permissions for\n     * @param _value the new permission. true = can burn, false = cannot burn\n     */\n    function updateBurners(address _key, bool _value) public onlyPolicy {\n        burners[_key] = _value;\n        emit UpdatedBurners(_key, _value);\n    }\n\n    /**\n     * mints tokens to a given address\n     * @param _to the address receiving tokens\n     * @param _value the amount of tokens being minted\n     */\n    function mint(address _to, uint256 _value) external onlyMinterRole {\n        _mint(_to, _value);\n    }\n\n    /**\n     * burns tokens to a given address\n     * @param _from the address whose tokens are being burned\n     * @param _value the amount of tokens being burned\n     */\n    function burn(\n        address _from,\n        uint256 _value\n    ) external onlyBurnerRoleOrSelf(_from) {\n        _burn(_from, _value);\n    }\n\n    // protecting future upgradeability\n    uint256[50] private __gapMintAndBurn3;\n}\n"
      },
      "contracts/currency/ERC20Pausable.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/security/Pausable.sol\";\nimport \"./ERC20.sol\";\n\n/**\n * Implementation of the {IERC20} interface with pausability\n * When paused by the pauser admin, transfers revert.\n */\ncontract ERC20Pausable is ERC20, Pausable {\n    address public immutable roleAdmin;\n\n    // initially no-one should have the pauser role\n    // it can be granted and revoked by the admin policy\n    address public pauser;\n\n    /**\n     * @notice event indicating the pauser was updated\n     * @param pauser The new pauser\n     */\n    event PauserAssignment(address indexed pauser);\n\n    constructor(\n        string memory name,\n        string memory symbol,\n        address _roleAdmin,\n        address _initialPauser\n    ) ERC20(name, symbol) {\n        require(\n            address(_roleAdmin) != address(0),\n            \"Unrecoverable: do not set the _roleAdmin as the zero address\"\n        );\n        roleAdmin = _roleAdmin;\n        pauser = _initialPauser;\n        emit PauserAssignment(_initialPauser);\n    }\n\n    modifier onlyAdmin() {\n        require(msg.sender == roleAdmin, \"ERC20Pausable: not admin\");\n        _;\n    }\n\n    modifier onlyPauser() {\n        require(msg.sender == pauser, \"ERC20Pausable: not pauser\");\n        _;\n    }\n\n    /**\n     * Hook that is called before any transfer of tokens. This includes\n     * minting and burning.\n     *\n     * If the token is not paused, it will pass through the amount\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override whenNotPaused returns (uint256) {\n        return amount;\n    }\n\n    /**\n     * @notice pauses transfers of this token\n     *\n     * Security Notes\n     *\n     * - only callable by the pause\n     * - reverts if already paused\n     */\n    function pause() external onlyPauser {\n        _pause();\n    }\n\n    /**\n     * @notice unpauses transfers of this token\n     * only callable by the pauser\n     *\n     * Security Notes\n     *\n     * - only callable by the pause\n     * - reverts if already unpaused\n     */\n    function unpause() external onlyPauser {\n        _unpause();\n    }\n\n    /**\n     * @notice set the given address as the pauser\n     * @param _pauser The address that can pause this token\n     * only the roleAdmin can call this function\n     */\n    function setPauser(address _pauser) public onlyAdmin {\n        require(_pauser != pauser, \"ERC20Pausable: must change pauser\");\n        pauser = _pauser;\n        emit PauserAssignment(_pauser);\n    }\n}\n"
      },
      "contracts/currency/ERC20Permit.sol": {
        "content": "// SPDX-License-Identifier: MIT\n// Heavily inspired by:\n// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-ERC20Permit.sol)\n\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/extensions/draft-IERC20Permit.sol\";\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"@openzeppelin/contracts/utils/Counters.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/ECDSA.sol\";\nimport \"@openzeppelin/contracts/utils/cryptography/EIP712.sol\";\n\n/**\n * Implementation of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in\n * [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612).\n *\n * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by\n * presenting a message signed by the account. By not relying on `{IERC20-approve}`, the token holder account doesn't\n * need to send a transaction, and thus is not required to hold Ether at all.\n *\n * _Available since v3.4._\n */\nabstract contract ERC20Permit is IERC20Permit, EIP712 {\n    using Counters for Counters.Counter;\n\n    mapping(address => Counters.Counter) private _nonces;\n\n    // solhint-disable-next-line var-name-mixedcase\n    bytes32 private immutable _PERMIT_TYPEHASH =\n        keccak256(\n            \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n        );\n\n    /**\n     * Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `\"2\"`.\n     *\n     * version number 1 was used already in a previous implementation\n     */\n    constructor(string memory name) EIP712(name, \"2\") {\n        //empty block in order to pass parameters to the parent EIP712 constructor\n    }\n\n    /**\n     * See {IERC20Permit-permit}.\n     */\n    function permit(\n        address owner,\n        address spender,\n        uint256 value,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public virtual override {\n        require(block.timestamp <= deadline, \"ERC20Permit: expired deadline\");\n\n        bytes32 structHash = keccak256(\n            abi.encode(\n                _PERMIT_TYPEHASH,\n                owner,\n                spender,\n                value,\n                _useNonce(owner),\n                deadline\n            )\n        );\n\n        bytes32 hash = _hashTypedDataV4(structHash);\n\n        address signer = ECDSA.recover(hash, v, r, s);\n        require(signer == owner, \"ERC20Permit: invalid signature\");\n\n        _approve(owner, spender, value);\n    }\n\n    /**\n     * See {IERC20Permit-nonces}.\n     */\n    function nonces(\n        address owner\n    ) public view virtual override returns (uint256) {\n        return _nonces[owner].current();\n    }\n\n    /**\n     * See {IERC20Permit-DOMAIN_SEPARATOR}.\n     */\n    // solhint-disable-next-line func-name-mixedcase\n    function DOMAIN_SEPARATOR() external view override returns (bytes32) {\n        return _domainSeparatorV4();\n    }\n\n    /**\n     * \"Consume a nonce\": return the current value and increment.\n     *\n     * _Available since v4.1._\n     */\n    function _useNonce(\n        address owner\n    ) internal virtual returns (uint256 current) {\n        Counters.Counter storage nonce = _nonces[owner];\n        current = nonce.current();\n        nonce.increment();\n    }\n\n    /**\n     * Sets `amount` as the allowance of `spender` over the `owner` s tokens.\n     *\n     * This internal function is equivalent to `approve`, and can be used to\n     * e.g. set automatic allowances for certain subsystems, etc.\n     *\n     * Emits an {Approval} event.\n     *\n     * Requirements:\n     *\n     * - `owner` cannot be the zero address.\n     * - `spender` cannot be the zero address.\n     */\n    function _approve(\n        address owner,\n        address spender,\n        uint256 amount\n    ) internal virtual;\n}\n"
      },
      "contracts/currency/IECO.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\n\ninterface IECO is IERC20 {\n    /**\n     * Only available to minters\n     * @param to the address to mint to\n     * @param amount the amount to mint\n     */\n    function mint(address to, uint256 amount) external;\n\n    /**\n     * Only available to token holders for their own tokens and burners\n     * @param from the address to burn from\n     * @param amount the amount to burn\n     */\n    function burn(address from, uint256 amount) external;\n\n    /**\n     * Returns the votes for the current snapshot\n     * @param account the address whose vote balance to check\n     * @return balance the balance of the account at the time of the Snapshot\n     */\n    function voteBalanceSnapshot(\n        address account\n    ) external view returns (uint256 balance);\n\n    /**\n     * Returns the inflation multiplier value for the current snapshot\n     * @return multiplier inflation multipler value\n     */\n    function inflationMultiplierSnapshot()\n        external\n        view\n        returns (uint256 multiplier);\n\n    /**\n     *  Returns the total supply for the current snapshot\n     * @return total total supply of the current snapshot\n     */\n    function totalSupplySnapshot() external view returns (uint256 total);\n\n    /**\n     * Enables voting with your ECO balance, but will transaction cost\n     */\n    function enableVoting() external;\n\n    /**\n     * Allows others to delegate voting power to you\n     * Disallows you from delegating your voting power to others\n     */\n    function enableDelegationTo() external;\n\n    /**\n     * Disallows others from delegating to you\n     * Does not change your ability to delegate to others\n     */\n    function disableDelegationTo() external;\n\n    /**\n     * Allows others to delegate to you\n     * Disallows you from delegating to others\n     */\n    function reenableDelegating() external;\n\n    /**\n     * Returns true if the address has no amount of their balance delegated, otherwise false\n     * @param account the address whose delegation status is being checked\n     */\n    function isOwnDelegate(address account) external returns (bool);\n\n    /**\n     * Fetches the primary address `account` is currently delegating to. Defaults to the account address itself if none specified.\n     * The primary delegate is the one that is delegated any new funds the address recieves\n     * @param account the address whose primary delegate is being fetched\n     */\n    function getPrimaryDelegate(\n        address account\n    ) external view returns (address);\n\n    /**\n     * Delegates all votes from the sender to `delegatee`\n     * This function assumes that you do not have partial delegations\n     * It will revert with \"ERC20Delegated: must have an undelegated amount available to cover delegation\" if you do\n     * @param delegatee the address being delegated to\n     */\n    function delegate(address delegatee) external;\n\n    /**\n     * Delegates all votes from the sender to `delegatee`\n     * This function assumes that you do not have partial delegations\n     * It will revert with \"ERC20Delegated: must have an undelegated amount available to cover delegation\" if you do\n     * @param delegator the address delegating votes\n     * @param delegatee the address being delegated to\n     * @param deadline the time at which the signature expires\n     * @param v signature value\n     * @param r signature value\n     * @param s signature value\n     */\n    function delegateBySig(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) external;\n\n    /**\n     * Delegate an `amount` of votes from the sender to `delegatee`\n     * @param delegatee the address being delegated to\n     * @param amount the amount of tokens being allocated\n     */\n    function delegateAmount(address delegatee, uint256 amount) external;\n\n    /**\n     * Undelegate all votes from the sender's primary delegate\n     */\n    function undelegate() external;\n\n    /**\n     * Allows a primary delegated individual to revoke delegations of unwanted delegators\n     * Useful for allowing yourself to call reenableDelegating after calling disableDelegationTo\n     * @param delegator the address whose delegation is being revoked\n     */\n    function revokeDelegation(address delegator) external;\n\n    /**\n     * Undelegate a specific amount of votes from the `delegatee` back to the sender\n     * @param delegatee the address being undelegated to\n     * @param amount the amount of tokens being undelegated\n     */\n    function undelegateAmountFromAddress(\n        address delegatee,\n        uint256 amount\n    ) external;\n\n    /**\n     * See {IERC20-balanceOf}.\n     * @param account the address whose vote balance is being checked\n     */\n    function voteBalanceOf(address account) external view returns (uint256);\n}\n"
      },
      "contracts/currency/InflationSnapshots.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"./VoteSnapshots.sol\";\n\n/**\n * @title InflationSnapshots\n * @notice This implements a scaling inflation multiplier on all balances and votes.\n * Changing this value (via implementing _rebase)\n */\nabstract contract InflationSnapshots is VoteSnapshots {\n    uint256 public constant INITIAL_INFLATION_MULTIPLIER = 1e18;\n\n    Snapshot internal _inflationMultiplierSnapshot;\n\n    uint256 public inflationMultiplier;\n\n    /**\n     * error for when a rebase attempts to rebase incorrectly\n     */\n    error BadRebaseValue();\n\n    /**\n     * Fired when a proposal with a new inflation multiplier is selected and passed.\n     * Used to calculate new values for the rebased token.\n     * @param adjustinginflationMultiplier the multiplier that has just been applied to the tokens\n     * @param cumulativeInflationMultiplier the total multiplier that is used to convert to and from gons\n     */\n    event NewInflationMultiplier(\n        uint256 adjustinginflationMultiplier,\n        uint256 cumulativeInflationMultiplier\n    );\n\n    /**\n     * to be used to record the transfer amounts after _beforeTokenTransfer\n     * these values are the base (unchanging) values the currency is stored in\n     * @param from address transferring from\n     * @param to address transferring to\n     * @param value the base value being transferred\n     */\n    event BaseValueTransfer(\n        address indexed from,\n        address indexed to,\n        uint256 value\n    );\n\n    /** Construct a new instance.\n     * Note that it is always necessary to call reAuthorize on the balance store\n     * after it is first constructed to populate the authorized interface\n     * contracts cache. These calls are separated to allow the authorized\n     * contracts to be configured/deployed after the balance store contract.\n     * @param _policy the Policy\n     * @param _name the token name\n     * @param _symbol the token symbol\n     * @param _initialPauser the initial Pauser\n     */\n    constructor(\n        Policy _policy,\n        string memory _name,\n        string memory _symbol,\n        address _initialPauser\n    ) VoteSnapshots(_policy, _name, _symbol, _initialPauser) {\n        inflationMultiplier = INITIAL_INFLATION_MULTIPLIER;\n        _updateInflationSnapshot();\n    }\n\n    /**\n     * Initialize\n     * @param _self the address to initialize\n     */\n    function initialize(\n        address _self\n    ) public virtual override onlyConstruction {\n        super.initialize(_self);\n        inflationMultiplier = INITIAL_INFLATION_MULTIPLIER;\n        _updateInflationSnapshot();\n    }\n\n    function _rebase(uint256 _inflationMultiplier) internal virtual {\n        if (_inflationMultiplier == 0) {\n            revert BadRebaseValue();\n        }\n\n        // update snapshot with old value\n        _updateInflationSnapshot();\n\n        uint256 newInflationMult = (_inflationMultiplier *\n            inflationMultiplier) / INITIAL_INFLATION_MULTIPLIER;\n\n        inflationMultiplier = newInflationMult;\n\n        emit NewInflationMultiplier(_inflationMultiplier, newInflationMult);\n    }\n\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override returns (uint256) {\n        amount = super._beforeTokenTransfer(from, to, amount);\n        uint256 gonsAmount = amount * inflationMultiplier;\n\n        emit BaseValueTransfer(from, to, gonsAmount);\n\n        return gonsAmount;\n    }\n\n    /**\n     * Inflation Multiplier Snapshot\n     * @return inflationValueMultiplier Inflation Value Muliplier at time of the Snapshot\n     */\n    function inflationMultiplierSnapshot()\n        public\n        view\n        returns (uint256 inflationValueMultiplier)\n    {\n        if (\n            currentSnapshotBlock != block.number &&\n            _inflationMultiplierSnapshot.snapshotBlock < currentSnapshotBlock\n        ) {\n            return inflationMultiplier;\n        } else {\n            return _inflationMultiplierSnapshot.value;\n        }\n    }\n\n    /**\n     * wrapper for inflationMultiplierSnapshot to maintain compatability with older interfaces\n     * no requires even though return value might be misleading given inability to query old snapshots just to maintain maximum compatability\n     * @return pastLinearInflationMultiplier Inflation Value Muliplier at time of the Snapshot\n     */\n    function getPastLinearInflation(\n        uint256\n    ) public view returns (uint256 pastLinearInflationMultiplier) {\n        return inflationMultiplier;\n    }\n\n    /**\n     * Access function to determine the token balance held by some address.\n     * @param _owner address of the owner of the voting balance\n     * @return inflationBalance value of the owner divided by the inflation multiplier\n     */\n    function balanceOf(\n        address _owner\n    ) public view override returns (uint256 inflationBalance) {\n        return _balances[_owner] / inflationMultiplier;\n    }\n\n    /**\n     * Access function to determine the voting balance (includes delegation) of some address.\n     * @param _owner the address of the account to get the balance for\n     * @return votingBalance The vote balance fo the owner divided by the inflation multiplier\n     */\n    function voteBalanceOf(\n        address _owner\n    ) public view override returns (uint256 votingBalance) {\n        return _voteBalances[_owner] / inflationMultiplier;\n    }\n\n    /**\n     * Returns the total (inflation corrected) token supply\n     * @return totalInflatedSupply The total supply divided by the inflation multiplier\n     */\n    function totalSupply()\n        public\n        view\n        override\n        returns (uint256 totalInflatedSupply)\n    {\n        return _totalSupply / inflationMultiplier;\n    }\n\n    /**\n     * Returns the total (inflation corrected) token supply for the current snapshot\n     * @return totalInflatedSupply The total supply snapshot divided by the inflation multiplier\n     */\n    function totalSupplySnapshot()\n        public\n        view\n        override\n        returns (uint256 totalInflatedSupply)\n    {\n        return super.totalSupplySnapshot() / inflationMultiplierSnapshot();\n    }\n\n    /**\n     * Return snapshotted voting balance (includes delegation) for the current snapshot.\n     * @param account The account to check the votes of.\n     * @return snapshotted voting balance (includes delegation) for the current snapshot.\n     */\n    function voteBalanceSnapshot(\n        address account\n    ) public view override returns (uint256) {\n        uint256 _inflationMultiplier = inflationMultiplierSnapshot();\n\n        if (_inflationMultiplier == 0) {\n            return 0;\n        }\n\n        return super.voteBalanceSnapshot(account) / _inflationMultiplier;\n    }\n\n    function _updateInflationSnapshot() private {\n        uint32 _currentSnapshotBlock = currentSnapshotBlock;\n        // take no action during the snapshot block, only after it\n        if (_currentSnapshotBlock == block.number) {\n            return;\n        }\n\n        if (\n            _inflationMultiplierSnapshot.snapshotBlock < _currentSnapshotBlock\n        ) {\n            uint256 currentValue = inflationMultiplier;\n            require(\n                currentValue <= type(uint224).max,\n                \"InflationSnapshots: new snapshot cannot be casted safely\"\n            );\n            _inflationMultiplierSnapshot.snapshotBlock = _currentSnapshotBlock;\n            _inflationMultiplierSnapshot.value = uint224(currentValue);\n        }\n    }\n\n    // protecting future upgradeability\n    uint256[50] private __gapInflationSnapshots;\n}\n"
      },
      "contracts/currency/TotalSupplySnapshots.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ERC20MintAndBurn.sol\";\n\n/**\n * @dev Basic snapshotting just for total supply.\n *\n * This extension maintains a snapshot the total supply which updates on mint or burn after a new snapshot is taken.\n */\nabstract contract TotalSupplySnapshots is ERC20MintAndBurn {\n    // structure for saving snapshotted values\n    struct Snapshot {\n        uint32 snapshotBlock;\n        uint224 value;\n    }\n\n    // the reference snapshotBlock that the update function checks against\n    uint32 public currentSnapshotBlock;\n\n    // the snapshot to track the token total supply\n    Snapshot internal _totalSupplySnapshot;\n\n    /**\n     * @dev Emitted by {_snapshot} when a new snapshot is created.\n     *\n     * @param block the new value of currentSnapshotBlock\n     */\n    event NewSnapshotBlock(uint256 block);\n\n    constructor(\n        Policy _policy,\n        string memory _name,\n        string memory _symbol,\n        address _initialPauser\n    ) ERC20MintAndBurn(_policy, _name, _symbol, _initialPauser) {\n        // snapshot on creation to make it clear that everyone's balances should be updated\n        _snapshot();\n    }\n\n    function initialize(\n        address _self\n    ) public virtual override onlyConstruction {\n        super.initialize(_self);\n        // snapshot on initialization to make it clear that everyone's balances should be updated after upgrade\n        _snapshot();\n    }\n\n    /**\n     * @dev Retrieve the `totalSupply` for the snapshot\n     */\n    function totalSupplySnapshot() public view virtual returns (uint256) {\n        if (\n            currentSnapshotBlock != block.number &&\n            _totalSupplySnapshot.snapshotBlock < currentSnapshotBlock\n        ) {\n            return _totalSupply;\n        } else {\n            return _totalSupplySnapshot.value;\n        }\n    }\n\n    /**\n     * Update total supply snapshots before the values are modified. This is implemented\n     * in the _beforeTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations.\n     */\n    function _beforeTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override returns (uint256) {\n        if (from == address(0)) {\n            // mint\n            _updateTotalSupplySnapshot();\n        } else if (to == address(0)) {\n            // burn\n            _updateTotalSupplySnapshot();\n        }\n\n        return super._beforeTokenTransfer(from, to, amount);\n    }\n\n    /**\n     * @dev Creates a new snapshot and returns its snapshot id.\n     *\n     * Emits a {NewSnapshotBlock} event that contains the same id.\n     */\n    function _snapshot() internal virtual {\n        // the math will error if the snapshot overflows\n        currentSnapshotBlock = uint32(block.number);\n\n        emit NewSnapshotBlock(block.number);\n    }\n\n    function _updateTotalSupplySnapshot() private {\n        uint32 _currentSnapshotBlock = currentSnapshotBlock;\n        // take no action during the snapshot block, only after it\n        if (_currentSnapshotBlock == block.number) {\n            return;\n        }\n\n        if (_totalSupplySnapshot.snapshotBlock < _currentSnapshotBlock) {\n            uint256 currentValue = _totalSupply;\n            require(\n                currentValue <= type(uint224).max,\n                \"VoteSnapshots: new snapshot cannot be casted safely\"\n            );\n            _totalSupplySnapshot.snapshotBlock = _currentSnapshotBlock;\n            _totalSupplySnapshot.value = uint224(currentValue);\n        }\n    }\n\n    // protecting future upgradeability\n    uint256[50] private __gapTotalSupplySnapshots;\n}\n"
      },
      "contracts/currency/VoteCheckpoints.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ERC20Pausable.sol\";\nimport \"./DelegatePermit.sol\";\n\n/**\n * Extension of ERC20 to support Compound-like voting and delegation. This version is more generic than Compound's,\n * and supports token supply up to `2^224^ - 1`, while COMP is limited to `2^96^ - 1`.\n *\n * This extension keeps a history (checkpoints) of each account's vote power. Vote power can be delegated either\n * by calling the {delegate} function directly, or by providing a signature to be used with {delegateBySig}. Voting\n * power can be queried through the public accessors {getVotingGons} and {getPastVotingGons}.\n *\n * By default, token balance does not account for voting power. This makes transfers cheaper. the downside is that it\n * requires users to delegate to themselves in order to activate checkpoints and have their voting power tracked.\n * Enabling self-delegation can easily be done by overriding the {delegates} function. Keep in mind however that this\n * will significantly increase the base gas cost of transfers.\n *\n * _Available since v4.2._\n */\nabstract contract VoteCheckpoints is ERC20Pausable, DelegatePermit {\n    /**\n     * structure for saving past voting balances, accounting for delegation\n     */\n    struct Checkpoint {\n        uint32 fromBlock;\n        uint224 value;\n    }\n\n    /**\n     * the mapping from an address to each address that it delegates to, then mapped to the amount delegated\n     */\n    mapping(address => mapping(address => uint256)) internal _delegates;\n\n    /**\n     * a mapping that aggregates the total delegated amounts in the mapping above\n     */\n    mapping(address => uint256) internal _delegatedTotals;\n\n    /**\n     * a mapping that tracks the primaryDelegates of each user\n     *\n     * Primary delegates can only be chosen using delegate() which sends the full balance\n     * the exist to maintain the functionality that recieving tokens gives those votes to the delegate\n     */\n    mapping(address => address) internal _primaryDelegates;\n\n    /**\n     * mapping that tracks if an address is willing to be delegated to\n     */\n    mapping(address => bool) public delegationToAddressEnabled;\n\n    /**\n     * mapping that tracks if an address is unable to delegate\n     */\n    mapping(address => bool) public delegationFromAddressDisabled;\n\n    /**\n     * mapping to the ordered arrays of voting checkpoints for each address\n     */\n    mapping(address => Checkpoint[]) public checkpoints;\n\n    /**\n     * the checkpoints to track the token total supply\n     */\n    Checkpoint[] private _totalSupplyCheckpoints;\n\n    /**\n     * Emitted when a delegatee is delegated new votes.\n     * @param delegator the delegators address\n     * @param delegatee the delegatee address\n     * @param amount the amount delegated\n     */\n    event DelegatedVotes(\n        address indexed delegator,\n        address indexed delegatee,\n        uint256 amount\n    );\n\n    /**\n     * Emitted when a token transfer or delegate change results in changes to an account's voting power.\n     * @param voter the address of the voter\n     * @param newVotes the new votes amount\n     */\n    event UpdatedVotes(address indexed voter, uint256 newVotes);\n\n    /**\n     * Emitted when an account denotes a primary delegate.\n     * @param delegator the delegator address\n     * @param primaryDelegate the primary delegates address\n     */\n    event NewPrimaryDelegate(\n        address indexed delegator,\n        address indexed primaryDelegate\n    );\n\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        address admin,\n        address _initialPauser\n    ) ERC20Pausable(_name, _symbol, admin, _initialPauser) {\n        // call to super constructor\n    }\n\n    /**\n     * Returns the total (inflation corrected) token supply at a specified block number\n     * @param _blockNumber the block number for retrieving the total supply\n     * @return pastTotalSupply  the total (inflation corrected) token supply at the specified block\n     */\n    function totalSupplyAt(\n        uint256 _blockNumber\n    ) public view virtual returns (uint256 pastTotalSupply) {\n        pastTotalSupply = getPastTotalSupply(_blockNumber);\n        return pastTotalSupply;\n    }\n\n    /**\n     * Return historical voting balance (includes delegation) at given block number.\n     *\n     * If the latest block number for the account is before the requested\n     * block then the most recent known balance is returned. Otherwise the\n     * exact block number requested is returned.\n     *\n     * @param _owner the account to check the balance of.\n     * @param _blockNumber the block number to check the balance at the start\n     *                        of. Must be less than or equal to the present\n     *                        block number.\n     * @return pastVotingGons historical voting balance (including delegation) at given block number\n     */\n    function getPastVotes(\n        address _owner,\n        uint256 _blockNumber\n    ) public view virtual returns (uint256 pastVotingGons) {\n        pastVotingGons = getPastVotingGons(_owner, _blockNumber);\n        return pastVotingGons;\n    }\n\n    /**\n     * Get number of checkpoints for `account`.\n     * @param account the address of the account\n     * @return checkPoints the number of checkpoints for the account\n     */\n    function numCheckpoints(\n        address account\n    ) public view virtual returns (uint32 checkPoints) {\n        uint256 _numCheckpoints = checkpoints[account].length;\n        require(\n            _numCheckpoints <= type(uint32).max,\n            \"number of checkpoints cannot be casted safely\"\n        );\n        checkPoints = uint32(_numCheckpoints);\n        return checkPoints;\n    }\n\n    /**\n     * Set yourself as willing to recieve delegates.\n     */\n    function enableDelegationTo() public {\n        require(\n            isOwnDelegate(msg.sender),\n            \"Cannot enable delegation if you have outstanding delegation\"\n        );\n\n        delegationToAddressEnabled[msg.sender] = true;\n        delegationFromAddressDisabled[msg.sender] = true;\n    }\n\n    /**\n     * Set yourself as no longer recieving delegates.\n     */\n    function disableDelegationTo() public {\n        delegationToAddressEnabled[msg.sender] = false;\n    }\n\n    /**\n     * Set yourself as being able to delegate again.\n     * also disables delegating to you\n     * NOTE: the condition for this is not easy and cannot be unilaterally achieved\n     */\n    function reenableDelegating() public {\n        delegationToAddressEnabled[msg.sender] = false;\n\n        require(\n            _balances[msg.sender] == getVotingGons(msg.sender) &&\n                isOwnDelegate(msg.sender),\n            \"Cannot re-enable delegating if you have outstanding delegations to you\"\n        );\n\n        delegationFromAddressDisabled[msg.sender] = false;\n    }\n\n    /**\n     * Returns true if the user has no amount of their balance delegated, otherwise false.\n     * @param account the account address to check for delegation\n     * @return noDelegation true if the user has no amount of their balance delegated, otherwise false.\n     */\n    function isOwnDelegate(\n        address account\n    ) public view returns (bool noDelegation) {\n        noDelegation =\n            _delegatedTotals[account] == 0 &&\n            _primaryDelegates[account] == address(0);\n        return noDelegation;\n    }\n\n    /**\n     * Get the primary address `account` is currently delegating to. Defaults to the account address itself if none specified.\n     * the primary delegate is the one that is delegated any new funds the address recieves.\n     * @param account the address of the account to check for primary delgate\n     * @return primaryDelegate the primary delegate for the account\n     */\n    function getPrimaryDelegate(\n        address account\n    ) public view virtual returns (address primaryDelegate) {\n        address _voter = _primaryDelegates[account];\n        primaryDelegate = _voter == address(0) ? account : _voter;\n        return primaryDelegate;\n    }\n\n    /**\n     * sets the primaryDelegate and emits an event to track it\n     * @param delegator the address of the delegator\n     * @param delegatee the address of the delegatee\n     */\n    function _setPrimaryDelegate(\n        address delegator,\n        address delegatee\n    ) internal {\n        _primaryDelegates[delegator] = delegatee;\n\n        emit NewPrimaryDelegate(\n            delegator,\n            delegatee == address(0) ? delegator : delegatee\n        );\n    }\n\n    /**\n     * Gets the current votes balance in gons for `account`\n     * @param account the address of the account\n     * @return votingGons the current votes balance in gons for the acccount\n     */\n    function getVotingGons(\n        address account\n    ) public view returns (uint256 votingGons) {\n        Checkpoint[] memory accountCheckpoints = checkpoints[account];\n        uint256 pos = accountCheckpoints.length;\n        votingGons = (pos == 0) ? 0 : accountCheckpoints[pos - 1].value;\n        return votingGons;\n    }\n\n    /**\n     * Retrieve the number of votes in gons for `account` at the end of `blockNumber`.\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     * @param account the address of the account to get the votes for\n     * @param blockNumber the blockNumber to get the votes for\n     * @return pastVotingGons the number of votes in gons for the account and block number\n     */\n    function getPastVotingGons(\n        address account,\n        uint256 blockNumber\n    ) public view returns (uint256 pastVotingGons) {\n        require(\n            blockNumber < block.number,\n            \"VoteCheckpoints: block not yet mined\"\n        );\n        pastVotingGons = _checkpointsLookup(checkpoints[account], blockNumber);\n        return pastVotingGons;\n    }\n\n    /**\n     * Retrieve the `totalSupply` at the end of `blockNumber`. Note, this value is the sum of all balances.\n     * It is NOT the sum of all the delegated votes!\n     *\n     * Requirements:\n     *\n     * - `blockNumber` must have been already mined\n     * @param blockNumber the block number to get the past total supply\n     * @return pastTotalSupply the totalSupply at the end of blockNumber calculated by summing all balances.\n     */\n    function getPastTotalSupply(\n        uint256 blockNumber\n    ) public view returns (uint256 pastTotalSupply) {\n        require(\n            blockNumber < block.number,\n            \"VoteCheckpoints: block not yet mined\"\n        );\n        pastTotalSupply = _checkpointsLookup(\n            _totalSupplyCheckpoints,\n            blockNumber\n        );\n        return pastTotalSupply;\n    }\n\n    /**\n     * Lookup a value in a list of (sorted) checkpoints.\n     *\n     * This function runs a binary search to look for the last checkpoint taken before `blockNumber`.\n     *\n     * During the loop, the index of the wanted checkpoint remains in the range [low-1, high).\n     * With each iteration, either `low` or `high` is moved towards the middle of the range to maintain the invariant.\n     *\n     * - If the middle checkpoint is after `blockNumber`, the next iteration looks in [low, mid)\n     * - If the middle checkpoint is before or equal to `blockNumber`, the next iteration looks in [mid+1, high)\n     *\n     * Once it reaches a single value (when low == high), it has found the right checkpoint at the index high-1, if not\n     * out of bounds (in which case it's looking too far in the past and the result is 0).\n     * Note that if the latest checkpoint available is exactly for `blockNumber`, it will end up with an index that is\n     * past the end of the array, so this technically doesn't find a checkpoint after `blockNumber`, but the result is\n     * the same.\n     * @param ckpts list of sorted checkpoints\n     * @param blockNumber the blockNumber to seerch for the last checkpoint taken before\n     * @return checkPoint the checkpoint\n     */\n    function _checkpointsLookup(\n        Checkpoint[] storage ckpts,\n        uint256 blockNumber\n    ) internal view returns (uint256 checkPoint) {\n        uint256 ckptsLength = ckpts.length;\n        if (ckptsLength == 0) return 0;\n        Checkpoint memory lastCkpt = ckpts[ckptsLength - 1];\n        if (blockNumber >= lastCkpt.fromBlock) return lastCkpt.value;\n\n        uint256 high = ckptsLength;\n        uint256 low = 0;\n\n        while (low < high) {\n            uint256 mid = low + ((high - low) >> 1);\n            if (ckpts[mid].fromBlock > blockNumber) {\n                high = mid;\n            } else {\n                low = mid + 1;\n            }\n        }\n\n        checkPoint = high == 0 ? 0 : ckpts[high - 1].value;\n        return checkPoint;\n    }\n\n    /**\n     * Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"Must have an undelegated amount available to cover delegation\" if you do\n     * @param delegatee the address of the delegatee\n     */\n    function delegate(address delegatee) public {\n        require(\n            delegatee != msg.sender,\n            \"Use undelegate instead of delegating to yourself\"\n        );\n\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"Primary delegates must enable delegation\"\n        );\n\n        if (!isOwnDelegate(msg.sender)) {\n            undelegateFromAddress(getPrimaryDelegate(msg.sender));\n        }\n\n        uint256 _amount = _balances[msg.sender];\n        _delegate(msg.sender, delegatee, _amount);\n        _setPrimaryDelegate(msg.sender, delegatee);\n    }\n\n    /**\n     * Delegate all votes from the sender to `delegatee`.\n     * NOTE: This function assumes that you do not have partial delegations\n     * It will revert with \"Must have an undelegated amount available to cover delegation\" if you do\n     * @param delegator The address delegating\n     * @param delegatee The address being delegated to\n     * @param deadline The deadling of the delegation after which it will be invalid\n     * @param v The v part of the signature\n     * @param r The r part of the signature\n     * @param s The s part of the signature\n     */\n    function delegateBySig(\n        address delegator,\n        address delegatee,\n        uint256 deadline,\n        uint8 v,\n        bytes32 r,\n        bytes32 s\n    ) public {\n        require(delegator != delegatee, \"Do not delegate to yourself\");\n        require(\n            delegationToAddressEnabled[delegatee],\n            \"Primary delegates must enable delegation\"\n        );\n\n        if (!isOwnDelegate(delegator)) {\n            _undelegateFromAddress(delegator, getPrimaryDelegate(delegator));\n        }\n\n        _verifyDelegatePermit(delegator, delegatee, deadline, v, r, s);\n\n        uint256 _amount = _balances[delegator];\n        _delegate(delegator, delegatee, _amount);\n        _setPrimaryDelegate(delegator, delegatee);\n    }\n\n    /**\n     * Delegate an `amount` of votes from the sender to `delegatee`.\n     * @param delegatee The address being delegated to\n     * @param amount The amount of votes\n     */\n    function delegateAmount(address delegatee, uint256 amount) public {\n        require(delegatee != msg.sender, \"Do not delegate to yourself\");\n\n        _delegate(msg.sender, delegatee, amount);\n    }\n\n    /**\n     * Change delegation for `delegator` to `delegatee`.\n     *\n     * Emits events {NewDelegatedAmount} and {UpdatedVotes}.\n     */\n    function _delegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        require(\n            amount <= _balances[delegator] - _delegatedTotals[delegator],\n            \"Must have an undelegated amount available to cover delegation\"\n        );\n\n        require(\n            !delegationFromAddressDisabled[delegator],\n            \"Cannot delegate if you have enabled primary delegation to yourself and/or have outstanding delegates\"\n        );\n\n        emit DelegatedVotes(delegator, delegatee, amount);\n\n        _delegates[delegator][delegatee] += amount;\n        _delegatedTotals[delegator] += amount;\n\n        _moveVotingPower(delegator, delegatee, amount);\n    }\n\n    /**\n     * Undelegate all votes from the sender's primary delegate.\n     */\n    function undelegate() public {\n        address _primaryDelegate = getPrimaryDelegate(msg.sender);\n        require(\n            _primaryDelegate != msg.sender,\n            \"Must specifiy address without a Primary Delegate\"\n        );\n        undelegateFromAddress(_primaryDelegate);\n    }\n\n    /**\n     * Undelegate votes from the `delegatee` back to the sender.\n     * @param delegatee the delegatee address\n     */\n    function undelegateFromAddress(address delegatee) public {\n        _undelegateFromAddress(msg.sender, delegatee);\n    }\n\n    /**\n     * Undelegate votes from the `delegatee` back to the delegator.\n     */\n    function _undelegateFromAddress(\n        address delegator,\n        address delegatee\n    ) internal {\n        uint256 _amount = _delegates[delegator][delegatee];\n        _undelegate(delegator, delegatee, _amount);\n        if (delegatee == getPrimaryDelegate(delegator)) {\n            _setPrimaryDelegate(delegator, address(0));\n        }\n    }\n\n    /**\n     * Undelegate a specific amount of votes from the `delegatee` back to the sender.\n     * @param delegatee The address being delegated to\n     * @param amount The amount of votes\n     */\n    function undelegateAmountFromAddress(\n        address delegatee,\n        uint256 amount\n    ) public {\n        require(\n            _delegates[msg.sender][delegatee] >= amount,\n            \"amount not available to undelegate\"\n        );\n        require(\n            msg.sender == getPrimaryDelegate(msg.sender),\n            \"undelegating amounts is only available for partial delegators\"\n        );\n        _undelegate(msg.sender, delegatee, amount);\n    }\n\n    function _undelegate(\n        address delegator,\n        address delegatee,\n        uint256 amount\n    ) internal virtual {\n        _delegatedTotals[delegator] -= amount;\n        _delegates[delegator][delegatee] -= amount;\n\n        _moveVotingPower(delegatee, delegator, amount);\n    }\n\n    /**\n     * Maximum token supply. Defaults to `type(uint224).max` (2^224^ - 1).\n     */\n    function _maxSupply() internal view virtual returns (uint224) {\n        return type(uint224).max;\n    }\n\n    /**\n     * Snapshots the totalSupply after it has been increased.\n     * @param account the account to mint from\n     * @param amount the amount to mint\n     */\n    function _mint(\n        address account,\n        uint256 amount\n    ) internal virtual override returns (uint256) {\n        amount = super._mint(account, amount);\n        require(\n            totalSupply() <= _maxSupply(),\n            \"VoteCheckpoints: total supply risks overflowing votes\"\n        );\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _add, amount);\n        return amount;\n    }\n\n    /**\n     * Snapshots the totalSupply after it has been decreased.\n     * @param account the account to burn from\n     * @param amount the amount to burn\n     */\n    function _burn(\n        address account,\n        uint256 amount\n    ) internal virtual override returns (uint256) {\n        amount = super._burn(account, amount);\n\n        _writeCheckpoint(_totalSupplyCheckpoints, _subtract, amount);\n        return amount;\n    }\n\n    /**\n     * Move voting power when tokens are transferred.\n     *\n     * Emits a {UpdatedVotes} event.\n     * @param from the transfer from address\n     * @param to the transfer to address\n     * @param amount the amount transferred\n     */\n    function _afterTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        if (from == to) {\n            // self transfers require no change in delegation and can be the source of exploits\n            return;\n        }\n\n        // if the address has delegated, they might be transfering tokens allotted to someone else\n        if (!isOwnDelegate(from)) {\n            uint256 _undelegatedAmount = _balances[from] +\n                amount -\n                _delegatedTotals[from];\n\n            // check to see if tokens must be undelegated to transefer\n            if (_undelegatedAmount < amount) {\n                address _sourcePrimaryDelegate = getPrimaryDelegate(from);\n                uint256 _sourcePrimaryDelegatement = _delegates[from][\n                    _sourcePrimaryDelegate\n                ];\n\n                require(\n                    amount <= _undelegatedAmount + _sourcePrimaryDelegatement,\n                    \"Delegation too complicated to transfer. Undelegate and simplify before trying again\"\n                );\n\n                _undelegate(\n                    from,\n                    _sourcePrimaryDelegate,\n                    amount - _undelegatedAmount\n                );\n            }\n        }\n\n        address _destPrimaryDelegate = _primaryDelegates[to];\n        // saving gas by manually doing isOwnDelegate since this function already needs to read the data for this conditional\n        if (_destPrimaryDelegate != address(0)) {\n            _delegates[to][_destPrimaryDelegate] += amount;\n            _delegatedTotals[to] += amount;\n            _moveVotingPower(from, _destPrimaryDelegate, amount);\n        } else {\n            _moveVotingPower(from, to, amount);\n        }\n    }\n\n    function _moveVotingPower(\n        address src,\n        address dst,\n        uint256 amount\n    ) private {\n        if (src != dst && amount > 0) {\n            if (src != address(0)) {\n                uint256 newWeight = _writeCheckpoint(\n                    checkpoints[src],\n                    _subtract,\n                    amount\n                );\n                emit UpdatedVotes(src, newWeight);\n            }\n\n            if (dst != address(0)) {\n                uint256 newWeight = _writeCheckpoint(\n                    checkpoints[dst],\n                    _add,\n                    amount\n                );\n                emit UpdatedVotes(dst, newWeight);\n            }\n        }\n    }\n\n    /**\n     * returns the newly written value in the checkpoint\n     */\n    function _writeCheckpoint(\n        Checkpoint[] storage ckpts,\n        function(uint256, uint256) view returns (uint256) op,\n        uint256 delta\n    ) internal returns (uint256) {\n        require(\n            delta <= type(uint224).max,\n            \"newWeight cannot be casted safely\"\n        );\n        require(\n            block.number <= type(uint32).max,\n            \"block number cannot be casted safely\"\n        );\n\n        uint256 pos = ckpts.length;\n\n        /* if there are no checkpoints, just write the value\n         * This part assumes that an account would never exist with a balance but without checkpoints.\n         * This function cannot be called directly, so there's no malicious way to exploit this. If this\n         * is somehow called with op = _subtract, it will revert as that action is nonsensical.\n         */\n        if (pos == 0) {\n            ckpts.push(\n                Checkpoint({\n                    fromBlock: uint32(block.number),\n                    value: uint224(op(0, delta))\n                })\n            );\n            return delta;\n        }\n\n        // else, iterate on the existing checkpoints as per usual\n        Checkpoint storage newestCkpt = ckpts[pos - 1];\n\n        uint256 oldWeight = newestCkpt.value;\n        uint256 newWeight = op(oldWeight, delta);\n\n        require(\n            newWeight <= type(uint224).max,\n            \"newWeight cannot be casted safely\"\n        );\n\n        if (newestCkpt.fromBlock == block.number) {\n            newestCkpt.value = uint224(newWeight);\n        } else {\n            ckpts.push(\n                Checkpoint({\n                    fromBlock: uint32(block.number),\n                    value: uint224(newWeight)\n                })\n            );\n        }\n        return newWeight;\n    }\n\n    function _add(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a + b;\n    }\n\n    function _subtract(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a - b;\n    }\n\n    function _replace(uint256, uint256 b) internal pure returns (uint256) {\n        return b;\n    }\n}\n"
      },
      "contracts/currency/VoteSnapshots.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\nimport \"./ERC20Delegated.sol\";\n\n/**\n * Extension of ERC20Delegated to support snapshotting.\n *\n * This extension maintains a snapshot of each addresses's votes which updates on the transfer after a new snapshot is taken.\n * Only addresses that have opted into voting are snapshotted.\n */\nabstract contract VoteSnapshots is ERC20Delegated {\n    /// mapping of each address to it's latest snapshot of votes\n    mapping(address => Snapshot) private _voteSnapshots;\n\n    /** Construct a new instance.\n     *\n     * the root _policy needs to be passed down through to service ERC20BurnAndMint\n     */\n    constructor(\n        Policy _policy,\n        string memory _name,\n        string memory _symbol,\n        address _initialPauser\n    ) ERC20Delegated(_policy, _name, _symbol, _initialPauser) {\n        // call to super constructor\n    }\n\n    /**\n     * Retrieve the balance for the snapshot\n     *\n     * @param account the address to check vote balances for\n     * @return balance the balance for the acccount for the snapshot\n     */\n    function voteBalanceSnapshot(\n        address account\n    ) public view virtual returns (uint256 balance) {\n        Snapshot memory _accountSnapshot = _voteSnapshots[account];\n\n        if (\n            currentSnapshotBlock != block.number &&\n            _accountSnapshot.snapshotBlock < currentSnapshotBlock\n        ) {\n            return _voteBalances[account];\n        } else {\n            balance = _accountSnapshot.value;\n        }\n        return balance;\n    }\n\n    /**\n     * Update balance snapshots for votes before the values are modified. This is implemented\n     * in the _beforeVoteTokenTransfer hook, which is executed for _mint, _burn, and _transfer operations.\n     * @param from the from address for the transfer\n     * @param to the to address for the transfer\n     * @param amount the amount of the transfer\n     */\n    function _beforeVoteTokenTransfer(\n        address from,\n        address to,\n        uint256 amount\n    ) internal virtual override {\n        super._beforeVoteTokenTransfer(from, to, amount);\n\n        if (from != address(0) && voter[from]) {\n            _updateAccountSnapshot(from);\n        }\n        if (to != address(0) && voter[to]) {\n            _updateAccountSnapshot(to);\n        }\n    }\n\n    function _updateAccountSnapshot(address account) private {\n        uint32 _currentSnapshotBlock = currentSnapshotBlock;\n        // take no action during the snapshot block, only after it\n        if (_currentSnapshotBlock == block.number) {\n            return;\n        }\n\n        Snapshot storage snapshot = _voteSnapshots[account];\n        uint256 currentValue = _voteBalances[account];\n\n        if (snapshot.snapshotBlock < _currentSnapshotBlock) {\n            require(\n                currentValue <= type(uint224).max,\n                \"VoteSnapshots: new snapshot cannot be casted safely\"\n            );\n\n            snapshot.snapshotBlock = _currentSnapshotBlock;\n            snapshot.value = uint224(currentValue);\n        }\n    }\n\n    // protecting future upgradeability\n    uint256[50] private __gapVoteSnapshots;\n}\n"
      },
      "contracts/governance/community/CommunityGovernance.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"@openzeppelin/contracts/security/Pausable.sol\";\nimport \"./VotingPower.sol\";\nimport \"./ECOxStaking.sol\";\nimport \"./proposals/Proposal.sol\";\n\ncontract CommunityGovernance is VotingPower, Pausable, TimeUtils {\n    //////////////////////////////////////////////\n    /////////////////// TYPES ////////////////////\n    //////////////////////////////////////////////\n    struct PropData {\n        uint256 cycle;\n        address proposer;\n        uint256 totalSupport;\n        uint256 refund;\n        mapping(address => uint256) support;\n        // considering putting these into a double mapping cycle -> address -> votes in CommunityGovernance, will check gas on this later\n        mapping(address => uint256) enactVotes;\n        mapping(address => uint256) rejectVotes;\n        mapping(address => uint256) abstainVotes;\n    }\n\n    enum Stage {\n        Done, // Done should be the default stage\n        Proposal,\n        Voting,\n        Delay,\n        Execution\n    }\n\n    enum Vote {\n        Reject,\n        Enact,\n        Abstain\n    }\n\n    //////////////////////////////////////////////\n    //////////////////// VARS ////////////////////\n    //////////////////////////////////////////////\n\n    /** the duration of the community governance cycle */\n    uint256 public constant CYCLE_LENGTH = 14 days;\n\n    /** the duration of the proposal stage */\n    uint256 public constant PROPOSAL_LENGTH = 9 days;\n\n    /** the duration of the voting stage */\n    uint256 public constant VOTING_LENGTH = 3 days;\n\n    /** the duration of the execution delay */\n    uint256 public constant DELAY_LENGTH = 1 days;\n\n    /** the duration of the execution window beyond the cycle end */\n    uint256 public constant EXECUTION_EXTRA_LENGTH = 1 days;\n\n    /** address allowed to pause community governance */\n    address public pauser;\n\n    /** reference any proposal by its address*/\n    mapping(address => PropData) public proposals;\n\n    /** number of voting cycles since launch */\n    uint256 public cycleCount;\n\n    /** start of the current cycle */\n    uint256 public cycleStart;\n\n    /** current stage in the cycle */\n    Stage public stage;\n\n    /** end time of current */\n    uint256 public currentStageEnd;\n\n    /** cost in ECO to submit a proposal */\n    uint256 public constant proposalFee = 1e22;\n\n    /** proposal fee to be refunded if proposal is not enacted */\n    uint256 public constant feeRefund = 5e21;\n\n    /** the percent of total VP that must be supporting a proposal in order to advance it to the voting stage */\n    uint256 public supportThresholdPercent = 15;\n\n    /** the percent of total VP that must have voted to enact a proposal in order to bypass the delay period */\n    uint256 public constant voteThresholdPercent = 50;\n\n    /** the divisor for the percent numbers above */\n    uint256 public constant thresholdPercentDivisor = 100;\n\n    /** the proposal being voted on this cycle */\n    address public selectedProposal;\n\n    /** total votes to enact the selected proposal*/\n    uint256 public totalEnactVotes;\n\n    /** total votes to reject the selected proposal*/\n    uint256 public totalRejectVotes;\n\n    /** total votes to abstain from voting on the selected proposal*/\n    uint256 public totalAbstainVotes;\n\n    /** redeemable tokens from fees  */\n    uint256 public pot;\n\n    //////////////////////////////////////////////\n    /////////////////// ERRORS ///////////////////\n    //////////////////////////////////////////////\n\n    /** thrown when constructor param CycleStart is out of bounds */\n    error BadCycleStart();\n\n    /** thrown when non-pauser tries to call pause without permission */\n    error OnlyPauser();\n\n    /** thrown when a call is made during the wrong stage of Community Governance */\n    error WrongStage();\n\n    /** thrown when a proposal that already exists is proposed again */\n    error DuplicateProposal();\n\n    /** thrown when there is an attempt to support a proposal submitted in a non-current cycle */\n    error OldProposalSupport();\n\n    /** thrown when related argument arrays have differing lengths */\n    error ArrayLengthMismatch();\n\n    /** thrown when the voting power of a support or vote action is invalid */\n    error BadVotingPower();\n\n    /** thrown when setSupportThresholdPercent is called with a bad value */\n    error BadSupportThresholdPercent();\n\n    /** thrown when unsupport is called without the caller having supported the proposal */\n    error NoSupportToRevoke();\n\n    /** thrown when vote is called with a vote type other than enact, reject, abstain */\n    error BadVoteType();\n\n    /**\n     * thrown when refund is called on a proposal for which no refund is available\n     * @param proposal the proposal whose refund was attempted\n     */\n    error NoRefundAvailable(address proposal);\n\n    /**\n     * thrown when refund is called on a proposal that was submitted in the current cycle\n     * @param proposal the proposal whose refund was attempted\n     */\n    error NoRefundDuringCycle(address proposal);\n\n    //////////////////////////////////////////////\n    /////////////////// EVENTS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * event indicating the pauser was updated\n     * @param pauser The new pauser\n     */\n    event PauserAssignment(address indexed pauser);\n\n    /**\n     * event indicating supportThresholdPercent was updated\n     * @param supportThresholdPercent The new supportThresholdPercent\n     */\n    event SupportThresholdPercentChanged(uint256 supportThresholdPercent);\n\n    /**\n     * event indicating a change in the community governance stage\n     * @param stage the new stage\n     */\n    event StageUpdated(Stage stage);\n\n    /**\n     * An event indicating a proposal has been registered\n     * @param proposer The address that submitted the proposal\n     * @param proposal The address of the proposal contract instance that was added\n     */\n    event ProposalRegistration(address proposer, Proposal proposal);\n\n    /**\n     * An event indicating a change in support for a proposal\n     * @param supporter The address that submitted the proposal\n     * @param proposal The address of the proposal contract instance that was added\n     * @param oldSupport The previous amount of support\n     * @param newSupport The new amount of support\n     */\n    event SupportChanged(\n        address indexed supporter,\n        Proposal indexed proposal,\n        uint256 oldSupport,\n        uint256 newSupport\n    );\n\n    /**\n     * An event indicating a vote cast on a proposal\n     * @param voter The address casting votes\n     * @param enactVotes The votes to enact\n     * @param rejectVotes The votes to reject\n     * @param abstainVotes The votes to abstain\n     */\n    event VotesChanged(\n        address indexed voter,\n        uint256 enactVotes,\n        uint256 rejectVotes,\n        uint256 abstainVotes\n    );\n\n    /**\n     * An event indicating that the proposal selected for this governance cycle was successfully executed\n     * @param proposal The proposal that was executed\n     */\n    event ExecutionComplete(address proposal);\n\n    /**\n     * An event indicating that a new cycle has begun\n     * @param cycleNumber the cycle number\n     */\n    event NewCycle(uint256 cycleNumber);\n\n    /**\n     An event indicating that the fee for a proposal was refunded\n     * @param proposal The address of the proposal being refunded\n     * @param proposer The address that registered the proposal\n     * @param refund The amount of tokens refunded to proposer\n     */\n    event FeeRefunded(address proposal, address proposer, uint256 refund);\n\n    /**\n     * An event indicating that the leftover funds from fees were swept to a recipient address\n     * @param recipient the recipient address\n     */\n    event Sweep(address recipient);\n\n    modifier onlyPauser() {\n        if (msg.sender != pauser) {\n            revert OnlyPauser();\n        }\n        _;\n    }\n\n    modifier updatesStage() {\n        updateStage();\n        _;\n    }\n\n    /**\n     * contract constructor\n     * @param policy the root policy address\n     * @param _eco the ECO contract address\n     * @param _ecoXStaking the ECOxStaking contract address\n     * @param _pauser the new pauser\n     * @param _cycleStart the time that the first cycle should begin\n     */\n    constructor(\n        Policy policy,\n        ECO _eco,\n        ECOx _ecox,\n        ECOxStaking _ecoXStaking,\n        uint256 _cycleStart,\n        address _pauser\n    ) VotingPower(policy, _eco, _ecox, _ecoXStaking) {\n        uint256 time = getTime();\n        if (\n            _cycleStart < time - CYCLE_LENGTH ||\n            _cycleStart > time + 2 * CYCLE_LENGTH\n        ) {\n            revert BadCycleStart();\n        }\n        pauser = _pauser;\n        cycleCount = 1040;\n        currentStageEnd = _cycleStart;\n    }\n\n    /**\n     * sets the pauser of community governance\n     * @param _pauser the new pauser\n     */\n    function setPauser(address _pauser) public onlyPolicy {\n        pauser = _pauser;\n        emit PauserAssignment(_pauser);\n    }\n\n    /**\n     * sets supportThresholdPercent\n     * @param _supportThresholdPercent new supportThresholdPercent\n     */\n    function setSupportThresholdPercent(\n        uint256 _supportThresholdPercent\n    ) public onlyPolicy {\n        if (_supportThresholdPercent > 100) {\n            revert BadSupportThresholdPercent();\n        }\n        supportThresholdPercent = _supportThresholdPercent;\n        emit SupportThresholdPercentChanged(supportThresholdPercent);\n    }\n\n    /**\n     * Pauses community governance\n     */\n    function pause() external onlyPauser {\n        _pause();\n    }\n\n    /**\n     * updates the current stage\n     * called by methods propose, vote, and execute.\n     */\n    function updateStage() public {\n        uint256 time = getTime();\n        bool emitEvent;\n\n        if (stage == Stage.Proposal && time > currentStageEnd) {\n            // no proposal was selected\n            stage = Stage.Done;\n            currentStageEnd = cycleStart + CYCLE_LENGTH;\n            emitEvent = true;\n        }\n\n        if (stage == Stage.Voting && time > currentStageEnd) {\n            if (totalEnactVotes > totalRejectVotes) {\n                // vote passes\n                stage = Stage.Delay;\n                currentStageEnd = currentStageEnd + DELAY_LENGTH;\n            } else {\n                // vote fails\n                stage = Stage.Done;\n                currentStageEnd = cycleStart + CYCLE_LENGTH;\n            }\n            emitEvent = true;\n        }\n\n        if (stage == Stage.Delay && time > currentStageEnd) {\n            // delay period ended, time to execute\n            stage = Stage.Execution;\n            //one additional day, ensuring a minimum of two days to enact the proposal, after which it will need to be resubmitted.\n            currentStageEnd =\n                cycleStart +\n                CYCLE_LENGTH +\n                EXECUTION_EXTRA_LENGTH;\n            emitEvent = true;\n        }\n\n        if (stage == Stage.Execution && time > currentStageEnd) {\n            // if the execution stage timed out, the proposal was not enacted in time\n            // either nobody called it, or the proposal failed during execution.\n            // this assumes the latter case, the former has been addressed in the end time of the execution stage\n            stage = Stage.Done;\n            nextCycle();\n            emitEvent = true;\n        }\n\n        if (stage == Stage.Done && time > currentStageEnd) {\n            nextCycle();\n            emitEvent = true;\n        }\n\n        // this saves the event spam\n        if (emitEvent) {\n            emit StageUpdated(stage);\n        }\n    }\n\n    /**\n     * moves community governance to the next cycle\n     */\n    function nextCycle() internal {\n        if (stage != Stage.Done) {\n            revert WrongStage();\n        }\n        if (cycleStart == 0) {\n            cycleStart = getTime() - CYCLE_LENGTH;\n        }\n\n        uint256 elapsed = getTime() - cycleStart;\n        uint256 cycles = elapsed / CYCLE_LENGTH;\n        uint256 cycleTime = elapsed % CYCLE_LENGTH;\n\n        cycleStart += cycles * CYCLE_LENGTH;\n        cycleCount += cycles;\n\n        if (cycleTime < PROPOSAL_LENGTH) {\n            stage = Stage.Proposal;\n            currentStageEnd = cycleStart + PROPOSAL_LENGTH;\n        } else {\n            stage = Stage.Done;\n            currentStageEnd = cycleStart + CYCLE_LENGTH;\n        }\n\n        ecoToken.snapshot();\n        ecoXToken.snapshot();\n        snapshotBlock = block.number;\n\n        delete selectedProposal;\n        delete totalEnactVotes;\n        delete totalRejectVotes;\n        delete totalAbstainVotes;\n\n        emit NewCycle(cycleCount);\n    }\n\n    /**\n     * allows a user to submit a community governance proposal\n     *\n     * Register a new proposal for community review. Registration is necessary but does not guarantee a vote for its implementation. The proposal is stored in proposals which is an array of all submissions as well as allProposals which stores the proposal addresses. A Register event is emitted.\n     *\n     * Registering a proposal requires a deposit of 10000 ECO (COST_REGISTER), which is transferred from the caller's balance to this contract. An allowance for this transfer must be made before calling. If the proposal does not get voted on then the caller will be entitled to claim a refund of 5000 ECO (REFUND_IF_LOST). If the Circuit Breaker is enacted, this registration fee is waived as transfers cannot be made. This will confuse the refund function, but that is deprioritized in the case of a circuit breaker emergency.\n     *\n     * **Security Notes**\n     *\n     * - Can only be called during the proposing period.\n     * - Requires creating an allowance for payment to call to prevent abuse.\n     * - You cannot propose the 0 address.\n     * - A proposal can only be registered once, regardless of proposer.\n     *\n     *\n     * @param _proposal the address of the deployed proposal\n     * fee is only levied if community governance is paused - we want to still be usable\n     * in the event that ECO transfers are paused.\n     */\n    function propose(Proposal _proposal) public updatesStage {\n        if (stage != Stage.Proposal) {\n            revert WrongStage();\n        }\n\n        PropData storage prop = proposals[address(_proposal)];\n        if (prop.proposer != address(0)) {\n            revert DuplicateProposal();\n        }\n        prop.cycle = cycleCount;\n        prop.proposer = msg.sender;\n\n        if (!paused()) {\n            ecoToken.transferFrom(msg.sender, address(this), proposalFee);\n            prop.refund = feeRefund;\n            pot += proposalFee - prop.refund;\n        }\n\n        emit ProposalRegistration(msg.sender, _proposal);\n    }\n\n    /**\n     * allows an address to register its full voting power in support of a proposal\n     * @param _proposal the address of proposal to be supported\n     */\n    function support(address _proposal) public updatesStage {\n        uint256 vp = votingPower(msg.sender);\n        if (vp == 0) {\n            revert BadVotingPower();\n        }\n        _changeSupport(msg.sender, _proposal, vp);\n    }\n\n    /**\n     * allows an address to register partial support for a set of proposals\n     * @param _proposals the array of proposals to be supported\n     * @param _allocations the respective voting power to put behind those proposals\n     * _changeSupport overwrites the previous supporting voting power, so having the same proposal multiple times in the _proposals array will not result in double counting of support\n     */\n    function supportPartial(\n        address[] memory _proposals,\n        uint256[] memory _allocations\n    ) public updatesStage {\n        uint256 length = _proposals.length;\n        if (length != _allocations.length) {\n            revert ArrayLengthMismatch();\n        }\n\n        // uint256 sumSupport = 0;\n        uint256 vp = votingPower(msg.sender);\n        for (uint256 i = 0; i < length; ++i) {\n            uint256 theSupport = _allocations[i];\n            if (theSupport > vp) {\n                revert BadVotingPower();\n            }\n            _changeSupport(msg.sender, _proposals[i], theSupport);\n            if (stage == Stage.Voting) {\n                break;\n            }\n        }\n    }\n\n    /**\n     * allows an address to revoke support for a proposal\n     * @param _proposal the address of proposal to be supported\n     */\n    function unsupport(address _proposal) public updatesStage {\n        if (proposals[_proposal].support[msg.sender] > 0) {\n            _changeSupport(msg.sender, _proposal, 0);\n        } else {\n            revert NoSupportToRevoke();\n        }\n    }\n\n    /**\n     * allows an address to change the support amount for a proposal\n     * @param supporter the adress of the supporter that is changing their support amount\n     * @param proposal the proposal for which the amount is being changed\n     * @param amount the new support amount\n     */\n    function _changeSupport(\n        address supporter,\n        address proposal,\n        uint256 amount\n    ) internal {\n        if (stage != Stage.Proposal) {\n            revert WrongStage();\n        }\n\n        PropData storage prop = proposals[proposal];\n        if (prop.cycle != cycleCount) {\n            revert OldProposalSupport();\n        }\n        uint256 support = prop.support[supporter];\n\n        emit SupportChanged(supporter, Proposal(proposal), support, amount);\n\n        prop.totalSupport -= support;\n        prop.support[supporter] = amount;\n        prop.totalSupport += amount;\n\n        if (\n            prop.totalSupport * thresholdPercentDivisor >\n            totalVotingPower() * supportThresholdPercent\n        ) {\n            selectedProposal = proposal;\n            pot -= (proposalFee - prop.refund);\n            prop.refund = proposalFee;\n            stage = Stage.Voting;\n            currentStageEnd = getTime() + VOTING_LENGTH;\n\n            emit StageUpdated(Stage.Voting);\n        }\n    }\n\n    /**\n     * fetches the voting power with which a given address supports a given proposal\n     * @param supporter the supporting address\n     * @param proposal the proposal\n     8 @return theSupport voting power with which a given address supports a given proposal \n     */\n    function getSupport(\n        address supporter,\n        address proposal\n    ) public view returns (uint256 theSupport) {\n        theSupport = proposals[proposal].support[supporter];\n        return theSupport;\n    }\n\n    /**\n     * allows an address to vote to enact, reject or abstain on a proposal with their full voting power\n     * @param choice the address' vote\n     */\n    function vote(Vote choice) public updatesStage {\n        uint256 vp = votingPower(msg.sender);\n        if (vp == 0) {\n            revert BadVotingPower();\n        }\n        if (choice == Vote.Enact) {\n            _vote(msg.sender, vp, 0, 0);\n        } else if (choice == Vote.Reject) {\n            _vote(msg.sender, 0, vp, 0);\n        } else if (choice == Vote.Abstain) {\n            _vote(msg.sender, 0, 0, vp);\n        } else {\n            revert BadVoteType();\n        }\n    }\n\n    /**\n     * allows an address to split their voting power allocation between enact, reject and abstain\n     * @param enactVotes votes to enact\n     * @param rejectVotes votes to reject\n     * @param abstainVotes votes to abstain\n     */\n    function votePartial(\n        uint256 enactVotes,\n        uint256 rejectVotes,\n        uint256 abstainVotes\n    ) public updatesStage {\n        if (enactVotes + rejectVotes + abstainVotes > votingPower(msg.sender)) {\n            revert BadVotingPower();\n        }\n        _vote(msg.sender, enactVotes, rejectVotes, abstainVotes);\n    }\n\n    function _vote(\n        address voter,\n        uint256 _enactVotes,\n        uint256 _rejectVotes,\n        uint256 _abstainVotes\n    ) internal {\n        if (stage != Stage.Voting) {\n            revert WrongStage();\n        }\n\n        PropData storage prop = proposals[selectedProposal];\n\n        totalEnactVotes -= prop.enactVotes[voter];\n        totalRejectVotes -= prop.rejectVotes[voter];\n        totalAbstainVotes -= prop.abstainVotes[voter];\n\n        prop.enactVotes[voter] = _enactVotes;\n        prop.rejectVotes[voter] = _rejectVotes;\n        prop.abstainVotes[voter] = _abstainVotes;\n\n        totalEnactVotes += _enactVotes;\n        totalRejectVotes += _rejectVotes;\n        totalAbstainVotes += _abstainVotes;\n\n        emit VotesChanged(voter, _enactVotes, _rejectVotes, _abstainVotes);\n\n        if (\n            totalEnactVotes * thresholdPercentDivisor >\n            totalVotingPower() * voteThresholdPercent\n        ) {\n            stage = Stage.Execution;\n            currentStageEnd =\n                cycleStart +\n                CYCLE_LENGTH +\n                EXECUTION_EXTRA_LENGTH;\n\n            emit StageUpdated(Stage.Execution);\n        }\n    }\n\n    /**\n     * fetches the votes an address has pledged toward enacting, rejecting, and abstaining on a given proposal\n     * @param voter the supporting address\n     * @return enactVotes Votes for enacting the policy\n     * @return rejectVotes Votes for rejecting the policy\n     * @return abstainVotes Votes for abstaining on the policy\n     */\n    function getVotes(\n        address voter\n    )\n        public\n        view\n        returns (uint256 enactVotes, uint256 rejectVotes, uint256 abstainVotes)\n    {\n        if (stage != Stage.Voting) {\n            revert WrongStage();\n        }\n        PropData storage prop = proposals[selectedProposal];\n        // enactVotes = prop.enactVotes[voter];\n        // rejectVotes = prop.rejectVotes[voter];\n        // abstainVotes = prop.abstainVotes[voter];\n        // return (enactVotes, rejectVotes, abstainVotes);\n        return (\n            prop.enactVotes[voter],\n            prop.rejectVotes[voter],\n            prop.abstainVotes[voter]\n        );\n    }\n\n    /**\n     * allows an address to enact a selected proposal that has passed the vote\n     * it is important to do this in a timely manner, once the cycle passes it will no longer be possible to execute the proposal.\n     * the community will have a minimum of 3 days 8 hours to enact the proposal.\n     */\n    function execute() public updatesStage {\n        if (stage != Stage.Execution) {\n            revert WrongStage();\n        }\n\n        policy.enact(selectedProposal);\n        stage = Stage.Done;\n        currentStageEnd = cycleStart + CYCLE_LENGTH; // ensure that an early execution allows for an on-time start to the next cycle\n\n        emit ExecutionComplete(selectedProposal);\n    }\n\n    /**\n     * allows redemption of proposal registration fees\n     * @param proposal the proposal whose fee is being redeemed\n     * the fee will be refunded to the proposer of the proposal, regardless of who calls refund\n     */\n    function refund(address proposal) public {\n        uint256 propRefund = proposals[proposal].refund;\n        address proposer = proposals[proposal].proposer;\n        if (propRefund > 0) {\n            if (proposals[proposal].cycle < cycleCount) {\n                ecoToken.transfer(proposer, propRefund);\n\n                emit FeeRefunded(proposal, proposer, propRefund);\n\n                proposals[proposal].refund = 0;\n            } else {\n                revert NoRefundDuringCycle(proposal);\n            }\n        } else {\n            revert NoRefundAvailable(proposal);\n        }\n    }\n\n    /**\n     * allows the leftover registration fees to be drained from the contract\n     * @param recipient the address receiving the tokens\n     * only the policy contract can call this\n     */\n    function sweep(address recipient) public onlyPolicy {\n        uint256 amount = pot;\n        pot = 0;\n        ecoToken.transfer(recipient, amount);\n        emit Sweep(recipient);\n    }\n}\n"
      },
      "contracts/governance/community/ECOxStaking.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\nimport \"@openzeppelin/contracts/token/ERC20/IERC20.sol\";\nimport \"../../currency/VoteCheckpoints.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"../../policy/PolicedUpgradeable.sol\";\n\n/**\n * @title ECOxStaking\n *\n */\ncontract ECOxStaking is VoteCheckpoints, PolicedUpgradeable {\n    /// the ECOx contract address\n    IERC20 public immutable ecoXToken;\n\n    /// error for if the constructor tries to set the ECOx address to zero\n    error NoZeroECOx();\n\n    /// error for if any transfer function is attempted to be used\n    error NonTransferrable();\n\n    /**\n     * The Deposit event indicates that ECOx has been locked up, credited\n     * to a particular address in a particular amount.\n     *\n     * @param source The address that a deposit certificate has been issued to.\n     * @param amount The amount of ECOx tokens deposited.\n     */\n    event Deposit(address indexed source, uint256 amount);\n\n    /**\n     * The Withdrawal event indicates that a withdrawal has been made to a particular\n     * address in a particular amount.\n     *\n     * @param destination The address that has made a withdrawal.\n     * @param amount The amount in basic unit of 10^{-18} ECOx (weicoX) tokens withdrawn.\n     */\n    event Withdrawal(address indexed destination, uint256 amount);\n\n    constructor(\n        Policy _policy,\n        IERC20 _ecoXAddr\n    )\n        // Note that the policy has the ability to pause transfers\n        // through ERC20Pausable, although transfers are paused by default\n        // therefore the pauser is unset\n        VoteCheckpoints(\"Staked ECOx\", \"sECOx\", address(_policy), address(0))\n        Policed(_policy)\n    {\n        if (address(_ecoXAddr) == address(0)) {\n            revert NoZeroECOx();\n        }\n        ecoXToken = _ecoXAddr;\n    }\n\n    /**\n     * deposit transfers ECOx to the contract and mints sECOx to the source of the transfer determined by `msg.sender`.\n     * @param _amount the amount of ECOx to deposit\n     *\n     */\n    function deposit(uint256 _amount) external {\n        address _source = msg.sender;\n\n        require(\n            ecoXToken.transferFrom(_source, address(this), _amount),\n            \"Transfer failed\"\n        );\n\n        _mint(_source, _amount);\n\n        emit Deposit(_source, _amount);\n    }\n\n    /**\n     * withdraw burns the senders sECOx and transfers ECOx to the source of the transfer determined by `msg.sender`.\n     * @param _amount the amount of ECOx to withdraw\n     *\n     */\n    function withdraw(uint256 _amount) external {\n        address _destination = msg.sender;\n\n        // do this first to ensure that any undelegations in this function are caught\n        _burn(_destination, _amount);\n\n        require(ecoXToken.transfer(_destination, _amount), \"Transfer Failed\");\n\n        emit Withdrawal(_destination, _amount);\n    }\n\n    /**\n     * Gets the past votes for a voter at a specific block\n     * @param _voter the address of the voter\n     * @param _blockNumber the block number to retrieve the votes from\n     * @return pastVotes the past votes at the block number\n     */\n    function votingECOx(\n        address _voter,\n        uint256 _blockNumber\n    ) external view returns (uint256 pastVotes) {\n        return getPastVotes(_voter, _blockNumber);\n    }\n\n    /**\n     * Gets the total supply at a specific block number\n     * @param _blockNumber the block to get the votes for\n     * @return totalSupply the total supply at the block number\n     */\n    function totalVotingECOx(\n        uint256 _blockNumber\n    ) external view returns (uint256 totalSupply) {\n        return totalSupplyAt(_blockNumber);\n    }\n\n    /**\n     * transfers are disabled and revert with a NonTransferrable error\n     */\n    function transfer(address, uint256) public pure override returns (bool) {\n        revert NonTransferrable();\n    }\n\n    /**\n     * transferFroms are disabled and revert with a NonTransferrable error\n     */\n    function transferFrom(\n        address,\n        address,\n        uint256\n    ) public pure override returns (bool) {\n        revert NonTransferrable();\n    }\n}\n"
      },
      "contracts/governance/community/proposals/Proposal.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title Proposal\n * @notice Interface specification for proposals. Any proposal submitted in the\n * policy decision process must implement this interface.\n */\ninterface Proposal {\n    /**\n     * The name of the proposal.\n     *\n     * This should be relatively unique and descriptive.\n     * @return name The name of the proposal\n     */\n    function name() external view returns (string memory name);\n\n    /**\n     * A longer description of what this proposal achieves.\n     * @return description A longer description of what this proposal achieves.\n     */\n    function description() external view returns (string memory description);\n\n    /**\n     * A URL where voters can go to see the case in favour of this proposal,\n     * and learn more about it.\n     * @return url A URL where voters can go to see the case in favour of this proposal\n     */\n    function url() external view returns (string memory url);\n\n    /**\n     * Called to enact the proposal.\n     *\n     * This will be called from the root policy contract using delegatecall,\n     * with the direct proposal address passed in as _self so that storage\n     * data can be accessed if needed.\n     *\n     * @param _self The address of the proposal contract.\n     */\n    function enacted(address _self) external;\n}\n"
      },
      "contracts/governance/community/VotingPower.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policed.sol\";\nimport \"../../currency/ECO.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"./ECOxStaking.sol\";\n\n/**\n * @title VotingPower\n * @notice Compute voting power for user\n */\ncontract VotingPower is Policed {\n    // the ECO contract address\n    ECO public immutable ecoToken;\n\n    // the ECOx contract address\n    ECOx public immutable ecoXToken;\n\n    // the ECOxStaking contract address\n    ECOxStaking public immutable ecoXStaking;\n\n    /** @notice snapshot block for calculating voting power */\n    uint256 public snapshotBlock;\n\n    // error for if total voting power is accessed during the snapshot block\n    error NoAtomicActionsWithSnapshot();\n\n    constructor(\n        Policy _policy,\n        ECO _ecoAddr,\n        ECOx _ecoXAddr,\n        ECOxStaking _ecoXStakingAddr\n    ) Policed(_policy) {\n        if (address(_ecoAddr) == address(0)) {\n            revert NonZeroContractAddr(\"ECO\");\n        }\n        if (address(_ecoXAddr) == address(0)) {\n            revert NonZeroContractAddr(\"ECOx\");\n        }\n        if (address(_ecoXStakingAddr) == address(0)) {\n            revert NonZeroContractAddr(\"ECOxStaking\");\n        }\n        ecoToken = _ecoAddr;\n        ecoXToken = _ecoXAddr;\n        ecoXStaking = _ecoXStakingAddr;\n    }\n\n    /**\n     * Calculates the total Voting Power by getting the total supply of ECO\n     * and adding total ECOX (multiplied by 10)\n     * @return total the total Voting Power\n     */\n    function totalVotingPower() public view returns (uint256 total) {\n        if (block.number == snapshotBlock) {\n            revert NoAtomicActionsWithSnapshot();\n        }\n\n        uint256 _supply = ecoToken.totalSupplySnapshot();\n        uint256 _supplyX = ecoXToken.totalSupplySnapshot();\n        // ECOx has 10x the voting power of ECO per unit\n        return _supply + 10 * _supplyX;\n    }\n\n    /**\n     * Calculates the voting power for an address at the Snapshot Block\n     * @param _who the address to calculate the voting power for\n     * @return total the total voting power for an address at the Snapshot Block\n     */\n\n    function votingPower(address _who) public view returns (uint256 total) {\n        if (block.number == snapshotBlock) {\n            revert NoAtomicActionsWithSnapshot();\n        }\n        uint256 _power = ecoToken.voteBalanceSnapshot(_who);\n        uint256 _powerX = ecoXStaking.votingECOx(_who, snapshotBlock);\n        // ECOx has 10x the voting power of ECO per unit\n        return _power + 10 * _powerX;\n    }\n}\n"
      },
      "contracts/governance/monetary/CurrencyGovernance.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./TrustedNodes.sol\";\nimport \"./MonetaryPolicyAdapter.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"../../policy/Policed.sol\";\n\n/**\n * @title Trustee monetary policy decision process\n * @notice This contract oversees the voting on the currency monetary levers.\n * Trustees vote on a policy that is implemented at the conclusion of the cycle\n */\ncontract CurrencyGovernance is Policed, TimeUtils {\n    //////////////////////////////////////////////\n    /////////////////// TYPES ////////////////////\n    //////////////////////////////////////////////\n\n    // data structure for monetary policy proposals\n    struct MonetaryPolicy {\n        // the cycle that the proposal was submitted during\n        uint256 cycle;\n        // addresses to call if the proposal succeeds\n        address[] targets;\n        // the function signatures to call\n        bytes4[] signatures;\n        // the abi encoded data to call\n        bytes[] calldatas;\n        // the number of trustees supporting the proposal\n        uint256 support;\n        // the mapping of who is supporting (note, this persists past deletion)\n        // this is to avoid double supporting and to confirm and record unspports\n        mapping(address => bool) supporters;\n        // to store a link to more information\n        string description;\n    }\n\n    // struct for the array of submitted votes\n    struct Vote {\n        // the address of the trustee who submitted the proposal being voted for\n        // proposals must be scored in ascending order of address to be accepted\n        bytes32 proposalId;\n        // the score of this proposal within the ballot, min recorded score is one\n        // to get a score of zero, an item must be unscored\n        uint256 score;\n    }\n\n    // struct for the getCurrentStage() return data type\n    struct TimingData {\n        // the cycle index\n        // calculated by looking at how many CYCLE_LENGTHs have elapsed since the governanceStartTime\n        uint256 currentCycle;\n        // the governance stage\n        // calculated by looking at how much time has progressed during the current cycle\n        Stage currentStage;\n    }\n\n    // enum for denoting the current stage in getCurrentStage()\n    enum Stage {\n        Propose,\n        Commit,\n        Reveal\n    }\n\n    //////////////////////////////////////////////\n    //////////////////// VARS ////////////////////\n    //////////////////////////////////////////////\n\n    /// this var stores the current contract that holds the trusted nodes role\n    TrustedNodes public trustedNodes;\n\n    /** this var stores the current contract that holds the enacter role */\n    MonetaryPolicyAdapter public enacter;\n\n    /** this variable tracks the start of governance\n     * it is used to track the voting cycle and stage\n     */\n    uint256 public immutable governanceStartTime;\n\n    // timescales\n    uint256 public constant PROPOSAL_TIME = 10 days;\n    uint256 public constant VOTING_TIME = 3 days;\n    uint256 public constant REVEAL_TIME = 1 days;\n    uint256 public constant CYCLE_LENGTH =\n        PROPOSAL_TIME + VOTING_TIME + REVEAL_TIME;\n\n    /**  start with cycle 1000 to avoid underflow and initial value issues */\n    uint256 public constant START_CYCLE = 1000;\n\n    uint256 public constant IDEMPOTENT_INFLATION_MULTIPLIER = 1e18;\n\n    /**  max length of description field */\n    uint256 public constant MAX_DESCRIPTION_DATA = 160;\n\n    /**  max length of the targets array\n     */\n    uint256 public constant MAX_TARGETS = 10;\n\n    /** mapping of proposal IDs to submitted proposals\n     * proposalId hashes include the _cycle as a parameter\n     */\n    mapping(bytes32 => MonetaryPolicy) public proposals;\n    /**  mapping of trustee addresses to cycle number to track if they have supported (and can therefore not support again) */\n    mapping(address => uint256) public trusteeSupports;\n    /**  mapping of trustee addresses to their most recent hash commits for voting */\n    mapping(address => bytes32) public commitments;\n    /**  mapping proposalIds to their voting score, accumulated during reveal */\n    mapping(bytes32 => uint256) public scores;\n\n    /**\n     * @notice minimum number participating trustees required for a policy to be enacted in any given cycle\n     */\n    uint256 public quorum;\n\n    /**\n     * @notice number of trustees that participated this cycle\n     */\n    uint256 public participation;\n\n    /** used to track the leading proposalId during the vote totalling\n     * tracks the winner between reveal phases\n     * is deleted on enact to ensure it can only be enacted once\n     */\n    bytes32 public leader;\n\n    //////////////////////////////////////////////\n    /////////////////// ERRORS ///////////////////\n    //////////////////////////////////////////////\n\n    /** setting the enacter address to the zero address stops governance */\n    error NonZeroEnacterAddr();\n\n    /**\n     * setting the quorum greater than the number of trustees stops governance\n     * inherently prevents the trustedNodes address from being set to the zero address\n     * something to keep in mind for the case in which trustees are removed via community governance\n     */\n    error BadQuorum();\n\n    /** For if a non-trustee address tries to access trustee role gated functionality */\n    error TrusteeOnlyFunction();\n\n    /** For when governance calls are made before or after their time windows for their stage */\n    error WrongStage();\n\n    /** Early finalization error\n     * for when a cycle is attempted to be finalized before it finishes\n     * @param requestedCycle the cycle submitted by the end user to access\n     * @param currentCycle the current cycle as calculated by the contract\n     */\n    error CycleIncomplete(uint256 requestedCycle, uint256 currentCycle);\n\n    /** Description length error\n     * for when a proposal is submitted with too long of a description\n     * @param submittedLength the length of the submitted description, to be compared against MAX_DESCRIPTION_DATA\n     */\n    error ExceedsMaxDescriptionSize(uint256 submittedLength);\n\n    /** Targets length error\n     * for when a proposal is submitted with too many actions or zero actions\n     * @param submittedLength the length of the submitted targets array, to be compared against MAX_TARGETS and 0\n     */\n    error BadNumTargets(uint256 submittedLength);\n\n    /** error for when the 3 arrays submitted for the proposal don't all have the same number of elements */\n    error ProposalActionsArrayMismatch();\n\n    /** error for when a trustee is already supporting a policy and tries to propose or support another policy */\n    error SupportAlreadyGiven();\n\n    /** error for when a trustee is not supporting a policy and tries unsupport */\n    error SupportNotGiven();\n\n    /** error for when a trustee tries unsupporting a proposal from a past cycle */\n    error ProposalNotCurrent();\n\n    /** error for when a proposal is submitted that's a total duplicate of an existing one */\n    error DuplicateProposal();\n\n    /** error for when a proposal is supported that hasn't actually been proposed */\n    error NoSuchProposal();\n\n    /** error for when a reveal is submitted with no votes */\n    error CannotVoteEmpty();\n\n    /** error for when a trustee with a commmitment tries to abstain */\n    error NoAbstainWithCommit();\n\n    /** error for when a reveal is submitted for an empty commitment, usually the sign of no commit being submitted */\n    error NoCommitFound();\n\n    /** error for when the submitted vote doesn't match the stored commit */\n    error CommitMismatch();\n\n    /** error for when a proposalId in a trustee's vote is not one from the current cycle or is completely invalid\n     * @param vote the vote containing the invalid proposalId\n     */\n    error InvalidVoteBadProposalId(Vote vote);\n\n    /** error for when the proposalIds in a trustee's vote are not strictly increasing\n     * @param prevVote the vote before the invalid vote\n     * @param vote the vote with the non-increasing proposalId\n     */\n    error InvalidVoteBadProposalOrder(Vote prevVote, Vote vote);\n\n    /** error for when a score in a trustee's vote is either duplicate or doesn't respect support weightings\n     * @param vote the vote containing the invalid score\n     */\n    error InvalidVoteBadScore(Vote vote);\n\n    /** error for when the scores for proposals are not monotonically increasing, accounting for support weighting */\n    error InvalidVotesOutOfBounds();\n\n    /** error for when the leader's score is less than the quorum */\n    error QuorumNotMet();\n\n    /** error for when enact is called, but the cycle it's called for does not match the proposal that's the current leader  */\n    error EnactCycleNotCurrent();\n\n    //////////////////////////////////////////////\n    /////////////////// EVENTS ///////////////////\n    //////////////////////////////////////////////\n\n    /**\n     * emits when the trustedNodes contract is changed\n     * @param newTrustedNodes denotes the new trustedNodes contract address\n     * @param oldTrustedNodes denotes the old trustedNodes contract address\n     */\n    event NewTrustedNodes(\n        TrustedNodes newTrustedNodes,\n        TrustedNodes oldTrustedNodes\n    );\n\n    /**\n     * @notice emits when the enacter contract is changed\n     * @param newEnacter denotes the new enacter contract address\n     * @param oldEnacter denotes the old enacter contract address\n     */\n    event NewEnacter(\n        MonetaryPolicyAdapter newEnacter,\n        MonetaryPolicyAdapter oldEnacter\n    );\n\n    /**\n     * @notice emits when setQuorum is called successfully\n     * @param newQuorum the new quorum\n     * @param oldQuorum the old quorum\n     */\n    event NewQuorum(uint256 newQuorum, uint256 oldQuorum);\n\n    /** Tracking for proposal creation\n     * emitted when a proposal is submitted to track the values\n     * @param _trusteeAddress the address of the trustee that submitted the proposal\n     * @param _cycle the cycle during which the proposal was submitted\n     * @param id the lookup id for the proposal in the proposals mapping\n     * is created via a hash of _cycle, _targets, _signatures, and _calldatas; see getProposalHash for more details\n     * @param _description a string allowing the trustee to describe the proposal or link to discussions on the proposal\n     */\n    event ProposalCreation(\n        address indexed _trusteeAddress,\n        uint256 indexed _cycle,\n        bytes32 id,\n        string _description\n    );\n\n    /** Tracking for support actions\n     * emitted when a trustee adds their support for a proposal\n     * @param trustee the address of the trustee supporting\n     * @param proposalId the lookup for the proposal being supported\n     * @param cycle the cycle during which the support action happened\n     */\n    event Support(\n        address indexed trustee,\n        bytes32 indexed proposalId,\n        uint256 indexed cycle\n    );\n\n    /** Tracking for unsupport actions\n     * emitted when a trustee retracts their support for a proposal\n     * @param trustee the address of the trustee unsupporting\n     * @param proposalId the lookup for the proposal being unsupported\n     * @param cycle the cycle during which the support action happened\n     */\n    event Unsupport(\n        address indexed trustee,\n        bytes32 indexed proposalId,\n        uint256 indexed cycle\n    );\n\n    /** Tracking for removed proposals\n     * emitted when the last trustee retracts their support for a proposal\n     * @param proposalId the lookup for the proposal being deleted\n     * @param cycle the cycle during which the unsupport deletion action happened\n     */\n    event ProposalDeleted(bytes32 indexed proposalId, uint256 indexed cycle);\n\n    /** Fired when a trustee commits their vote.\n     * @param trustee the trustee that committed the vote\n     * @param cycle the cycle for the commitment\n     */\n    event VoteCommit(address indexed trustee, uint256 indexed cycle);\n\n    /** Fired when a vote is revealed, to create a voting history for all participants.\n     * Records the voter, as well as all of the parameters of the vote cast.\n     * @param voter the trustee who revealed their vote\n     * @param cycle the cycle when the vote was cast and counted\n     * @param votes the array of Vote structs that composed the trustee's ballot\n     */\n    event VoteReveal(\n        address indexed voter,\n        uint256 indexed cycle,\n        Vote[] votes\n    );\n\n    // fired when cycle participation is high enough to enact monetary policy\n    event QuorumReached();\n\n    /** Fired when an address choses to abstain\n     * @param voter the address of the voter\n     * @param cycle the cycle for which the voter abstained\n     */\n    event Abstain(address indexed voter, uint256 indexed cycle);\n\n    /** Fired when vote results are computed, creating a permanent record of vote outcomes.\n     * @param cycle the cycle for which this is the vote result\n     * @param winner the proposalId for the proposal that won\n     */\n    event VoteResult(uint256 cycle, bytes32 winner);\n\n    //////////////////////////////////////////////\n    ////////////////// MODIFIERS /////////////////\n    //////////////////////////////////////////////\n\n    /** Restrict access to trusted nodes only.\n     */\n    modifier onlyTrusted() {\n        if (!trustedNodes.isTrusted(msg.sender)) {\n            revert TrusteeOnlyFunction();\n        }\n        _;\n    }\n\n    /**  for functions related to proposing monetary policy */\n    modifier duringProposePhase() {\n        if ((getTime() - governanceStartTime) % CYCLE_LENGTH >= PROPOSAL_TIME) {\n            revert WrongStage();\n        }\n        _;\n    }\n\n    /** for functions related to committing votes */\n    modifier duringVotePhase() {\n        uint256 governanceTime = (getTime() - governanceStartTime) %\n            CYCLE_LENGTH;\n\n        if (\n            governanceTime < PROPOSAL_TIME ||\n            governanceTime >= PROPOSAL_TIME + VOTING_TIME\n        ) {\n            revert WrongStage();\n        }\n        _;\n    }\n\n    /** for functions related to revealing votes */\n    modifier duringRevealPhase() {\n        if (\n            (getTime() - governanceStartTime) % CYCLE_LENGTH <\n            PROPOSAL_TIME + VOTING_TIME\n        ) {\n            revert WrongStage();\n        }\n        _;\n    }\n\n    //////////////////////////////////////////////\n    ///////////////// CONSTRUCTOR ////////////////\n    //////////////////////////////////////////////\n\n    /** constructor\n     * @param _policy the owning policy address for the contract\n     * @param _enacter the monetary policy adapter\n     * @param _quorum the required quorum for enactment of monetary policy\n     * @param _termStart the time the current CurrencyGovernance term starts\n     */\n    constructor(\n        Policy _policy,\n        MonetaryPolicyAdapter _enacter,\n        uint256 _quorum,\n        uint256 _termStart\n    ) Policed(_policy) {\n        _setEnacter(_enacter);\n        quorum = _quorum; // can't use _setQuorum as it's not linked to trustedNodes until after initial deploy\n        governanceStartTime = _termStart;\n    }\n\n    //////////////////////////////////////////////\n    ////////////////// FUNCTIONS /////////////////\n    //////////////////////////////////////////////\n\n    /** setter function for trustedNodes var\n     * This function is very disruptive to the currency governance process and the timing of calling it should be VERY INTENTIONAL\n     * The proposal that does so should have a timing restriction on its enaction, don't just let it be enacted as soon as it passes!\n     *\n     * only available to the owning policy contract\n     * @param _trustedNodes the value to set the new trustedNodes address to, must have enough trustees to be able to hit quorum\n     */\n    function setTrustedNodes(TrustedNodes _trustedNodes) external onlyPolicy {\n        emit NewTrustedNodes(_trustedNodes, trustedNodes);\n        _setTrustedNodes(_trustedNodes);\n    }\n\n    function _setTrustedNodes(TrustedNodes _trustedNodes) internal {\n        // don't allow a new trusted nodes contract without enough trustees to hit quorum\n        // also makes sure you cannot set the trusted nodes contract to an address which doesn't have a `numTrustees()` function\n        if (quorum > _trustedNodes.numTrustees()) {\n            revert BadQuorum();\n        }\n        trustedNodes = _trustedNodes;\n    }\n\n    /** setter function for enacter var\n     * only available to the owning policy contract\n     * @param _enacter the value to set the new enacter address to, cannot be zero\n     */\n    function setEnacter(MonetaryPolicyAdapter _enacter) external onlyPolicy {\n        emit NewEnacter(_enacter, enacter);\n        _setEnacter(_enacter);\n    }\n\n    function _setEnacter(MonetaryPolicyAdapter _enacter) internal {\n        if (address(_enacter) == address(0)) {\n            revert NonZeroEnacterAddr();\n        }\n        enacter = _enacter;\n    }\n\n    function setQuorum(uint256 _quorum) external onlyPolicy {\n        emit NewQuorum(_quorum, quorum);\n        _setQuorum(_quorum);\n    }\n\n    function _setQuorum(uint256 _quorum) internal {\n        if (_quorum > trustedNodes.numTrustees() || _quorum == 0) {\n            revert BadQuorum();\n        }\n        quorum = _quorum;\n    }\n\n    /** getter for timing data\n     * calculates and returns the current cycle and the current stage\n     * @return timingData Timin Data type of { uint256 cycle, Stage stage }\n     */\n    function getCurrentStage()\n        public\n        view\n        returns (TimingData memory timingData)\n    {\n        uint256 timeDifference = getTime() - governanceStartTime;\n        uint256 completedCycles = START_CYCLE + timeDifference / CYCLE_LENGTH;\n        uint256 governanceTime = timeDifference % CYCLE_LENGTH;\n\n        if (governanceTime < PROPOSAL_TIME) {\n            return TimingData(completedCycles, Stage.Propose);\n        } else if (governanceTime < PROPOSAL_TIME + VOTING_TIME) {\n            return TimingData(completedCycles, Stage.Commit);\n        } else {\n            return TimingData(completedCycles, Stage.Reveal);\n        }\n    }\n\n    /** getter for just the current cycle\n     * calculates and returns, used internally\n     * @return cycle the index for the currently used governance recording mappings\n     */\n    function getCurrentCycle() public view returns (uint256 cycle) {\n        return START_CYCLE + (getTime() - governanceStartTime) / CYCLE_LENGTH;\n    }\n\n    /** propose a monetary policy\n     * this function allows trustees to submit a potential monetary policy\n     * if there is already a proposed monetary policy by the trustee, this overwrites it\n     * @param targets array of target addresses\n     * @param signatures array of signatures\n     * @param calldatas array of calldata\n     * @param description descrption of the monetary policy\n     */\n    function propose(\n        address[] calldata targets,\n        bytes4[] calldata signatures,\n        bytes[] memory calldatas,\n        string calldata description\n    ) external onlyTrusted duringProposePhase {\n        uint256 cycle = getCurrentCycle();\n        if (!canSupport(msg.sender)) {\n            revert SupportAlreadyGiven();\n        }\n\n        trusteeSupports[msg.sender] = cycle;\n\n        uint256 descriptionLength = bytes(description).length;\n        if (descriptionLength > MAX_DESCRIPTION_DATA) {\n            revert ExceedsMaxDescriptionSize(descriptionLength);\n        }\n\n        uint256 numTargets = targets.length;\n        if (numTargets > MAX_TARGETS || numTargets <= 0) {\n            revert BadNumTargets(numTargets);\n        }\n        if (numTargets != signatures.length || numTargets != calldatas.length) {\n            revert ProposalActionsArrayMismatch();\n        }\n\n        bytes32 proposalId = getProposalId(\n            cycle,\n            targets,\n            signatures,\n            calldatas\n        );\n\n        MonetaryPolicy storage p = proposals[proposalId];\n\n        // THIS IS NOT A GUARANTEE FOR DUPLICATE PROPOSALS JUST A SAFEGUARD FOR OVERWRITING\n        if (p.support != 0) {\n            revert DuplicateProposal();\n        }\n        p.support = 1;\n        p.supporters[msg.sender] = true;\n\n        p.cycle = cycle;\n        p.targets = targets;\n        p.signatures = signatures;\n        p.calldatas = calldatas;\n        p.description = description;\n\n        emit ProposalCreation(msg.sender, cycle, proposalId, description);\n        emit Support(msg.sender, proposalId, cycle);\n    }\n\n    /** getter for duplicate support checks\n     * the function just pulls to see if the address has supported this generation\n     * doesn't check to see if the address is a trustee\n     * @param _address the address to check. not msg.sender for dapp related purposes\n     */\n    function canSupport(address _address) public view returns (bool) {\n        return trusteeSupports[_address] < getCurrentCycle();\n    }\n\n    function getProposalId(\n        uint256 _cycle,\n        address[] calldata _targets,\n        bytes4[] calldata _signatures,\n        bytes[] memory _calldatas\n    ) public pure returns (bytes32) {\n        return\n            keccak256(\n                abi.encodePacked(\n                    _cycle,\n                    keccak256(abi.encode(_targets, _signatures, _calldatas))\n                )\n            );\n    }\n\n    function getProposalTargets(\n        bytes32 proposalId\n    ) external view returns (address[] memory) {\n        return proposals[proposalId].targets;\n    }\n\n    function getProposalSignatures(\n        bytes32 proposalId\n    ) external view returns (bytes4[] memory) {\n        return proposals[proposalId].signatures;\n    }\n\n    function getProposalCalldatas(\n        bytes32 proposalId\n    ) external view returns (bytes[] memory) {\n        return proposals[proposalId].calldatas;\n    }\n\n    function getProposalSupporter(\n        bytes32 proposalId,\n        address supporter\n    ) external view returns (bool) {\n        return proposals[proposalId].supporters[supporter];\n    }\n\n    /** add your support to a monetary policy\n     * this function allows you to increase the support weight to an already submitted proposal\n     * the submitter of a proposal default supports it\n     * support for a proposal is close to equivalent of submitting a duplicate proposal to pad the ranking\n     * @param proposalId the lookup ID for the proposal that's being supported\n     */\n    function supportProposal(\n        bytes32 proposalId\n    ) external onlyTrusted duringProposePhase {\n        if (!canSupport(msg.sender)) {\n            revert SupportAlreadyGiven();\n        }\n\n        uint256 cycle = getCurrentCycle();\n\n        MonetaryPolicy storage p = proposals[proposalId];\n\n        // can support the default proposal even though is doesn't get initialized\n        // the support parameter is bumped by 1 for the default proposal when its vote is counted\n        // cannot support future cycle default proposals\n        if (proposalId != bytes32(cycle)) {\n            if (p.support == 0) {\n                revert NoSuchProposal();\n            }\n            if (p.cycle != cycle) {\n                revert ProposalNotCurrent();\n            }\n        }\n\n        trusteeSupports[msg.sender] = cycle;\n\n        ++p.support;\n        p.supporters[msg.sender] = true;\n        emit Support(msg.sender, proposalId, getCurrentCycle());\n    }\n\n    /** removes your support to a monetary policy\n     * this function allows you to reduce the support weight to an already submitted proposal\n     * you must unsupport first if you currently have supported if you want to support or propose another proposal\n     * the last person who unsupports the proposal deletes the proposal\n     * @param proposalId the lookup ID for the proposal that's being unsupported\n     */\n    function unsupportProposal(\n        bytes32 proposalId\n    ) external onlyTrusted duringProposePhase {\n        uint256 cycle = getCurrentCycle();\n\n        MonetaryPolicy storage p = proposals[proposalId];\n        uint256 support = p.support;\n\n        if (support == 0) {\n            revert NoSuchProposal();\n        }\n        if (!p.supporters[msg.sender]) {\n            revert SupportNotGiven();\n        }\n        if (p.cycle != cycle && proposalId != bytes32(cycle)) {\n            revert ProposalNotCurrent();\n        }\n\n        p.supporters[msg.sender] = false;\n\n        // deleting the default proposal doesn't do anything, but you don't want to emit the event\n        if (support == 1 && proposalId != bytes32(cycle)) {\n            delete proposals[proposalId];\n            emit ProposalDeleted(proposalId, cycle);\n        } else {\n            --p.support;\n        }\n\n        trusteeSupports[msg.sender] = 0;\n        emit Unsupport(msg.sender, proposalId, cycle);\n    }\n\n    /** submit a vote commitment\n     * this function allows trustees to submit a commit hash of their vote\n     * commitment is salted so that it is a blind vote process\n     * calling additional times overwrites previous commitments\n     * @param _commitment the hash commit to check against when revealing\n     * the structure of the commit is keccak256(abi.encode(salt, cycleIndex, msg.sender, votes)) where votes is an array of Vote structs\n     */\n    function commit(bytes32 _commitment) external onlyTrusted duringVotePhase {\n        commitments[msg.sender] = _commitment;\n        emit VoteCommit(msg.sender, getCurrentCycle());\n    }\n\n    /** signal abstainment to the protocol\n     * does not count as a vote (cannot be revealed to record positive participation for a reward)\n     * signals the abstainment with an event\n     * due to a small quirk, forgetting to reveal your vote in the previous round requires you to first call commit with zero data\n     */\n    function abstain() external onlyTrusted duringVotePhase {\n        if (commitments[msg.sender] != bytes32(0)) {\n            revert NoAbstainWithCommit();\n        }\n        emit Abstain(msg.sender, getCurrentCycle());\n    }\n\n    /** reveal a committed vote\n     * this function allows trustees to reveal their previously committed votes once the reveal phase is entered\n     * in revealing the vote, votes are tallied, a running tally of each proposal's votes is kept in storage during this phase\n     * @param _trustee the trustee's commit to try and reveal\n     * trustees can obviously reveal their own commits, but this allows for a delegated reveal\n     * the commit structure means that only the correct committed vote can ever be revealed, no matter who reveals it\n     * reveals are attributed to this trustee\n     * @param _salt the salt for the commit hash to make the vote secret\n     * @param _votes the array of Vote objects { bytes32 proposal, uint256 ranking } that follows our modified Borda scheme. The votes need to be arranged in ascending order of address and ranked via the integers 1 to the number of proposals ranked.\n     */\n    function reveal(\n        address _trustee,\n        bytes32 _salt,\n        Vote[] calldata _votes\n    ) external duringRevealPhase {\n        uint256 _cycle = getCurrentCycle();\n        uint256 numVotes = _votes.length;\n        if (numVotes == 0) {\n            revert CannotVoteEmpty();\n        }\n        if (\n            keccak256(abi.encode(_salt, _cycle, _trustee, _votes)) !=\n            commitments[_trustee]\n        ) {\n            revert CommitMismatch();\n        }\n\n        // an easy way to prevent double counting votes\n        delete commitments[_trustee];\n\n        // use memory vars to store and track the changes of the leader\n        bytes32 priorLeader = leader;\n        if (priorLeader != 0) {\n            // Check if this is a leader from a past cycle that was never enacted\n            if (\n                priorLeader != bytes32(_cycle) &&\n                proposals[priorLeader].cycle != _cycle\n            ) {\n                delete participation;\n                delete leader;\n                priorLeader = 0;\n            }\n        }\n\n        bytes32 leaderTracker = priorLeader;\n        uint256 leaderRankTracker = 0;\n\n        participation += 1;\n        if (participation == quorum) {\n            emit QuorumReached();\n        }\n\n        /**\n         * this variable is a bitmap to check that the scores in the ballot are correct\n         */\n        uint256 scoreDuplicateCheck = 0;\n\n        uint256 i = 0;\n        Vote calldata firstV = _votes[0];\n        bytes32 firstProposalId = firstV.proposalId;\n        // the default proposal will be first every time as its identifier has so many leading zeros that the likelyhood of a proposalId having more leading zeros is astronomically small\n        if (firstProposalId == bytes32(_cycle)) {\n            uint256 firstScore = firstV.score;\n            uint256 _support = proposals[firstProposalId].support + 1; // default proposal has one more support than recorded in storage\n            if (_support > firstScore) {\n                revert InvalidVoteBadScore(firstV);\n            }\n            // the only bad score for the duplicate check is out of bounds\n            if (firstScore > 255) {\n                revert InvalidVoteBadScore(firstV);\n            }\n            scoreDuplicateCheck +=\n                (2 ** _support - 1) <<\n                (firstScore - _support);\n            scores[firstProposalId] += firstScore;\n            // can simplify the leader rank tracker check because we know it's the first element\n            if (scores[firstProposalId] >= scores[leaderTracker]) {\n                leaderTracker = firstProposalId;\n                leaderRankTracker = firstScore;\n            }\n\n            // make sure to skip the first element in the following loop as it has already been handled\n            ++i;\n        }\n\n        for (; i < numVotes; ++i) {\n            Vote calldata v = _votes[i];\n            bytes32 _proposalId = v.proposalId;\n            uint256 _score = v.score;\n            MonetaryPolicy storage p = proposals[_proposalId];\n\n            if (p.cycle != _cycle) {\n                revert InvalidVoteBadProposalId(v);\n            }\n            if (i != 0 && _votes[i - 1].proposalId >= _proposalId) {\n                revert InvalidVoteBadProposalOrder(_votes[i - 1], v);\n            }\n\n            uint256 _support = p.support;\n            if (_support > _score) {\n                revert InvalidVoteBadScore(v);\n            }\n            if (_score > 255) {\n                revert InvalidVoteBadScore(v);\n            }\n            uint256 duplicateCompare = (2 ** _support - 1) <<\n                (_score - _support);\n\n            if (scoreDuplicateCheck & duplicateCompare > 0) {\n                revert InvalidVoteBadScore(v);\n            }\n\n            scoreDuplicateCheck += duplicateCompare;\n\n            // now that the scores have been ensured to respect supporting, the previous leader calculation method is still valid\n            scores[_proposalId] += _score;\n            if (scores[_proposalId] > scores[leaderTracker]) {\n                leaderTracker = _proposalId;\n                leaderRankTracker = _score;\n            } else if (scores[_proposalId] == scores[leaderTracker]) {\n                if (_score > leaderRankTracker) {\n                    leaderTracker = _proposalId;\n                    leaderRankTracker = _score;\n                }\n            }\n        }\n\n        // this check afterward is very important to understand\n        // it makes sure that the votes have been sequentially increasing and have been respecting the support values of each proposal\n        // the only way this check succeeds is if scoreDuplicate check is of the form 1111111111etc in its binary representation after all the votes from the ballot are in\n        if (scoreDuplicateCheck & (scoreDuplicateCheck + 1) > 0) {\n            revert InvalidVotesOutOfBounds();\n        }\n\n        // only changes the leader if the new leader is of greater score\n        if (\n            leaderTracker != priorLeader &&\n            scores[leaderTracker] > scores[priorLeader]\n        ) {\n            leader = leaderTracker;\n        }\n\n        // record the trustee's vote for compensation purposes\n        trustedNodes.recordVote(_trustee);\n\n        emit VoteReveal(_trustee, _cycle, _votes);\n    }\n\n    /** send the results to the adapter for enaction\n     */\n    function enact() external duringProposePhase {\n        uint256 _cycle = getCurrentCycle() - 1;\n        uint256 _participation = participation;\n        if (\n            _participation < quorum &&\n            _participation < trustedNodes.numTrustees()\n        ) {\n            revert QuorumNotMet();\n        }\n        bytes32 _leader = leader;\n\n        // this ensures that this function can only be called maximum once per winning MP\n        delete leader;\n        // clear this variable to reset for next cycle\n        delete participation;\n\n        // the default proposal doesn't do anything\n        if (_leader == bytes32(_cycle)) {\n            emit VoteResult(_cycle, _leader); // included for completionist's sake, will likely never be called\n            return;\n        }\n\n        MonetaryPolicy storage _winner = proposals[_leader];\n\n        if (_winner.cycle != _cycle) {\n            revert EnactCycleNotCurrent();\n        }\n\n        enacter.enact(\n            _leader,\n            _winner.targets,\n            _winner.signatures,\n            _winner.calldatas\n        );\n\n        emit VoteResult(_cycle, _leader); // will not be emittable if enact cannot be called without reverting (downstream error)\n    }\n}\n"
      },
      "contracts/governance/monetary/MonetaryPolicyAdapter.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policed.sol\";\nimport \"../../policy/Policy.sol\";\nimport \"./CurrencyGovernance.sol\";\n\n/**\n * @title Contract for managing permissions between currency governance and monetary policy levers\n * @notice This contract enacts the results of the currency governance\n * Its goal is to act as a long term address to pemission to allow execution of trustee governance and as a long term reference for event indexing of the results\n * This module can be replaced, but it eases the difficulty of the potentially more frequent changes to the CurrencyGovernance contract\n */\ncontract MonetaryPolicyAdapter is Policed {\n    CurrencyGovernance public currencyGovernance;\n\n    // If the currencyGovernance address is set to zero, the contract is unrecoverably ungovernable\n    error NonZeroCurrencyGovernanceAddr();\n\n    // For if a non-currencyGovernance address tries to access currencyGovernance role gated functionality\n    error CurrencyGovernanceOnlyFunction();\n\n    /**\n     * error for when a part of enacting a policy reverts\n     */\n    error FailedPolicy();\n\n    /**\n     * emits when the currencyGovernance contract is changed\n     * @param newCurrencyGovernance denotes the new currencyGovernance contract address\n     * @param oldCurrencyGovernance denotes the old currencyGovernance contract address\n     */\n    event NewCurrencyGovernance(\n        CurrencyGovernance newCurrencyGovernance,\n        CurrencyGovernance oldCurrencyGovernance\n    );\n\n    /**\n     * emits when enaction happens to keep record of enaction\n     * @param proposalId the proposal lookup that got successfully enacted\n     * @param currencyGovernance the CurrencyGovernance contract where you can look up the proposal calldata\n     */\n    event EnactedMonetaryPolicy(\n        bytes32 proposalId,\n        CurrencyGovernance currencyGovernance\n    );\n\n    /** Restrict method access to the root policy instance only.\n     */\n    modifier onlyCurrencyGovernance() {\n        if (msg.sender != address(currencyGovernance)) {\n            revert CurrencyGovernanceOnlyFunction();\n        }\n        _;\n    }\n\n    constructor(Policy _policy) Policed(_policy) {}\n\n    /** setter function for currencyGovernance var\n     * only available to the owning policy contract\n     * @param _currencyGovernance the value to set the new currencyGovernance address to, cannot be zero\n     */\n    function setCurrencyGovernance(\n        CurrencyGovernance _currencyGovernance\n    ) public onlyPolicy {\n        emit NewCurrencyGovernance(_currencyGovernance, currencyGovernance);\n        _setCurrencyGovernance(_currencyGovernance);\n    }\n\n    function _setCurrencyGovernance(\n        CurrencyGovernance _currencyGovernance\n    ) internal {\n        if (address(_currencyGovernance) == address(0)) {\n            revert NonZeroCurrencyGovernanceAddr();\n        }\n        currencyGovernance = _currencyGovernance;\n    }\n\n    function enact(\n        bytes32 proposalId,\n        address[] calldata targets,\n        bytes4[] calldata signatures,\n        bytes[] memory calldatas\n    ) external virtual onlyCurrencyGovernance {\n        // the array lengths have all been vetted already by the proposal-making process\n        // upstream is just trusted\n        for (uint256 i = 0; i < targets.length; ++i) {\n            (bool success, bytes memory returnData) = targets[i].call(\n                abi.encodePacked(signatures[i], calldatas[i])\n            );\n\n            // we might not actually need to fail gracefully, lets consider if reverting here is just fine\n            if (!success) {\n                revert FailedPolicy();\n            }\n        }\n\n        emit EnactedMonetaryPolicy(proposalId, currencyGovernance);\n    }\n}\n"
      },
      "contracts/governance/monetary/TrustedNodes.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../policy/Policed.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"../../utils/TimeUtils.sol\";\nimport \"./CurrencyGovernance.sol\";\n\n/**\n * @title TrustedNodes\n * @notice A registry of trusted nodes. Trusted nodes (trustees) are able to vote\n * on monetary policy and can only be added or removed using community\n * governance.\n *\n */\ncontract TrustedNodes is Policed, TimeUtils {\n    uint256 public constant GENERATION_TIME = 14 days;\n\n    uint256 public immutable termStart;\n\n    uint256 public immutable termEnd;\n\n    /** address with the currencyGovernance role */\n    CurrencyGovernance public currencyGovernance;\n\n    ECOx public immutable ecoX;\n\n    mapping(address => uint256) public trusteeNumbers;\n\n    address[] public trustees;\n\n    /** voting record of each trustee\n     */\n    mapping(address => uint256) public votingRecord;\n\n    /** timestamp of last withdrawal\n     */\n    mapping(address => uint256) private lastWithdrawals;\n\n    /** reward earned per completed and revealed vote\n     */\n    uint256 public immutable voteReward;\n\n    // error for functions gated only to the currency governance contract\n    error GovernanceOnlyFunction();\n\n    /** Redundant node trusting error\n     * error for when an already trusted node tries to be trusted again\n     * @param trusteeNumber the existing trustee number for the address\n     */\n    error NodeAlreadyTrusted(uint256 trusteeNumber);\n\n    // error for when distrust is called but the address is already not trusted\n    error DistrustNotTrusted();\n\n    // error for when action is taken outside of the trustee term\n    error InactiveTerm();\n\n    // error for when withdraw is called but no tokens have been earned to withdraw\n    error WithdrawNoTokens();\n\n    /** Event emitted when a node added to a list of trusted nodes.\n     * @param trustee the trustee being added\n     */\n    event TrustedNodeAddition(address indexed trustee);\n\n    /** Event emitted when a node removed from a list of trusted nodes\n     * @param trustee the trustee being removed\n     */\n    event TrustedNodeRemoval(address indexed trustee);\n\n    /** Event emitted when a node removed from a list of trusted nodes\n     * @param trustee the trustee whose vote was recorded\n     * @param newVotingRecord the new voting record for the trustee\n     */\n    event VoteRecorded(address indexed trustee, uint256 newVotingRecord);\n\n    /** Event emitted when voting rewards are redeemed\n     * @param recipient the address redeeming the rewards\n     * @param amount the amount being redeemed\n     */\n    event VotingRewardRedemption(address indexed recipient, uint256 amount);\n\n    /** Event emitted when the currencyGovernance role changes\n     * @param newRoleHolder the new holder of the currencyGovernance role\n     */\n    event CurrencyGovernanceChanged(address newRoleHolder);\n\n    modifier onlyCurrencyGovernance() {\n        if (msg.sender != address(currencyGovernance)) {\n            revert GovernanceOnlyFunction();\n        }\n        _;\n    }\n\n    /** Creates a new trusted node registry, populated with some initial nodes\n     * @param _policy the address of the root policy contract\n     * @param _currencyGovernance the address of the currencyGovernance contract\n     * @param _ecoX the address of the EcoX contract\n     * @param _termStart the start time of the trustee term\n     * @param _termLength the length of the trustee term\n     * @param _voteReward the reward awarded to a trustee for each successfully revealed vote\n     * @param _initialTrustees the initial cohort of trustees\n     */\n    constructor(\n        Policy _policy,\n        CurrencyGovernance _currencyGovernance,\n        ECOx _ecoX,\n        uint256 _termStart,\n        uint256 _termLength,\n        uint256 _voteReward,\n        address[] memory _initialTrustees\n    ) Policed(_policy) {\n        currencyGovernance = _currencyGovernance;\n        ecoX = _ecoX;\n        termStart = _termStart;\n        termEnd = termStart + _termLength;\n        voteReward = _voteReward;\n        uint256 _numTrustees = _initialTrustees.length;\n        for (uint256 i = 0; i < _numTrustees; ++i) {\n            _trust(_initialTrustees[i]);\n        }\n    }\n\n    function getTrustees() public view returns (address[] memory _trustees) {\n        return trustees;\n    }\n\n    /** Fetches the date of a trustee's last withdrawal\n     * @param trustee the trustee whose last withdrawal date is being fetched\n     * @return time the date of a trustee's last withdrawal\n     */\n    function getLastWithdrawal(\n        address trustee\n    ) internal view returns (uint256 time) {\n        return termEnd + lastWithdrawals[trustee];\n    }\n\n    /** Changes the holder currencyGovernance role\n     * @param _currencyGovernance the new currencyGovernance role holder\n     */\n    function updateCurrencyGovernance(\n        CurrencyGovernance _currencyGovernance\n    ) public onlyPolicy {\n        currencyGovernance = _currencyGovernance;\n        emit CurrencyGovernanceChanged(address(_currencyGovernance));\n    }\n\n    /** Grant trust to a node.\n     *\n     * The node is pushed to trustedNodes array.\n     *\n     * @param _node The node to start trusting.\n     */\n    function trust(address _node) external onlyPolicy {\n        _trust(_node);\n    }\n\n    /** Helper for trust\n     * @param _node The node to start trusting\n     */\n    function _trust(address _node) internal {\n        if (isTrusted(_node)) {\n            revert NodeAlreadyTrusted(trusteeNumbers[_node]);\n        }\n        trustees.push(_node);\n        trusteeNumbers[_node] = trustees.length;\n        emit TrustedNodeAddition(_node);\n    }\n\n    /** Removes a trustee from the set\n     * THIS FUNCTION CAN AND WILL DISRUPT THE CURRENCY GOVERNANCE CYCLE IF CALLED DURING THE WRONG TIME\n     * Try not to call this function during the commit or reveal part of the cycle in a way that interrupts the distrusted trustee\n     *\n     * Node to distrust swaped to be a last element in the trustedNodes, then deleted\n     * @param _node The trustee to be removed\n     */\n    function distrust(address _node) external onlyPolicy {\n        if (!isTrusted(_node)) {\n            revert DistrustNotTrusted();\n        }\n\n        uint256 lastIndex = trustees.length - 1;\n        uint256 trusteeIndex = trusteeNumbers[_node] - 1;\n        if (trusteeIndex != lastIndex) {\n            address lastNode = trustees[lastIndex];\n            trustees[trusteeIndex] = lastNode;\n            trusteeNumbers[lastNode] = trusteeIndex + 1;\n        }\n        delete trusteeNumbers[_node];\n        trustees.pop();\n        emit TrustedNodeRemoval(_node);\n    }\n\n    /** Incements the counter when the trustee reveals their vote\n     * @param _who address whose vote is being recorded\n     */\n    function recordVote(address _who) external onlyCurrencyGovernance {\n        uint256 time = getTime();\n        if (time > termStart) {\n            ++votingRecord[_who];\n            emit VoteRecorded(_who, votingRecord[_who]);\n        } else {\n            revert InactiveTerm();\n        }\n    }\n\n    /** Return the number of entries in trustedNodes array.\n     */\n    function numTrustees() external view returns (uint256) {\n        return trustees.length;\n    }\n\n    /** Checks if a node address is trusted in the current cohort\n     * @param _node the address whose trustee status we want to check\n     */\n    function isTrusted(address _node) public view returns (bool) {\n        return trusteeNumbers[_node] > 0;\n    }\n\n    /** withdraws everything that can be withdrawn\n     */\n    function withdraw() public {\n        uint256 numWithdrawals = calculateWithdrawal(msg.sender);\n        if (numWithdrawals == 0) {\n            revert WithdrawNoTokens();\n        }\n        uint256 toWithdraw = numWithdrawals * voteReward;\n        lastWithdrawals[msg.sender] += numWithdrawals * GENERATION_TIME;\n        votingRecord[msg.sender] -= numWithdrawals;\n\n        if (!ecoX.transfer(msg.sender, toWithdraw)) {\n            revert ECOx.TransferFailed();\n        }\n        emit VotingRewardRedemption(msg.sender, toWithdraw);\n    }\n\n    /** returns the amount of tokens that are currently withdrawable\n     * @return amount  the amount of tokens that are currently withdrawable\n     */\n    function currentlyWithdrawable() public view returns (uint256 amount) {\n        return voteReward * calculateWithdrawal(msg.sender);\n    }\n\n    /** helper for withdraw\n     * @param withdrawer the addres fo the withdrawer\n     * @return amount the amount of withdrawals for the withdrawer\n     */\n    function calculateWithdrawal(\n        address withdrawer\n    ) internal view returns (uint256 amount) {\n        uint256 timeNow = getTime();\n        if (timeNow < termEnd) {\n            return 0;\n        }\n\n        uint256 lastWithdrawal = getLastWithdrawal(withdrawer);\n        uint256 limit = (timeNow - lastWithdrawal) / GENERATION_TIME;\n        uint256 numWithdrawals = limit > votingRecord[withdrawer]\n            ? votingRecord[withdrawer]\n            : limit;\n        return numWithdrawals;\n    }\n\n    /** returns the number of tokens the sender is currently entitled to\n     * which they will be able to withdraw upon vesting\n     * @return amount the amount of tokens the message sender will be entitled to when fully vested\n     * @return timestamp the timestamp when the message sender will be fully vested\n     */\n    function fullyVested()\n        public\n        view\n        returns (uint256 amount, uint256 timestamp)\n    {\n        uint256 record = votingRecord[msg.sender];\n        return (record * voteReward, termEnd + record * GENERATION_TIME);\n    }\n\n    /** drains all the ECOx in TrustedNodes to a recipient address\n     * @param recipient the address to receive the ECOx\n     */\n    function sweep(address recipient, uint256 amount) public onlyPolicy {\n        if (!ecoX.transfer(recipient, amount)) {\n            revert ECOx.TransferFailed();\n        }\n    }\n}\n"
      },
      "contracts/policy/Policed.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./Policy.sol\";\n\n/**\n * @title Policed Contracts\n * @notice A policed contract is any contract managed by a policy.\n */\nabstract contract Policed {\n    /** The address of the root policy instance overseeing this instance.\n     */\n    Policy public immutable policy;\n\n    /** If the policy address is set to zero, the contract is unrecoverably ungovernable\n     */\n    error NonZeroPolicyAddr();\n\n    /**\n     * If this address is set to zero the contract is an unusable state\n     * @param contractName the name of the contract that was given as the zero address\n     */\n    error NonZeroContractAddr(string contractName);\n\n    /** For if a non-policy address tries to access policy role gated functionality\n     */\n    error PolicyOnlyFunction();\n\n    /** Restrict method access to the root policy instance only.\n     */\n    modifier onlyPolicy() {\n        if (msg.sender != address(policy)) {\n            revert PolicyOnlyFunction();\n        }\n        _;\n    }\n\n    /** constructor\n     * @param _policy the address of the owning policy contract\n     */\n    constructor(Policy _policy) {\n        // _setPolicy(_policy);\n        if (address(_policy) == address(0)) {\n            revert NonZeroPolicyAddr();\n        }\n        policy = _policy;\n    }\n}\n"
      },
      "contracts/policy/PolicedUpgradeable.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"./Policed.sol\";\n\n/** @title Policed Proxy Contracts\n *\n * A PolicedUpgradeable contract is any proxied contract managed by a policy.\n */\nabstract contract PolicedUpgradeable is Policed, ForwardTarget {\n    // storage gap covers PolicedUtils.expectedInterfaceSet\n    // relevant for ECOxStaking\n    uint256 private __gapPolicedUpgradeable;\n\n    function setImplementation(address _impl) public onlyPolicy {\n        _setImplementation(_impl);\n    }\n}\n"
      },
      "contracts/policy/Policy.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../proxy/ForwardTarget.sol\";\n\n/**\n * @title The policy contract that oversees other contracts\n * @notice Policy contracts provide a mechanism for building pluggable (after deploy)\n * governance systems for other contracts.\n */\ncontract Policy is ForwardTarget {\n    uint256 private __gapPolicy; // to cover setters mapping\n\n    /**\n     * the contract allowed enact proposals\n     */\n    address public governor;\n\n    /**\n     * error for when an address tries submit proposal actions without permission\n     */\n    error OnlyGovernor();\n\n    /**\n     * error for when an address tries to call a pseudo-internal function\n     */\n    error OnlySelf();\n\n    /**\n     * for when a part of enacting a proposal reverts without a readable error\n     * @param proposal the proposal address that got reverted during enaction\n     */\n    error FailedProposal(address proposal);\n\n    /**\n     * emits when the governor permissions are changed\n     * @param oldGovernor denotes the old address whose permissions are being removed\n     * @param newGovernor denotes the new address whose permissions are being added\n     */\n    event UpdatedGovernor(address oldGovernor, address newGovernor);\n\n    /**\n     * emits when enaction happens to keep record of enaction\n     * @param proposal the proposal address that got successfully enacted\n     * @param governor the contract which was the source of the proposal, source for looking up the calldata\n     */\n    event EnactedGovernanceProposal(address proposal, address governor);\n\n    /**\n     * Modifier for checking if the sender is a governor\n     */\n    modifier onlyGovernorRole() {\n        if (msg.sender != governor) {\n            revert OnlyGovernor();\n        }\n        _;\n    }\n\n    /**\n     * Modifier for faux internal calls\n     * needed for function to be called only during delegate call\n     */\n    modifier onlySelf() {\n        if (msg.sender != address(this)) {\n            revert OnlySelf();\n        }\n        _;\n    }\n\n    constructor(address _governor) {\n        governor = _governor;\n    }\n\n    /**\n     * initializes the governor\n     */\n    function initialize(\n        address _self\n    ) public virtual override onlyConstruction {\n        super.initialize(_self);\n\n        governor = Policy(_self).governor();\n    }\n\n    /**\n     * pass the governance permissions to another address\n     * @param _newGovernor the address to make the new governor\n     */\n    function updateGovernor(address _newGovernor) public onlySelf {\n        emit UpdatedGovernor(governor, _newGovernor);\n        governor = _newGovernor;\n    }\n\n    function enact(address proposal) external virtual onlyGovernorRole {\n        // solhint-disable-next-line avoid-low-level-calls\n        (bool _success, bytes memory returndata) = proposal.delegatecall(\n            abi.encodeWithSignature(\"enacted(address)\", proposal)\n        );\n        if (!_success) {\n            if (returndata.length == 0) revert FailedProposal(proposal);\n            assembly {\n                revert(add(32, returndata), mload(returndata))\n            }\n        }\n\n        emit EnactedGovernanceProposal(proposal, msg.sender);\n    }\n\n    // function required for backwards compatability of the contract interface to allow for the old governance execution call to complete\n    function removeSelf(bytes32) external {}\n}\n"
      },
      "contracts/proxy/ForwardTarget.sol": {
        "content": "/* -*- c-basic-offset: 4 -*- */\n// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/* solhint-disable no-inline-assembly */\n\n/**\n * @title Target for ForwardProxy and EcoInitializable\n */\nabstract contract ForwardTarget {\n    // Must match definition in ForwardProxy\n    // keccak256(\"com.eco.ForwardProxy.target\")\n    uint256 private constant IMPLEMENTATION_SLOT =\n        0xf86c915dad5894faca0dfa067c58fdf4307406d255ed0a65db394f82b77f53d4;\n\n    modifier onlyConstruction() {\n        require(\n            implementation() == address(0),\n            \"Can only be called during initialization\"\n        );\n        _;\n    }\n\n    constructor() {\n        _setImplementation(address(this));\n    }\n\n    /** Storage initialization of cloned contract\n     *\n     * This is used to initialize the storage of the forwarded contract, and\n     * should (typically) copy or repeat any work that would normally be\n     * done in the constructor of the proxied contract.\n     *\n     * Implementations of ForwardTarget should override this function,\n     * and chain to super.initialize(_self).\n     *\n     * @param _self The address of the original contract instance (the one being\n     *              forwarded to).\n     */\n    function initialize(address _self) public virtual onlyConstruction {\n        address _implAddress = address(ForwardTarget(_self).implementation());\n        require(\n            _implAddress != address(0),\n            \"initialization failure: nothing to implement\"\n        );\n        _setImplementation(_implAddress);\n    }\n\n    /** Get the address of the proxy target contract.\n     */\n    function implementation() public view returns (address _impl) {\n        assembly {\n            _impl := sload(IMPLEMENTATION_SLOT)\n        }\n    }\n\n    /** Set new implementation */\n    function _setImplementation(address _impl) internal {\n        require(implementation() != _impl, \"Implementation already matching\");\n        assembly {\n            sstore(IMPLEMENTATION_SLOT, _impl)\n        }\n    }\n}\n"
      },
      "contracts/test/deploy/NoMonetaryMigrationLinker.propo.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"../../governance/community/proposals/Proposal.sol\";\nimport \"../../policy/Policy.sol\";\nimport \"../../currency/ECO.sol\";\nimport \"../../currency/ECOx.sol\";\nimport \"../../currency/ECOxExchange.sol\";\nimport \"../../governance/community/CommunityGovernance.sol\";\nimport {Policed as PolicedOld} from \"@helix-foundation/currency-dev/contracts/policy/Policed.sol\";\nimport {ECO as ECOOld} from \"@helix-foundation/currency-dev/contracts/currency/ECO.sol\";\nimport {ImplementationUpdatingTarget} from \"@helix-foundation/currency-dev/contracts/test/ImplementationUpdatingTarget.sol\";\n\n/** @title Migration Proposal\n *\n * A proposal used to update the 1.0 proxies and link upwards permissions for all necessary contracts\n */\ncontract NoMonetaryMigrationLinker is Policy, Proposal {\n    address public immutable newEcoImpl;\n\n    address public immutable ecoProxyAddress;\n\n    address public immutable newEcoxImpl;\n\n    address public immutable ecoxProxyAddress;\n\n    address public immutable newEcoxStakingImpl;\n\n    address public immutable ecoXStakingProxyAddress;\n\n    CommunityGovernance public immutable communityGovernance;\n\n    ECOxExchange public immutable ecoXExchange;\n\n    address public immutable newPolicyImpl;\n\n    /** The address of the updating contract for proxies\n     */\n    address public immutable implementationUpdatingTarget;\n\n    /** The address of the updating contract for inflationMultiplier\n     */\n    address public immutable snapshotUpdatingTarget;\n\n    constructor(\n        CommunityGovernance _communityGovernance,\n        ECOxExchange _ecoXExchange,\n        address _newPolicyImpl,\n        address _newEcoImpl,\n        address _newEcoxImpl,\n        address _newEcoxStakingImpl,\n        address _implementationUpdatingTarget,\n        address _snapshotUpdatingTarget\n    ) Policy(address(0x0)) {\n        communityGovernance = _communityGovernance;\n        ecoXExchange = _ecoXExchange;\n\n        newPolicyImpl = _newPolicyImpl;\n        newEcoImpl = _newEcoImpl;\n        newEcoxImpl = _newEcoxImpl;\n        newEcoxStakingImpl = _newEcoxStakingImpl;\n        implementationUpdatingTarget = _implementationUpdatingTarget;\n        snapshotUpdatingTarget = _snapshotUpdatingTarget;\n\n        ecoProxyAddress = address(_ecoXExchange.eco());\n        ecoxProxyAddress = address(_ecoXExchange.ecox());\n        ecoXStakingProxyAddress = address(communityGovernance.ecoXStaking());\n    }\n\n    /** The name of the proposal.\n     */\n    function name() public pure override returns (string memory) {\n        return \"Eco Protocol Migrator and Linker\";\n    }\n\n    /** A description of what the proposal does.\n     */\n    function description() public pure override returns (string memory) {\n        return \"Update 1.0 proxies and add role permissions\";\n    }\n\n    /** A URL for more information.\n     */\n    function url() public pure override returns (string memory) {\n        return \"n/a\";\n    }\n\n    /** Enact the proposal.\n     */\n    function enacted(address) public override {\n        // update root policy\n        (bool success, bytes memory returnedData) = implementationUpdatingTarget\n            .delegatecall(\n                abi.encodeWithSelector(\n                    ImplementationUpdatingTarget.updateImplementation.selector,\n                    newPolicyImpl\n                )\n            );\n\n        if (!success) {\n            revert(string(returnedData));\n        }\n\n        // add new governance permissions\n        this.updateGovernor(address(communityGovernance));\n\n        // get old inflation multiplier\n        uint256 _inflationMultiplier = ECOOld(ecoProxyAddress)\n            .getPastLinearInflation(block.number);\n\n        // give eco the new multiplier\n        PolicedOld(ecoProxyAddress).policyCommand(\n            snapshotUpdatingTarget,\n            abi.encodeWithSignature(\n                \"setInflationMultiplier(uint256)\",\n                _inflationMultiplier\n            )\n        );\n\n        // propogate total supply snapshots in eco and ecox\n        PolicedOld(ecoProxyAddress).policyCommand(\n            snapshotUpdatingTarget,\n            abi.encodeWithSignature(\"setTotalSupplySnapshot()\")\n        );\n\n        PolicedOld(ecoxProxyAddress).policyCommand(\n            snapshotUpdatingTarget,\n            abi.encodeWithSignature(\"setTotalSupplySnapshot()\")\n        );\n\n        // update ecox\n        PolicedOld(ecoxProxyAddress).policyCommand(\n            implementationUpdatingTarget,\n            abi.encodeWithSignature(\n                \"updateImplementation(address)\",\n                newEcoxImpl\n            )\n        );\n\n        // link ecox\n        ECOx(ecoxProxyAddress).updateBurners(address(ecoXExchange), true);\n\n        // update eco\n        PolicedOld(ecoProxyAddress).policyCommand(\n            implementationUpdatingTarget,\n            abi.encodeWithSignature(\"updateImplementation(address)\", newEcoImpl)\n        );\n\n        // link eco\n        ECO(ecoProxyAddress).updateMinters(address(ecoXExchange), true);\n        ECO(ecoProxyAddress).updateSnapshotters(\n            address(communityGovernance),\n            true\n        );\n\n        // link ecox\n        ECOx(ecoxProxyAddress).updateSnapshotters(\n            address(communityGovernance),\n            true\n        );\n\n        // perform eco initialization\n        ECO(ecoProxyAddress).updateRebasers(address(this), true);\n        ECO(ecoProxyAddress).rebase(\n            ECO(ecoProxyAddress).INITIAL_INFLATION_MULTIPLIER()\n        );\n        ECO(ecoProxyAddress).updateRebasers(address(this), false);\n        ECO(ecoProxyAddress).updateSnapshotters(address(this), true);\n        ECO(ecoProxyAddress).snapshot();\n        ECO(ecoProxyAddress).updateSnapshotters(address(this), false);\n\n        // perform ecox initialization\n        ECOx(ecoxProxyAddress).updateSnapshotters(address(this), true);\n        ECOx(ecoxProxyAddress).snapshot();\n        ECOx(ecoxProxyAddress).updateSnapshotters(address(this), false);\n\n        // update ecoXStaking\n        PolicedOld(ecoXStakingProxyAddress).policyCommand(\n            implementationUpdatingTarget,\n            abi.encodeWithSignature(\n                \"updateImplementation(address)\",\n                newEcoxStakingImpl\n            )\n        );\n    }\n}\n"
      },
      "contracts/utils/StringPacker.sol": {
        "content": "// SPDX-License-Identifier: MIT\n\npragma solidity ^0.8.0;\n\n// might not need this\n\nlibrary StringPacker {\n    // takes a string of 31 or less characters and converts it to bytes32\n    function pack(\n        string memory unpacked\n    ) internal pure returns (bytes32 packed) {\n        // do not use this function in a lossy way, it will not work\n        // only strings with 31 or less characters are stored in memory packed with their length value\n        require(bytes(unpacked).length < 32);\n        // shift the memory pointer to pack the length of the string into the high byte\n        // by assigning this to the return value, the type of bytes32 means that, when returning,\n        // the pointer continues to read into the string data\n        assembly {\n            packed := mload(add(unpacked, 31))\n        }\n    }\n\n    // takes a bytes32 packed in the format above and unpacks it into a string\n    function unpack(\n        bytes32 packed\n    ) internal pure returns (string memory unpacked) {\n        // get the high byte which stores the length of the string when unpacked\n        uint256 len = uint256(packed >> 248);\n        // ensure that the length of the unpacked string doesn't read beyond the input value\n        require(len < 32);\n        // initialize the return value with the length\n        unpacked = string(new bytes(len));\n        // shift the pointer so that the length will be at the bottom of the word to match string encoding\n        // then store the packed value\n        assembly {\n            // Potentially writes into unallocated memory as the length in the packed form will trail off the end\n            // This is fine as there are no other relevant memory values to overwrite\n            mstore(add(unpacked, 31), packed)\n        }\n    }\n}\n"
      },
      "contracts/utils/TimeUtils.sol": {
        "content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\n/**\n * @title TimeUtils\n * @notice Utility class for time, allowing easy unit testing.\n */\nabstract contract TimeUtils {\n    /** Determine the current time as perceived by the policy timing contract.\n     *\n     * Used extensively in testing, but also useful in production for\n     * determining what processes can currently be run.\n     * @return blockTimeStamp The current block timestamp\n     */\n    function getTime() internal view returns (uint256 blockTimeStamp) {\n        // solhint-disable-next-line not-rely-on-time\n        return block.timestamp;\n    }\n}\n"
      }
    },
    "settings": {
      "optimizer": {
        "enabled": true,
        "runs": 200
      },
      "outputSelection": {
        "*": {
          "*": [
            "evm.bytecode",
            "evm.deployedBytecode",
            "devdoc",
            "userdoc",
            "metadata",
            "abi"
          ]
        }
      },
      "libraries": {}
    }
  }}