ETH Price: $2,984.68 (+4.31%)
Gas: 2 Gwei

Contract

0x8d01a258bC1ADB728322499E5D84173EA971d665
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
Create Grants Pr...199629892024-05-27 18:27:1139 days ago1716834431IN
0x8d01a258...EA971d665
0 ETH0.003900819.67031361
Sync Proposals199120502024-05-20 15:31:5946 days ago1716219119IN
0x8d01a258...EA971d665
0 ETH0.00178815.87351883
Ratify Or Reject198428752024-05-10 23:19:5956 days ago1715383199IN
0x8d01a258...EA971d665
0 ETH0.000420855.27821022
Create Veto Coun...198346862024-05-09 19:50:3557 days ago1715284235IN
0x8d01a258...EA971d665
0 ETH0.00085234.14920756
Sync Proposals198040022024-05-05 12:50:2361 days ago1714913423IN
0x8d01a258...EA971d665
0 ETH0.000739375.83698578
Sync Proposals197838592024-05-02 17:14:1164 days ago1714670051IN
0x8d01a258...EA971d665
0 ETH0.001740512.44542347
Ratify Or Reject197242192024-04-24 9:02:5972 days ago1713949379IN
0x8d01a258...EA971d665
0 ETH0.0010815813.57262037
Create GCA Counc...196916892024-04-19 19:53:3577 days ago1713556415IN
0x8d01a258...EA971d665
0 ETH0.001538579.66121984
Create GCA Counc...196462112024-04-13 10:59:5983 days ago1713005999IN
0x8d01a258...EA971d665
0 ETH0.0015510410.99181401
Create Grants Pr...196130432024-04-08 19:30:5988 days ago1712604659IN
0x8d01a258...EA971d665
0 ETH0.0059008130.09804289
Create Grants Pr...195850592024-04-04 21:24:5992 days ago1712265899IN
0x8d01a258...EA971d665
0 ETH0.0049125625.07460125
Create Grants Pr...195850252024-04-04 21:18:1192 days ago1712265491IN
0x8d01a258...EA971d665
0 ETH0.0051697926.38351826
Create Grants Pr...195003762024-03-23 22:51:35104 days ago1711234295IN
0x8d01a258...EA971d665
0 ETH0.0030269915.45451207
Create Grants Pr...193994932024-03-09 19:00:59118 days ago1710010859IN
0x8d01a258...EA971d665
0 ETH0.0134773868.86615406
Sync Proposals190564182024-01-21 16:25:23166 days ago1705854323IN
0x8d01a258...EA971d665
0 ETH0.0019509115.12779556
Sync Proposals190138272024-01-15 17:39:23172 days ago1705340363IN
0x8d01a258...EA971d665
0 ETH0.0011230227.49402225
Create Grants Pr...190136352024-01-15 17:00:35172 days ago1705338035IN
0x8d01a258...EA971d665
0 ETH0.0052213626.69382088
Create Grants Pr...190136302024-01-15 16:59:35172 days ago1705337975IN
0x8d01a258...EA971d665
0 ETH0.0049050625.08394482
Create Grants Pr...190136272024-01-15 16:58:59172 days ago1705337939IN
0x8d01a258...EA971d665
0 ETH0.0046240223.64673615
Ratify Or Reject189285182024-01-03 18:08:59184 days ago1704305339IN
0x8d01a258...EA971d665
0 ETH0.0022256327.92901052
Create GCA Counc...188300982023-12-20 22:30:47198 days ago1703111447IN
0x8d01a258...EA971d665
0 ETH0.0086983450.25706471
0x61022060188092332023-12-18 0:13:11201 days ago1702858391IN
 Create: Governance
0 ETH0.2224250541.27620631

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Governance

Compiler Version
v0.8.21+commit.d9974bed

Optimization Enabled:
Yes with 1000000 runs

Other Settings:
paris EvmVersion
File 1 of 27 : Governance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IGovernance} from "@/interfaces/IGovernance.sol";
import {HalfLife} from "@/libraries/HalfLife.sol";
import {ABDKMath64x64} from "@/libraries/ABDKMath64x64.sol";
import {IGlow} from "@/interfaces/IGlow.sol";
import {IVetoCouncil} from "@/interfaces/IVetoCouncil.sol";
import {IGCA} from "@/interfaces/IGCA.sol";
import {IGrantsTreasury} from "@/interfaces/IGrantsTreasury.sol";
import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
import {SignatureChecker} from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import {NULL_ADDRESS} from "@/VetoCouncil/VetoCouncilSalaryHelper.sol";
import {SafeCast} from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import {_BUCKET_DURATION} from "@/Constants/Constants.sol";
/**
 * @title Governance
 * @author DavidVorick
 * @author 0xSimon(twitter) - 0xSimbo(githuhb)
 * @notice This contract is used to manage the Glow governance
 *               - The governance contract is used to manage the Glow protocol
 *               - Proposals are denoted by their types in {ProposalType} enum
 *               - Proposals can be created by anyone and cost nominations
 *               - It should cost (1.1)^n nominations where n = # of active proposals
 *                 - Proposals can be ratified or rejected by long stakers
 *                 - Veto council members can veto proposals (besides elections proposals)
 *                 - Proposals can be executed if they are ratified
 *                     -   RFC Proposals and Grants Proposals don't need to be ratified to be executed
 *                 - Once created, proposals are active for 16 weeks
 *                 - Each week, a most popular proposal is selected
 *                 - Governance also handles rewarding and depreciating nominations
 *                 - Nominations have a half-life of 52 weeks and are earned by committing GCC
 *                 - Nominations are used to create and vote on proposals
 *                 - Nominations are in 12 decimals
 *                      - the equation for calculating nominations is sqrt(amount gcc added to lp * amount usdc added in lp) from a 'commit' event
 *                      - multiplying gcc (18 decimals) and usdc (6 decimals) gives us an output in 24 decimals.
 *                      - since we are sqrt'ing this, we factor out 12 decimals of precision since sqrt(1e24) = 1e12
 *                      - and end up in 12 decimals of precision
 */

contract Governance is IGovernance, EIP712 {
    using ABDKMath64x64 for int128;

    /* -------------------------------------------------------------------------- */
    /*                                  constants                                 */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice  Spend nominations EIP712 Typehash
     */
    bytes32 public constant SPEND_NOMINATIONS_ON_PROPOSAL_TYPEHASH = keccak256(
        "SpendNominationsOnProposal(uint8 proposalType,uint256 nominationsToSpend,uint256 nonce,uint256 deadline,bytes data)"
    );

    /**
     * @dev one in 64x64 fixed point
     */
    int128 private constant ONE_64x64 = (1 << 64);

    /**
     * @dev 1.1 in 128x128 fixed point
     * @dev used in the nomination cost calculation
     */
    int128 private constant ONE_POINT_ONE_128 = (1 << 64) + 0x1999999999999a00;

    /**
     * @dev The maximum duration of a proposal: 16 weeks
     */
    uint256 private constant MAX_PROPOSAL_DURATION = 9676800;

    /**
     *   @dev the maximum number of weeks a proposal can be ratified or rejected
     *      - from the time it it has been finalized (i.e. the week has passed)
     *  For example: If proposal 1 is the most popular proposal for week 2, then it can be ratified or rejected until the end of week 6
     */
    uint256 private constant _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL = 4;

    /**
     * @dev The percentage of ratify to reject votes that is required to execute a proposal
     * @dev exceptions are noted in the implemntation of executeProposalAtWeek
     */
    uint256 private constant DEFAULT_PERCENTAGE_TO_EXECUTE_PROPOSAL = 60; //60%

    /**
     * @dev there can be a maximum of 5 endorsements on a GCA election proposal
     */
    uint256 private constant MAX_ENDORSEMENTS_ON_GCA_PROPOSALS = 5;

    /**
     * @dev the maximum number of GCA council members that can be concurrently active
     */
    uint256 private constant MAX_GCAS_AT_ONE_POINT_IN_TIME = 5;

    /**
     * @dev the maximum number of slashes that can be executed in a single GCA election
     * @dev this is to prevent DoS attacks that could cause the execution to run out of gas
     */
    uint256 private constant MAX_SLASHES_IN_ONE_GCA_ELECTION = 10;

    /**
     * @dev the maximum number of concurrently active GCA council members
     */
    uint256 private constant MAX_GCAS = 5;

    /**
     * @dev each endorsement decreases the required percentage to execute a GCA election proposal by 5%
     */
    uint256 private constant ENDORSEMENT_WEIGHT = 5;

    /* -------------------------------------------------------------------------- */
    /*                                  immutables                                */
    /* -------------------------------------------------------------------------- */

    /**
     * @dev The GCC contract
     */
    address public immutable GCC;

    /**
     * @dev The GCA contract
     */
    address public immutable GCA;

    /**
     * @dev The Genesis Timestamp of the protocol from GLW
     */
    uint256 public immutable GENESIS_TIMESTAMP;

    /**
     * @dev The Veto Council contract
     */
    address public immutable VETO_COUNCIL;

    /**
     * @dev The Grants Treasury contract
     */
    address public immutable GRANTS_TREASURY;

    /**
     * @dev The GLW contract
     */
    address public immutable GLOW;

    /* -------------------------------------------------------------------------- */
    /*                                 state vars                                */
    /* -------------------------------------------------------------------------- */
    /**
     * @dev The total number of proposals created
     * @dev we start at one to ensure that a proposal with id 0 is invalid
     */
    uint256 private _proposalCount = 1;

    /**
     * @notice The last expired proposal id (should not be used for anything other than caching)
     * @dev The last proposal that expired (in storage)
     * @dev this may be out of sync with the actual last expired proposal id
     *      -  it's used as a cache to make _numActiveProposalsAndLastExpiredProposalId() more efficient
     */
    uint256 internal lastExpiredProposalId;

    /**
     * @notice the last executed week (should not be used for anything other than caching)
     * @dev The last proposal that was executed
     * @dev this may be out of sync with the actual last executed proposal id
     * @dev initiaized as type(uint256).max to avoid conflicts which starting checks at week 0
     */
    uint256 internal lastExecutedWeek = type(uint256).max;

    /* -------------------------------------------------------------------------- */
    /*                                   mappings                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice The next nonce of a user to use in a spend nominations on proposal transaction
     * @dev This is used to prevent replay attacks
     */
    mapping(address => uint256) public spendNominationsOnProposalNonce;

    /**
     * @dev proposalId -> _proposalLongStakerVotes
     * @dev long stakers can only vote on proposals that are the most popular proposal for their respective week
     *             - The week must have already passed
     */
    mapping(uint256 => ProposalLongStakerVotes) private _proposalLongStakerVotes;

    /**
     * @dev address -> proposalId -> numVotes
     * @dev long stakers can only vote on proposals that are the most popular proposal for their respective week
     *             - The week must have already passed
     * @dev Users can have as many votes as number of glow staked they have.
     *         -   we need this mapping to prevent double spend.
     *         -   the protocol does not worry about adjusting for unstaked glow
     *             - for example, a user is allowed to stake 100 glw , vote on a proposal, and then unstake 100 glw
     *             - the protocol will not adjust for the unstaked glow
     *             - there is a 5 year cooldown when claiming tokens after unstaking glow so this should not be a problem
     */
    mapping(address => mapping(uint256 => uint256)) public longStakerVotesForProposal;

    /**
     * @dev The nominations of each account
     */
    mapping(address => Nominations) private _nominations;

    /**
     * @dev proposalId -> Proposal
     */
    mapping(uint256 => IGovernance.Proposal) private _proposals;

    /**
     * @notice the most popular proposal of a given week
     * @dev Certain actions such as using nominations will trigger this update for the current week
     * @dev At the start of every new week, there is no mostt popular proposal stored for that week
     *         -  the {setMostPopularProposalForCurrentWeek} or {useNominationsOnProposal} are the only ways to update
     *         - the mostPopularProposalOfWeek
     *         - Governance relies on those functions to be called to correctly set the most popular proposal
     * @dev if neither of the functions mentioned above are called within the week, the week will not contain a most popular proposal
     *        - as it was not explicitly set
     * @dev it is also possible for a proposal that is not actually the most popular to be selected as the most popular proposal for that week
     *         - For example, if it's a new week and Proposal A and Proposal B have 20 and 10 nominations respectively,
     *         - It is possible to set the most popular proposal to Proposal A.
     *         - If {setMostPopularProposalForCurrentWeek} isn't called to set Proposal B as the most popular proposal
     *         - Or if no nominations are used on Proposal B during that week,
     *         - The week will finalize with Proposal A as the most popular proposal for that week even though proposal B had more nominations
     *         - This is not a problem as the {setMostPopularProposalForCurrentWeek} is permissionless
     * @dev updating the mostPopularProposalOfWeek can be manu
     */
    mapping(uint256 => uint256) public mostPopularProposalOfWeek;

    /// @dev The most popular proposal status at a proposal id
    /// @dev since there are only 8 proposal statuses, we can use a uint256 to store the status
    /// @dev each uint256 is 32 bytes, so we can store 32 statuses in a single uint256
    mapping(uint256 => uint256) private _packedProposalStatus;

    /**
     * @notice the number of endorsements on the most popular proposal of a given week
     * @dev only GCA elections can be endorsed
     * @dev only veto council members can endorse a proposal
     * @dev an endorsement represents a 5% drop to the default percentage to execute a proposal
     * @dev the default percentage to execute a proposal is 60%
     * @dev the minimum percentage to execute GCA election proposal is 35%
     *             -  that means there can be a maximumn of 5 endorsements on a GCA election proposal
     */
    mapping(uint256 => uint256) public numEndorsementsOnWeek;

    /**
     * @dev veto council agent -> key -> bitmap
     * @dev one mapping slot holds 256 bits
     *             - each bit represents a week
     *             - if the bit is set, then the veto council agent has vetoed the most popular proposal for that week
     */
    mapping(address => mapping(uint256 => uint256)) private _hasEndorsedProposalBitmap;

    /* -------------------------------------------------------------------------- */
    /*                                   structs                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @param amount the amount of nominations that an account has
     * @param lastUpdate the last time that the account's balance was updated
     *         -   {lastUpdate} is used to calculate the user's balance according to the half-life formula
     *         -   Check {HalfLife.calculateHalfLifeValue} for more details
     */
    struct Nominations {
        uint192 amount;
        uint64 lastUpdate;
    }

    /**
     * @param ratifyVotes - the amount of ratify votes on the proposal
     * @param rejectionVotes - the amount of rejection votes on the proposal
     * @dev only most popular proposals can be voted on
     */
    struct ProposalLongStakerVotes {
        uint128 ratifyVotes;
        uint128 rejectionVotes;
    }

    /* -------------------------------------------------------------------------- */
    /*                                 constructor                                */
    /* -------------------------------------------------------------------------- */

    /**
     * @param gcc - the GCC contract
     * @param gca - the GCA contract
     * @param vetoCouncil - the Veto Council contract
     * @param grantsTreasury - the Grants Treasury contract
     * @param glw - the GLW contract
     */
    constructor(address gcc, address gca, address vetoCouncil, address grantsTreasury, address glw)
        payable
        EIP712("Glow Governance", "1")
    {
        GCC = gcc;
        GCA = gca;
        GENESIS_TIMESTAMP = IGlow(glw).GENESIS_TIMESTAMP();
        VETO_COUNCIL = vetoCouncil;
        GRANTS_TREASURY = grantsTreasury;
        GLOW = glw;
    }

    /* -------------------------------------------------------------------------- */
    /*                               proposal execution                           */
    /* -------------------------------------------------------------------------- */

    /**
     * @inheritdoc IGovernance
     * @dev proposal execution should be sub-100k gas
     */
    function executeProposalAtWeek(uint256 week) public {
        uint256 _nextWeekToExecute = lastExecutedWeek;
        unchecked {
            //We actually want this to overflow since we start at type(uint256).max
            ++_nextWeekToExecute;
        }

        //We need all proposals to be executed synchronously
        if (_nextWeekToExecute != week) {
            _revert(IGovernance.ProposalsMustBeExecutedSynchonously.selector);
        }

        uint256 proposalId = mostPopularProposalOfWeek[week];

        if (!isProposalEligibleForExecution(proposalId)) {
            lastExecutedWeek = week;
            return;
        }

        IGovernance.Proposal memory proposal = _proposals[proposalId];
        IGovernance.ProposalType proposalType = proposal.proposalType;
        ProposalLongStakerVotes memory longStakerVotes = _proposalLongStakerVotes[proposalId];

        //Revert if the ratify/reject period and veto period is not yet ended
        if (block.timestamp < _weekEndTime(week + _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL)) {
            _revert(IGovernance.RatifyOrRejectPeriodNotEnded.selector);
        }

        //If the proposal is a gca election, we can check endorsements to
        //dynamically determine the required percentage to execute the proposal
        //The default percentage to execute a  proposal is 60%
        //The minimum percentage to execute a gca proposal is 35%
        //RFC and Grants Treasury proposals don't need to be ratified to pass
        if (proposalType == IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
            uint256 numEndorsements = numEndorsementsOnWeek[week];
            uint256 requiredWeight = DEFAULT_PERCENTAGE_TO_EXECUTE_PROPOSAL - (numEndorsements * ENDORSEMENT_WEIGHT);
            uint256 totalVotes = longStakerVotes.ratifyVotes + longStakerVotes.rejectionVotes;
            //If no one votes, we don't execute the proposal
            if (totalVotes == 0) {
                lastExecutedWeek = week;
                return;
            }
            uint256 percentage = (longStakerVotes.ratifyVotes * 100) / totalVotes;
            if (percentage < requiredWeight) {
                lastExecutedWeek = week;
                return;
            }
        } else {
            if (
                (
                    proposalType != IGovernance.ProposalType.REQUEST_FOR_COMMENT
                        && proposalType != IGovernance.ProposalType.GRANTS_PROPOSAL
                )
            ) {
                uint256 totalVotes = longStakerVotes.ratifyVotes + longStakerVotes.rejectionVotes;
                if (totalVotes == 0) {
                    lastExecutedWeek = week;
                    return;
                }
                uint256 percentage = (longStakerVotes.ratifyVotes * 100) / totalVotes;
                if (percentage < DEFAULT_PERCENTAGE_TO_EXECUTE_PROPOSAL) {
                    lastExecutedWeek = week;
                    return;
                }
            }
        }

        handleProposalExecution(week, proposalId, proposalType, proposal.data);
        lastExecutedWeek = week;
    }

    /**
     *     Note: Sync proposals should be max 100k gas per proposal
     *     to make sure that users aren't too heavily penalized for
     *     syncing proposals
     */

    /**
     * @inheritdoc IGovernance
     */
    function syncProposals() public {
        uint256 currentWeek = currentWeek();
        if (currentWeek == 0) return;
        uint256 _nextWeekToExecute = lastExecutedWeek;
        unchecked {
            //We actually want this to overflow since we start at type(uint256).max
            ++_nextWeekToExecute;
            //increment current week to not have to <= check, we can just < check in the for loop
            ++currentWeek;
            //we increment up the the current week to make sure that _weekEndTime(_nextWeekToExecute)
            //eventually becomes greater than block.timestamp so we can stop the loop and update state
        }
        for (_nextWeekToExecute; _nextWeekToExecute < currentWeek; ++_nextWeekToExecute) {
            //If the proposal is vetoed, we can skip the execution
            //We still need to update the lastExecutedWeek so the next proposal can be executed
            uint256 proposalId = mostPopularProposalOfWeek[_nextWeekToExecute];
            if (!isProposalEligibleForExecution(proposalId)) {
                continue;
            }

            IGovernance.Proposal memory proposal = _proposals[proposalId];
            IGovernance.ProposalType proposalType = proposal.proposalType;
            ProposalLongStakerVotes memory longStakerVotes = _proposalLongStakerVotes[proposalId];

            //Revert if the ratify/reject and veto period is not yet ended
            if (block.timestamp < _weekEndTime(_nextWeekToExecute + _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL)) {
                lastExecutedWeek = _nextWeekToExecute == 0 ? type(uint256).max : _nextWeekToExecute - 1;
                return;
            }

            //If the proposal is a gca election, we can check endorsements to
            //dynamically determine the required percentage to execute the proposal
            //The default percentage to execute a  proposal is 60%
            //The minimum percentage to execute a gca proposal is 35%
            //RFC and Grants Treasury proposals don't need to be ratified to pass
            if (proposalType == IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
                uint256 numEndorsements = numEndorsementsOnWeek[_nextWeekToExecute];
                uint256 requiredWeight = DEFAULT_PERCENTAGE_TO_EXECUTE_PROPOSAL - (numEndorsements * ENDORSEMENT_WEIGHT);
                uint256 totalVotes = longStakerVotes.ratifyVotes + longStakerVotes.rejectionVotes;
                //If no one votes, we don't execute the proposal
                //This also prevents division by zero error
                if (totalVotes == 0) {
                    continue;
                }
                uint256 percentage = (longStakerVotes.ratifyVotes * 100) / totalVotes;
                if (percentage < requiredWeight) {
                    continue;
                }
            } else {
                if (
                    (
                        proposalType != IGovernance.ProposalType.REQUEST_FOR_COMMENT
                            && proposalType != IGovernance.ProposalType.GRANTS_PROPOSAL
                    )
                ) {
                    uint256 totalVotes = longStakerVotes.ratifyVotes + longStakerVotes.rejectionVotes;
                    //If no one votes, we don't execute the proposal
                    //Prevent division by zero error
                    if (totalVotes == 0) {
                        continue;
                    }
                    uint256 percentage = (longStakerVotes.ratifyVotes * 100) / totalVotes;
                    if (percentage < DEFAULT_PERCENTAGE_TO_EXECUTE_PROPOSAL) {
                        continue;
                    }
                }
            }
            handleProposalExecution(_nextWeekToExecute, proposalId, proposalType, proposal.data);
        }
    }

    /* -------------------------------------------------------------------------- */
    /*                            proposal   endorsement                          */
    /* -------------------------------------------------------------------------- */

    /**
     * @inheritdoc IGovernance
     */
    function endorseGCAProposal(uint256 weekId) external {
        if (!IVetoCouncil(VETO_COUNCIL).isCouncilMember(msg.sender)) {
            _revert(IGovernance.CallerNotVetoCouncilMember.selector);
        }

        uint256 _currentWeek = currentWeek();
        if (weekId >= _currentWeek) {
            _revert(IGovernance.WeekNotStarted.selector);
        }
        //Also make sure it's not already finalized
        uint256 _weekEndTime = _weekEndTime(weekId + _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL);
        if (block.timestamp > _weekEndTime) {
            _revert(IGovernance.RatifyOrRejectPeriodEnded.selector);
        }

        uint256 key = weekId / 256;
        uint256 shift = weekId % 256;
        uint256 existingEndorsementBitmap = _hasEndorsedProposalBitmap[msg.sender][key];
        uint256 bitVal = (1 << shift);
        if (existingEndorsementBitmap & bitVal != 0) {
            _revert(IGovernance.AlreadyEndorsedWeek.selector);
        }
        _hasEndorsedProposalBitmap[msg.sender][key] = existingEndorsementBitmap | bitVal;
        uint256 numEndorsements = numEndorsementsOnWeek[weekId];
        uint256 proposalId = mostPopularProposalOfWeek[weekId];
        IGovernance.ProposalType proposalType = _proposals[proposalId].proposalType;
        if (proposalType != IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
            _revert(IGovernance.OnlyGCAElectionsCanBeEndorsed.selector);
        }

        numEndorsements += 1;
        if (numEndorsements > MAX_ENDORSEMENTS_ON_GCA_PROPOSALS) {
            _revert(IGovernance.MaxGCAEndorsementsReached.selector);
        }

        numEndorsementsOnWeek[weekId] = numEndorsements;
    }

    /* -------------------------------------------------------------------------- */
    /*                              nonce management                              */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Allows a user to increase their nonce
     * - This is in case they set a deadline that is too far in the future
     * - The user can increase their nonce to invalidate the previous signature
     */
    function selfIncrementNonce() external {
        ++spendNominationsOnProposalNonce[msg.sender];
    }

    /* -------------------------------------------------------------------------- */
    /*                                veto proposals                              */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice entrypoint for veto council members to veto a most popular proposal
     * @param weekId - the id of the week to veto the most popular proposal in
     * @param proposalId - the id of the proposal to veto
     */
    function vetoProposal(uint256 weekId, uint256 proposalId) external {
        if (!IVetoCouncil(VETO_COUNCIL).isCouncilMember(msg.sender)) {
            _revert(IGovernance.CallerNotVetoCouncilMember.selector);
        }

        if (mostPopularProposalOfWeek[weekId] != proposalId) {
            _revert(IGovernance.ProposalIdDoesNotMatchMostPopularProposal.selector);
        }

        uint256 _currentWeek = currentWeek();
        if (weekId >= _currentWeek) {
            _revert(IGovernance.WeekNotStarted.selector);
        }
        //Also make sure it's not already finalized
        uint256 _weekEndTime = _weekEndTime(weekId + _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL);
        if (block.timestamp > _weekEndTime) {
            _revert(IGovernance.RatifyOrRejectPeriodEnded.selector);
        }

        ProposalType proposalType = _proposals[proposalId].proposalType;
        //Elections can't be vetoed
        if (proposalType == ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH) {
            _revert(IGovernance.VetoCouncilElectionsCannotBeVetoed.selector);
        }

        if (proposalType == ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
            _revert(IGovernance.GCACouncilElectionsCannotBeVetoed.selector);
        }

        _setProposalStatus(proposalId, IGovernance.ProposalStatus.VETOED);
        emit IGovernance.ProposalVetoed(weekId, msg.sender, proposalId);
    }

    /* -------------------------------------------------------------------------- */
    /*                                 nominations                                */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Entry point for GCC contract to grant nominations to {to} when they retire GCC
     * @param to the address to grant nominations to
     * @param amount the amount of nominations to grant
     * @dev this function is only callable by the GCC contract
     * @dev nominations decay with a half life of 1 year.
     *         -for implementation details check {src/libraries/HalfLife.sol}
     */
    function grantNominations(address to, uint256 amount) external override {
        if (msg.sender != GCC) {
            _revert(IGovernance.CallerNotGCC.selector);
        }
        //Step 1: check their current balance
        Nominations memory n = _nominations[to];
        uint256 currentBalance = HalfLife.calculateHalfLifeValue(n.amount, block.timestamp - n.lastUpdate);
        //Step 2: update their balance
        _nominations[to] = Nominations(SafeCast.toUint192(currentBalance + amount), SafeCast.toUint64(block.timestamp));
        return;
    }

    /**
     * @notice Allows a user to vote on a proposal
     * @param proposalId the id of the proposal
     * @param amount the amount of nominations to vote with
     * @dev also syncs proposals if need be.
     */
    function useNominationsOnProposal(uint256 proposalId, uint256 amount) public {
        //Sync the proposals
        syncProposals();
        //If the proposal has been executed or vetoed, using nominations should revert
        _revertIfProposalExecutedOrVetoed(proposalId);
        //Cache the nomination end timestamp
        uint256 nominationEndTimestamp = _proposals[proposalId].expirationTimestamp;
        // we don't need this check, but we add it for clarity on the revert reason
        if (nominationEndTimestamp == 0) {
            _revert(IGovernance.ProposalDoesNotExist.selector);
        }
        //nomination spend on expired proposals is not allowed
        if (block.timestamp > nominationEndTimestamp) {
            _revert(IGovernance.ProposalExpired.selector);
        }

        //Spend the nominations
        _spendNominations(msg.sender, amount);
        //Get the new total votes
        uint184 newTotalVotes = SafeCast.toUint184(_proposals[proposalId].votes + amount);
        //Update the state of the proposal with the new total votes
        _proposals[proposalId].votes = newTotalVotes;
        //Get teh current week
        uint256 currentWeek = currentWeek();
        //Grab the currently most popular proposal at the current week
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        //If the proposal which nominatiosn are being used on
        //has more nominatiosn than the current most popular proposal
        //we update the most popular proposal to the one on which nominations are being used
        if (proposalId != _mostPopularProposalOfWeek) {
            if (newTotalVotes > _proposals[_mostPopularProposalOfWeek].votes) {
                mostPopularProposalOfWeek[currentWeek] = proposalId;
                emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
            }
        }

        emit IGovernance.NominationsUsedOnProposal(proposalId, msg.sender, amount);
    }

    /* -------------------------------------------------------------------------- */
    /*                         selecting most popular proposal                    */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice sets the proposal as the most popular proposal for the current week
     * @dev checks if the proposal is the most popular proposal for the current week and sets it if it is
     * @dev throws an error if the proposal is not the most popular proposal or if the proposal has expired
     * @param proposalId The ID of the proposal to set as the most popular.
     */
    function setMostPopularProposalForCurrentWeek(uint256 proposalId) external {
        syncProposals();
        _revertIfProposalExecutedOrVetoed(proposalId);
        // get the current week
        uint256 currentWeek = currentWeek();
        // get the most popular proposal for the current week
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        // get the expiration timestamp of the proposal
        uint256 expirationTimestamp = _proposals[proposalId].expirationTimestamp;
        // get the number of votes on the proposal
        uint256 numVotesOnProposal = _proposals[proposalId].votes;
        // check if the proposal has expired
        if (expirationTimestamp < block.timestamp) {
            _revert(IGovernance.ProposalExpired.selector);
        }
        // check if the proposal is already the most popular proposal
        if (proposalId != _mostPopularProposalOfWeek) {
            // check if the number of votes on the proposal is greater than the number of votes on the current most popular proposal
            if (numVotesOnProposal > _proposals[_mostPopularProposalOfWeek].votes) {
                // set the proposal as the most popular proposal for the current week
                mostPopularProposalOfWeek[currentWeek] = proposalId;
            } else {
                // throw an error if the proposal is not the most popular proposal
                _revert(IGovernance.ProposalNotMostPopular.selector);
            }
        }
        emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
    }

    /* -------------------------------------------------------------------------- */
    /*                                ratify/reject                               */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice entrypoint for long staked glow holders to vote on proposals
     * @param weekOfMostPopularProposal - the week that the proposal got selected as the most popular proposal for
     * @param trueForRatify  - if true the stakers are ratifying the proposal
     *                             - if false they are rejecting it
     * @param numVotes  - the number of ratify/reject votes they want to apply on this proposal
     *                  - the total number of ratify/reject votes must always be lte than
     *                  - the total glow they have staked
     */
    function ratifyOrReject(uint256 weekOfMostPopularProposal, bool trueForRatify, uint256 numVotes) external {
        //Cache the current week
        uint256 currentWeek = currentWeek();
        //Cache the most popular propsal at `weekOfMostPopularProposal`
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[weekOfMostPopularProposal];

        //Get the proposal status
        IGovernance.ProposalStatus status = getProposalStatus(_mostPopularProposalOfWeek);
        //if the proposal has been vetoed,
        //It cannot accept ratify or reject votes
        if (status == IGovernance.ProposalStatus.VETOED) {
            _revert(IGovernance.ProposalAlreadyVetoed.selector);
        }
        //If the proposal has already been executed
        //The proposal cannot accept ratify or reject votes
        if (
            status == IGovernance.ProposalStatus.EXECUTED_SUCCESSFULLY
                || status == IGovernance.ProposalStatus.EXECUTED_WITH_ERROR
        ) {
            _revert(IGovernance.ProposalAlreadyExecuted.selector);
        }

        //The week of which the proposal is the most popular proposal for
        //must have already ended
        if (weekOfMostPopularProposal >= currentWeek) {
            _revert(IGovernance.WeekMustHaveEndedToAcceptRatifyOrRejectVotes.selector);
        }

        //The proposal cannot accept ratify/reject votes
        //Past the ratify/reject window
        if (block.timestamp > _weekEndTime(weekOfMostPopularProposal + _NUM_WEEKS_TO_VOTE_ON_MOST_POPULAR_PROPOSAL)) {
            _revert(IGovernance.RatifyOrRejectPeriodEnded.selector);
        }
        //If the proposal was not set at all
        //The function must revert as well
        if (_mostPopularProposalOfWeek == 0) {
            _revert(IGovernance.MostPopularProposalNotSelected.selector);
        }

        //Load the amount of glow the sender has staked
        uint256 userNumStakedGlow = IGlow(GLOW).numStaked(msg.sender);
        //Load how many votes the sender has already used on this proposal
        uint256 amountVotesUsed = longStakerVotesForProposal[msg.sender][_mostPopularProposalOfWeek];
        //revert if the amount of votes the sender has already used
        //Plus the additional votes to cast is greater than their total amount of staked glow
        if (amountVotesUsed + numVotes > userNumStakedGlow) {
            _revert(IGovernance.InsufficientRatifyOrRejectVotes.selector);
        }

        //Spend the ratify/reject votes accordingly
        if (trueForRatify) {
            _proposalLongStakerVotes[_mostPopularProposalOfWeek].ratifyVotes += uint128(numVotes);
            emit IGovernance.RatifyCast(_mostPopularProposalOfWeek, msg.sender, numVotes);
        } else {
            _proposalLongStakerVotes[_mostPopularProposalOfWeek].rejectionVotes += uint128(numVotes);
            emit IGovernance.RejectCast(_mostPopularProposalOfWeek, msg.sender, numVotes);
        }
        //Update the amount of votes the sender has spent on this proposal
        longStakerVotesForProposal[msg.sender][_mostPopularProposalOfWeek] = amountVotesUsed + numVotes;
    }

    /* -------------------------------------------------------------------------- */
    /*                              creating proposals                            */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Creates a proposal to send a grant to a recipient
     * @param grantsRecipient the recipient of the grant
     * @param amount the amount of the grant
     * @param hash the hash of the proposal
     *             - the pre-image should be made public off-chain
     * @param maxNominations the maximum amount of nominations to spend on this proposal
     */

    function createGrantsProposal(address grantsRecipient, uint256 amount, bytes32 hash, uint256 maxNominations)
        external
    {
        uint256 proposalId = _proposalCount;
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();
        if (maxNominations < nominationCost) {
            _revert(IGovernance.NominationCostGreaterThanAllowance.selector);
        }
        _spendNominations(msg.sender, nominationCost);
        _proposals[proposalId] = IGovernance.Proposal(
            IGovernance.ProposalType.GRANTS_PROPOSAL,
            SafeCast.toUint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(nominationCost),
            abi.encode(grantsRecipient, amount, hash)
        );

        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        _proposalCount = proposalId + 1;

        emit IGovernance.GrantsProposalCreation(proposalId, msg.sender, grantsRecipient, amount, hash, nominationCost);
    }

    /**
     * @notice Creates a proposal to change the GCA requirements
     * @param newRequirementsHash the new requirements hash
     *             - the pre-image should be made public off-chain
     * @param maxNominations the maximum amount of nominations to spend on this proposal
     */
    function createChangeGCARequirementsProposal(bytes32 newRequirementsHash, uint256 maxNominations) external {
        uint256 proposalId = _proposalCount;
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();
        if (maxNominations < nominationCost) {
            _revert(IGovernance.NominationCostGreaterThanAllowance.selector);
        }
        _spendNominations(msg.sender, nominationCost);
        _proposals[proposalId] = IGovernance.Proposal(
            IGovernance.ProposalType.CHANGE_GCA_REQUIREMENTS,
            SafeCast.toUint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(nominationCost),
            abi.encode(newRequirementsHash)
        );

        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        _proposalCount = proposalId + 1;

        emit IGovernance.ChangeGCARequirementsProposalCreation(
            proposalId, msg.sender, newRequirementsHash, nominationCost
        );
    }

    /**
     * @notice Creates a proposal to create an RFC
     *     - the pre-image should be made public off-chain
     *     - if accepted, veto council members must read the RFC (up to 10k Words) and provide a written statement on their thoughts
     *
     * @param hash the hash of the proposal
     * @param maxNominations the maximum amount of nominations to spend on this proposal
     */
    function createRFCProposal(bytes32 hash, uint256 maxNominations) external {
        uint256 proposalId = _proposalCount;
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();
        if (maxNominations < nominationCost) {
            _revert(IGovernance.NominationCostGreaterThanAllowance.selector);
        }
        _spendNominations(msg.sender, nominationCost);

        _proposals[proposalId] = IGovernance.Proposal(
            IGovernance.ProposalType.REQUEST_FOR_COMMENT,
            SafeCast.toUint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(nominationCost),
            abi.encode(hash)
        );

        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        _proposalCount = proposalId + 1;

        emit IGovernance.RFCProposalCreation(proposalId, msg.sender, hash, nominationCost);
    }

    /**
     * @notice Creates a proposal to add, replace, or slash GCA council members
     * @param agentsToSlash an array of all gca's that are to be slashed
     *         - could be empty
     *         - could be a subset of the current GCAs
     *         - could be any address [in order to account for previous GCA's]
     * @param newGCAs the new GCAs
     *     -   can be empty if all GCA's are bad actors
     * @param maxNominations the maximum amount of nominations to spend on this proposal
     */
    function createGCACouncilElectionOrSlashProposal(
        address[] calldata agentsToSlash,
        address[] calldata newGCAs,
        uint256 maxNominations
    ) external {
        if (newGCAs.length > MAX_GCAS_AT_ONE_POINT_IN_TIME) {
            _revert(IGovernance.MaximumNumberOfGCAS.selector);
        }
        if (agentsToSlash.length > MAX_SLASHES_IN_ONE_GCA_ELECTION) {
            _revert(IGovernance.MaxSlashesInGCAElection.selector);
        }
        //[agentsToSlash,newGCAs,proposalCreationTimestamp]
        bytes32 hash = keccak256(abi.encode(agentsToSlash, newGCAs, block.timestamp));
        uint256 proposalId = _proposalCount;
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();
        if (maxNominations < nominationCost) {
            _revert(IGovernance.NominationCostGreaterThanAllowance.selector);
        }
        bool incrementSlashNonce = agentsToSlash.length > 0;
        _spendNominations(msg.sender, nominationCost);
        _proposals[proposalId] = IGovernance.Proposal(
            IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH,
            uint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(nominationCost),
            abi.encode(hash, incrementSlashNonce)
        );

        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        _proposalCount = proposalId + 1;

        emit IGovernance.GCACouncilElectionOrSlashCreation(
            proposalId, msg.sender, agentsToSlash, newGCAs, block.timestamp, nominationCost
        );
    }

    /**
     * @notice Creates a proposal to add, replace, or slash Veto a single veto council member
     * @param oldMember the old agent to be replaced
     *         -   If the agent is address(0), it means we are simply adding a new agent
     * @param newMember the new agent to replace the old agent
     *         -   If the agent is address(0), it means we are simply removing an agent
     * @param slashOldMember whether or not to slash the old agent
     * @param maxNominations the maximum amount of nominations to spend on this proposal
     */
    function createVetoCouncilElectionOrSlash(
        address oldMember,
        address newMember,
        bool slashOldMember,
        uint256 maxNominations
    ) external {
        if (oldMember == newMember) {
            _revert(IGovernance.VetoCouncilProposalCreationOldMemberCannotEqualNewMember.selector);
        }

        if (oldMember == NULL_ADDRESS) {
            _revert(IGovernance.VetoMemberCannotBeNullAddress.selector);
        }
        if (newMember == NULL_ADDRESS) {
            _revert(IGovernance.VetoMemberCannotBeNullAddress.selector);
        }

        uint256 proposalId = _proposalCount;
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();
        if (maxNominations < nominationCost) {
            _revert(IGovernance.NominationCostGreaterThanAllowance.selector);
        }
        _spendNominations(msg.sender, nominationCost);
        _proposals[proposalId] = IGovernance.Proposal(
            IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH,
            uint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(nominationCost),
            abi.encode(oldMember, newMember, slashOldMember, block.timestamp)
        );
        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        _proposalCount = proposalId + 1;

        emit IGovernance.VetoCouncilElectionOrSlash(
            proposalId, msg.sender, oldMember, newMember, slashOldMember, nominationCost
        );
    }

    /**
     * @notice Creates a proposal to send a grant to a recipient
     */
    function createGrantsProposalSigs(
        address grantsRecipient,
        uint256 amount,
        bytes32 hash,
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs
    ) external {
        bytes memory data = abi.encode(grantsRecipient, amount, hash);

        (uint256 proposalId, uint256 nominationsSpent) = checkBulkSignaturesAndCheckSufficientNominations(
            deadlines, nominationsToSpend, signers, sigs, data, IGovernance.ProposalType.GRANTS_PROPOSAL
        );
        emit IGovernance.GrantsProposalCreation(proposalId, msg.sender, grantsRecipient, amount, hash, nominationsSpent);
    }

    /**
     * @notice Creates a proposal to change the GCA requirements
     */
    function createChangeGCARequirementsProposalSigs(
        bytes32 newRequirementsHash,
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs
    ) external {
        bytes memory data = abi.encode(newRequirementsHash);
        (uint256 proposalId, uint256 nominationsSpent) = checkBulkSignaturesAndCheckSufficientNominations(
            deadlines, nominationsToSpend, signers, sigs, data, IGovernance.ProposalType.CHANGE_GCA_REQUIREMENTS
        );

        emit IGovernance.ChangeGCARequirementsProposalCreation(
            proposalId, msg.sender, newRequirementsHash, nominationsSpent
        );
    }

    /**
     * @notice Creates a proposal to create an RFC
     *     - the pre-image should be made public off-chain
     *     - if accepted, veto council members must read the RFC (up to 10k Words) and provide a written statement on their thoughts
     */
    function createRFCProposalSigs(
        bytes32 hash,
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs
    ) external {
        bytes memory data = abi.encode(hash);
        (uint256 proposalId, uint256 nominationsSpent) = checkBulkSignaturesAndCheckSufficientNominations(
            deadlines, nominationsToSpend, signers, sigs, data, IGovernance.ProposalType.REQUEST_FOR_COMMENT
        );
        emit IGovernance.RFCProposalCreation(proposalId, msg.sender, hash, nominationsSpent);
    }

    /**
     * @notice Creates a proposal to add, replace, or slash GCA council members
     * @param agentsToSlash an array of all gca's that are to be slashed
     *         - could be empty
     *         - could be a subset of the current GCAs
     *         - could be any address [in order to account for previous GCA's]
     * @param newGCAs the new GCAs
     *     -   can be empty if all GCA's are bad actors
     */
    function createGCACouncilElectionOrSlashProposalSigs(
        address[] memory agentsToSlash,
        address[] memory newGCAs,
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs
    ) external {
        {
            if (newGCAs.length > MAX_GCAS_AT_ONE_POINT_IN_TIME) {
                _revert(IGovernance.MaximumNumberOfGCAS.selector);
            }
            if (agentsToSlash.length > MAX_SLASHES_IN_ONE_GCA_ELECTION) {
                _revert(IGovernance.MaxSlashesInGCAElection.selector);
            }
        }

        /// Note: these bytes do not match the bytes that will be saved in storage through the
        /// `checkBulkSignaturesAndCheckSufficientNominations` function
        /// We need to encode this data to check the signatures
        /// Checking `data` as processed in `createGCACouncilElectionOrSlashProposal` would be painful
        /// As signers would need to align on the `block.timestamp`
        bytes memory data = abi.encode(agentsToSlash, newGCAs);

        (uint256 proposalId, uint256 nominationsSpent) = checkBulkSignaturesAndCheckSufficientNominations(
            deadlines, nominationsToSpend, signers, sigs, data, IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH
        );
        emit IGovernance.GCACouncilElectionOrSlashCreation(
            proposalId, msg.sender, agentsToSlash, newGCAs, block.timestamp, nominationsSpent
        );
    }

    /**
     * @notice Creates a proposal to add, replace, or slash Veto a single veto council member
     * @param oldMember the old agent to be replaced
     *         -   If the agent is address(0), it means we are simply adding a new agent
     * @param newMember the new agent to replace the old agent
     *         -   If the agent is address(0), it means we are simply removing an agent
     * @param slashOldMember whether or not to slash the old agent
     */
    function createVetoCouncilElectionOrSlashSigs(
        address oldMember,
        address newMember,
        bool slashOldMember,
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs
    ) external {
        if (oldMember == newMember) {
            _revert(IGovernance.VetoCouncilProposalCreationOldMemberCannotEqualNewMember.selector);
        }
        /// Note: these bytes do not match the bytes that will be saved in storage through the
        /// `checkBulkSignaturesAndCheckSufficientNominations` function
        /// We need to encode this data to check the signatures
        /// Checking `data` as processed in `createVetoCouncilElectionOrSlash` would be painful
        /// As signers would need to align on the `block.timestamp`
        bytes memory data = abi.encode(oldMember, newMember, slashOldMember);
        (uint256 proposalId, uint256 nominationsSpent) = checkBulkSignaturesAndCheckSufficientNominations(
            deadlines, nominationsToSpend, signers, sigs, data, IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH
        );

        emit IGovernance.VetoCouncilElectionOrSlash(
            proposalId, msg.sender, oldMember, newMember, slashOldMember, nominationsSpent
        );
    }

    /**
     * @notice Updates the last expired proposal id
     *         - could be called by a good actor to update the last expired proposal id
     *         - so that _numActiveProposalsAndLastExpiredProposalId() is more efficient
     */
    function updateLastExpiredProposalId() public {
        (, uint256 _lastExpiredProposalId,) = _numActiveProposalsAndLastExpiredProposalId();
        lastExpiredProposalId = _lastExpiredProposalId;
    }

    /* -------------------------------------------------------------------------- */
    /*                                 view functions                             */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice returns {true} if a gca has endorsed the proposal at {weekId}
     * @param gca - the address of the gca to check
     * @param weekId - the week to check
     * @return hasEndorsedProposal - true if the specified gca endorsed the proposal at the specified week
     */
    function hasEndorsedProposal(address gca, uint256 weekId) external view returns (bool) {
        uint256 key = weekId / 256;
        uint256 shift = weekId % 256;
        return _hasEndorsedProposalBitmap[gca][key] & (1 << shift) != 0;
    }

    /**
     * @notice Gets the amount of nominations that an account has
     *             - adjusts for half-life of 12 months
     * @param account the account to get the nominations of
     * @return amount amount of nominations that the account has
     */
    function nominationsOf(address account) public view returns (uint256) {
        Nominations memory n = _nominations[account];
        uint256 elapsedSeconds = block.timestamp - n.lastUpdate;
        return HalfLife.calculateHalfLifeValue(n.amount, elapsedSeconds);
    }

    /**
     * @notice Gets the cost for a new proposal
     * @return cost the cost for a new proposal
     * @dev calculates cost as 1 * 1.1^numActiveProposals
     */
    function costForNewProposal() public view returns (uint256) {
        uint256 numActiveProposals;
        (numActiveProposals,,) = _numActiveProposalsAndLastExpiredProposalId();
        return _getNominationCostForProposalCreation(numActiveProposals);
    }

    /**
     * @notice Gets the current week (since genesis)
     * @return currentWeek - the current week (since genesis)
     */
    function currentWeek() public view returns (uint256) {
        return (block.timestamp - GENESIS_TIMESTAMP) / bucketDuration();
    }

    /**
     * @notice Gets the status of the most popular proposal of a given week
     * @param proposalId the id of the proposal
     * @return status the status of the proposal
     */
    function getProposalStatus(uint256 proposalId) public view returns (IGovernance.ProposalStatus) {
        uint256 key = proposalId / 32;
        uint256 shift = (proposalId % 32) * 8;
        uint256 mask = uint256(0xff) << shift;
        uint256 value = (_packedProposalStatus[key] & mask) >> shift;
        return IGovernance.ProposalStatus(value);
    }

    /**
     * @notice Gets the total number of proposals created
     * @return proposalCount - the total number of proposals created
     * @dev we have to subtract 1 because we start at 1
     */
    function proposalCount() public view returns (uint256) {
        return _proposalCount - 1;
    }

    /**
     * @notice Gets the proposal at a given id
     * @param proposalId the id of the proposal
     * @return proposal the proposal at the given id
     */
    function proposals(uint256 proposalId) external view returns (IGovernance.Proposal memory) {
        return _proposals[proposalId];
    }

    /**
     * @notice returns the number of ratify and reject votes on a given proposal
     * @param proposalId - the id of the proposal to query for
     * @dev the proposalId is different than the weekId
     * @return proposalLongStakerVotes - the {ProposalLongStakerVotes struct} for a proposal
     */
    function proposalLongStakerVotes(uint256 proposalId) external view returns (ProposalLongStakerVotes memory) {
        return _proposalLongStakerVotes[proposalId];
    }

    /* -------------------------------------------------------------------------- */
    /*                                 internal                                 */
    /* -------------------------------------------------------------------------- */

    /**
     * @dev internal function to execute a proposal
     * @param week the week where the proposal was most popular
     * @param proposalId the id of the proposal
     * @param proposalType the type of the proposal
     * @param data the data of the proposal
     */
    function handleProposalExecution(
        uint256 week,
        uint256 proposalId,
        IGovernance.ProposalType proposalType,
        bytes memory data
    ) internal {
        bool success;
        if (proposalType == IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH) {
            (address oldMember, address newMember, bool slashOldMember) = abi.decode(data, (address, address, bool));
            success = IVetoCouncil(VETO_COUNCIL).addAndRemoveCouncilMember(oldMember, newMember, slashOldMember);
        }

        if (proposalType == IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
            (bytes32 hash, bool incrementSlashNonce) = abi.decode(data, (bytes32, bool));
            //push hash should never revert;
            IGCA(GCA).pushHash(hash, incrementSlashNonce);
            success = true;
        }

        if (proposalType == IGovernance.ProposalType.GRANTS_PROPOSAL) {
            (address grantsRecipient, uint256 amount,) = abi.decode(data, (address, uint256, bytes32));
            success = IGrantsTreasury(GRANTS_TREASURY).allocateGrantFunds(grantsRecipient, amount);
        }

        if (proposalType == IGovernance.ProposalType.CHANGE_GCA_REQUIREMENTS) {
            (bytes32 newRequirementsHash) = abi.decode(data, (bytes32));
            //setRequirementsHash should never revert
            IGCA(GCA).setRequirementsHash(newRequirementsHash);
            success = true;
        }

        if (proposalType == IGovernance.ProposalType.REQUEST_FOR_COMMENT) {
            bytes32 rfcHash = abi.decode(data, (bytes32));
            //Emitting the event should never revert
            emit IGovernance.RFCProposalExecuted(proposalId, rfcHash);
            success = true;
        }

        if (success) {
            _setProposalStatus(proposalId, IGovernance.ProposalStatus.EXECUTED_SUCCESSFULLY);
        } else {
            _setProposalStatus(proposalId, IGovernance.ProposalStatus.EXECUTED_WITH_ERROR);
        }

        emit IGovernance.ProposalExecution(week, proposalId, proposalType, success);
    }

    /**
     * @dev internal function to get the cost for a new proposal that also updates the
     *         -  last expired proposal id if need be
     */
    function costForNewProposalAndUpdateLastExpiredProposalId() internal returns (uint256) {
        (uint256 numActiveProposals,) = _numActiveProposalsAndLastExpiredProposalIdAndUpdateState();
        return _getNominationCostForProposalCreation(numActiveProposals);
    }

    /**
     * @dev helper func to spend nominations from an account
     *         -   should never be public
     * @param account the account to spend nominations from
     * @param amount the amount of nominations to spend
     */
    function _spendNominations(address account, uint256 amount) internal {
        uint256 currentBalance = nominationsOf(account);
        if (currentBalance < amount) {
            _revert(IGovernance.InsufficientNominations.selector);
        }
        _nominations[account] =
            Nominations(SafeCast.toUint192(currentBalance - amount), SafeCast.toUint64(block.timestamp));
    }

    /**
     * @dev sets the proposal status for the most popular proposal of a given week
     * @param proposalId the id of the proposal
     * @param status the status of the proposal
     */
    function _setProposalStatus(uint256 proposalId, IGovernance.ProposalStatus status) internal {
        //Each uint256 is 32 bytes, and can hold 32 uint8 statuses
        uint256 key = proposalId / 32;
        //Each enum takes up 8 bits since it's casted to a uint8
        uint256 shift = (proposalId % 32) * 8;
        //8 bits << shift
        uint256 mask = uint256(0xff) << shift;
        //the status bitshifted
        uint256 value = uint256(status) << shift;
        _packedProposalStatus[key] = (_packedProposalStatus[key] & ~mask) | value;
    }

    /**
     * @notice Gets the number of active proposals and the last expired proposal id
     * @dev also updates state
     * @return numActiveProposals the number of active proposals
     * @return _lastExpiredProposalId the last expired proposal id
     */

    function _numActiveProposalsAndLastExpiredProposalIdAndUpdateState()
        internal
        returns (uint256 numActiveProposals, uint256 _lastExpiredProposalId)
    {
        bool updateState;
        (numActiveProposals, _lastExpiredProposalId, updateState) = _numActiveProposalsAndLastExpiredProposalId();
        if (updateState) {
            lastExpiredProposalId = _lastExpiredProposalId;
        }
    }

    /**
     * @dev helper function that
     *             1. Checks the signatures of the signers
     *             2. Checks that the total nominations to spend is greater than the nomination cost
     *             3. Checks that the deadline has not passed
     *             4. Spends the nominations
     *             5. Updates the most popular proposal
     *             6. Creates the proposal
     * @param deadlines the deadlines of the signatures
     * @param nominationsToSpend the nominations to spend of the signatures
     * @param signers the signers of the signatures
     * @param sigs the sigs of the signatures
     * @param data the data of the proposal
     * @param proposalType the type of the proposal
     * @return proposalId the id of the proposal that was created
     * @return totalNominationsToSpend the total nominations that were spent on the proposal
     */
    function checkBulkSignaturesAndCheckSufficientNominations(
        uint256[] memory deadlines,
        uint256[] memory nominationsToSpend,
        address[] memory signers,
        bytes[] memory sigs,
        bytes memory data,
        IGovernance.ProposalType proposalType
    ) internal returns (uint256, uint256) {
        uint256 proposalId = _proposalCount;
        uint256 totalNominationsToSpend;
        for (uint256 i; i < signers.length;) {
            _checkSpendNominationsOnProposalDigest(
                proposalType, nominationsToSpend[i], deadlines[i], signers[i], sigs[i], data
            );
            _spendNominations(signers[i], nominationsToSpend[i]);
            totalNominationsToSpend += nominationsToSpend[i];
            unchecked {
                ++i;
            }
        }
        uint256 nominationCost = costForNewProposalAndUpdateLastExpiredProposalId();

        if (totalNominationsToSpend < nominationCost) {
            _revert(IGovernance.InsufficientNominations.selector);
        }

        uint256 currentWeek = currentWeek();
        uint256 _mostPopularProposalOfWeek = mostPopularProposalOfWeek[currentWeek];
        if (nominationCost > _proposals[_mostPopularProposalOfWeek].votes) {
            mostPopularProposalOfWeek[currentWeek] = proposalId;
            emit IGovernance.MostPopularProposalSet(currentWeek, proposalId);
        }

        if (proposalType == IGovernance.ProposalType.GCA_COUNCIL_ELECTION_OR_SLASH) {
            (address[] memory agentsToSlash, address[] memory newGCAs) = abi.decode(data, (address[], address[]));
            bytes32 hash = keccak256(abi.encode(agentsToSlash, newGCAs, block.timestamp));
            bool incrementSlashNonce = agentsToSlash.length > 0;
            data = abi.encode(hash, incrementSlashNonce);
        }

        if (proposalType == IGovernance.ProposalType.VETO_COUNCIL_ELECTION_OR_SLASH) {
            (address oldMember, address newMember, bool slashOldMember) = abi.decode(data, (address, address, bool));
            data = abi.encode(oldMember, newMember, slashOldMember, block.timestamp);
        }

        _proposals[proposalId] = IGovernance.Proposal(
            proposalType,
            SafeCast.toUint64(block.timestamp + MAX_PROPOSAL_DURATION),
            SafeCast.toUint184(totalNominationsToSpend),
            data
        );

        ++proposalId;
        _proposalCount = proposalId;
        //Need to send the preincremented proposalId
        return (proposalId - 1, totalNominationsToSpend);
    }

    /**
     * @dev helper function that checks the signature of a signer
     * @param proposalType the type of the proposal
     * @param nominationsToSpend the nominations to spend of the signature
     * @param deadline the deadline of the signature
     * @param signer the signer of the signature
     * @param sig the sig of the signature
     * @param data the data of the proposal
     */
    function _checkSpendNominationsOnProposalDigest(
        ProposalType proposalType,
        uint256 nominationsToSpend,
        uint256 deadline,
        address signer,
        bytes memory sig,
        bytes memory data
    ) internal {
        uint256 nonce = spendNominationsOnProposalNonce[signer];
        if (block.timestamp > deadline) {
            _revert(IGovernance.SpendNominationsOnProposalSignatureExpired.selector);
        }
        bytes32 digest =
            _createSpendNominationsOnProposalDigest(proposalType, nominationsToSpend, nonce, deadline, data);
        if (!SignatureChecker.isValidSignatureNow(signer, digest, sig)) {
            _revert(IGovernance.InvalidSpendNominationsOnProposalSignature.selector);
        }
        spendNominationsOnProposalNonce[signer] = nonce + 1;
    }

    /**
     * @notice Gets the nomination cost for proposal creation based on {numActiveProposals}
     * @param numActiveProposals the number of active proposals
     * @return res the nomination cost for proposal creation
     * @dev calculates cost as 1 * 1.1^numActiveProposals
     * @dev we only use 4 decimals of precision
     */
    function _getNominationCostForProposalCreation(uint256 numActiveProposals) internal pure returns (uint256) {
        uint256 res = ONE_64x64.mul(ABDKMath64x64.pow(ONE_POINT_ONE_128, numActiveProposals)).mulu(1e4);
        //Multiply by 1e8 to get it in 12 decimals
        //nominations are in 12 decimals of precision
        // as the formula for calculating nominations is sqrt(amount gcc added to lp * amount usdc added in lp)
        //from a 'commit' event
        //multiplying gcc (18 decimals) and usdc (6 decimals) gives us an output in 24 decimals.
        // since we are sqrt'ing this, we factor our 12 decimals of precision since sqrt(1e24) = 1e12
        // and end up in 12 decimals of precision
        return res * 1e8;
    }

    /**
     * @notice returns the bucket duration
     * @return bucketDuration - the bucket duration
     */
    function bucketDuration() internal pure virtual returns (uint256) {
        return _BUCKET_DURATION;
    }

    /**
     * @notice Gets the number of active proposals and the last expired proposal id
     * @return numActiveProposals the number of active proposals
     * @return _lastExpiredProposalId the last expired proposal id
     * @return updateState whether or not to update the state
     */
    function _numActiveProposalsAndLastExpiredProposalId()
        internal
        view
        returns (uint256 numActiveProposals, uint256 _lastExpiredProposalId, bool updateState)
    {
        uint256 cachedLastExpiredProposalId = lastExpiredProposalId;
        _lastExpiredProposalId = cachedLastExpiredProposalId;
        _lastExpiredProposalId = _lastExpiredProposalId == 0 ? 1 : _lastExpiredProposalId;
        uint256 cachedProposalCount = _proposalCount;
        unchecked {
            for (uint256 i = _lastExpiredProposalId; i < cachedProposalCount; ++i) {
                if (_proposals[i].expirationTimestamp < block.timestamp) {
                    _lastExpiredProposalId = i;
                } else {
                    break;
                }
            }
        }
        numActiveProposals = cachedProposalCount - _lastExpiredProposalId;
        updateState = _lastExpiredProposalId != cachedLastExpiredProposalId;
    }

    /**
     * @dev returns true if the proposal is eligible for execution
     * returns false otherwise
     * @param proposalId - the proposal id to check
     */
    function isProposalEligibleForExecution(uint256 proposalId) internal view returns (bool) {
        IGovernance.ProposalStatus status = getProposalStatus(proposalId);
        //If the proposal is vetoed, we can skip the execution
        if (status == IGovernance.ProposalStatus.VETOED) {
            return false;
        }
        //We also skip execution if the proposal somehow gets elected twice for execution
        if (
            status == IGovernance.ProposalStatus.EXECUTED_SUCCESSFULLY
                || status == IGovernance.ProposalStatus.EXECUTED_WITH_ERROR
        ) {
            return false;
        }

        return true;
    }
    /**
     * @dev reverts if the proposal has already been executed
     * @param proposalId the id of the proposal
     */

    function _revertIfProposalExecutedOrVetoed(uint256 proposalId) internal view {
        IGovernance.ProposalStatus status = getProposalStatus(proposalId);
        if (status == IGovernance.ProposalStatus.EXECUTED_SUCCESSFULLY) {
            _revert(IGovernance.ProposalAlreadyExecuted.selector);
        }

        if (status == IGovernance.ProposalStatus.EXECUTED_WITH_ERROR) {
            _revert(IGovernance.ProposalAlreadyExecuted.selector);
        }
        if (status == IGovernance.ProposalStatus.VETOED) _revert(IGovernance.ProposalIsVetoed.selector);
    }
    /**
     * @notice finds the time at which the week ends
     * @dev for example, {weekNumber = 1} would give the timestamp at which week 1 would be over
     * @param weekNumber - the week number to find the end timestamp for
     * @return endTimestamp - the end timestamp of the week number
     */

    function _weekEndTime(uint256 weekNumber) internal view returns (uint256) {
        return GENESIS_TIMESTAMP + ((weekNumber + 1) * bucketDuration());
    }

    /**
     * @dev reverts if the address is the zero address
     * @param a the address to check
     */
    function _checkZeroAddress(address a) private pure {
        if (_isZeroAddress(a)) {
            _revert(IGovernance.ZeroAddressNotAllowed.selector);
        }
    }

    /**
     * @dev efficiently determines if an address is the zero address
     * @param a the address to check
     */
    function _isZeroAddress(address a) private pure returns (bool isZero) {
        // solhint-disable-next-line no-inline-assembly
        assembly ("memory-safe") {
            isZero := iszero(a)
        }
    }

    /**
     * @dev helper function that creates the digest for a spend nominations on proposal signature
     * @param proposalType the type of the proposal
     * @param nominationsToSpend the nominations to spend of the signature
     * @param nonce the nonce of the signature
     * @param deadline the deadline of the signature
     * @param data the data of the proposal
     * @return digest the digest of the signature
     */
    function _createSpendNominationsOnProposalDigest(
        ProposalType proposalType,
        uint256 nominationsToSpend,
        uint256 nonce,
        uint256 deadline,
        bytes memory data
    ) internal view returns (bytes32) {
        return keccak256(
            abi.encodePacked(
                "\x19\x01",
                _domainSeparatorV4(),
                keccak256(
                    abi.encode(
                        SPEND_NOMINATIONS_ON_PROPOSAL_TYPEHASH,
                        uint8(proposalType),
                        nominationsToSpend,
                        nonce,
                        deadline,
                        keccak256(data)
                    )
                )
            )
        );
    }

    /**
     * @notice More efficiently reverts with a bytes4 selector
     * @param selector The selector to revert with
     */
    function _revert(bytes4 selector) private pure {
        // solhint-disable-next-line no-inline-assembly
        assembly {
            mstore(0x0, selector)
            revert(0x0, 0x04)
        }
    }
}

File 2 of 27 : IGovernance.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IGovernance {
    /* -------------------------------------------------------------------------- */
    /*                                   errors                                   */
    /* -------------------------------------------------------------------------- */
    error ProposalHasNotExpired(uint256 proposalId);
    error ProposalExpired();
    error InsufficientNominations();
    error GCAContractAlreadySet();
    error CallerNotGCA();
    error CallerNotGCC();
    error CallerNotVetoCouncilMember();
    error ZeroAddressNotAllowed();
    error ContractsAlreadySet();
    error NominationCostGreaterThanAllowance();
    error ProposalDoesNotExist();
    error WeekNotStarted();
    error WeekNotFinalized();
    error InsufficientRatifyOrRejectVotes();
    error RatifyOrRejectPeriodEnded();
    error RatifyOrRejectPeriodNotEnded();
    error MostPopularProposalNotSelected();
    error ProposalAlreadyVetoed();
    error AlreadyEndorsedWeek();
    error OnlyGCAElectionsCanBeEndorsed();
    error MaxGCAEndorsementsReached();
    error VetoCouncilElectionsCannotBeVetoed();
    error GCACouncilElectionsCannotBeVetoed();
    error ProposalsMustBeExecutedSynchonously();
    error ProposalNotInitialized();
    error RFCPeriodNotEnded();
    error ProposalAlreadyExecuted();
    error ProposalIdDoesNotMatchMostPopularProposal();
    error ProposalNotMostPopular();
    error VetoCouncilProposalCreationOldMemberCannotEqualNewMember();
    error MaximumNumberOfGCAS();
    error InvalidSpendNominationsOnProposalSignature();

    error MaxSlashesInGCAElection();
    error SpendNominationsOnProposalSignatureExpired();
    error ProposalIsVetoed();
    error VetoMemberCannotBeNullAddress();
    error WeekMustHaveEndedToAcceptRatifyOrRejectVotes();

    /* -------------------------------------------------------------------------- */
    /*                                    enums                                   */
    /* -------------------------------------------------------------------------- */
    enum ProposalType {
        NONE, //default value for unset proposals
        VETO_COUNCIL_ELECTION_OR_SLASH,
        GCA_COUNCIL_ELECTION_OR_SLASH,
        GRANTS_PROPOSAL,
        CHANGE_GCA_REQUIREMENTS,
        REQUEST_FOR_COMMENT
    }

    enum ProposalStatus {
        NONE,
        EXECUTED_WITH_ERROR,
        EXECUTED_SUCCESSFULLY,
        VETOED
    }

    /* -------------------------------------------------------------------------- */
    /*                                   structs                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @param proposalType the type of the proposal
     * @param expirationTimestamp the timestamp at which the proposal expires
     * @param data the data of the proposal
     */
    struct Proposal {
        ProposalType proposalType;
        uint64 expirationTimestamp;
        uint184 votes;
        bytes data;
    }

    /* -------------------------------------------------------------------------- */
    /*                                   events                                   */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice Emitted when a Veto Council Election or Slash proposal is created
     * @param proposalId the id of the proposal
     * @param proposer the address of the proposer
     * @param oldAgent the address of the old agent
     * @param newAgent the address of the new agent
     * @param slashOldAgent whether or not to slash the old agent
     * @param nominationsUsed the amount of nominations used
     */
    event VetoCouncilElectionOrSlash(
        uint256 indexed proposalId,
        address indexed proposer,
        address oldAgent,
        address newAgent,
        bool slashOldAgent,
        uint256 nominationsUsed
    );

    /**
     * @notice Emitted when a GCA Council Election or Slash proposal is created
     * @param proposalId the id of the proposal
     * @param proposer the address of the proposer
     * @param agentsToSlash the addresses of the agents to slash
     * @param newGCAs the addresses of the new GCAs
     * @param proposalCreationTimestamp the timestamp at which the proposal was created
     *         -   This is necessary due to the proposalHashes logic in GCA
     * @param nominationsUsed the amount of nominations used
     */
    event GCACouncilElectionOrSlashCreation(
        uint256 indexed proposalId,
        address indexed proposer,
        address[] agentsToSlash,
        address[] newGCAs,
        uint256 proposalCreationTimestamp,
        uint256 nominationsUsed
    );

    /**
     * @notice emitted when a grants proposal is created
     * @param proposalId the id of the proposal
     * @param proposer the address of the proposer
     * @param recipient the address of the recipient
     * @param amount the amount of tokens to send
     * @param hash the hash of the proposal contents
     * @param nominationsUsed the amount of nominations used
     */
    event GrantsProposalCreation(
        uint256 indexed proposalId,
        address indexed proposer,
        address recipient,
        uint256 amount,
        bytes32 hash,
        uint256 nominationsUsed
    );

    /**
     * @notice emitted when a proposal to change the GCA requirements is created
     * @param proposalId the id of the proposal
     * @param proposer the address of the proposer
     * @param requirementsHash the hash of the requirements
     * @param nominationsUsed the amount of nominations used
     */
    event ChangeGCARequirementsProposalCreation(
        uint256 indexed proposalId, address indexed proposer, bytes32 requirementsHash, uint256 nominationsUsed
    );

    /**
     * @notice emitted when a request for comment is created
     * @param proposalId the id of the proposal
     * @param proposer the address of the proposer
     * @param rfcHash the hash of the requirements string
     * @param nominationsUsed the amount of nominations used
     */
    event RFCProposalCreation(
        uint256 indexed proposalId, address indexed proposer, bytes32 rfcHash, uint256 nominationsUsed
    );

    /**
     * @notice emitted when a long glow staker casts a ratify vote on a proposal
     * @param proposalId the id of the proposal
     * @param voter the address of the voter
     * @param numVotes the number of ratify votes
     */
    event RatifyCast(uint256 indexed proposalId, address indexed voter, uint256 numVotes);

    /**
     * @notice emitted when a long glow staker casts a reject vote on a proposal
     * @param proposalId the id of the proposal
     * @param voter the address of the voter
     * @param numVotes the number of reject votes
     */
    event RejectCast(uint256 indexed proposalId, address indexed voter, uint256 numVotes);

    /**
     * @notice emitted when nominations are used on a proposal
     * @param proposalId the id of the proposal
     * @param spender the address of the spender
     * @param amount the amount of nominations used
     */
    event NominationsUsedOnProposal(uint256 indexed proposalId, address indexed spender, uint256 amount);

    /**
     * @notice emitted when a proposal is set as the most popular proposal at a week
     * @param weekId - the weekId in which the proposal was selected as the most popular proposal
     * @param proposalId - the id of the proposal that was selected as the most popular proposal
     */
    event MostPopularProposalSet(uint256 indexed weekId, uint256 indexed proposalId);

    /**
     * @notice emitted when a proposal is ratified
     * @param weekId - the weekId in which the proposal to be vetoed was selected as the most popular proposal
     * @param vetoer - the address of the veto council member who vetoed the proposal
     * @param proposalId - the id of the proposal that was vetoed
     */
    event ProposalVetoed(uint256 indexed weekId, address indexed vetoer, uint256 proposalId);

    /**
     * @notice emitted when an rfc proposal is executed succesfully.
     * - RFC Proposals don't change the state of the system, so rather than performing state changes
     *         - we emit an event to alert that the proposal was executed succesfully
     *         - and that the rfc requires attention
     * @param proposalId - the id of the proposal from which the rfc was created
     * @param requirementsHash - the hash of the requirements string
     */
    event RFCProposalExecuted(uint256 indexed proposalId, bytes32 requirementsHash);

    /**
     * @notice emitted when a proposal is executed  for the week
     * @param week - the week for which the proposal was the most popular proposal
     * @param proposalId - the id of the proposal that was executed
     * @param proposalType - the type of the proposal that was executed
     * @param success - whether or not the proposal was executed succesfully
     */
    event ProposalExecution(uint256 indexed week, uint256 proposalId, ProposalType proposalType, bool success);

    /**
     * @notice Allows the GCC contract to grant nominations to {to} when they retire GCC
     * @param to the address to grant nominations to
     * @param amount the amount of nominations to grant
     */
    function grantNominations(address to, uint256 amount) external;

    /**
     * @notice Executes a most popular proposal at a given week
     * @dev a proposal that has not been ratified or rejected can be executed
     *         - but should never make any changes to the system (exceptions are detailed in the implementation)
     * @dev proposals that have met their requirements to perform state changes are executed as well
     * @dev no execution of any proposal should ever revert as this will freeze the governance contract
     * @param weekId the weekId that containst the 'mostPopularProposal' at that week
     * @dev proposals must be executed synchronously to ensure that the state of the system is consistent
     */
    function executeProposalAtWeek(uint256 weekId) external;

    /**
     * @notice syncs all proposals that must be synced
     */
    function syncProposals() external;

    /**
     * @notice allows a veto council member to endorse a gca election
     * @param weekId the weekId of the gca election to endorse
     */
    function endorseGCAProposal(uint256 weekId) external;
}

File 3 of 27 : HalfLife.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@/libraries/ABDKMath64x64.sol";

library HalfLife {
    /**
     * @dev the halving period in seconds (1 year)
     * @dev nominations have a half-life of 1 year
     */
    uint256 private constant SECONDS_IN_YEAR = 365 * uint256(1 days);

    /**
     * @notice calculates the value remaining after a given amount of time has elapsed
     *         - using a half-life of 52 weeks
     * @param initialValue the initial value
     * @param elapsedSeconds the number of seconds that have elapsed
     * @return value - the value remaining given a half-life of 52 weeks
     */
    function calculateHalfLifeValue(uint256 initialValue, uint256 elapsedSeconds) public pure returns (uint256) {
        // Convert the half-life from months to seconds
        uint256 halfLifeSeconds = SECONDS_IN_YEAR;

        // Calculate the ratio of elapsed time to half-life in fixed point format
        int128 tOverT =
            ABDKMath64x64.div(ABDKMath64x64.fromUInt(elapsedSeconds), ABDKMath64x64.fromUInt(halfLifeSeconds));

        // Calculate (1/2)^(t/T) using the fact that e^(ln(0.5)*t/T) = (0.5)^(t/T)
        int128 halfPowerTOverT =
            ABDKMath64x64.exp(ABDKMath64x64.mul(ABDKMath64x64.ln(ABDKMath64x64.divu(1, 2)), tOverT));

        // Calculate the final amount
        uint256 finalValue = ABDKMath64x64.mulu(halfPowerTOverT, initialValue);

        return finalValue;
    }
}

File 4 of 27 : ABDKMath64x64.sol
// SPDX-License-Identifier: BSD-4-Clause
/*
 * ABDK Math 64.64 Smart Contract Library.  Copyright © 2019 by ABDK Consulting.
 * Author: Mikhail Vladimirov <[email protected]>
 */
pragma solidity ^0.8.0;

/**
 * Smart contract library of mathematical functions operating with signed
 * 64.64-bit fixed point numbers.  Signed 64.64-bit fixed point number is
 * basically a simple fraction whose numerator is signed 128-bit integer and
 * denominator is 2^64.  As long as denominator is always the same, there is no
 * need to store it, thus in Solidity signed 64.64-bit fixed point numbers are
 * represented by int128 type holding only the numerator.
 */
library ABDKMath64x64 {
    /*
    * Minimum value signed 64.64-bit fixed point number may have. 
    */
    int128 private constant MIN_64x64 = -0x80000000000000000000000000000000;

    /*
    * Maximum value signed 64.64-bit fixed point number may have. 
    */
    int128 private constant MAX_64x64 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;

    /**
     * Convert signed 256-bit integer number into signed 64.64-bit fixed point
     * number.  Revert on overflow.
     *
     * @param x signed 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function fromInt(int256 x) internal pure returns (int128) {
        unchecked {
            require(x >= -0x8000000000000000 && x <= 0x7FFFFFFFFFFFFFFF);
            return int128(x << 64);
        }
    }

    /**
     * Convert signed 64.64 fixed point number into signed 64-bit integer number
     * rounding down.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64-bit integer number
     */
    function toInt(int128 x) internal pure returns (int64) {
        unchecked {
            return int64(x >> 64);
        }
    }

    /**
     * Convert unsigned 256-bit integer number into signed 64.64-bit fixed point
     * number.  Revert on overflow.
     *
     * @param x unsigned 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function fromUInt(uint256 x) internal pure returns (int128) {
        unchecked {
            require(x <= 0x7FFFFFFFFFFFFFFF);
            return int128(int256(x << 64));
        }
    }

    /**
     * Convert signed 64.64 fixed point number into unsigned 64-bit integer
     * number rounding down.  Revert on underflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return unsigned 64-bit integer number
     */
    function toUInt(int128 x) internal pure returns (uint64) {
        unchecked {
            require(x >= 0);
            return uint64(uint128(x >> 64));
        }
    }

    /**
     * Convert signed 128.128 fixed point number into signed 64.64-bit fixed point
     * number rounding down.  Revert on overflow.
     *
     * @param x signed 128.128-bin fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function from128x128(int256 x) internal pure returns (int128) {
        unchecked {
            int256 result = x >> 64;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Convert signed 64.64 fixed point number into signed 128.128 fixed point
     * number.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 128.128 fixed point number
     */
    function to128x128(int128 x) internal pure returns (int256) {
        unchecked {
            return int256(x) << 64;
        }
    }

    /**
     * Calculate x + y.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function add(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            int256 result = int256(x) + y;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate x - y.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function sub(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            int256 result = int256(x) - y;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate x * y rounding down.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function mul(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            int256 result = int256(x) * y >> 64;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate x * y rounding towards zero, where x is signed 64.64 fixed point
     * number and y is signed 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64 fixed point number
     * @param y signed 256-bit integer number
     * @return signed 256-bit integer number
     */
    function muli(int128 x, int256 y) internal pure returns (int256) {
        unchecked {
            if (x == MIN_64x64) {
                require(
                    y >= -0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
                        && y <= 0x1000000000000000000000000000000000000000000000000
                );
                return -y << 63;
            } else {
                bool negativeResult = false;
                if (x < 0) {
                    x = -x;
                    negativeResult = true;
                }
                if (y < 0) {
                    y = -y; // We rely on overflow behavior here
                    negativeResult = !negativeResult;
                }
                uint256 absoluteResult = mulu(x, uint256(y));
                if (negativeResult) {
                    require(absoluteResult <= 0x8000000000000000000000000000000000000000000000000000000000000000);
                    return -int256(absoluteResult); // We rely on overflow behavior here
                } else {
                    require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
                    return int256(absoluteResult);
                }
            }
        }
    }

    /**
     * Calculate x * y rounding down, where x is signed 64.64 fixed point number
     * and y is unsigned 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64 fixed point number
     * @param y unsigned 256-bit integer number
     * @return unsigned 256-bit integer number
     */
    function mulu(int128 x, uint256 y) internal pure returns (uint256) {
        unchecked {
            if (y == 0) return 0;

            require(x >= 0);

            uint256 lo = (uint256(int256(x)) * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)) >> 64;
            uint256 hi = uint256(int256(x)) * (y >> 128);

            require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
            hi <<= 64;

            require(hi <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF - lo);
            return hi + lo;
        }
    }

    /**
     * Calculate x / y rounding towards zero.  Revert on overflow or when y is
     * zero.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function div(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            require(y != 0);
            int256 result = (int256(x) << 64) / y;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are signed 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x signed 256-bit integer number
     * @param y signed 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function divi(int256 x, int256 y) internal pure returns (int128) {
        unchecked {
            require(y != 0);

            bool negativeResult = false;
            if (x < 0) {
                x = -x; // We rely on overflow behavior here
                negativeResult = true;
            }
            if (y < 0) {
                y = -y; // We rely on overflow behavior here
                negativeResult = !negativeResult;
            }
            uint128 absoluteResult = divuu(uint256(x), uint256(y));
            if (negativeResult) {
                require(absoluteResult <= 0x80000000000000000000000000000000);
                return -int128(absoluteResult); // We rely on overflow behavior here
            } else {
                require(absoluteResult <= 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
                return int128(absoluteResult); // We rely on overflow behavior here
            }
        }
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x unsigned 256-bit integer number
     * @param y unsigned 256-bit integer number
     * @return signed 64.64-bit fixed point number
     */
    function divu(uint256 x, uint256 y) internal pure returns (int128) {
        unchecked {
            require(y != 0);
            uint128 result = divuu(x, y);
            require(result <= uint128(MAX_64x64));
            return int128(result);
        }
    }

    /**
     * Calculate -x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function neg(int128 x) internal pure returns (int128) {
        unchecked {
            require(x != MIN_64x64);
            return -x;
        }
    }

    /**
     * Calculate |x|.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function abs(int128 x) internal pure returns (int128) {
        unchecked {
            require(x != MIN_64x64);
            return x < 0 ? -x : x;
        }
    }

    /**
     * Calculate 1 / x rounding towards zero.  Revert on overflow or when x is
     * zero.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function inv(int128 x) internal pure returns (int128) {
        unchecked {
            require(x != 0);
            int256 result = int256(0x100000000000000000000000000000000) / x;
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate arithmetics average of x and y, i.e. (x + y) / 2 rounding down.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function avg(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            return int128((int256(x) + int256(y)) >> 1);
        }
    }

    /**
     * Calculate geometric average of x and y, i.e. sqrt (x * y) rounding down.
     * Revert on overflow or in case x * y is negative.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function gavg(int128 x, int128 y) internal pure returns (int128) {
        unchecked {
            int256 m = int256(x) * int256(y);
            require(m >= 0);
            require(m < 0x4000000000000000000000000000000000000000000000000000000000000000);
            return int128(sqrtu(uint256(m)));
        }
    }

    /**
     * Calculate x^y assuming 0^0 is 1, where x is signed 64.64 fixed point number
     * and y is unsigned 256-bit integer number.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @param y uint256 value
     * @return signed 64.64-bit fixed point number
     */
    function pow(int128 x, uint256 y) internal pure returns (int128) {
        unchecked {
            bool negative = x < 0 && y & 1 == 1;

            uint256 absX = uint128(x < 0 ? -x : x);
            uint256 absResult;
            absResult = 0x100000000000000000000000000000000;

            if (absX <= 0x10000000000000000) {
                absX <<= 63;
                while (y != 0) {
                    if (y & 0x1 != 0) {
                        absResult = absResult * absX >> 127;
                    }
                    absX = absX * absX >> 127;

                    if (y & 0x2 != 0) {
                        absResult = absResult * absX >> 127;
                    }
                    absX = absX * absX >> 127;

                    if (y & 0x4 != 0) {
                        absResult = absResult * absX >> 127;
                    }
                    absX = absX * absX >> 127;

                    if (y & 0x8 != 0) {
                        absResult = absResult * absX >> 127;
                    }
                    absX = absX * absX >> 127;

                    y >>= 4;
                }

                absResult >>= 64;
            } else {
                uint256 absXShift = 63;
                if (absX < 0x1000000000000000000000000) {
                    absX <<= 32;
                    absXShift -= 32;
                }
                if (absX < 0x10000000000000000000000000000) {
                    absX <<= 16;
                    absXShift -= 16;
                }
                if (absX < 0x1000000000000000000000000000000) {
                    absX <<= 8;
                    absXShift -= 8;
                }
                if (absX < 0x10000000000000000000000000000000) {
                    absX <<= 4;
                    absXShift -= 4;
                }
                if (absX < 0x40000000000000000000000000000000) {
                    absX <<= 2;
                    absXShift -= 2;
                }
                if (absX < 0x80000000000000000000000000000000) {
                    absX <<= 1;
                    absXShift -= 1;
                }

                uint256 resultShift = 0;
                while (y != 0) {
                    require(absXShift < 64);

                    if (y & 0x1 != 0) {
                        absResult = absResult * absX >> 127;
                        resultShift += absXShift;
                        if (absResult > 0x100000000000000000000000000000000) {
                            absResult >>= 1;
                            resultShift += 1;
                        }
                    }
                    absX = absX * absX >> 127;
                    absXShift <<= 1;
                    if (absX >= 0x100000000000000000000000000000000) {
                        absX >>= 1;
                        absXShift += 1;
                    }

                    y >>= 1;
                }

                require(resultShift < 64);
                absResult >>= 64 - resultShift;
            }
            int256 result = negative ? -int256(absResult) : int256(absResult);
            require(result >= MIN_64x64 && result <= MAX_64x64);
            return int128(result);
        }
    }

    /**
     * Calculate sqrt (x) rounding down.  Revert if x < 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function sqrt(int128 x) internal pure returns (int128) {
        unchecked {
            require(x >= 0);
            return int128(sqrtu(uint256(int256(x)) << 64));
        }
    }

    /**
     * Calculate binary logarithm of x.  Revert if x <= 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function log_2(int128 x) internal pure returns (int128) {
        unchecked {
            require(x > 0);

            int256 msb = 0;
            int256 xc = x;
            if (xc >= 0x10000000000000000) {
                xc >>= 64;
                msb += 64;
            }
            if (xc >= 0x100000000) {
                xc >>= 32;
                msb += 32;
            }
            if (xc >= 0x10000) {
                xc >>= 16;
                msb += 16;
            }
            if (xc >= 0x100) {
                xc >>= 8;
                msb += 8;
            }
            if (xc >= 0x10) {
                xc >>= 4;
                msb += 4;
            }
            if (xc >= 0x4) {
                xc >>= 2;
                msb += 2;
            }
            if (xc >= 0x2) msb += 1; // No need to shift xc anymore

            int256 result = msb - 64 << 64;
            uint256 ux = uint256(int256(x)) << uint256(127 - msb);
            for (int256 bit = 0x8000000000000000; bit > 0; bit >>= 1) {
                ux *= ux;
                uint256 b = ux >> 255;
                ux >>= 127 + b;
                result += bit * int256(b);
            }

            return int128(result);
        }
    }

    /**
     * Calculate natural logarithm of x.  Revert if x <= 0.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function ln(int128 x) internal pure returns (int128) {
        unchecked {
            require(x > 0);

            return int128(int256(uint256(int256(log_2(x))) * 0xB17217F7D1CF79ABC9E3B39803F2F6AF >> 128));
        }
    }

    /**
     * Calculate binary exponent of x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function exp_2(int128 x) internal pure returns (int128) {
        unchecked {
            require(x < 0x400000000000000000); // Overflow

            if (x < -0x400000000000000000) return 0; // Underflow

            uint256 result = 0x80000000000000000000000000000000;

            if (x & 0x8000000000000000 > 0) {
                result = result * 0x16A09E667F3BCC908B2FB1366EA957D3E >> 128;
            }
            if (x & 0x4000000000000000 > 0) {
                result = result * 0x1306FE0A31B7152DE8D5A46305C85EDEC >> 128;
            }
            if (x & 0x2000000000000000 > 0) {
                result = result * 0x1172B83C7D517ADCDF7C8C50EB14A791F >> 128;
            }
            if (x & 0x1000000000000000 > 0) {
                result = result * 0x10B5586CF9890F6298B92B71842A98363 >> 128;
            }
            if (x & 0x800000000000000 > 0) {
                result = result * 0x1059B0D31585743AE7C548EB68CA417FD >> 128;
            }
            if (x & 0x400000000000000 > 0) {
                result = result * 0x102C9A3E778060EE6F7CACA4F7A29BDE8 >> 128;
            }
            if (x & 0x200000000000000 > 0) {
                result = result * 0x10163DA9FB33356D84A66AE336DCDFA3F >> 128;
            }
            if (x & 0x100000000000000 > 0) {
                result = result * 0x100B1AFA5ABCBED6129AB13EC11DC9543 >> 128;
            }
            if (x & 0x80000000000000 > 0) {
                result = result * 0x10058C86DA1C09EA1FF19D294CF2F679B >> 128;
            }
            if (x & 0x40000000000000 > 0) {
                result = result * 0x1002C605E2E8CEC506D21BFC89A23A00F >> 128;
            }
            if (x & 0x20000000000000 > 0) {
                result = result * 0x100162F3904051FA128BCA9C55C31E5DF >> 128;
            }
            if (x & 0x10000000000000 > 0) {
                result = result * 0x1000B175EFFDC76BA38E31671CA939725 >> 128;
            }
            if (x & 0x8000000000000 > 0) {
                result = result * 0x100058BA01FB9F96D6CACD4B180917C3D >> 128;
            }
            if (x & 0x4000000000000 > 0) {
                result = result * 0x10002C5CC37DA9491D0985C348C68E7B3 >> 128;
            }
            if (x & 0x2000000000000 > 0) {
                result = result * 0x1000162E525EE054754457D5995292026 >> 128;
            }
            if (x & 0x1000000000000 > 0) {
                result = result * 0x10000B17255775C040618BF4A4ADE83FC >> 128;
            }
            if (x & 0x800000000000 > 0) {
                result = result * 0x1000058B91B5BC9AE2EED81E9B7D4CFAB >> 128;
            }
            if (x & 0x400000000000 > 0) {
                result = result * 0x100002C5C89D5EC6CA4D7C8ACC017B7C9 >> 128;
            }
            if (x & 0x200000000000 > 0) {
                result = result * 0x10000162E43F4F831060E02D839A9D16D >> 128;
            }
            if (x & 0x100000000000 > 0) {
                result = result * 0x100000B1721BCFC99D9F890EA06911763 >> 128;
            }
            if (x & 0x80000000000 > 0) {
                result = result * 0x10000058B90CF1E6D97F9CA14DBCC1628 >> 128;
            }
            if (x & 0x40000000000 > 0) {
                result = result * 0x1000002C5C863B73F016468F6BAC5CA2B >> 128;
            }
            if (x & 0x20000000000 > 0) {
                result = result * 0x100000162E430E5A18F6119E3C02282A5 >> 128;
            }
            if (x & 0x10000000000 > 0) {
                result = result * 0x1000000B1721835514B86E6D96EFD1BFE >> 128;
            }
            if (x & 0x8000000000 > 0) {
                result = result * 0x100000058B90C0B48C6BE5DF846C5B2EF >> 128;
            }
            if (x & 0x4000000000 > 0) {
                result = result * 0x10000002C5C8601CC6B9E94213C72737A >> 128;
            }
            if (x & 0x2000000000 > 0) {
                result = result * 0x1000000162E42FFF037DF38AA2B219F06 >> 128;
            }
            if (x & 0x1000000000 > 0) {
                result = result * 0x10000000B17217FBA9C739AA5819F44F9 >> 128;
            }
            if (x & 0x800000000 > 0) {
                result = result * 0x1000000058B90BFCDEE5ACD3C1CEDC823 >> 128;
            }
            if (x & 0x400000000 > 0) {
                result = result * 0x100000002C5C85FE31F35A6A30DA1BE50 >> 128;
            }
            if (x & 0x200000000 > 0) {
                result = result * 0x10000000162E42FF0999CE3541B9FFFCF >> 128;
            }
            if (x & 0x100000000 > 0) {
                result = result * 0x100000000B17217F80F4EF5AADDA45554 >> 128;
            }
            if (x & 0x80000000 > 0) {
                result = result * 0x10000000058B90BFBF8479BD5A81B51AD >> 128;
            }
            if (x & 0x40000000 > 0) {
                result = result * 0x1000000002C5C85FDF84BD62AE30A74CC >> 128;
            }
            if (x & 0x20000000 > 0) {
                result = result * 0x100000000162E42FEFB2FED257559BDAA >> 128;
            }
            if (x & 0x10000000 > 0) {
                result = result * 0x1000000000B17217F7D5A7716BBA4A9AE >> 128;
            }
            if (x & 0x8000000 > 0) {
                result = result * 0x100000000058B90BFBE9DDBAC5E109CCE >> 128;
            }
            if (x & 0x4000000 > 0) {
                result = result * 0x10000000002C5C85FDF4B15DE6F17EB0D >> 128;
            }
            if (x & 0x2000000 > 0) {
                result = result * 0x1000000000162E42FEFA494F1478FDE05 >> 128;
            }
            if (x & 0x1000000 > 0) {
                result = result * 0x10000000000B17217F7D20CF927C8E94C >> 128;
            }
            if (x & 0x800000 > 0) {
                result = result * 0x1000000000058B90BFBE8F71CB4E4B33D >> 128;
            }
            if (x & 0x400000 > 0) {
                result = result * 0x100000000002C5C85FDF477B662B26945 >> 128;
            }
            if (x & 0x200000 > 0) {
                result = result * 0x10000000000162E42FEFA3AE53369388C >> 128;
            }
            if (x & 0x100000 > 0) {
                result = result * 0x100000000000B17217F7D1D351A389D40 >> 128;
            }
            if (x & 0x80000 > 0) {
                result = result * 0x10000000000058B90BFBE8E8B2D3D4EDE >> 128;
            }
            if (x & 0x40000 > 0) {
                result = result * 0x1000000000002C5C85FDF4741BEA6E77E >> 128;
            }
            if (x & 0x20000 > 0) {
                result = result * 0x100000000000162E42FEFA39FE95583C2 >> 128;
            }
            if (x & 0x10000 > 0) {
                result = result * 0x1000000000000B17217F7D1CFB72B45E1 >> 128;
            }
            if (x & 0x8000 > 0) {
                result = result * 0x100000000000058B90BFBE8E7CC35C3F0 >> 128;
            }
            if (x & 0x4000 > 0) {
                result = result * 0x10000000000002C5C85FDF473E242EA38 >> 128;
            }
            if (x & 0x2000 > 0) {
                result = result * 0x1000000000000162E42FEFA39F02B772C >> 128;
            }
            if (x & 0x1000 > 0) {
                result = result * 0x10000000000000B17217F7D1CF7D83C1A >> 128;
            }
            if (x & 0x800 > 0) {
                result = result * 0x1000000000000058B90BFBE8E7BDCBE2E >> 128;
            }
            if (x & 0x400 > 0) {
                result = result * 0x100000000000002C5C85FDF473DEA871F >> 128;
            }
            if (x & 0x200 > 0) {
                result = result * 0x10000000000000162E42FEFA39EF44D91 >> 128;
            }
            if (x & 0x100 > 0) {
                result = result * 0x100000000000000B17217F7D1CF79E949 >> 128;
            }
            if (x & 0x80 > 0) {
                result = result * 0x10000000000000058B90BFBE8E7BCE544 >> 128;
            }
            if (x & 0x40 > 0) {
                result = result * 0x1000000000000002C5C85FDF473DE6ECA >> 128;
            }
            if (x & 0x20 > 0) {
                result = result * 0x100000000000000162E42FEFA39EF366F >> 128;
            }
            if (x & 0x10 > 0) {
                result = result * 0x1000000000000000B17217F7D1CF79AFA >> 128;
            }
            if (x & 0x8 > 0) {
                result = result * 0x100000000000000058B90BFBE8E7BCD6D >> 128;
            }
            if (x & 0x4 > 0) {
                result = result * 0x10000000000000002C5C85FDF473DE6B2 >> 128;
            }
            if (x & 0x2 > 0) {
                result = result * 0x1000000000000000162E42FEFA39EF358 >> 128;
            }
            if (x & 0x1 > 0) {
                result = result * 0x10000000000000000B17217F7D1CF79AB >> 128;
            }

            result >>= uint256(int256(63 - (x >> 64)));
            require(result <= uint256(int256(MAX_64x64)));

            return int128(int256(result));
        }
    }

    /**
     * Calculate natural exponent of x.  Revert on overflow.
     *
     * @param x signed 64.64-bit fixed point number
     * @return signed 64.64-bit fixed point number
     */
    function exp(int128 x) internal pure returns (int128) {
        unchecked {
            require(x < 0x400000000000000000); // Overflow

            if (x < -0x400000000000000000) return 0; // Underflow

            return exp_2(int128(int256(x) * 0x171547652B82FE1777D0FFDA0D23A7D12 >> 128));
        }
    }

    /**
     * Calculate x / y rounding towards zero, where x and y are unsigned 256-bit
     * integer numbers.  Revert on overflow or when y is zero.
     *
     * @param x unsigned 256-bit integer number
     * @param y unsigned 256-bit integer number
     * @return unsigned 64.64-bit fixed point number
     */
    function divuu(uint256 x, uint256 y) private pure returns (uint128) {
        unchecked {
            require(y != 0);

            uint256 result;

            if (x <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF) {
                result = (x << 64) / y;
            } else {
                uint256 msb = 192;
                uint256 xc = x >> 192;
                if (xc >= 0x100000000) {
                    xc >>= 32;
                    msb += 32;
                }
                if (xc >= 0x10000) {
                    xc >>= 16;
                    msb += 16;
                }
                if (xc >= 0x100) {
                    xc >>= 8;
                    msb += 8;
                }
                if (xc >= 0x10) {
                    xc >>= 4;
                    msb += 4;
                }
                if (xc >= 0x4) {
                    xc >>= 2;
                    msb += 2;
                }
                if (xc >= 0x2) msb += 1; // No need to shift xc anymore

                result = (x << 255 - msb) / ((y - 1 >> msb - 191) + 1);
                require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

                uint256 hi = result * (y >> 128);
                uint256 lo = result * (y & 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);

                uint256 xh = x >> 192;
                uint256 xl = x << 64;

                if (xl < lo) xh -= 1;
                xl -= lo; // We rely on overflow behavior here
                lo = hi << 128;
                if (xl < lo) xh -= 1;
                xl -= lo; // We rely on overflow behavior here

                result += xh == hi >> 128 ? xl / y : 1;
            }

            require(result <= 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
            return uint128(result);
        }
    }

    /**
     * Calculate sqrt (x) rounding down, where x is unsigned 256-bit integer
     * number.
     *
     * @param x unsigned 256-bit integer number
     * @return unsigned 128-bit integer number
     */
    function sqrtu(uint256 x) private pure returns (uint128) {
        unchecked {
            if (x == 0) {
                return 0;
            } else {
                uint256 xx = x;
                uint256 r = 1;
                if (xx >= 0x100000000000000000000000000000000) {
                    xx >>= 128;
                    r <<= 64;
                }
                if (xx >= 0x10000000000000000) {
                    xx >>= 64;
                    r <<= 32;
                }
                if (xx >= 0x100000000) {
                    xx >>= 32;
                    r <<= 16;
                }
                if (xx >= 0x10000) {
                    xx >>= 16;
                    r <<= 8;
                }
                if (xx >= 0x100) {
                    xx >>= 8;
                    r <<= 4;
                }
                if (xx >= 0x10) {
                    xx >>= 4;
                    r <<= 2;
                }
                if (xx >= 0x4) r <<= 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1;
                r = (r + x / r) >> 1; // Seven iterations should be enough
                uint256 r1 = x / r;
                return uint128(r < r1 ? r : r1);
            }
        }
    }
}

File 5 of 27 : IGlow.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IGlow is IERC20 {
    /* -------------------------------------------------------------------------- */
    /*                                   errors                                   */
    /* -------------------------------------------------------------------------- */
    error UnstakeAmountExceedsStakedBalance();
    error InsufficientClaimableBalance();
    error CannotStakeZeroTokens();
    error CannotUnstakeZeroTokens();
    error AddressAlreadySet();
    error AddressNotSet();
    error CallerNotGCA();
    error CallerNotVetoCouncil();
    error CallerNotGrantsTreasury();
    error UnstakingOnEmergencyCooldown();
    error ZeroAddressNotAllowed();
    error DuplicateAddressNotAllowed();
    error CannotClaimZeroTokens();

    /* -------------------------------------------------------------------------- */
    /*                                      events                                */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice Emitted when a user stakes GLOW
     * @param user The address of the user that is staking
     * @param amount The amount staked
     */
    event Stake(address indexed user, uint256 amount);

    /**
     * @notice Emitted when a user unstakes GLOW
     * @param user The address of the user that is unstaking
     * @param amount The amount unstaked
     */
    event Unstake(address indexed user, uint256 amount);

    /**
     * @notice Emitted when a user claims GLOW from there unstaked positions
     * @param user The address of the user that is claiming
     * @param amount The amount claimed
     */
    event ClaimUnstakedGLW(address indexed user, uint256 amount);

    /* -------------------------------------------------------------------------- */
    /*                                   structs                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice represents an unstaked position
     * @param amount The amount of GLOW unstaked
     * @param cooldownEnd The timestamp when the user can reclaim the tokens
     */
    struct UnstakedPosition {
        uint192 amount;
        uint64 cooldownEnd;
    }

    /**
     * @dev helper for managing tail and head in a mapping
     * @param tail the tail of the mapping
     * @param head the head of the mapping
     * @dev the head is the last index with data. If we need to push, we push at head + 1
     * @dev there are edge cases where head == tail and there is data,
     *         -   and conversely, head == tail and there is no data
     *         - These special cases are handled in the code
     */
    struct Pointers {
        uint128 tail;
        uint128 head;
    }

    /* -------------------------------------------------------------------------- */
    /*                                   staking                                  */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice The entry point for a user to stake glow.
     * @notice A user earns 1 ratify/reject vote per glw staked
     * @param amount The amount of GLOW to stake
     */
    function stake(uint256 amount) external;

    /**
     * @notice The entry point for a user to unstake glow.
     * @param amount The amount of GLOW to unstake
     */
    function unstake(uint256 amount) external;

    /* -------------------------------------------------------------------------- */
    /*                                   inflation                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice Entry point for users to claim unstaked tokens that are no longer on cooldown
     * @param amount The amount of tokens to claim
     * @dev emits a ```ClaimUnstakedGLW``` event
     */
    function claimUnstakedTokens(uint256 amount) external;

    /**
     * @notice Allows the GCA and Miner Pool Contract to claim GLW from inflation
     * @notice The GCA and Miner Pool Contract receives 185,00 * 1e18 tokens per week
     */
    function claimGLWFromGCAAndMinerPool() external returns (uint256);

    /**
     * @notice Allows the Veto Council to claim GLW from inflation
     * @notice The veto council receives 5,000 * 1e18 tokens per week
     */
    function claimGLWFromVetoCouncil() external returns (uint256);

    /**
     * @notice Allows the Grants Treasury to claim GLW from inflation
     * @notice The grants treasury receives 40,000 * 1e18 tokens per week
     */
    function claimGLWFromGrantsTreasury() external returns (uint256);

    /* -------------------------------------------------------------------------- */
    /*                            view unstaked positions                          */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Returns the unstaked positions of a user
     * @param account The address of the user
     */
    function unstakedPositionsOf(address account) external view returns (UnstakedPosition[] memory);

    /**
     * @notice Returns the unstaked positions of a user
     * @param account The address of the user
     * @param start The start index of the positions to return
     * @param end The end index of the positions to return
     */
    function unstakedPositionsOf(address account, uint256 start, uint256 end)
        external
        view
        returns (UnstakedPosition[] memory);

    /* -------------------------------------------------------------------------- */
    /*                             view inflation data                           */
    /* -------------------------------------------------------------------------- */
    /**
     * @return lastClaimTimestamp The last time the GCA and Miner Pool Contract claimed GLW
     * @return totalAlreadyClaimed The total amount of GLW already claimed by the GCA and Miner Pool Contract
     * @return totalToClaim The total amount of GLW available to claim by the GCA and Miner Pool Contract
     */
    function gcaInflationData()
        external
        view
        returns (uint256 lastClaimTimestamp, uint256 totalAlreadyClaimed, uint256 totalToClaim);

    /**
     * @return lastClaimTimestamp The last time the Veto Council claimed GLW
     * @return totalAlreadyClaimed The total amount of GLW already claimed by the Veto Council
     * @return totalToClaim The total amount of GLW available to claim by the Veto Council
     */
    function vetoCouncilInflationData()
        external
        view
        returns (uint256 lastClaimTimestamp, uint256 totalAlreadyClaimed, uint256 totalToClaim);

    /**
     * @return lastClaimTimestamp The last time the Grants Treasury claimed GLW
     * @return totalAlreadyClaimed The total amount of GLW already claimed by the Grants Treasury
     * @return totalToClaim The total amount of GLW available to claim by the Grants Treasury
     */
    function grantsTreasuryInflationData()
        external
        view
        returns (uint256 lastClaimTimestamp, uint256 totalAlreadyClaimed, uint256 totalToClaim);

    /* -------------------------------------------------------------------------- */
    /*                                   view                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @return the genesis timestamp
     */
    function GENESIS_TIMESTAMP() external view returns (uint256);

    /**
     * @notice the total amount of GLW currently staked by {account}
     * @return numStaked total amount of GLW currently staked by {account}
     * @param account the address of the account to get the staked balance of
     */
    function numStaked(address account) external view returns (uint256);
}

File 6 of 27 : IVetoCouncil.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IVetoCouncil {
    /* -------------------------------------------------------------------------- */
    /*                                   errors                                    */
    /* -------------------------------------------------------------------------- */
    error CallerNotGovernance();
    error NoRewards();
    error ZeroAddressInConstructor();
    error MaxCouncilMembersExceeded();

    /* -------------------------------------------------------------------------- */
    /*                                   events                                    */
    /* -------------------------------------------------------------------------- */

    /**
     * @param oldMember The address of the member to be slashed or removed
     * @param newMember The address of the new member (0 = no new member)
     * @param slashOldMember Whether to slash the member or not
     */
    event VetoCouncilSeatsEdited(address indexed oldMember, address indexed newMember, bool slashOldMember);

    /**
     * @dev emitted when a council member is paid out
     * @param account The address of the council member
     * @param amountNow The amount paid out now
     * @param amountToBeVested The amount to be vested
     */
    event CouncilMemberPayout(address indexed account, uint256 amountNow, uint256 amountToBeVested);
    /* -------------------------------------------------------------------------- */
    /*                                 state-changing                             */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice Add or remove a council member
     * @param oldMember The address of the member to be slashed or removed
     * @param newMember The address of the new member (0 = no new member)
     * @param slashOldMember Whether to slash the member or not
     * @return - true if the council member was added or removed, false if nothing was done
     *                 - the function should return false if the new member is already a council member
     *                 - if the old member is not a council member, the function should return false
     *                 - if the old member is a council member and the new member is the same as the old member, the function should return false
     *                 - by adding a new member there would be more than 7 council members, the function should return false
     */

    function addAndRemoveCouncilMember(address oldMember, address newMember, bool slashOldMember)
        external
        returns (bool);

    /**
     * @notice Payout the council member
     * @param member The address of the council member
     * @param nonce The payout nonce to claim from
     * @param sync Whether to sync the vesting schedule or not
     * @param members The addresses of the council members that were active at `nonce`
     */
    function claimPayout(address member, uint256 nonce, bool sync, address[] memory members) external;

    /* -------------------------------------------------------------------------- */
    /*                                   view                                    */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice returns true if the member is a council member
     * @param member The address of the member to be checked
     * @return - true if the member is a council member
     */
    function isCouncilMember(address member) external view returns (bool);
}

File 7 of 27 : IGCA.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IGCA {
    /* -------------------------------------------------------------------------- */
    /*                                   errors                                  */
    /* -------------------------------------------------------------------------- */
    error NotGCA();
    error CallerNotGCA();
    error CompensationPlanLengthMustBeGreaterThanZero();
    error InsufficientShares();
    error NoBalanceToPayout();
    error CallerNotGovernance();
    error ProposalHashesNotUpdated();
    error ProposalHashDoesNotMatch();
    error IndexDoesNotMatchNextProposalIndex();
    error ProposalHashesEmpty();
    error ProposalAlreadyUpdated();
    error BucketAlreadyFinalized();
    error ReportGCCMustBeLT200Billion();
    error ReportWeightMustBeLTUint64MaxDiv5();
    error BucketSubmissionNotOpen();
    error BucketSubmissionEnded();
    error EmptyRoot();
    error CallerNotGCAAtIndex();
    error GCCAlreadySet();
    error BucketIndexOutOfBounds();

    /* -------------------------------------------------------------------------- */
    /*                                   structs                                  */
    /* -------------------------------------------------------------------------- */
    /**
     * @dev a struct to represent a compensation plan
     * @dev packed into a single uint256
     * @param shares - the amount of shares to be distributed
     * @param agent - the address of the gca agent to receive the shares
     */
    struct ICompensation {
        uint80 shares;
        address agent;
    }

    /**
     * @dev a struct to represent a gca payout
     * @param lastClaimedTimestamp - the last time the gca claimed their payout
     * @param totalSlashableBalance - the total slashable balance of the gca
     */
    struct GCAPayout {
        uint64 lastClaimedTimestamp;
        uint64 maxClaimTimestamp;
        uint128 totalSlashableBalance;
    }

    /**
     * @dev a struct to represent a report
     * @param totalNewGCC - the total amount of new gcc
     * @param totalGLWRewardsWeight - the total amount of glw rewards weight
     * @param totalGRCRewardsWeight - the total amount of grc rewards weight
     * @param merkleRoot - the root containing all the reports (leaves) for the period
     *             - The leaf structure is as follows:
     *                 -   (address payoutWallet,uint256 glwRewardsWeight,uint256 grcRewardsWeight)
     * @param proposingAgent - the address of the gca agent proposing the report
     */
    struct Report {
        uint128 totalNewGCC;
        uint64 totalGLWRewardsWeight;
        uint64 totalGRCRewardsWeight;
        bytes32 merkleRoot;
        address proposingAgent;
    }
    //3 slots

    /**
     * @param originalNonce - the slash nonce in storage at the time of report submission
     * @param lastUpdatedNonce - the slash nonce in storage at the time of the last report submission
     * @param finalizationTimestamp - the finalization timestamp for the bucket according to the weekly bucket schedule
     * @param reports - the reports for the bucket
     */
    struct Bucket {
        uint64 originalNonce;
        uint64 lastUpdatedNonce;
        uint128 finalizationTimestamp;
        Report[] reports;
    }

    /**
     * @dev a struct to represent a bucket global state
     * @dev its used as a caching mechanism to avoid iterating over all buckets
     * @param totalNewGCC - the total amount of new gcc
     * @param totalGLWRewardsWeight - the total amount of glw rewards weight
     * @param totalGRCRewardsWeight - the total amount of grc rewards weight
     */
    struct BucketGlobalState {
        uint128 totalNewGCC;
        uint64 totalGLWRewardsWeight;
        uint64 totalGRCRewardsWeight;
    }

    /* -------------------------------------------------------------------------- */
    /*                                   events                                   */
    /* -------------------------------------------------------------------------- */
    /**
     * @dev Emitted when a gca submits a new compensation plan.
     * @param agent - the address of the gca agent proposing
     * @param plan - the compensation plan of the agent
     */
    event CompensationPlanSubmitted(address indexed agent, uint32[5] plan);

    /**
     * @dev Emitted when a gca claims their payout
     * @param agent - the address of the gca agent claiming
     * @param amount - the amount of tokens claimed
     * @param totalSlashableBalance - the total slashable balance of the gca
     */
    event GCAPayoutClaimed(address indexed agent, uint256 amount, uint256 totalSlashableBalance);

    /**
     * @dev Emitted when a proposal hash is acted upon
     * @param index - the index of the proposal hash inside the {proposalHashes} array
     * @param proposalHash - the proposal hash
     */
    event ProposalHashUpdate(uint256 indexed index, bytes32 proposalHash);

    /**
     * @dev emitted when a proposal hash is pushed
     * @param proposalHash - the proposal hash
     */
    event ProposalHashPushed(bytes32 proposalHash);

    /**
     * @dev Emitted when governacne updates the {requirementsHash}
     * @param requirementsHash - the new requirements hash gcas must abide by
     */
    event RequirementsHashUpdated(bytes32 requirementsHash);

    /**
     * @dev emitted when new GCAs are appointed
     * @dev the new GCAs completely replace the old ones
     * @param newGcas - the new GCAs
     */
    event NewGCAsAppointed(address[] newGcas);

    /**
     * @dev emitted when GCAs are slashed
     * @param slashedGcas - the slashed GCAs
     */
    event GCAsSlashed(address[] slashedGcas);

    /**
     * @notice emitted when a GCA submits a report for a bucket
     * @param bucketId - the id of the bucket
     * @param gca - the address of the gca agent submitting the report
     * @param slashNonce - the slash nonce at the time of report submission
     * @param totalNewGCC - the total amount of new gcc from the farms the GCA is reporting on
     * @param totalGlwRewardsWeight - the total amount of glw rewards weight from the farms the GCA is reporting on
     * @param totalGRCRewardsWeight - the total amount of grc rewards weight from the farms the GCA is reporting on
     * @param root - the merkle root of the reports
     * @param extraData - extra data to be emitted.
     *                         - This extra data can be anything as long as the GCA communicates it to the community
     *                         - and should ideally, if possible, be the leaves of the merkle tree
     */
    event BucketSubmissionEvent(
        uint256 indexed bucketId,
        address gca,
        uint256 slashNonce,
        uint256 totalNewGCC,
        uint256 totalGlwRewardsWeight,
        uint256 totalGRCRewardsWeight,
        bytes32 root,
        bytes extraData
    );

    /* -------------------------------------------------------------------------- */
    /*                                 state changing funcs                       */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice allows governance to push a hash to execute against
     * @param hash - the hash to execute against
     * @param incrementSlashNonce - whether or not to increment the slash nonce
     *         - incrementing the slash nonce means that all non-finalized buckets will be slashed
     *             - and must be reinstated
     * @dev the hash is the abi.encode of the following:
     *         - the gca agents to slash
     *         - the new gca agents
     *         - the proposal creation timestamp
     */
    function pushHash(bytes32 hash, bool incrementSlashNonce) external;

    /**
     * @notice allows governance to change the requirements hash of GCA's
     *         - the requirements hash represents a hash of the duties and responsibilities of a GCA
     * @param  _requirementsHash - the new requirements hash
     */
    function setRequirementsHash(bytes32 _requirementsHash) external;

    /// @dev allows GCAs to submit a compensation plan
    function submitCompensationPlan(uint32[5] calldata plan, uint256 indexOfGCA) external;

    /// @dev allows the contract to pull glow from inflation
    function claimGlowFromInflation() external;

    /* -------------------------------------------------------------------------- */
    /*                                   view functions                            */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice returns true if the caller is a gca
     * @param account - the address of the account to check
     * @return status -  true if the account is a gca , false otherwise
     */
    function isGCA(address account) external view returns (bool);

    /**
     * @notice returns true if the caller is a gca
     * @param account - the address of the account to check
     * @param index - the index of the gca in the gca array
     * @return status -  true if the account is a gca , false otherwise
     */
    function isGCA(address account, uint256 index) external view returns (bool);

    /// @return - returns all the gcas
    function allGcas() external view returns (address[] memory);

    /**
     * @param gca - the address of the gca to check
     * @return - returns the {GCAPayout} struct data for a gca
     */
    function gcaPayoutData(address gca) external view returns (GCAPayout memory);

    /**
     * @notice - returns all proposal hashes
     * @return proposalHashes - the proposal hashes
     */
    function getProposalHashes() external view returns (bytes32[] memory);

    /**
     * @notice - returns a range of proposal hashes
     * @param start - the start index
     * @param end - the end index
     * @return proposalHashes - the proposal hashes
     */
    function getProposalHashes(uint256 start, uint256 end) external view returns (bytes32[] memory);

    /**
     * @notice returns the global state of a bucket
     * @param bucketId - the id of the bucket
     * @return the global state of a bucket
     */
    function bucketGlobalState(uint256 bucketId) external view returns (BucketGlobalState memory);

    /**
     * @notice returns the {Bucket} struct for a given week / bucketId
     * @param bucketId - the id of the bucket
     * @return bucket - the {Bucket} struct for a given bucketId
     */
    function bucket(uint256 bucketId) external view returns (Bucket memory);

    /**
     * @notice returns if the bucket is finalized or not
     * @param bucketId - the id of the bucket
     */

    function isBucketFinalized(uint256 bucketId) external view returns (bool);
}

File 8 of 27 : IGrantsTreasury.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IGrantsTreasury {
    /* -------------------------------------------------------------------------- */
    /*                                   errors                                    */
    /* -------------------------------------------------------------------------- */
    error CallerNotGovernance();
    error AllocationCannotBeZero();

    /* -------------------------------------------------------------------------- */
    /*                                   events                                    */
    /* -------------------------------------------------------------------------- */

    /**
     * @notice Emitted when a grant is succesfully allocated
     *     @param recipient The address of the recipient
     *     @param amount The amount of GLOW allocated
     */
    event GrantFundsAllocated(address indexed recipient, uint256 amount);

    /**
     * @notice Emitted when a grant allocation fails due to insufficient balance
     *     @param recipient The address of the recipient
     *     @param amount The amount of GLOW allocated
     */
    event GrantFundsAllocationFailed(address indexed recipient, uint256 amount);

    /**
     * @notice Emitted when a grant is succesfully claimed
     * @param to The address of the recipient
     * @param amount The amount of GLOW claimed
     */
    event GrantFundsClaimed(address indexed to, uint256 amount);

    /**
     * @notice Emitted when the treasury is synced
     *     @param amount The amount of GLOW synced
     */
    event TreasurySynced(uint256 amount);

    /* -------------------------------------------------------------------------- */
    /*                                  state-changing                            */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice The entry point for the Governance contract to allocate grant funds
     * @param to The address of the recipient
     * @param amount The amount of GLOW to allocate
     * @dev emits a {GrantFundsAllocated} event on success
     * @dev emits a {GrantFundsAllocationFailed} event on failure
     * @return true on success and false on failure
     */
    function allocateGrantFunds(address to, uint256 amount) external returns (bool);

    /**
     *   @notice The entry point for a recipient to claim their grant funds
     *   @dev emits a {GrantFundsClaimed} event on success
     */
    function claimGrantReward() external;

    /**
     * @notice pulls any unclaimed GLW from the Glow contract
     */
    function claimGlowFromTreasury() external;

    /* -------------------------------------------------------------------------- */
    /*                                   view                                    */
    /* -------------------------------------------------------------------------- */
    /**
     * @notice returns the total balance of GLW in the GrantsTreasury
     *     @return the total available balance that the Grants Treasury can allocate to new grants
     */
    function totalBalanceInGrantsTreasury() external view returns (uint256);
}

File 9 of 27 : EIP712.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/EIP712.sol)

pragma solidity ^0.8.20;

import {MessageHashUtils} from "./MessageHashUtils.sol";
import {ShortStrings, ShortString} from "../ShortStrings.sol";
import {IERC5267} from "../../interfaces/IERC5267.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding scheme specified in the EIP requires a domain separator and a hash of the typed structured data, whose
 * encoding is very generic and therefore its implementation in Solidity is not feasible, thus this contract
 * does not implement the encoding itself. Protocols need to implement the type-specific encoding they need in order to
 * produce the hash of their typed data using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * NOTE: In the upgradeable version of this contract, the cached values will correspond to the address, and the domain
 * separator of the implementation contract. This will cause the {_domainSeparatorV4} function to always rebuild the
 * separator from the immutable values, which is cheaper than accessing a cached version in cold storage.
 *
 * @custom:oz-upgrades-unsafe-allow state-variable-immutable
 */
abstract contract EIP712 is IERC5267 {
    using ShortStrings for *;

    bytes32 private constant _TYPE_HASH =
        keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)");

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _cachedDomainSeparator;
    uint256 private immutable _cachedChainId;
    address private immutable _cachedThis;

    bytes32 private immutable _hashedName;
    bytes32 private immutable _hashedVersion;

    ShortString private immutable _name;
    ShortString private immutable _version;
    string private _nameFallback;
    string private _versionFallback;

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        _name = name.toShortStringWithFallback(_nameFallback);
        _version = version.toShortStringWithFallback(_versionFallback);
        _hashedName = keccak256(bytes(name));
        _hashedVersion = keccak256(bytes(version));

        _cachedChainId = block.chainid;
        _cachedDomainSeparator = _buildDomainSeparator();
        _cachedThis = address(this);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _cachedThis && block.chainid == _cachedChainId) {
            return _cachedDomainSeparator;
        } else {
            return _buildDomainSeparator();
        }
    }

    function _buildDomainSeparator() private view returns (bytes32) {
        return keccak256(abi.encode(_TYPE_HASH, _hashedName, _hashedVersion, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return MessageHashUtils.toTypedDataHash(_domainSeparatorV4(), structHash);
    }

    /**
     * @dev See {IERC-5267}.
     */
    function eip712Domain()
        public
        view
        virtual
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        )
    {
        return (
            hex"0f", // 01111
            _EIP712Name(),
            _EIP712Version(),
            block.chainid,
            address(this),
            bytes32(0),
            new uint256[](0)
        );
    }

    /**
     * @dev The name parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _name which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Name() internal view returns (string memory) {
        return _name.toStringWithFallback(_nameFallback);
    }

    /**
     * @dev The version parameter for the EIP712 domain.
     *
     * NOTE: By default this function reads _version which is an immutable value.
     * It only reads from storage if necessary (in case the value is too large to fit in a ShortString).
     */
    // solhint-disable-next-line func-name-mixedcase
    function _EIP712Version() internal view returns (string memory) {
        return _version.toStringWithFallback(_versionFallback);
    }
}

File 10 of 27 : SignatureChecker.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/SignatureChecker.sol)

pragma solidity ^0.8.20;

import {ECDSA} from "./ECDSA.sol";
import {IERC1271} from "../../interfaces/IERC1271.sol";

/**
 * @dev Signature verification helper that can be used instead of `ECDSA.recover` to seamlessly support both ECDSA
 * signatures from externally owned accounts (EOAs) as well as ERC1271 signatures from smart contract wallets like
 * Argent and Safe Wallet (previously Gnosis Safe).
 */
library SignatureChecker {
    /**
     * @dev Checks if a signature is valid for a given signer and data hash. If the signer is a smart contract, the
     * signature is validated against that smart contract using ERC1271, otherwise it's validated using `ECDSA.recover`.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool) {
        (address recovered, ECDSA.RecoverError error, ) = ECDSA.tryRecover(hash, signature);
        return
            (error == ECDSA.RecoverError.NoError && recovered == signer) ||
            isValidERC1271SignatureNow(signer, hash, signature);
    }

    /**
     * @dev Checks if a signature is valid for a given signer and data hash. The signature is validated
     * against the signer smart contract using ERC1271.
     *
     * NOTE: Unlike ECDSA signatures, contract signatures are revocable, and the outcome of this function can thus
     * change through time. It could return true at block N and false at block N+1 (or the opposite).
     */
    function isValidERC1271SignatureNow(
        address signer,
        bytes32 hash,
        bytes memory signature
    ) internal view returns (bool) {
        (bool success, bytes memory result) = signer.staticcall(
            abi.encodeCall(IERC1271.isValidSignature, (hash, signature))
        );
        return (success &&
            result.length >= 32 &&
            abi.decode(result, (bytes32)) == bytes32(IERC1271.isValidSignature.selector));
    }
}

File 11 of 27 : VetoCouncilSalaryHelper.sol
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.19;

import {VestingMathLib} from "@/libraries/VestingMathLib.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IVetoCouncil} from "@/interfaces/IVetoCouncil.sol";

/// @dev we use a > 0 value as the null address
//      - to avoid deleting a slot and having to reinitialize it with a cold sstore
address constant NULL_ADDRESS = 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF;

/// @dev since there are no more than 7 veto council members
///     -   we use uint8.max as the null index
uint8 constant NULL_INDEX = type(uint8).max;

/**
 * @param isActive - whether or not the member is active
 * @param isSlashed - whether or not the member is slashed
 * @param indexInArray - the index inside the veto council members array
 */
struct Status {
    bool isActive;
    bool isSlashed;
    uint8 indexInArray;
}

/**
 * @title VetoCouncilSalaryHelper
 * @notice A library to help with the salary of the Veto Council
 *         -  handles the salary and payout of the Veto Council
 * @author DavidVorick
 * @author 0xSimon(twitter) - 0xSimbo(github)
 * @dev a nonce is a unique identifier for a shift and is incremented every time the salary rate changes
 *         - if an member is removed before the rate has changed, they will earn until their `shiftEndTimestamp`
 *  @dev payouts vest linearly at 1% per week.
 */
contract VetoCouncilSalaryHelper {
    error HashesNotUpdated();
    error CannotSetNonceToZero();
    error MaxSevenVetoCouncilMembers();
    error MemberNotFound();
    error ShiftHasNotStarted();
    error HashMismatch();

    /**
     * @dev The amount of GLOW that is awarded per second
     *          -   for the entire veto council
     */
    uint256 private constant REWARDS_PER_SECOND = 5000 ether / uint256(7 days);

    /**
     * @notice The nonce at which the current shift started
     * @dev initialized as 1 to avoid cold sstore for the first payment nonce
     */
    uint256 public paymentNonce = 1;

    /**
     * @dev (member -> Status)
     */
    mapping(address => Status) private _status;

    /**
     * @notice an array containing all the veto council members
     * @dev the null address is represented as 0xFFfFfFffFFfffFFfFFfFFFFFffFFFffffFfFFFfF
     */
    address[7] private _vetoCouncilMembers;

    /**
     * @notice paymentNonce -> keccak256(abi.encodePacked(vetoCouncilMembers))
     * @dev used in withdrawing rewards
     */
    mapping(uint256 => bytes32) public paymentNonceTomembersHash;

    /**
     * @dev payment nonce -> shift start timestamp
     */
    mapping(uint256 => uint256) private _paymentNonceToShiftStartTimestamp;

    /**
     * @notice The amount of tokens that have been withdrawn from a given payment nonce for a given member
     * @dev member -> payment nonce -> amount withdrawn
     */
    mapping(address => mapping(uint256 => uint256)) public amountAlreadyWithdrawnFromPaymentNonce;

    /**
     * @dev emitted when a member claims a payout
     * @param member - the address of the member that claimed the payout
     * @param nonce - the nonce of the payout
     * @param amount - the amount of tokens that were claimed
     */
    event PayoutClaimed(address indexed member, uint256 indexed nonce, uint256 amount);

    /**
     * ----------------------------------------------
     */
    /**
     * ----------       EXTERNAL VIEW --------------
     */
    /**
     * ----------------------------------------------
     */

    /**
     * @notice Returns the (withdrawableAmount, slashableAmount) for an member for a given nonce
     * @param member - the address of the members
     * @param nonce - the nonce of the payout
     * @return (withdrawableAmount, slashableAmount) - the amount of tokens that can be withdrawn and the amount that are still vesting
     */
    function payoutData(address member, uint256 nonce, address[] memory members)
        external
        view
        returns (uint256, uint256)
    {
        return _payoutData(member, nonce, members);
    }

    /**
     * @notice returns the `Status` struct for a given member
     * @param member The address of the member to get the `Status` struct for
     * @return status - the `Status` struct for the given member
     */
    function memberStatus(address member) public view returns (Status memory) {
        return _status[member];
    }

    /**
     * @notice returns the `shiftStartTimestamp` for a given nonce
     * @param nonce The nonce to get the `shiftStartTimestamp` for
     * @return shiftStartTimestamp - the `shiftStartTimestamp` for the given nonce
     */
    function paymentNonceToShiftStartTimestamp(uint256 nonce) public view returns (uint256) {
        return _paymentNonceToShiftStartTimestamp[nonce];
    }

    /**
     * @notice returns the array of veto council members without null addresses
     * @return sanitizedArray - all currently active veto council members
     */
    function vetoCouncilMembers() external view returns (address[] memory) {
        return arrayWithoutNulls(_vetoCouncilMembers);
    }

    /**
     * ----------------------------------------------
     */
    /**
     * -------     INTERNAL STATE CHANGING ---------
     */
    /**
     * ----------------------------------------------
     */

    /**
     * @dev Initializes the Veto Council
     * @dev should only be used in the constructor
     * @param members The addresses of the starting council members
     * @param genesisTimestamp The timestamp of the genesis block
     */
    function initializeMembers(address[] memory members, uint256 genesisTimestamp) internal {
        address[7] memory initmembers;
        if (members.length > type(uint8).max) {
            _revert(MaxSevenVetoCouncilMembers.selector);
        }
        uint8 len = uint8(members.length);
        unchecked {
            for (uint8 i; i < len; ++i) {
                if (isZero(members[i])) {
                    _revert(IVetoCouncil.ZeroAddressInConstructor.selector);
                }
                initmembers[i] = members[i];
                _status[members[i]] = Status({isActive: true, isSlashed: false, indexInArray: i});
            }
            for (uint8 i = len; i < 7; ++i) {
                initmembers[i] = NULL_ADDRESS;
            }
        }
        _vetoCouncilMembers = initmembers;
        paymentNonceTomembersHash[1] = keccak256(abi.encodePacked(members));
        _paymentNonceToShiftStartTimestamp[1] = genesisTimestamp;
    }

    /**
     * @dev Add or remove a council member
     * @param oldMember The address of the member to be slashed or removed
     * @param newMember The address of the new member (0 = no new member)
     * @param slashOldMember Whether to slash the member or not
     * @return - true if a council member was added or removed, false if nothing was done
     */
    function replaceMember(address oldMember, address newMember, bool slashOldMember) internal returns (bool) {
        //Cache the old member index
        uint8 memberOldIndex;

        bool isoldMemberZeroAddress = isZero(oldMember);
        bool isnewMemberZeroAddress = isZero(newMember);
        //If the old member is the zero address,
        //We need to loop until we find the first position in the array
        //Until we find a null address as that's where
        //we'll write the new member to
        //We start from the back of the array as that's where the null address will most likely be
        if (isoldMemberZeroAddress) {
            for (uint256 i; i < 7;) {
                uint256 index = 6 - i;
                address _vetomember = _vetoCouncilMembers[index];
                if (_vetomember == NULL_ADDRESS) {
                    memberOldIndex = uint8(index);
                    break;
                }
                unchecked {
                    ++i;
                }
            }
        } else {
            //load in the old member status
            Status memory oldMemberStatus = _status[oldMember];
            //Old member cannot be inactive if they're not the zero address
            if (!oldMemberStatus.isActive) {
                return false;
            }
            //find old member index to insert the new member
            memberOldIndex = oldMemberStatus.indexInArray;
        }

        //if the new member is not the zero address
        if (!isnewMemberZeroAddress) {
            Status memory newmemberStatus = _status[newMember];
            //A slashed member can never become an member again
            if (newmemberStatus.isSlashed) {
                return false;
            }
            //A new member cannot already be active
            if (newmemberStatus.isActive) {
                return false;
            }
            //Update the new member status
            _status[newMember] = Status({isActive: true, isSlashed: false, indexInArray: memberOldIndex});
        }

        if (!isoldMemberZeroAddress) {
            //Set the old member to inactive as it's not the zero address
            //State changes need to happen after all conditions clear,
            //So we put this change after checking the new member conditions
            _status[oldMember] = Status({isActive: false, isSlashed: slashOldMember, indexInArray: NULL_INDEX});
        }

        _vetoCouncilMembers[memberOldIndex] = isnewMemberZeroAddress ? NULL_ADDRESS : newMember;

        //cache the payment nonce
        uint256 paymentNonceToWriteTo = paymentNonce;
        //Increment the cached payment nonce
        ++paymentNonceToWriteTo;

        //Set the hash for the new payment nonce
        paymentNonceTomembersHash[paymentNonceToWriteTo] =
            keccak256(abi.encodePacked(arrayWithoutNulls(_vetoCouncilMembers)));
        //Set the shift start timestamp for the new payment nonce
        _paymentNonceToShiftStartTimestamp[paymentNonceToWriteTo] = block.timestamp;
        //Set the new payment nonce
        paymentNonce = paymentNonceToWriteTo;
        return true;
    }

    /**
     * @dev Used to payout the council member for their work at a given nonce
     * @param member The address of the council member
     * @param payoutNonce The payout nonce to claim from
     * @param token The token to pay out (GLOW)
     * @param members The addresses of the council members that were active at `nonce`
     *         -   This is used to verify that the member was active at the nonce
     *         -   By comparing the hash of the members at the nonce to the hash stored in the contract
     */
    function claimPayout(address member, uint256 payoutNonce, IERC20 token, address[] memory members) internal {
        uint256 withdrawableAmount = nextPayoutAmount(member, payoutNonce, members);
        amountAlreadyWithdrawnFromPaymentNonce[member][payoutNonce] += withdrawableAmount;
        SafeERC20.safeTransfer(token, member, withdrawableAmount);
        emit PayoutClaimed(member, payoutNonce, withdrawableAmount);
    }

    /**
     * ----------------------------------------------
     */
    /**
     * -------     INTERNAL VIEW ---------
     */
    /**
     * ----------------------------------------------
     */

    /**
     * @dev a helper function to get (rewardPerSecond, secondsActive, secondsStopped, amountAlreadyWithdrawn)
     * @param member The address of the member to get the data for
     * @param nonce The nonce to get the data for
     * @param members The addresses of the council members that were active at `nonce`
     *         -   This is used to verify that the member was active at the nonce
     *         -   By comparing the hash of the members at the nonce to the hash stored in the contract
     */

    function getDataToCalculatePayout(address member, uint256 nonce, address[] memory members)
        internal
        view
        returns (uint256 rewardPerSecond, uint256 secondsActive, uint256 secondsStopped, uint256 amountAlreadyWithdrawn)
    {
        //Hash the members array and check if it matches the hash stored in the contract
        if (keccak256(abi.encodePacked(members)) != paymentNonceTomembersHash[nonce]) {
            _revert(HashMismatch.selector);
        }

        //Check if the member was active at the nonce
        {
            bool found;
            unchecked {
                for (uint256 i; i < members.length; ++i) {
                    if (members[i] == member) {
                        found = true;
                        break;
                    }
                }
            }
            if (!found) {
                _revert(MemberNotFound.selector);
            }
        }

        //Should not get a divison by zero error as {found} should be true if there is at least one member
        uint256 rewardPerSecond = REWARDS_PER_SECOND / members.length;
        uint256 shiftStartTimestamp = _paymentNonceToShiftStartTimestamp[nonce];
        //We dont need to check the shift start timestamp
        //Since the hash for an uninitialized nonce will always be zero
        //and there will be no data
        uint256 shiftEndTimestamp = _paymentNonceToShiftStartTimestamp[nonce + 1];

        //This means the shift has ended
        if (shiftEndTimestamp != 0) {
            secondsStopped = block.timestamp - shiftEndTimestamp;
            secondsActive = shiftEndTimestamp - shiftStartTimestamp;
        } else {
            secondsActive = block.timestamp - shiftStartTimestamp;
        }
        amountAlreadyWithdrawn = amountAlreadyWithdrawnFromPaymentNonce[member][nonce];
        return (rewardPerSecond, secondsActive, secondsStopped, amountAlreadyWithdrawn);
    }

    /**
     * @dev a helper function to get (rewardPerSecond, secondsActive, secondsStopped, amountAlreadyWithdrawn)
     * @param member The address of the member to get the data for
     * @param nonce The nonce to get the data for
     * @param members The addresses of the council members that were active at `nonce`
     *         -   This is used to verify that the member was active at the nonce
     *         -   By comparing the hash of the members at the nonce to the hash stored in the contract
     */
    function _payoutData(address member, uint256 nonce, address[] memory members)
        private
        view
        returns (uint256, uint256)
    {
        if (_status[member].isSlashed) {
            return (0, 0);
        }
        (uint256 rewardPerSecond, uint256 secondsActive, uint256 secondsStopped, uint256 amountAlreadyWithdrawn) =
            getDataToCalculatePayout(member, nonce, members);
        (uint256 withdrawableAmount, uint256 slashableAmount) = VestingMathLib
            .calculateWithdrawableAmountAndSlashableAmount(
            rewardPerSecond, secondsActive, secondsStopped, amountAlreadyWithdrawn
        );

        return (withdrawableAmount, slashableAmount);
    }

    /**
     * @dev returns the amount of tokens that can be withdrawn by an member for a given nonce
     * @param member The address of the member to get the withdrawable amount for
     * @param nonce The nonce to get the withdrawable amount for
     * @param members The addresses of the council members that were active at `nonce`
     *         -   This is used to verify that the member was active at the nonce
     *         -   By comparing the hash of the members at the nonce to the hash stored in the contract
     * @return withdrawableAmount - the amount of tokens that can be withdrawn by the member
     */
    function nextPayoutAmount(address member, uint256 nonce, address[] memory members)
        internal
        view
        returns (uint256)
    {
        (uint256 withdrawableAmount,) = _payoutData(member, nonce, members);
        return withdrawableAmount;
    }

    /**
     * @param member The address of the member to be checked
     */
    function _isCouncilMember(address member) internal view returns (bool) {
        return _status[member].isActive;
    }

    /**
     * @dev efficiently determines if an address is the zero address
     * @param a the address to check
     * @return res - true if the address is the zero address
     */
    function isZero(address a) private pure returns (bool res) {
        // solhint-disable-next-line no-inline-assembly
        assembly ("memory-safe") {
            res := iszero(a)
        }
    }

    /**
     * @dev removes all null addresses from an array
     * @param arr the array to sanitize
     * @dev used to sanitize _vetoCouncilMembers before encoding and hashing
     * @return sanitizedArray - the sanitized array without any null addresses
     */
    function arrayWithoutNulls(address[7] memory arr) internal pure returns (address[] memory) {
        address[] memory sanitizedArray = new address[](arr.length);
        uint256 numNotNulls;
        unchecked {
            for (uint256 i; i < arr.length; ++i) {
                if (!isNull(arr[i])) {
                    sanitizedArray[numNotNulls] = arr[i];
                    ++numNotNulls;
                }
            }
        }
        // solhint-disable-next-line no-inline-assembly
        assembly ("memory-safe") {
            mstore(sanitizedArray, numNotNulls)
        }

        return sanitizedArray;
    }

    /**
     * @dev efficiently determines if an address is null address
     * @param a the address to check
     * @return res - true if the address is the null address, false otherwise
     */
    function isNull(address a) internal pure returns (bool res) {
        address _null = NULL_ADDRESS;
        // solhint-disable-next-line no-inline-assembly
        assembly ("memory-safe") {
            res := eq(a, _null)
        }
    }

    /**
     * @notice Efficiently reverts with a bytes4 selector
     * @param selector The selector to revert with
     */
    function _revert(bytes4 selector) internal pure {
        // solhint-disable-next-line no-inline-assembly
        assembly ("memory-safe") {
            mstore(0x0, selector)
            revert(0x0, 0x04)
        }
    }
}

File 12 of 27 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

pragma solidity ^0.8.20;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeCast {
    /**
     * @dev Value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedUintDowncast(uint8 bits, uint256 value);

    /**
     * @dev An int value doesn't fit in an uint of `bits` size.
     */
    error SafeCastOverflowedIntToUint(int256 value);

    /**
     * @dev Value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedIntDowncast(uint8 bits, int256 value);

    /**
     * @dev An uint value doesn't fit in an int of `bits` size.
     */
    error SafeCastOverflowedUintToInt(uint256 value);

    /**
     * @dev Returns the downcasted uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        if (value > type(uint248).max) {
            revert SafeCastOverflowedUintDowncast(248, value);
        }
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        if (value > type(uint240).max) {
            revert SafeCastOverflowedUintDowncast(240, value);
        }
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        if (value > type(uint232).max) {
            revert SafeCastOverflowedUintDowncast(232, value);
        }
        return uint232(value);
    }

    /**
     * @dev Returns the downcasted uint224 from uint256, reverting on
     * overflow (when the input is greater than largest uint224).
     *
     * Counterpart to Solidity's `uint224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toUint224(uint256 value) internal pure returns (uint224) {
        if (value > type(uint224).max) {
            revert SafeCastOverflowedUintDowncast(224, value);
        }
        return uint224(value);
    }

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        if (value > type(uint216).max) {
            revert SafeCastOverflowedUintDowncast(216, value);
        }
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        if (value > type(uint208).max) {
            revert SafeCastOverflowedUintDowncast(208, value);
        }
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        if (value > type(uint200).max) {
            revert SafeCastOverflowedUintDowncast(200, value);
        }
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        if (value > type(uint192).max) {
            revert SafeCastOverflowedUintDowncast(192, value);
        }
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        if (value > type(uint184).max) {
            revert SafeCastOverflowedUintDowncast(184, value);
        }
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        if (value > type(uint176).max) {
            revert SafeCastOverflowedUintDowncast(176, value);
        }
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        if (value > type(uint168).max) {
            revert SafeCastOverflowedUintDowncast(168, value);
        }
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        if (value > type(uint160).max) {
            revert SafeCastOverflowedUintDowncast(160, value);
        }
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        if (value > type(uint152).max) {
            revert SafeCastOverflowedUintDowncast(152, value);
        }
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        if (value > type(uint144).max) {
            revert SafeCastOverflowedUintDowncast(144, value);
        }
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        if (value > type(uint136).max) {
            revert SafeCastOverflowedUintDowncast(136, value);
        }
        return uint136(value);
    }

    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        if (value > type(uint128).max) {
            revert SafeCastOverflowedUintDowncast(128, value);
        }
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        if (value > type(uint120).max) {
            revert SafeCastOverflowedUintDowncast(120, value);
        }
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        if (value > type(uint112).max) {
            revert SafeCastOverflowedUintDowncast(112, value);
        }
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        if (value > type(uint104).max) {
            revert SafeCastOverflowedUintDowncast(104, value);
        }
        return uint104(value);
    }

    /**
     * @dev Returns the downcasted uint96 from uint256, reverting on
     * overflow (when the input is greater than largest uint96).
     *
     * Counterpart to Solidity's `uint96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toUint96(uint256 value) internal pure returns (uint96) {
        if (value > type(uint96).max) {
            revert SafeCastOverflowedUintDowncast(96, value);
        }
        return uint96(value);
    }

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        if (value > type(uint88).max) {
            revert SafeCastOverflowedUintDowncast(88, value);
        }
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        if (value > type(uint80).max) {
            revert SafeCastOverflowedUintDowncast(80, value);
        }
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        if (value > type(uint72).max) {
            revert SafeCastOverflowedUintDowncast(72, value);
        }
        return uint72(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        if (value > type(uint64).max) {
            revert SafeCastOverflowedUintDowncast(64, value);
        }
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        if (value > type(uint56).max) {
            revert SafeCastOverflowedUintDowncast(56, value);
        }
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        if (value > type(uint48).max) {
            revert SafeCastOverflowedUintDowncast(48, value);
        }
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        if (value > type(uint40).max) {
            revert SafeCastOverflowedUintDowncast(40, value);
        }
        return uint40(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        if (value > type(uint32).max) {
            revert SafeCastOverflowedUintDowncast(32, value);
        }
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        if (value > type(uint24).max) {
            revert SafeCastOverflowedUintDowncast(24, value);
        }
        return uint24(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        if (value > type(uint16).max) {
            revert SafeCastOverflowedUintDowncast(16, value);
        }
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        if (value > type(uint8).max) {
            revert SafeCastOverflowedUintDowncast(8, value);
        }
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        if (value < 0) {
            revert SafeCastOverflowedIntToUint(value);
        }
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int248 from int256, reverting on
     * overflow (when the input is less than smallest int248 or
     * greater than largest int248).
     *
     * Counterpart to Solidity's `int248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     */
    function toInt248(int256 value) internal pure returns (int248 downcasted) {
        downcasted = int248(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(248, value);
        }
    }

    /**
     * @dev Returns the downcasted int240 from int256, reverting on
     * overflow (when the input is less than smallest int240 or
     * greater than largest int240).
     *
     * Counterpart to Solidity's `int240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     */
    function toInt240(int256 value) internal pure returns (int240 downcasted) {
        downcasted = int240(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(240, value);
        }
    }

    /**
     * @dev Returns the downcasted int232 from int256, reverting on
     * overflow (when the input is less than smallest int232 or
     * greater than largest int232).
     *
     * Counterpart to Solidity's `int232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     */
    function toInt232(int256 value) internal pure returns (int232 downcasted) {
        downcasted = int232(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(232, value);
        }
    }

    /**
     * @dev Returns the downcasted int224 from int256, reverting on
     * overflow (when the input is less than smallest int224 or
     * greater than largest int224).
     *
     * Counterpart to Solidity's `int224` operator.
     *
     * Requirements:
     *
     * - input must fit into 224 bits
     */
    function toInt224(int256 value) internal pure returns (int224 downcasted) {
        downcasted = int224(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(224, value);
        }
    }

    /**
     * @dev Returns the downcasted int216 from int256, reverting on
     * overflow (when the input is less than smallest int216 or
     * greater than largest int216).
     *
     * Counterpart to Solidity's `int216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     */
    function toInt216(int256 value) internal pure returns (int216 downcasted) {
        downcasted = int216(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(216, value);
        }
    }

    /**
     * @dev Returns the downcasted int208 from int256, reverting on
     * overflow (when the input is less than smallest int208 or
     * greater than largest int208).
     *
     * Counterpart to Solidity's `int208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     */
    function toInt208(int256 value) internal pure returns (int208 downcasted) {
        downcasted = int208(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(208, value);
        }
    }

    /**
     * @dev Returns the downcasted int200 from int256, reverting on
     * overflow (when the input is less than smallest int200 or
     * greater than largest int200).
     *
     * Counterpart to Solidity's `int200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     */
    function toInt200(int256 value) internal pure returns (int200 downcasted) {
        downcasted = int200(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(200, value);
        }
    }

    /**
     * @dev Returns the downcasted int192 from int256, reverting on
     * overflow (when the input is less than smallest int192 or
     * greater than largest int192).
     *
     * Counterpart to Solidity's `int192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     */
    function toInt192(int256 value) internal pure returns (int192 downcasted) {
        downcasted = int192(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(192, value);
        }
    }

    /**
     * @dev Returns the downcasted int184 from int256, reverting on
     * overflow (when the input is less than smallest int184 or
     * greater than largest int184).
     *
     * Counterpart to Solidity's `int184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     */
    function toInt184(int256 value) internal pure returns (int184 downcasted) {
        downcasted = int184(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(184, value);
        }
    }

    /**
     * @dev Returns the downcasted int176 from int256, reverting on
     * overflow (when the input is less than smallest int176 or
     * greater than largest int176).
     *
     * Counterpart to Solidity's `int176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     */
    function toInt176(int256 value) internal pure returns (int176 downcasted) {
        downcasted = int176(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(176, value);
        }
    }

    /**
     * @dev Returns the downcasted int168 from int256, reverting on
     * overflow (when the input is less than smallest int168 or
     * greater than largest int168).
     *
     * Counterpart to Solidity's `int168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     */
    function toInt168(int256 value) internal pure returns (int168 downcasted) {
        downcasted = int168(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(168, value);
        }
    }

    /**
     * @dev Returns the downcasted int160 from int256, reverting on
     * overflow (when the input is less than smallest int160 or
     * greater than largest int160).
     *
     * Counterpart to Solidity's `int160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     */
    function toInt160(int256 value) internal pure returns (int160 downcasted) {
        downcasted = int160(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(160, value);
        }
    }

    /**
     * @dev Returns the downcasted int152 from int256, reverting on
     * overflow (when the input is less than smallest int152 or
     * greater than largest int152).
     *
     * Counterpart to Solidity's `int152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     */
    function toInt152(int256 value) internal pure returns (int152 downcasted) {
        downcasted = int152(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(152, value);
        }
    }

    /**
     * @dev Returns the downcasted int144 from int256, reverting on
     * overflow (when the input is less than smallest int144 or
     * greater than largest int144).
     *
     * Counterpart to Solidity's `int144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     */
    function toInt144(int256 value) internal pure returns (int144 downcasted) {
        downcasted = int144(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(144, value);
        }
    }

    /**
     * @dev Returns the downcasted int136 from int256, reverting on
     * overflow (when the input is less than smallest int136 or
     * greater than largest int136).
     *
     * Counterpart to Solidity's `int136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     */
    function toInt136(int256 value) internal pure returns (int136 downcasted) {
        downcasted = int136(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(136, value);
        }
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toInt128(int256 value) internal pure returns (int128 downcasted) {
        downcasted = int128(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(128, value);
        }
    }

    /**
     * @dev Returns the downcasted int120 from int256, reverting on
     * overflow (when the input is less than smallest int120 or
     * greater than largest int120).
     *
     * Counterpart to Solidity's `int120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     */
    function toInt120(int256 value) internal pure returns (int120 downcasted) {
        downcasted = int120(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(120, value);
        }
    }

    /**
     * @dev Returns the downcasted int112 from int256, reverting on
     * overflow (when the input is less than smallest int112 or
     * greater than largest int112).
     *
     * Counterpart to Solidity's `int112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     */
    function toInt112(int256 value) internal pure returns (int112 downcasted) {
        downcasted = int112(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(112, value);
        }
    }

    /**
     * @dev Returns the downcasted int104 from int256, reverting on
     * overflow (when the input is less than smallest int104 or
     * greater than largest int104).
     *
     * Counterpart to Solidity's `int104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     */
    function toInt104(int256 value) internal pure returns (int104 downcasted) {
        downcasted = int104(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(104, value);
        }
    }

    /**
     * @dev Returns the downcasted int96 from int256, reverting on
     * overflow (when the input is less than smallest int96 or
     * greater than largest int96).
     *
     * Counterpart to Solidity's `int96` operator.
     *
     * Requirements:
     *
     * - input must fit into 96 bits
     */
    function toInt96(int256 value) internal pure returns (int96 downcasted) {
        downcasted = int96(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(96, value);
        }
    }

    /**
     * @dev Returns the downcasted int88 from int256, reverting on
     * overflow (when the input is less than smallest int88 or
     * greater than largest int88).
     *
     * Counterpart to Solidity's `int88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     */
    function toInt88(int256 value) internal pure returns (int88 downcasted) {
        downcasted = int88(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(88, value);
        }
    }

    /**
     * @dev Returns the downcasted int80 from int256, reverting on
     * overflow (when the input is less than smallest int80 or
     * greater than largest int80).
     *
     * Counterpart to Solidity's `int80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     */
    function toInt80(int256 value) internal pure returns (int80 downcasted) {
        downcasted = int80(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(80, value);
        }
    }

    /**
     * @dev Returns the downcasted int72 from int256, reverting on
     * overflow (when the input is less than smallest int72 or
     * greater than largest int72).
     *
     * Counterpart to Solidity's `int72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     */
    function toInt72(int256 value) internal pure returns (int72 downcasted) {
        downcasted = int72(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(72, value);
        }
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toInt64(int256 value) internal pure returns (int64 downcasted) {
        downcasted = int64(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(64, value);
        }
    }

    /**
     * @dev Returns the downcasted int56 from int256, reverting on
     * overflow (when the input is less than smallest int56 or
     * greater than largest int56).
     *
     * Counterpart to Solidity's `int56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     */
    function toInt56(int256 value) internal pure returns (int56 downcasted) {
        downcasted = int56(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(56, value);
        }
    }

    /**
     * @dev Returns the downcasted int48 from int256, reverting on
     * overflow (when the input is less than smallest int48 or
     * greater than largest int48).
     *
     * Counterpart to Solidity's `int48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     */
    function toInt48(int256 value) internal pure returns (int48 downcasted) {
        downcasted = int48(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(48, value);
        }
    }

    /**
     * @dev Returns the downcasted int40 from int256, reverting on
     * overflow (when the input is less than smallest int40 or
     * greater than largest int40).
     *
     * Counterpart to Solidity's `int40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     */
    function toInt40(int256 value) internal pure returns (int40 downcasted) {
        downcasted = int40(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(40, value);
        }
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toInt32(int256 value) internal pure returns (int32 downcasted) {
        downcasted = int32(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(32, value);
        }
    }

    /**
     * @dev Returns the downcasted int24 from int256, reverting on
     * overflow (when the input is less than smallest int24 or
     * greater than largest int24).
     *
     * Counterpart to Solidity's `int24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     */
    function toInt24(int256 value) internal pure returns (int24 downcasted) {
        downcasted = int24(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(24, value);
        }
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toInt16(int256 value) internal pure returns (int16 downcasted) {
        downcasted = int16(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(16, value);
        }
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits
     */
    function toInt8(int256 value) internal pure returns (int8 downcasted) {
        downcasted = int8(value);
        if (downcasted != value) {
            revert SafeCastOverflowedIntDowncast(8, value);
        }
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        if (value > uint256(type(int256).max)) {
            revert SafeCastOverflowedUintToInt(value);
        }
        return int256(value);
    }
}

File 13 of 27 : Constants.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

uint256 constant _BUCKET_DURATION = uint256(7 days);
uint256 constant _GENESIS_TIMESTAMP = 1700352000;

File 14 of 27 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 15 of 27 : MessageHashUtils.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.20;

import {Strings} from "../Strings.sol";

/**
 * @dev Signature message hash utilities for producing digests to be consumed by {ECDSA} recovery or signing.
 *
 * The library provides methods for generating a hash of a message that conforms to the
 * https://eips.ethereum.org/EIPS/eip-191[EIP 191] and https://eips.ethereum.org/EIPS/eip-712[EIP 712]
 * specifications.
 */
library MessageHashUtils {
    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing a bytes32 `messageHash` with
     * `"\x19Ethereum Signed Message:\n32"` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * NOTE: The `hash` parameter is intended to be the result of hashing a raw message with
     * keccak256, although any bytes32 value can be safely used because the final digest will
     * be re-hashed.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes32 messageHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, "\x19Ethereum Signed Message:\n32") // 32 is the bytes-length of messageHash
            mstore(0x1c, messageHash) // 0x1c (28) is the length of the prefix
            digest := keccak256(0x00, 0x3c) // 0x3c is the length of the prefix (0x1c) + messageHash (0x20)
        }
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x45` (`personal_sign` messages).
     *
     * The digest is calculated by prefixing an arbitrary `message` with
     * `"\x19Ethereum Signed Message:\n" + len(message)` and hashing the result. It corresponds with the
     * hash signed when using the https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`] JSON-RPC method.
     *
     * See {ECDSA-recover}.
     */
    function toEthSignedMessageHash(bytes memory message) internal pure returns (bytes32 digest) {
        return
            keccak256(bytes.concat("\x19Ethereum Signed Message:\n", bytes(Strings.toString(message.length)), message));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-191 signed data with version
     * `0x00` (data with intended validator).
     *
     * The digest is calculated by prefixing an arbitrary `data` with `"\x19\x00"` and the intended
     * `validator` address. Then hashing the result.
     *
     * See {ECDSA-recover}.
     */
    function toDataWithIntendedValidatorHash(
        address validator,
        bytes memory data
    ) internal pure returns (bytes32 digest) {
        return keccak256(abi.encodePacked(hex"19_00", validator, data));
    }

    /**
     * @dev Returns the keccak256 digest of an EIP-712 typed data (EIP-191 version `0x01`).
     *
     * The digest is calculated from a `domainSeparator` and a `structHash`, by prefixing them with
     * `\x19\x01` and hashing the result. It corresponds to the hash signed by the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`] JSON-RPC method as part of EIP-712.
     *
     * See {ECDSA-recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32 digest) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, hex"19_01")
            mstore(add(ptr, 0x02), domainSeparator)
            mstore(add(ptr, 0x22), structHash)
            digest := keccak256(ptr, 0x42)
        }
    }
}

File 16 of 27 : ShortStrings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/ShortStrings.sol)

pragma solidity ^0.8.20;

import {StorageSlot} from "./StorageSlot.sol";

// | string  | 0xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA   |
// | length  | 0x                                                              BB |
type ShortString is bytes32;

/**
 * @dev This library provides functions to convert short memory strings
 * into a `ShortString` type that can be used as an immutable variable.
 *
 * Strings of arbitrary length can be optimized using this library if
 * they are short enough (up to 31 bytes) by packing them with their
 * length (1 byte) in a single EVM word (32 bytes). Additionally, a
 * fallback mechanism can be used for every other case.
 *
 * Usage example:
 *
 * ```solidity
 * contract Named {
 *     using ShortStrings for *;
 *
 *     ShortString private immutable _name;
 *     string private _nameFallback;
 *
 *     constructor(string memory contractName) {
 *         _name = contractName.toShortStringWithFallback(_nameFallback);
 *     }
 *
 *     function name() external view returns (string memory) {
 *         return _name.toStringWithFallback(_nameFallback);
 *     }
 * }
 * ```
 */
library ShortStrings {
    // Used as an identifier for strings longer than 31 bytes.
    bytes32 private constant _FALLBACK_SENTINEL = 0x00000000000000000000000000000000000000000000000000000000000000FF;

    error StringTooLong(string str);
    error InvalidShortString();

    /**
     * @dev Encode a string of at most 31 chars into a `ShortString`.
     *
     * This will trigger a `StringTooLong` error is the input string is too long.
     */
    function toShortString(string memory str) internal pure returns (ShortString) {
        bytes memory bstr = bytes(str);
        if (bstr.length > 31) {
            revert StringTooLong(str);
        }
        return ShortString.wrap(bytes32(uint256(bytes32(bstr)) | bstr.length));
    }

    /**
     * @dev Decode a `ShortString` back to a "normal" string.
     */
    function toString(ShortString sstr) internal pure returns (string memory) {
        uint256 len = byteLength(sstr);
        // using `new string(len)` would work locally but is not memory safe.
        string memory str = new string(32);
        /// @solidity memory-safe-assembly
        assembly {
            mstore(str, len)
            mstore(add(str, 0x20), sstr)
        }
        return str;
    }

    /**
     * @dev Return the length of a `ShortString`.
     */
    function byteLength(ShortString sstr) internal pure returns (uint256) {
        uint256 result = uint256(ShortString.unwrap(sstr)) & 0xFF;
        if (result > 31) {
            revert InvalidShortString();
        }
        return result;
    }

    /**
     * @dev Encode a string into a `ShortString`, or write it to storage if it is too long.
     */
    function toShortStringWithFallback(string memory value, string storage store) internal returns (ShortString) {
        if (bytes(value).length < 32) {
            return toShortString(value);
        } else {
            StorageSlot.getStringSlot(store).value = value;
            return ShortString.wrap(_FALLBACK_SENTINEL);
        }
    }

    /**
     * @dev Decode a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     */
    function toStringWithFallback(ShortString value, string storage store) internal pure returns (string memory) {
        if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
            return toString(value);
        } else {
            return store;
        }
    }

    /**
     * @dev Return the length of a string that was encoded to `ShortString` or written to storage using {setWithFallback}.
     *
     * WARNING: This will return the "byte length" of the string. This may not reflect the actual length in terms of
     * actual characters as the UTF-8 encoding of a single character can span over multiple bytes.
     */
    function byteLengthWithFallback(ShortString value, string storage store) internal view returns (uint256) {
        if (ShortString.unwrap(value) != _FALLBACK_SENTINEL) {
            return byteLength(value);
        } else {
            return bytes(store).length;
        }
    }
}

File 17 of 27 : IERC5267.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (interfaces/IERC5267.sol)

pragma solidity ^0.8.20;

interface IERC5267 {
    /**
     * @dev MAY be emitted to signal that the domain could have changed.
     */
    event EIP712DomainChanged();

    /**
     * @dev returns the fields and values that describe the domain separator used by this contract for EIP-712
     * signature.
     */
    function eip712Domain()
        external
        view
        returns (
            bytes1 fields,
            string memory name,
            string memory version,
            uint256 chainId,
            address verifyingContract,
            bytes32 salt,
            uint256[] memory extensions
        );
}

File 18 of 27 : ECDSA.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.20;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS
    }

    /**
     * @dev The signature derives the `address(0)`.
     */
    error ECDSAInvalidSignature();

    /**
     * @dev The signature has an invalid length.
     */
    error ECDSAInvalidSignatureLength(uint256 length);

    /**
     * @dev The signature has an S value that is in the upper half order.
     */
    error ECDSAInvalidSignatureS(bytes32 s);

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError, bytes32) {
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength, bytes32(signature.length));
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM precompile allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {MessageHashUtils-toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, signature);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     */
    function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address, RecoverError, bytes32) {
        unchecked {
            bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
            // We do not check for an overflow here since the shift operation results in 0 or 1.
            uint8 v = uint8((uint256(vs) >> 255) + 27);
            return tryRecover(hash, v, r, s);
        }
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     */
    function recover(bytes32 hash, bytes32 r, bytes32 vs) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, r, vs);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError, bytes32) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS, s);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature, bytes32(0));
        }

        return (signer, RecoverError.NoError, bytes32(0));
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error, bytes32 errorArg) = tryRecover(hash, v, r, s);
        _throwError(error, errorArg);
        return recovered;
    }

    /**
     * @dev Optionally reverts with the corresponding custom error according to the `error` argument provided.
     */
    function _throwError(RecoverError error, bytes32 errorArg) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert ECDSAInvalidSignature();
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert ECDSAInvalidSignatureLength(uint256(errorArg));
        } else if (error == RecoverError.InvalidSignatureS) {
            revert ECDSAInvalidSignatureS(errorArg);
        }
    }
}

File 19 of 27 : IERC1271.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC1271.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC1271 standard signature validation method for
 * contracts as defined in https://eips.ethereum.org/EIPS/eip-1271[ERC-1271].
 */
interface IERC1271 {
    /**
     * @dev Should return whether the signature provided is valid for the provided data
     * @param hash      Hash of the data to be signed
     * @param signature Signature byte array associated with _data
     */
    function isValidSignature(bytes32 hash, bytes memory signature) external view returns (bytes4 magicValue);
}

File 20 of 27 : VestingMathLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

uint256 constant VESTING_PERIODS = 100;
/// @dev the maximum amount of seconds a second can vest for
/// @dev this is to prevent a second from over-vesting in payout
/// @dev since rewards vest at 1% per week, this is 100 weeks
uint256 constant MAX_VESTING_SECONDS = uint256(7 days) * 100;

library VestingMathLib {
    /**
     * @dev Find total owed now and slashable balance using the summation of an arithmetic series
     * @dev formula = n/2 * (2a + (n-1)d) or n/2 * (a + l)
     * @dev read more about this  https://github.com/glowlabs-org/glow-docs/issues/4
     * @param rewardsPerSecond - the amount of glow per second the agent earns
     * @param secondsActive - the amount of seconds the agent has worked on a given shift
     * @param secondsStopped - the amount of seconds since the agent has stopped working on their shift
     * @param amountAlreadyWithdrawn - the amount of glow already withdrawn by the agent
     * @return withdrawableAmount - the amount of glow owed now
     * @return slashableAmount - the total slashable amount of glow (total owed - withdrawableAmount)
     */
    function calculateWithdrawableAmountAndSlashableAmount(
        uint256 rewardsPerSecond,
        uint256 secondsActive,
        uint256 secondsStopped,
        uint256 amountAlreadyWithdrawn
    ) internal pure returns (uint256 withdrawableAmount, uint256 slashableAmount) {
        //Placeholder for fully vested seconds.
        uint256 fullyVestedSeconds;

        //If (secondsActive + secondsStopped) > MAX_VESTING_SECONDS,
        //That means that there are some seconds that are fully vested.
        if (secondsActive + secondsStopped > MAX_VESTING_SECONDS) {
            //The fully vested seconds are as follows:
            fullyVestedSeconds = secondsActive + secondsStopped - MAX_VESTING_SECONDS;
        }

        //We make sure that the fully vested seconds are not greater than the seconds active.
        //This can happen as secondsStopped grows once the agent stops working
        if (fullyVestedSeconds > secondsActive) {
            fullyVestedSeconds = secondsActive;
        }

        //The fully vested rewards are a result of the fully vested seconds * the rewards per second.
        uint256 fullyVestedRewards = rewardsPerSecond * fullyVestedSeconds;

        //The partially vested seconds are the seconds active minus the fully vested seconds.
        uint256 partiallyVestedSeconds = secondsActive - fullyVestedSeconds;

        uint256 lowestValueSecond = (1 + secondsStopped) * rewardsPerSecond / MAX_VESTING_SECONDS;

        uint256 highestValueSecond = (secondsActive + secondsStopped) * rewardsPerSecond / MAX_VESTING_SECONDS;
        if (highestValueSecond > rewardsPerSecond) {
            highestValueSecond = rewardsPerSecond;
        }

        //Arithmetic series
        uint256 partiallyVestedSecondsValue = partiallyVestedSeconds * (lowestValueSecond + highestValueSecond) / 2;

        uint256 totalRewards = secondsActive * rewardsPerSecond;
        withdrawableAmount = fullyVestedRewards + partiallyVestedSecondsValue;
        slashableAmount = totalRewards - withdrawableAmount;
        withdrawableAmount -= amountAlreadyWithdrawn;

        return (withdrawableAmount, slashableAmount);
    }
}

File 21 of 27 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC20Permit} from "../extensions/IERC20Permit.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev An operation with an ERC20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        if (nonceAfter != nonceBefore + 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data);
        if (returndata.length != 0 && !abi.decode(returndata, (bool))) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return success && (returndata.length == 0 || abi.decode(returndata, (bool))) && address(token).code.length > 0;
    }
}

File 22 of 27 : Strings.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)

pragma solidity ^0.8.20;

import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_DIGITS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev The `value` string doesn't fit in the specified `length`.
     */
    error StringsInsufficientHexLength(uint256 value, uint256 length);

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        unchecked {
            uint256 length = Math.log10(value) + 1;
            string memory buffer = new string(length);
            uint256 ptr;
            /// @solidity memory-safe-assembly
            assembly {
                ptr := add(buffer, add(32, length))
            }
            while (true) {
                ptr--;
                /// @solidity memory-safe-assembly
                assembly {
                    mstore8(ptr, byte(mod(value, 10), _HEX_DIGITS))
                }
                value /= 10;
                if (value == 0) break;
            }
            return buffer;
        }
    }

    /**
     * @dev Converts a `int256` to its ASCII `string` decimal representation.
     */
    function toStringSigned(int256 value) internal pure returns (string memory) {
        return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        unchecked {
            return toHexString(value, Math.log256(value) + 1);
        }
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        uint256 localValue = value;
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_DIGITS[localValue & 0xf];
            localValue >>= 4;
        }
        if (localValue != 0) {
            revert StringsInsufficientHexLength(value, length);
        }
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }

    /**
     * @dev Returns true if the two strings are equal.
     */
    function equal(string memory a, string memory b) internal pure returns (bool) {
        return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
    }
}

File 23 of 27 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.20;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(newImplementation.code.length > 0);
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

File 24 of 27 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 25 of 27 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error AddressInsufficientBalance(address account);

    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedInnerCall();

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert AddressInsufficientBalance(address(this));
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert FailedInnerCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {FailedInnerCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert AddressInsufficientBalance(address(this));
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {FailedInnerCall}) in case of an
     * unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {FailedInnerCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {FailedInnerCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert FailedInnerCall();
        }
    }
}

File 26 of 27 : Math.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard math utilities missing in the Solidity language.
 */
library Math {
    /**
     * @dev Muldiv operation overflow.
     */
    error MathOverflowedMulDiv();

    enum Rounding {
        Floor, // Toward negative infinity
        Ceil, // Toward positive infinity
        Trunc, // Toward zero
        Expand // Away from zero
    }

    /**
     * @dev Returns the addition of two unsigned integers, with an overflow flag.
     */
    function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, with an overflow flag.
     */
    function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
     */
    function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    }

    /**
     * @dev Returns the division of two unsigned integers, with a division by zero flag.
     */
    function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
     */
    function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
        unchecked {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    }

    /**
     * @dev Returns the largest of two numbers.
     */
    function max(uint256 a, uint256 b) internal pure returns (uint256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two numbers.
     */
    function min(uint256 a, uint256 b) internal pure returns (uint256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two numbers. The result is rounded towards
     * zero.
     */
    function average(uint256 a, uint256 b) internal pure returns (uint256) {
        // (a + b) / 2 can overflow.
        return (a & b) + (a ^ b) / 2;
    }

    /**
     * @dev Returns the ceiling of the division of two numbers.
     *
     * This differs from standard division with `/` in that it rounds towards infinity instead
     * of rounding towards zero.
     */
    function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
        if (b == 0) {
            // Guarantee the same behavior as in a regular Solidity division.
            return a / b;
        }

        // (a + b - 1) / b can overflow on addition, so we distribute.
        return a == 0 ? 0 : (a - 1) / b + 1;
    }

    /**
     * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
     * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
     * with further edits by Uniswap Labs also under MIT license.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
        unchecked {
            // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
            // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
            // variables such that product = prod1 * 2^256 + prod0.
            uint256 prod0 = x * y; // Least significant 256 bits of the product
            uint256 prod1; // Most significant 256 bits of the product
            assembly {
                let mm := mulmod(x, y, not(0))
                prod1 := sub(sub(mm, prod0), lt(mm, prod0))
            }

            // Handle non-overflow cases, 256 by 256 division.
            if (prod1 == 0) {
                // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                // The surrounding unchecked block does not change this fact.
                // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                return prod0 / denominator;
            }

            // Make sure the result is less than 2^256. Also prevents denominator == 0.
            if (denominator <= prod1) {
                revert MathOverflowedMulDiv();
            }

            ///////////////////////////////////////////////
            // 512 by 256 division.
            ///////////////////////////////////////////////

            // Make division exact by subtracting the remainder from [prod1 prod0].
            uint256 remainder;
            assembly {
                // Compute remainder using mulmod.
                remainder := mulmod(x, y, denominator)

                // Subtract 256 bit number from 512 bit number.
                prod1 := sub(prod1, gt(remainder, prod0))
                prod0 := sub(prod0, remainder)
            }

            // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
            // See https://cs.stackexchange.com/q/138556/92363.

            uint256 twos = denominator & (0 - denominator);
            assembly {
                // Divide denominator by twos.
                denominator := div(denominator, twos)

                // Divide [prod1 prod0] by twos.
                prod0 := div(prod0, twos)

                // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                twos := add(div(sub(0, twos), twos), 1)
            }

            // Shift in bits from prod1 into prod0.
            prod0 |= prod1 * twos;

            // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
            // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
            // four bits. That is, denominator * inv = 1 mod 2^4.
            uint256 inverse = (3 * denominator) ^ 2;

            // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
            // in modular arithmetic, doubling the correct bits in each step.
            inverse *= 2 - denominator * inverse; // inverse mod 2^8
            inverse *= 2 - denominator * inverse; // inverse mod 2^16
            inverse *= 2 - denominator * inverse; // inverse mod 2^32
            inverse *= 2 - denominator * inverse; // inverse mod 2^64
            inverse *= 2 - denominator * inverse; // inverse mod 2^128
            inverse *= 2 - denominator * inverse; // inverse mod 2^256

            // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
            // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
            // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
            // is no longer required.
            result = prod0 * inverse;
            return result;
        }
    }

    /**
     * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
     */
    function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
        uint256 result = mulDiv(x, y, denominator);
        if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
            result += 1;
        }
        return result;
    }

    /**
     * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
     * towards zero.
     *
     * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
     */
    function sqrt(uint256 a) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
        //
        // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
        // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
        //
        // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
        // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
        // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
        //
        // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
        uint256 result = 1 << (log2(a) >> 1);

        // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
        // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
        // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
        // into the expected uint128 result.
        unchecked {
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            result = (result + a / result) >> 1;
            return min(result, a / result);
        }
    }

    /**
     * @notice Calculates sqrt(a), following the selected rounding direction.
     */
    function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = sqrt(a);
            return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 2 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log2(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 128;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 64;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 32;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 16;
            }
            if (value >> 8 > 0) {
                value >>= 8;
                result += 8;
            }
            if (value >> 4 > 0) {
                value >>= 4;
                result += 4;
            }
            if (value >> 2 > 0) {
                value >>= 2;
                result += 2;
            }
            if (value >> 1 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log2(value);
            return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 10 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     */
    function log10(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >= 10 ** 64) {
                value /= 10 ** 64;
                result += 64;
            }
            if (value >= 10 ** 32) {
                value /= 10 ** 32;
                result += 32;
            }
            if (value >= 10 ** 16) {
                value /= 10 ** 16;
                result += 16;
            }
            if (value >= 10 ** 8) {
                value /= 10 ** 8;
                result += 8;
            }
            if (value >= 10 ** 4) {
                value /= 10 ** 4;
                result += 4;
            }
            if (value >= 10 ** 2) {
                value /= 10 ** 2;
                result += 2;
            }
            if (value >= 10 ** 1) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log10(value);
            return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
        }
    }

    /**
     * @dev Return the log in base 256 of a positive value rounded towards zero.
     * Returns 0 if given 0.
     *
     * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
     */
    function log256(uint256 value) internal pure returns (uint256) {
        uint256 result = 0;
        unchecked {
            if (value >> 128 > 0) {
                value >>= 128;
                result += 16;
            }
            if (value >> 64 > 0) {
                value >>= 64;
                result += 8;
            }
            if (value >> 32 > 0) {
                value >>= 32;
                result += 4;
            }
            if (value >> 16 > 0) {
                value >>= 16;
                result += 2;
            }
            if (value >> 8 > 0) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
     * Returns 0 if given 0.
     */
    function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
        unchecked {
            uint256 result = log256(value);
            return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
        }
    }

    /**
     * @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
     */
    function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
        return uint8(rounding) % 2 == 1;
    }
}

File 27 of 27 : SignedMath.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)

pragma solidity ^0.8.20;

/**
 * @dev Standard signed math utilities missing in the Solidity language.
 */
library SignedMath {
    /**
     * @dev Returns the largest of two signed numbers.
     */
    function max(int256 a, int256 b) internal pure returns (int256) {
        return a > b ? a : b;
    }

    /**
     * @dev Returns the smallest of two signed numbers.
     */
    function min(int256 a, int256 b) internal pure returns (int256) {
        return a < b ? a : b;
    }

    /**
     * @dev Returns the average of two signed numbers without overflow.
     * The result is rounded towards zero.
     */
    function average(int256 a, int256 b) internal pure returns (int256) {
        // Formula from the book "Hacker's Delight"
        int256 x = (a & b) + ((a ^ b) >> 1);
        return x + (int256(uint256(x) >> 255) & (a ^ b));
    }

    /**
     * @dev Returns the absolute unsigned value of a signed value.
     */
    function abs(int256 n) internal pure returns (uint256) {
        unchecked {
            // must be unchecked in order to support `n = type(int256).min`
            return uint256(n >= 0 ? n : -n);
        }
    }
}

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "solmate/=lib/solmate/src/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "@openzeppelin/contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/contracts/",
    "@/=src/",
    "@solady/=lib/solady/src/",
    "@unifapv2/=src/UnifapV2/",
    "clones/=lib/clones-with-immutable-args/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/contracts/",
    "@clones/=lib/unifap-v2/lib/clones-with-immutable-args/src/",
    "@ds/=lib/unifap-v2/lib/ds-test/src/",
    "@solmate/=lib/unifap-v2/lib/solmate/src/",
    "@std/=lib/unifap-v2/lib/forge-std/src/",
    "abdk-libraries-solidity/=lib/abdk-libraries-solidity/",
    "clones-with-immutable-args/=lib/clones-with-immutable-args/src/",
    "clones/=lib/unifap-v2/lib/clones-with-immutable-args/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/solady/",
    "unifap-v2/=lib/unifap-v2/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 1000000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {
    "src/libraries/HalfLife.sol": {
      "HalfLife": "0xcf4d7552ca9f07c474d69e89a88943fabb60b199"
    },
    "src/libraries/HalfLifeCarbonCreditAuction.sol": {
      "HalfLifeCarbonCreditAuction": "0xd178525026bafc51d045a2e98b0c79a526d446de"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"gcc","type":"address"},{"internalType":"address","name":"gca","type":"address"},{"internalType":"address","name":"vetoCouncil","type":"address"},{"internalType":"address","name":"grantsTreasury","type":"address"},{"internalType":"address","name":"glw","type":"address"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"AlreadyEndorsedWeek","type":"error"},{"inputs":[],"name":"CallerNotGCA","type":"error"},{"inputs":[],"name":"CallerNotGCC","type":"error"},{"inputs":[],"name":"CallerNotVetoCouncilMember","type":"error"},{"inputs":[],"name":"ContractsAlreadySet","type":"error"},{"inputs":[],"name":"GCAContractAlreadySet","type":"error"},{"inputs":[],"name":"GCACouncilElectionsCannotBeVetoed","type":"error"},{"inputs":[],"name":"InsufficientNominations","type":"error"},{"inputs":[],"name":"InsufficientRatifyOrRejectVotes","type":"error"},{"inputs":[],"name":"InvalidShortString","type":"error"},{"inputs":[],"name":"InvalidSpendNominationsOnProposalSignature","type":"error"},{"inputs":[],"name":"MaxGCAEndorsementsReached","type":"error"},{"inputs":[],"name":"MaxSlashesInGCAElection","type":"error"},{"inputs":[],"name":"MaximumNumberOfGCAS","type":"error"},{"inputs":[],"name":"MostPopularProposalNotSelected","type":"error"},{"inputs":[],"name":"NominationCostGreaterThanAllowance","type":"error"},{"inputs":[],"name":"OnlyGCAElectionsCanBeEndorsed","type":"error"},{"inputs":[],"name":"ProposalAlreadyExecuted","type":"error"},{"inputs":[],"name":"ProposalAlreadyVetoed","type":"error"},{"inputs":[],"name":"ProposalDoesNotExist","type":"error"},{"inputs":[],"name":"ProposalExpired","type":"error"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalHasNotExpired","type":"error"},{"inputs":[],"name":"ProposalIdDoesNotMatchMostPopularProposal","type":"error"},{"inputs":[],"name":"ProposalIsVetoed","type":"error"},{"inputs":[],"name":"ProposalNotInitialized","type":"error"},{"inputs":[],"name":"ProposalNotMostPopular","type":"error"},{"inputs":[],"name":"ProposalsMustBeExecutedSynchonously","type":"error"},{"inputs":[],"name":"RFCPeriodNotEnded","type":"error"},{"inputs":[],"name":"RatifyOrRejectPeriodEnded","type":"error"},{"inputs":[],"name":"RatifyOrRejectPeriodNotEnded","type":"error"},{"inputs":[{"internalType":"uint8","name":"bits","type":"uint8"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"SafeCastOverflowedUintDowncast","type":"error"},{"inputs":[],"name":"SpendNominationsOnProposalSignatureExpired","type":"error"},{"inputs":[{"internalType":"string","name":"str","type":"string"}],"name":"StringTooLong","type":"error"},{"inputs":[],"name":"VetoCouncilElectionsCannotBeVetoed","type":"error"},{"inputs":[],"name":"VetoCouncilProposalCreationOldMemberCannotEqualNewMember","type":"error"},{"inputs":[],"name":"VetoMemberCannotBeNullAddress","type":"error"},{"inputs":[],"name":"WeekMustHaveEndedToAcceptRatifyOrRejectVotes","type":"error"},{"inputs":[],"name":"WeekNotFinalized","type":"error"},{"inputs":[],"name":"WeekNotStarted","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"requirementsHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"nominationsUsed","type":"uint256"}],"name":"ChangeGCARequirementsProposalCreation","type":"event"},{"anonymous":false,"inputs":[],"name":"EIP712DomainChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"address[]","name":"agentsToSlash","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"newGCAs","type":"address[]"},{"indexed":false,"internalType":"uint256","name":"proposalCreationTimestamp","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"nominationsUsed","type":"uint256"}],"name":"GCACouncilElectionOrSlashCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"hash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"nominationsUsed","type":"uint256"}],"name":"GrantsProposalCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"weekId","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"MostPopularProposalSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NominationsUsedOnProposal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"week","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"enum IGovernance.ProposalType","name":"proposalType","type":"uint8"},{"indexed":false,"internalType":"bool","name":"success","type":"bool"}],"name":"ProposalExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"weekId","type":"uint256"},{"indexed":true,"internalType":"address","name":"vetoer","type":"address"},{"indexed":false,"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"ProposalVetoed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"bytes32","name":"rfcHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"nominationsUsed","type":"uint256"}],"name":"RFCProposalCreation","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"requirementsHash","type":"bytes32"}],"name":"RFCProposalExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"uint256","name":"numVotes","type":"uint256"}],"name":"RatifyCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"voter","type":"address"},{"indexed":false,"internalType":"uint256","name":"numVotes","type":"uint256"}],"name":"RejectCast","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"proposalId","type":"uint256"},{"indexed":true,"internalType":"address","name":"proposer","type":"address"},{"indexed":false,"internalType":"address","name":"oldAgent","type":"address"},{"indexed":false,"internalType":"address","name":"newAgent","type":"address"},{"indexed":false,"internalType":"bool","name":"slashOldAgent","type":"bool"},{"indexed":false,"internalType":"uint256","name":"nominationsUsed","type":"uint256"}],"name":"VetoCouncilElectionOrSlash","type":"event"},{"inputs":[],"name":"GCA","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GCC","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GENESIS_TIMESTAMP","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GLOW","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"GRANTS_TREASURY","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SPEND_NOMINATIONS_ON_PROPOSAL_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"VETO_COUNCIL","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"costForNewProposal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newRequirementsHash","type":"bytes32"},{"internalType":"uint256","name":"maxNominations","type":"uint256"}],"name":"createChangeGCARequirementsProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"newRequirementsHash","type":"bytes32"},{"internalType":"uint256[]","name":"deadlines","type":"uint256[]"},{"internalType":"uint256[]","name":"nominationsToSpend","type":"uint256[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"}],"name":"createChangeGCARequirementsProposalSigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"agentsToSlash","type":"address[]"},{"internalType":"address[]","name":"newGCAs","type":"address[]"},{"internalType":"uint256","name":"maxNominations","type":"uint256"}],"name":"createGCACouncilElectionOrSlashProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"agentsToSlash","type":"address[]"},{"internalType":"address[]","name":"newGCAs","type":"address[]"},{"internalType":"uint256[]","name":"deadlines","type":"uint256[]"},{"internalType":"uint256[]","name":"nominationsToSpend","type":"uint256[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"}],"name":"createGCACouncilElectionOrSlashProposalSigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"grantsRecipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"maxNominations","type":"uint256"}],"name":"createGrantsProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"grantsRecipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256[]","name":"deadlines","type":"uint256[]"},{"internalType":"uint256[]","name":"nominationsToSpend","type":"uint256[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"}],"name":"createGrantsProposalSigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256","name":"maxNominations","type":"uint256"}],"name":"createRFCProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"uint256[]","name":"deadlines","type":"uint256[]"},{"internalType":"uint256[]","name":"nominationsToSpend","type":"uint256[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"}],"name":"createRFCProposalSigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldMember","type":"address"},{"internalType":"address","name":"newMember","type":"address"},{"internalType":"bool","name":"slashOldMember","type":"bool"},{"internalType":"uint256","name":"maxNominations","type":"uint256"}],"name":"createVetoCouncilElectionOrSlash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"oldMember","type":"address"},{"internalType":"address","name":"newMember","type":"address"},{"internalType":"bool","name":"slashOldMember","type":"bool"},{"internalType":"uint256[]","name":"deadlines","type":"uint256[]"},{"internalType":"uint256[]","name":"nominationsToSpend","type":"uint256[]"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"bytes[]","name":"sigs","type":"bytes[]"}],"name":"createVetoCouncilElectionOrSlashSigs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"weekId","type":"uint256"}],"name":"endorseGCAProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"week","type":"uint256"}],"name":"executeProposalAtWeek","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"getProposalStatus","outputs":[{"internalType":"enum IGovernance.ProposalStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"grantNominations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"gca","type":"address"},{"internalType":"uint256","name":"weekId","type":"uint256"}],"name":"hasEndorsedProposal","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"longStakerVotesForProposal","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mostPopularProposalOfWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"nominationsOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"numEndorsementsOnWeek","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proposalCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"proposalLongStakerVotes","outputs":[{"components":[{"internalType":"uint128","name":"ratifyVotes","type":"uint128"},{"internalType":"uint128","name":"rejectionVotes","type":"uint128"}],"internalType":"struct Governance.ProposalLongStakerVotes","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"proposals","outputs":[{"components":[{"internalType":"enum IGovernance.ProposalType","name":"proposalType","type":"uint8"},{"internalType":"uint64","name":"expirationTimestamp","type":"uint64"},{"internalType":"uint184","name":"votes","type":"uint184"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IGovernance.Proposal","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"weekOfMostPopularProposal","type":"uint256"},{"internalType":"bool","name":"trueForRatify","type":"bool"},{"internalType":"uint256","name":"numVotes","type":"uint256"}],"name":"ratifyOrReject","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"selfIncrementNonce","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"setMostPopularProposalForCurrentWeek","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"spendNominationsOnProposalNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"syncProposals","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"updateLastExpiredProposalId","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"proposalId","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"useNominationsOnProposal","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"weekId","type":"uint256"},{"internalType":"uint256","name":"proposalId","type":"uint256"}],"name":"vetoProposal","outputs":[],"stateMutability":"nonpayable","type":"function"}]

6102206040526001600255600019600455604051620065923803806200659283398101604081905262000032916200026c565b604080518082018252600f81526e476c6f7720476f7665726e616e636560881b602080830191909152825180840190935260018352603160f81b90830152906200007e826000620001ca565b610120526200008f816001620001ca565b61014052815160208084019190912060e052815190820120610100524660a0526200011d60e05161010051604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201529081019290925260608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60805250503060c0526001600160a01b03858116610160528481166101805260408051630308135160e21b8152905191831691630c204d44916004808201926020929091908290030181865afa1580156200017c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001a29190620002dc565b6101a0526001600160a01b039283166101c0529082166101e052166102005250620004dc9050565b6000602083511015620001ea57620001e28362000203565b9050620001fd565b81620001f784826200039b565b5060ff90505b92915050565b600080829050601f815111156200023a578260405163305a27a960e01b815260040162000231919062000467565b60405180910390fd5b80516200024782620004b7565b179392505050565b80516001600160a01b03811681146200026757600080fd5b919050565b600080600080600060a086880312156200028557600080fd5b62000290866200024f565b9450620002a0602087016200024f565b9350620002b0604087016200024f565b9250620002c0606087016200024f565b9150620002d0608087016200024f565b90509295509295909350565b600060208284031215620002ef57600080fd5b5051919050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200032157607f821691505b6020821081036200034257634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200039657600081815260208120601f850160051c81016020861015620003715750805b601f850160051c820191505b8181101562000392578281556001016200037d565b5050505b505050565b81516001600160401b03811115620003b757620003b7620002f6565b620003cf81620003c884546200030c565b8462000348565b602080601f831160018114620004075760008415620003ee5750858301515b600019600386901b1c1916600185901b17855562000392565b600085815260208120601f198616915b82811015620004385788860151825594840194600190910190840162000417565b5085821015620004575787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208083528351808285015260005b81811015620004965785810183015185820160400152820162000478565b506000604082860101526040601f19601f8301168501019250505092915050565b80516020808301519190811015620003425760001960209190910360031b1b16919050565b60805160a05160c05160e05161010051610120516101405161016051610180516101a0516101c0516101e05161020051615fd3620005bf60003960008181610339015261262c0152600081816103850152613f530152600081816105660152818161094d01528181610fc60152613d770152600081816103ac01528181610bd801526139a801526000818161063e01528181613e5801526140280152600081816106f10152612eae0152600061420f015260006141e201526000614be201526000614bba01526000614b1501526000614b3f01526000614b690152615fd36000f3fe608060405234801561001057600080fd5b50600436106102c85760003560e01c806381818b3e1161017b578063b9f2431a116100d8578063da35c6641161008c578063dcd84d2411610071578063dcd84d2414610713578063e61679fb14610726578063f9dd03cb1461073957600080fd5b8063da35c664146106e4578063dc847fbb146106ec57600080fd5b8063c64c27d5116100bd578063c64c27d51461069e578063ca6416d5146106b1578063d98a525a146106d157600080fd5b8063b9f2431a14610660578063c5b2933c1461067357600080fd5b806396a6f5941161012f5780639dc46a30116101145780639dc46a301461061e578063aafa18bd14610631578063b71ce6591461063957600080fd5b806396a6f594146105e45780639ad191f2146105f757600080fd5b806387ad5df31161016057806387ad5df3146105b65780638d73ae6b146105c95780638f1e1abe146105d157600080fd5b806381818b3e1461058857806384b0196e1461059b57600080fd5b8063401853b7116102295780635446e644116101dd57806374a6c665116101c257806374a6c6651461053b578063791fe63c1461054e5780637a6471891461056157600080fd5b80635446e644146105135780635e73ab041461053357600080fd5b8063417b06771161020e578063417b0677146104bd57806344cfc311146104dd5780634bd69db9146104f057600080fd5b8063401853b71461048a57806340918fd9146104aa57600080fd5b80630bd9cadb11610280578063123751d411610265578063123751d4146103ce57806318bc45db146103d657806318d98a4b146103e957600080fd5b80630bd9cadb146103805780630c204d44146103a757600080fd5b806305a8a644116102b157806305a8a6441461030b57806306575c891461031e578063097514231461033457600080fd5b8063013cf08b146102cd5780630577ef4b146102f6575b600080fd5b6102e06102db366004614f08565b61074c565b6040516102ed9190614fd2565b60405180910390f35b6103096103043660046152dd565b610899565b005b610309610319366004614f08565b61091f565b610326610bcd565b6040519081526020016102ed565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ed565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b6103267f000000000000000000000000000000000000000000000000000000000000000081565b610309610c0c565b6103096103e4366004615394565b610c2f565b61045a6103f7366004614f08565b6040805180820190915260008082526020820152506000908152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015290565b6040805182516fffffffffffffffffffffffffffffffff90811682526020938401511692810192909252016102ed565b61049d610498366004614f08565b610d31565b6040516102ed9190615489565b6103096104b83660046154a3565b610d90565b6103266104cb3660046154c5565b60056020526000908152604090205481565b6103096104eb3660046154a3565b610f98565b6105036104fe3660046154e2565b61120f565b60405190151581526020016102ed565b610326610521366004614f08565b600c6020526000908152604090205481565b610309611275565b6103266105493660046154c5565b611636565b61030961055c36600461550e565b611778565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b610309610596366004615549565b611a42565b6105a3611b0c565b6040516102ed979695949392919061561a565b6103096105c43660046156f2565b611b6e565b610309611f69565b6103096105df366004615743565b611f7b565b6103096105f23660046154a3565b61209b565b6103267f03f41c6366d1b8eee338b5696f0b3ce825e8b8eaf9a99b2665c8fb1f68b82aa181565b61030961062c366004614f08565b61231a565b610326612474565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b61030961066e3660046157a0565b612494565b6103266106813660046154e2565b600760209081526000928352604080842090915290825290205481565b6103096106ac366004615824565b6128c8565b6103266106bf366004614f08565b600a6020526000908152604090205481565b6103096106df3660046154a3565b612c06565b610326612e85565b61035b7f000000000000000000000000000000000000000000000000000000000000000081565b6103096107213660046154e2565b612e96565b6103096107343660046152dd565b613102565b610309610747366004614f08565b61317a565b61077660408051608081019091528060008152600060208201819052604082015260609081015290565b600082815260096020526040908190208151608081019092528054829060ff1660058111156107a7576107a7614f21565b60058111156107b8576107b8614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161081090615898565b80601f016020809104026020016040519081016040528092919081815260200182805461083c90615898565b80156108895780601f1061085e57610100808354040283529160200191610889565b820191906000526020600020905b81548152906001019060200180831161086c57829003601f168201915b5050505050815250509050919050565b6000856040516020016108ae91815260200190565b60405160208183030381529060405290506000806108d187878787876004613532565b604080518b815260208101839052929450909250339184917f940f82c67bc94b7c8d3cd1b2880ec0118cb36e350461977bea1330d0cdd8079a91015b60405180910390a35050505050505050565b6040517febd7dc520000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063ebd7dc5290602401602060405180830381865afa1580156109a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cd91906158eb565b6109fa576109fa7f0622c3290000000000000000000000000000000000000000000000000000000061397d565b6000610a04610bcd565b9050808210610a3657610a367fdb6754140000000000000000000000000000000000000000000000000000000061397d565b6000610a4b610a46600485615937565b613987565b905080421115610a7e57610a7e7f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b6000610a8c61010085615979565b90506000610a9c6101008661598d565b336000908152600d602090815260408083208684529091529020549091506001821b80821615610aef57610aef7f74175e970000000000000000000000000000000000000000000000000000000061397d565b336000908152600d6020908152604080832087845282528083208585179055898352600c825280832054600a835281842054808552600990935292205460ff166002816005811115610b4357610b43614f21565b14610b7157610b717feffa48790000000000000000000000000000000000000000000000000000000061397d565b610b7c600184615937565b92506005831115610bb057610bb07f41d075010000000000000000000000000000000000000000000000000000000061397d565b50506000978852600c602052604090972096909655505050505050565b600062093a80610bfd7f0000000000000000000000000000000000000000000000000000000000000000426159a1565b610c079190615979565b905090565b3360009081526005602052604081208054909190610c29906159b4565b90915550565b600585511115610c6257610c627f1e6a29350000000000000000000000000000000000000000000000000000000061397d565b600a86511115610c9557610c957f7a8ed5d80000000000000000000000000000000000000000000000000000000061397d565b60008686604051602001610caa929190615a3d565b6040516020818303038152906040529050600080610ccd87878787876002613532565b915091503373ffffffffffffffffffffffffffffffffffffffff16827f7d4b61e999c91b6fae43058c3e02c29f8048bba71d9198a4e60e3730420be9d68b8b4286604051610d1e9493929190615a6b565b60405180910390a3505050505050505050565b600080610d3f602084615979565b90506000610d4e60208561598d565b610d59906008615aa4565b6000838152600b602052604090205490915060ff821b908116821c806003811115610d8657610d86614f21565b9695505050505050565b610d98611275565b610da1826139cc565b600082815260096020526040812054610100900467ffffffffffffffff1690819003610df057610df07fd9c78e020000000000000000000000000000000000000000000000000000000061397d565b80421115610e2157610e217f28a723790000000000000000000000000000000000000000000000000000000061397d565b610e2b3383613a9f565b600083815260096020526040812054610e7490610e6f9085906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16615937565b613ba0565b6000858152600960205260408120805468ffffffffffffffffff16690100000000000000000076ffffffffffffffffffffffffffffffffffffffffffffff851602179055909150610ec3610bcd565b6000818152600a6020526040902054909150858114610f585760008181526009602052604090205476ffffffffffffffffffffffffffffffffffffffffffffff690100000000000000000090910481169084161115610f58576000828152600a602052604080822088905551879184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b604051858152339087907fc44b98809ee80ebce271d1746069982ebd2dcca69e7a7040fbab30a796664d4c906020015b60405180910390a3505050505050565b6040517febd7dc520000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063ebd7dc5290602401602060405180830381865afa158015611022573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104691906158eb565b611073576110737f0622c3290000000000000000000000000000000000000000000000000000000061397d565b6000828152600a602052604090205481146110b1576110b17fcb4331500000000000000000000000000000000000000000000000000000000061397d565b60006110bb610bcd565b90508083106110ed576110ed7fdb6754140000000000000000000000000000000000000000000000000000000061397d565b60006110fd610a46600486615937565b905080421115611130576111307f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b60008381526009602052604090205460ff16600181600581111561115657611156614f21565b03611184576111847ff3ac1b520000000000000000000000000000000000000000000000000000000061397d565b600281600581111561119857611198614f21565b036111c6576111c67f562ece0a0000000000000000000000000000000000000000000000000000000061397d565b6111d1846003613c06565b604051848152339086907f7ab1a7c147acfa67a40c50647a306a7b98ad5beebb756da4df2841171ffc5aca9060200160405180910390a35050505050565b60008061121e61010084615979565b9050600061122e6101008561598d565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600d602090815260408083209583529490529290922054600190921b90911615159150505b92915050565b600061127f610bcd565b90508060000361128c5750565b600454600191820191015b81811015611632576000818152600a60205260409020546112b781613c6e565b6112c15750611622565b6000818152600960205260408082208151608081019092528054829060ff1660058111156112f1576112f1614f21565b600581111561130257611302614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161135a90615898565b80601f016020809104026020016040519081016040528092919081815260200182805461138690615898565b80156113d35780601f106113a8576101008083540402835291602001916113d3565b820191906000526020600020905b8154815290600101906020018083116113b657829003601f168201915b50505091909252505081516000858152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015292935091905061143d610a46600487615937565b42101561148757841561145a576114556001866159a1565b61147c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600455505050505050565b600282600581111561149b5761149b614f21565b03611554576000858152600c6020526040812054906114bb600583615aa4565b6114c690603c6159a1565b90506000836020015184600001516114de9190615abb565b6fffffffffffffffffffffffffffffffff169050806000036115065750505050505050611622565b83516000908290611518906064615aeb565b6fffffffffffffffffffffffffffffffff166115349190615979565b90508281101561154b575050505050505050611622565b5050505061160d565b600582600581111561156857611568614f21565b141580156115885750600382600581111561158557611585614f21565b14155b1561160d57602081015181516000916115a091615abb565b6fffffffffffffffffffffffffffffffff169050806000036115c6575050505050611622565b815160009082906115d8906064615aeb565b6fffffffffffffffffffffffffffffffff166115f49190615979565b9050603c81101561160a57505050505050611622565b50505b61161d8585848660600151613ce6565b505050505b61162b816159b4565b9050611297565b5050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260086020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff811682527801000000000000000000000000000000000000000000000000900467ffffffffffffffff169181018290529082906116bd90426159a1565b82516040517fab45f3aa00000000000000000000000000000000000000000000000000000000815277ffffffffffffffffffffffffffffffffffffffffffffffff90911660048201526024810182905290915073cf4d7552ca9f07c474d69e89a88943fabb60b1999063ab45f3aa90604401602060405180830381865af415801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117709190615b1f565b949350505050565b6002546000611785614174565b9050808310156117b8576117b87fd1c628250000000000000000000000000000000000000000000000000000000061397d565b6117c23382613a9f565b604080516080810190915280600381526020016117ea6117e56293a80042615937565b61418b565b67ffffffffffffffff16815260200161180283613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526040805173ffffffffffffffffffffffffffffffffffffffff8a1660208281019190915291810189905260608101889052910190608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156118cb576118cb614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff909116171781556060820151600182019061193c9082615b87565b50905050600061194a610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156119d5576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b6119e0846001615937565b6002556040805173ffffffffffffffffffffffffffffffffffffffff8a1681526020810189905290810187905260608101849052339085907fe12dc78051e06dc7c1212d6dbafcf85f4a97c5dfa2268e206aaa3c22ebbabfd29060800161090d565b6040805173ffffffffffffffffffffffffffffffffffffffff89166020820152908101879052606081018690526000906080016040516020818303038152906040529050600080611a9887878787876003613532565b6040805173ffffffffffffffffffffffffffffffffffffffff8e168152602081018d90529081018b9052606081018290529193509150339083907fe12dc78051e06dc7c1212d6dbafcf85f4a97c5dfa2268e206aaa3c22ebbabfd2906080015b60405180910390a350505050505050505050565b600060608060008060006060611b206141db565b611b28614208565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bca57611bca7f1b05f4bd0000000000000000000000000000000000000000000000000000000061397d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000173ffffffffffffffffffffffffffffffffffffffff851601611c3057611c307fc27cd7710000000000000000000000000000000000000000000000000000000061397d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000173ffffffffffffffffffffffffffffffffffffffff841601611c9657611c967fc27cd7710000000000000000000000000000000000000000000000000000000061397d565b6002546000611ca3614174565b905080831015611cd657611cd67fd1c628250000000000000000000000000000000000000000000000000000000061397d565b611ce03382613a9f565b60408051608081019091528060018152602001611d006293a80042615937565b67ffffffffffffffff168152602001611d1883613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526040805173ffffffffffffffffffffffffffffffffffffffff808b16602083810191909152908a1692820192909252871515606082015242608082015291019060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115611ded57611ded614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190611e5e9082615b87565b509050506000611e6c610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16831115611ef7576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b611f02846001615937565b6002556040805173ffffffffffffffffffffffffffffffffffffffff808b168252891660208201528715159181019190915260608101849052339085907f90ba2ce71a1bfada21ece0a0a16d173169337ac350d41671831d4475336efb419060800161090d565b6000611f73614235565b506003555050565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611fd757611fd77f1b05f4bd0000000000000000000000000000000000000000000000000000000061397d565b6040805173ffffffffffffffffffffffffffffffffffffffff808a1660208301528816918101919091528515156060820152600090608001604051602081830303815290604052905060008061203287878787876001613532565b6040805173ffffffffffffffffffffffffffffffffffffffff8e811682528d1660208201528b151591810191909152606081018290529193509150339083907f90ba2ce71a1bfada21ece0a0a16d173169337ac350d41671831d4475336efb4190608001611af8565b60025460006120a8614174565b9050808310156120db576120db7fd1c628250000000000000000000000000000000000000000000000000000000061397d565b6120e53382613a9f565b604080516080810190915280600581526020016121086117e56293a80042615937565b67ffffffffffffffff16815260200161212083613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526020018560405160200161215191815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156121c8576121c8614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff90911617178155606082015160018201906122399082615b87565b509050506000612247610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156122d2576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b6122dd846001615937565b6002556040805187815260208101859052339186917f1c2379a7c23a1b01b01df87517e84e0794326effc88ac06031734520651174e09101610f88565b612322611275565b61232b816139cc565b6000612335610bcd565b6000818152600a602090815260408083205486845260099092529091205491925090610100810467ffffffffffffffff16906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16428210156123be576123be7f28a723790000000000000000000000000000000000000000000000000000000061397d565b828514612440576000838152600960205260409020546901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16811115612417576000848152600a60205260409020859055612440565b6124407f9472ad340000000000000000000000000000000000000000000000000000000061397d565b604051859085907f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d0490600090a35050505050565b60008061247f614235565b5090915061248e9050816142af565b91505090565b600061249e610bcd565b6000858152600a60205260408120549192506124b982610d31565b905060038160038111156124cf576124cf614f21565b036124fd576124fd7f205513150000000000000000000000000000000000000000000000000000000061397d565b600281600381111561251157612511614f21565b148061252e5750600181600381111561252c5761252c614f21565b145b1561255c5761255c7f51618d530000000000000000000000000000000000000000000000000000000061397d565b82861061258c5761258c7fb7d0ea710000000000000000000000000000000000000000000000000000000061397d565b61259a610a46600488615937565b4211156125ca576125ca7f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b816000036125fb576125fb7fdb391df90000000000000000000000000000000000000000000000000000000061397d565b6040517f08ee0c740000000000000000000000000000000000000000000000000000000081523360048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906308ee0c7490602401602060405180830381865afa158015612688573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ac9190615b1f565b336000908152600760209081526040808320878452909152902054909150816126d58783615937565b1115612704576127047fa00141bd0000000000000000000000000000000000000000000000000000000061397d565b86156127c6576000848152600660205260408120805488929061273a9084906fffffffffffffffffffffffffffffffff16615abb565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16847f93274e0943f2ec27ac6dc1c6971d739e99ef1895382f76a3818b159328e3766d886040516127b991815260200190565b60405180910390a3612895565b6000848152600660205260409020805487919060109061280d90849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16615abb565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16847f9698f272413c440f69fc0a22e53a7db613af3c038d9f342385253e62de361fb98860405161288c91815260200190565b60405180910390a35b61289f8682615937565b336000908152600760209081526040808320978352969052949094209390935550505050505050565b60058211156128fa576128fa7f1e6a29350000000000000000000000000000000000000000000000000000000061397d565b600a84111561292c5761292c7f7a8ed5d80000000000000000000000000000000000000000000000000000000061397d565b60008585858542604051602001612947959493929190615cec565b604051602081830303815290604052805190602001209050600060025490506000612970614174565b9050808410156129a3576129a37fd1c628250000000000000000000000000000000000000000000000000000000061397d565b8615156129b03383613a9f565b604080516080810190915280600281526020016129d06293a80042615937565b67ffffffffffffffff1681526020016129e884613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526020018583604051602001612a249291909182521515602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008581526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115612a9b57612a9b614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190612b0c9082615b87565b509050506000612b1a610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16841115612ba5576000828152600a602052604080822087905551869184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b612bb0856001615937565b600255604051339086907f7d4b61e999c91b6fae43058c3e02c29f8048bba71d9198a4e60e3730420be9d690612bf1908f908f908f908f9042908d90615d26565b60405180910390a35050505050505050505050565b6002546000612c13614174565b905080831015612c4657612c467fd1c628250000000000000000000000000000000000000000000000000000000061397d565b612c503382613a9f565b60408051608081019091528060048152602001612c736117e56293a80042615937565b67ffffffffffffffff168152602001612c8b83613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff16815260200185604051602001612cbc91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115612d3357612d33614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190612da49082615b87565b509050506000612db2610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16831115612e3d576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b612e48846001615937565b6002556040805187815260208101859052339186917f940f82c67bc94b7c8d3cd1b2880ec0118cb36e350461977bea1330d0cdd8079a9101610f88565b60006001600254610c0791906159a1565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614612efc57612efc7fceaef8650000000000000000000000000000000000000000000000000000000061397d565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff8116808352780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1692820183905290929173cf4d7552ca9f07c474d69e89a88943fabb60b1999163ab45f3aa91612fa190426159a1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815277ffffffffffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381865af4158015613013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130379190615b1f565b9050604051806040016040528061305885846130539190615937565b6142fe565b77ffffffffffffffffffffffffffffffffffffffffffffffff1681526020016130804261418b565b67ffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff90951660009081526008602090815260409091208251929091015190951678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff90911617909355505050565b60008560405160200161311791815260200190565b604051602081830303815290604052905060008061313a87878787876005613532565b604080518b815260208101839052929450909250339184917f1c2379a7c23a1b01b01df87517e84e0794326effc88ac06031734520651174e0910161090d565b6004546001018181146131b0576131b07f6032dc5a0000000000000000000000000000000000000000000000000000000061397d565b6000828152600a60205260409020546131c881613c6e565b6131d3575050600455565b6000818152600960205260408082208151608081019092528054829060ff16600581111561320357613203614f21565b600581111561321457613214614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161326c90615898565b80601f016020809104026020016040519081016040528092919081815260200182805461329890615898565b80156132e55780601f106132ba576101008083540402835291602001916132e5565b820191906000526020600020905b8154815290600101906020018083116132c857829003601f168201915b50505091909252505081516000858152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015292935091905061334f610a46600488615937565b42101561337f5761337f7f3646d7820000000000000000000000000000000000000000000000000000000061397d565b600282600581111561339357613393614f21565b03613454576000868152600c6020526040812054906133b3600583615aa4565b6133be90603c6159a1565b90506000836020015184600001516133d69190615abb565b6fffffffffffffffffffffffffffffffff16905080600003613402575050506004959095555050505050565b83516000908290613414906064615aeb565b6fffffffffffffffffffffffffffffffff166134309190615979565b90508281101561344b57505050600496909655505050505050565b50505050613515565b600582600581111561346857613468614f21565b141580156134885750600382600581111561348557613485614f21565b14155b1561351557602081015181516000916134a091615abb565b6fffffffffffffffffffffffffffffffff169050806000036134ca57505050600493909355505050565b815160009082906134dc906064615aeb565b6fffffffffffffffffffffffffffffffff166134f89190615979565b9050603c8110156135125750505060049490945550505050565b50505b6135258685848660600151613ce6565b5050506004929092555050565b600254600090819081805b8851811015613623576135b8868b838151811061355c5761355c615d63565b60200260200101518d848151811061357657613576615d63565b60200260200101518c858151811061359057613590615d63565b60200260200101518c86815181106135aa576135aa615d63565b60200260200101518c61435c565b6135f48982815181106135cd576135cd615d63565b60200260200101518b83815181106135e7576135e7615d63565b6020026020010151613a9f565b89818151811061360657613606615d63565b6020026020010151826136199190615937565b915060010161353d565b50600061362e614174565b905080821015613661576136617f620bc4960000000000000000000000000000000000000000000000000000000061397d565b600061366b610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156136f6576000828152600a602052604080822087905551869184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b600288600581111561370a5761370a614f21565b0361379e576000808a8060200190518101906137269190615df6565b91509150600082824260405160200161374193929190615e5a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012095519083019590955293151581850152835180820385018152606090910190935250909950505b60018860058111156137b2576137b2614f21565b036138225760008060008b8060200190518101906137d09190615e90565b6040805173ffffffffffffffffffffffffffffffffffffffff9485166020820152929093168284015215156060820152426080808301919091528251808303909101815260a09091019091529b505050505b604051806080016040528089600581111561383f5761383f614f21565b81526020016138546117e56293a80042615937565b67ffffffffffffffff16815260200161386c86613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff16815260209081018b905260008781526009909152604090208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156138d9576138d9614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff909116171781556060820151600182019061394a9082615b87565b5090505084613958906159b4565b6002819055945061396a6001866159a1565b9d939c50929a5050505050505050505050565b8060005260046000fd5b600062093a80613998836001615937565b6139a29190615aa4565b61126f907f0000000000000000000000000000000000000000000000000000000000000000615937565b60006139d782610d31565b905060028160038111156139ed576139ed614f21565b03613a1b57613a1b7f51618d530000000000000000000000000000000000000000000000000000000061397d565b6001816003811115613a2f57613a2f614f21565b03613a5d57613a5d7f51618d530000000000000000000000000000000000000000000000000000000061397d565b6003816003811115613a7157613a71614f21565b03611632576116327f6d3e62930000000000000000000000000000000000000000000000000000000061397d565b6000613aaa83611636565b905081811015613add57613add7f620bc4960000000000000000000000000000000000000000000000000000000061397d565b6040518060400160405280613af7848461305391906159a1565b77ffffffffffffffffffffffffffffffffffffffffffffffff168152602001613b1f4261418b565b67ffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff90941660009081526008602090815260409091208251929091015190941678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff909116179092555050565b600076ffffffffffffffffffffffffffffffffffffffffffffff821115613c02576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260b86004820152602481018390526044015b60405180910390fd5b5090565b6000613c13602084615979565b90506000613c2260208561598d565b613c2d906008615aa4565b905060ff811b600082856003811115613c4857613c48614f21565b6000958652600b6020526040909520805493199390931694901b93909317905550505050565b600080613c7a83610d31565b90506003816003811115613c9057613c90614f21565b03613c9e5750600092915050565b6002816003811115613cb257613cb2614f21565b1480613ccf57506001816003811115613ccd57613ccd614f21565b145b15613cdd5750600092915050565b50600192915050565b60006001836005811115613cfc57613cfc614f21565b03613dec57600080600084806020019051810190613d1a9190615e90565b6040517f20bac31d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528381166024830152821515604483015293965091945092507f0000000000000000000000000000000000000000000000000000000000000000909116906320bac31d906064016020604051808303816000875af1158015613dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de691906158eb565b93505050505b6002836005811115613e0057613e00614f21565b03613ed05760008083806020019051810190613e1c9190615edd565b6040517f296e540700000000000000000000000000000000000000000000000000000000815260048101839052811515602482015291935091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063296e540790604401600060405180830381600087803b158015613eb157600080fd5b505af1158015613ec5573d6000803e3d6000fd5b505050506001925050505b6003836005811115613ee457613ee4614f21565b03613fc75760008083806020019051810190613f009190615f0d565b506040517fcd12099000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8084166004830152602482018390529294509092507f00000000000000000000000000000000000000000000000000000000000000009091169063cd120990906044016020604051808303816000875af1158015613f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fc291906158eb565b925050505b6004836005811115613fdb57613fdb614f21565b0361409f57600082806020019051810190613ff69190615b1f565b6040517fb744aaa5000000000000000000000000000000000000000000000000000000008152600481018290529091507f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063b744aaa590602401600060405180830381600087803b15801561408157600080fd5b505af1158015614095573d6000803e3d6000fd5b5050505060019150505b60058360058111156140b3576140b3614f21565b03614110576000828060200190518101906140ce9190615b1f565b9050847fe25a4d93d90a403cb2ee36abec0c7dbf52b064220b5cb47d26b670b987325d558260405161410291815260200190565b60405180910390a260019150505b801561412657614121846002613c06565b614131565b614131846001613c06565b847fdcb90c5cbc98ab88833cf2ddca2514638b8f7f96c83c1826bdf8f503b21e1e6385858460405161416593929190615f44565b60405180910390a25050505050565b60008061417f61443a565b50905061248e816142af565b600067ffffffffffffffff821115613c0257604080517f6dfcc650000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401613bf9565b6060610c077f0000000000000000000000000000000000000000000000000000000000000000600061445f565b6060610c077f0000000000000000000000000000000000000000000000000000000000000000600161445f565b60035460009081818015614249578261424c565b60015b600254909350835b81811015614297576000818152600960205260409020544261010090910467ffffffffffffffff16101561428a5780945061428f565b614297565b600101614254565b506142a284826159a1565b9593945050831415919050565b6000806142e76127106142de6142ce68011999999999999a008761450a565b6801000000000000000090614871565b600f0b906148c9565b90506142f7816305f5e100615aa4565b9392505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff821115613c02576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260c0600482015260248101839052604401613bf9565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260056020526040902054428510156143b3576143b37faab28a450000000000000000000000000000000000000000000000000000000061397d565b60006143c2888884898761494e565b90506143cf858286614a4a565b6143fc576143fc7f7caf5a700000000000000000000000000000000000000000000000000000000061397d565b614407826001615937565b73ffffffffffffffffffffffffffffffffffffffff90951660009081526005602052604090209490945550505050505050565b6000806000614447614235565b91945092509050801561445a5760038290555b509091565b606060ff83146144795761447283614abc565b905061126f565b81805461448590615898565b80601f01602080910402602001604051908101604052809291908181526020018280546144b190615898565b80156144fe5780601f106144d3576101008083540402835291602001916144fe565b820191906000526020600020905b8154815290600101906020018083116144e157829003601f168201915b5050505050905061126f565b600080600084600f0b1280156145235750826001166001145b905060008085600f0b12614537578461453c565b846000035b6fffffffffffffffffffffffffffffffff1690507001000000000000000000000000000000006801000000000000000082116145ec57603f82901b91505b84156145e457600185161561458f578102607f1c5b908002607f1c9060028516156145a5578102607f1c5b908002607f1c9060048516156145bb578102607f1c5b908002607f1c9060088516156145d1578102607f1c5b60049490941c93908002607f1c9061457a565b60401c614814565b603f6c0100000000000000000000000083101561462d5760209290921b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015b6e01000000000000000000000000000083101561466e5760109290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0015b6f010000000000000000000000000000008310156146b05760089290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8015b6f100000000000000000000000000000008310156146f25760049290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc015b6f400000000000000000000000000000008310156147345760029290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe015b6f800000000000000000000000000000008310156147765760019290921b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b60005b86156147fd576040821061478c57600080fd5b60018716156147bf57918302607f1c9181017001000000000000000000000000000000008311156147bf57600192831c92015b928002607f1c9260019190911b9070010000000000000000000000000000000084106147f157600193841c9391909101905b600187901c9650614779565b6040811061480a57600080fd5b6040039190911c90505b6000836148215781614826565b816000035b90507fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061486857506f7fffffffffffffffffffffffffffffff8113155b610d8657600080fd5b6000600f83810b9083900b0260401d7fffffffffffffffffffffffffffffffff8000000000000000000000000000000081128015906148c057506f7fffffffffffffffffffffffffffffff8113155b6142f757600080fd5b6000816000036148db5750600061126f565b600083600f0b12156148ec57600080fd5b600f83900b6fffffffffffffffffffffffffffffffff8316810260401c90608084901c0277ffffffffffffffffffffffffffffffffffffffffffffffff81111561493557600080fd5b60401b811981111561494657600080fd5b019392505050565b6000614958614afb565b7f03f41c6366d1b8eee338b5696f0b3ce825e8b8eaf9a99b2665c8fb1f68b82aa187600581111561498b5761498b614f21565b87878787805190602001206040516020016149d19695949392919095865260ff94909416602086015260408501929092526060840152608083015260a082015260c00190565b60405160208183030381529060405280519060200120604051602001614a299291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905095945050505050565b6000806000614a598585614c33565b5090925090506000816003811115614a7357614a73614f21565b148015614aab57508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b80610d865750610d86868686614c80565b60606000614ac983614dcd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60003073ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016148015614b6157507f000000000000000000000000000000000000000000000000000000000000000046145b15614b8b57507f000000000000000000000000000000000000000000000000000000000000000090565b610c07604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527f0000000000000000000000000000000000000000000000000000000000000000918101919091527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008060008351604103614c6d5760208401516040850151606086015160001a614c5f88828585614e0e565b955095509550505050614c79565b50508151600091506002905b9250925092565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401614caf929190615f68565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e0000000000000000000000000000000000000000000000000000000017905251614d309190615f81565b600060405180830381855afa9150503d8060008114614d6b576040519150601f19603f3d011682016040523d82523d6000602084013e614d70565b606091505b5091509150818015614d8457506020815110155b8015610d86575080517f1626ba7e0000000000000000000000000000000000000000000000000000000090614dc29083016020908101908401615b1f565b149695505050505050565b600060ff8216601f81111561126f576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115614e495750600091506003905082614efe565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015614e9d573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116614ef457506000925060019150829050614efe565b9250600091508190505b9450945094915050565b600060208284031215614f1a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60068110614f6057614f60614f21565b9052565b60005b83811015614f7f578181015183820152602001614f67565b50506000910152565b60008151808452614fa0816020860160208601614f64565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152614fe4602082018351614f50565b67ffffffffffffffff602083015116604082015276ffffffffffffffffffffffffffffffffffffffffffffff60408301511660608201526000606083015160808084015261177060a0840182614f88565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156150ab576150ab615035565b604052919050565b600067ffffffffffffffff8211156150cd576150cd615035565b5060051b60200190565b600082601f8301126150e857600080fd5b813560206150fd6150f8836150b3565b615064565b82815260059290921b8401810191818101908684111561511c57600080fd5b8286015b848110156151375780358352918301918301615120565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461516457600080fd5b50565b803561517281615142565b919050565b600082601f83011261518857600080fd5b813560206151986150f8836150b3565b82815260059290921b840181019181810190868411156151b757600080fd5b8286015b848110156151375780356151ce81615142565b83529183019183016151bb565b6000601f83818401126151ed57600080fd5b823560206151fd6150f8836150b3565b82815260059290921b8501810191818101908784111561521c57600080fd5b8287015b848110156152d157803567ffffffffffffffff808211156152415760008081fd5b818a0191508a603f8301126152565760008081fd5b8582013560408282111561526c5761526c615035565b61529b887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601615064565b92508183528c818386010111156152b25760008081fd5b8181850189850137506000908201870152845250918301918301615220565b50979650505050505050565b600080600080600060a086880312156152f557600080fd5b85359450602086013567ffffffffffffffff8082111561531457600080fd5b61532089838a016150d7565b9550604088013591508082111561533657600080fd5b61534289838a016150d7565b9450606088013591508082111561535857600080fd5b61536489838a01615177565b9350608088013591508082111561537a57600080fd5b50615387888289016151db565b9150509295509295909350565b60008060008060008060c087890312156153ad57600080fd5b863567ffffffffffffffff808211156153c557600080fd5b6153d18a838b01615177565b975060208901359150808211156153e757600080fd5b6153f38a838b01615177565b9650604089013591508082111561540957600080fd5b6154158a838b016150d7565b9550606089013591508082111561542b57600080fd5b6154378a838b016150d7565b9450608089013591508082111561544d57600080fd5b6154598a838b01615177565b935060a089013591508082111561546f57600080fd5b5061547c89828a016151db565b9150509295509295509295565b602081016004831061549d5761549d614f21565b91905290565b600080604083850312156154b657600080fd5b50508035926020909101359150565b6000602082840312156154d757600080fd5b81356142f781615142565b600080604083850312156154f557600080fd5b823561550081615142565b946020939093013593505050565b6000806000806080858703121561552457600080fd5b843561552f81615142565b966020860135965060408601359560600135945092505050565b600080600080600080600060e0888a03121561556457600080fd5b61556d88615167565b96506020880135955060408801359450606088013567ffffffffffffffff8082111561559857600080fd5b6155a48b838c016150d7565b955060808a01359150808211156155ba57600080fd5b6155c68b838c016150d7565b945060a08a01359150808211156155dc57600080fd5b6155e88b838c01615177565b935060c08a01359150808211156155fe57600080fd5b5061560b8a828b016151db565b91505092959891949750929550565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e08184015261565660e084018a614f88565b8381036040850152615668818a614f88565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156156c7578351835292840192918401916001016156ab565b50909c9b505050505050505050505050565b801515811461516457600080fd5b8035615172816156d9565b6000806000806080858703121561570857600080fd5b843561571381615142565b9350602085013561572381615142565b92506040850135615733816156d9565b9396929550929360600135925050565b600080600080600080600060e0888a03121561575e57600080fd5b61576788615167565b965061577560208901615167565b9550615783604089016156e7565b9450606088013567ffffffffffffffff8082111561559857600080fd5b6000806000606084860312156157b557600080fd5b8335925060208401356157c7816156d9565b929592945050506040919091013590565b60008083601f8401126157ea57600080fd5b50813567ffffffffffffffff81111561580257600080fd5b6020830191508360208260051b850101111561581d57600080fd5b9250929050565b60008060008060006060868803121561583c57600080fd5b853567ffffffffffffffff8082111561585457600080fd5b61586089838a016157d8565b9097509550602088013591508082111561587957600080fd5b50615886888289016157d8565b96999598509660400135949350505050565b600181811c908216806158ac57607f821691505b6020821081036158e5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000602082840312156158fd57600080fd5b81516142f7816156d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561126f5761126f615908565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159885761598861594a565b500490565b60008261599c5761599c61594a565b500690565b8181038181111561126f5761126f615908565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036159e5576159e5615908565b5060010190565b600081518084526020808501945080840160005b83811015615a3257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615a00565b509495945050505050565b604081526000615a5060408301856159ec565b8281036020840152615a6281856159ec565b95945050505050565b608081526000615a7e60808301876159ec565b8281036020840152615a9081876159ec565b604084019590955250506060015292915050565b808202811582820484141761126f5761126f615908565b6fffffffffffffffffffffffffffffffff818116838216019080821115615ae457615ae4615908565b5092915050565b6fffffffffffffffffffffffffffffffff818116838216028082169190828114615b1757615b17615908565b505092915050565b600060208284031215615b3157600080fd5b5051919050565b601f821115615b8257600081815260208120601f850160051c81016020861015615b5f5750805b601f850160051c820191505b81811015615b7e57828155600101615b6b565b5050505b505050565b815167ffffffffffffffff811115615ba157615ba1615035565b615bb581615baf8454615898565b84615b38565b602080601f831160018114615c085760008415615bd25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555615b7e565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615c5557888601518255948401946001909101908401615c36565b5085821015615c9157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015615a32578135615cc481615142565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615cb1565b606081526000615d00606083018789615ca1565b8281036020840152615d13818688615ca1565b9150508260408301529695505050505050565b608081526000615d3a60808301888a615ca1565b8281036020840152615d4d818789615ca1565b6040840195909552505060600152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082601f830112615da357600080fd5b81516020615db36150f8836150b3565b82815260059290921b84018101918181019086841115615dd257600080fd5b8286015b84811015615137578051615de981615142565b8352918301918301615dd6565b60008060408385031215615e0957600080fd5b825167ffffffffffffffff80821115615e2157600080fd5b615e2d86838701615d92565b93506020850151915080821115615e4357600080fd5b50615e5085828601615d92565b9150509250929050565b606081526000615e6d60608301866159ec565b8281036020840152615e7f81866159ec565b915050826040830152949350505050565b600080600060608486031215615ea557600080fd5b8351615eb081615142565b6020850151909350615ec181615142565b6040850151909250615ed2816156d9565b809150509250925092565b60008060408385031215615ef057600080fd5b825191506020830151615f02816156d9565b809150509250929050565b600080600060608486031215615f2257600080fd5b8351615f2d81615142565b602085015160409095015190969495509392505050565b83815260608101615f586020830185614f50565b8215156040830152949350505050565b8281526040602082015260006117706040830184614f88565b60008251615f93818460208701614f64565b919091019291505056fea2646970667358221220a4a0ea6d9f5a360187cd380013d49245c410ee614a03c675337a55fa46401dfe64736f6c6343000815003300000000000000000000000021c46173591f39afc1d2b634b74c98f0576a272b0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c4000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c0000000000000000000000000116da066517f010e59b32274bf18083af34e108000000000000000000000000f4fbc617a5733eaaf9af08e1ab816b103388d8b6

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102c85760003560e01c806381818b3e1161017b578063b9f2431a116100d8578063da35c6641161008c578063dcd84d2411610071578063dcd84d2414610713578063e61679fb14610726578063f9dd03cb1461073957600080fd5b8063da35c664146106e4578063dc847fbb146106ec57600080fd5b8063c64c27d5116100bd578063c64c27d51461069e578063ca6416d5146106b1578063d98a525a146106d157600080fd5b8063b9f2431a14610660578063c5b2933c1461067357600080fd5b806396a6f5941161012f5780639dc46a30116101145780639dc46a301461061e578063aafa18bd14610631578063b71ce6591461063957600080fd5b806396a6f594146105e45780639ad191f2146105f757600080fd5b806387ad5df31161016057806387ad5df3146105b65780638d73ae6b146105c95780638f1e1abe146105d157600080fd5b806381818b3e1461058857806384b0196e1461059b57600080fd5b8063401853b7116102295780635446e644116101dd57806374a6c665116101c257806374a6c6651461053b578063791fe63c1461054e5780637a6471891461056157600080fd5b80635446e644146105135780635e73ab041461053357600080fd5b8063417b06771161020e578063417b0677146104bd57806344cfc311146104dd5780634bd69db9146104f057600080fd5b8063401853b71461048a57806340918fd9146104aa57600080fd5b80630bd9cadb11610280578063123751d411610265578063123751d4146103ce57806318bc45db146103d657806318d98a4b146103e957600080fd5b80630bd9cadb146103805780630c204d44146103a757600080fd5b806305a8a644116102b157806305a8a6441461030b57806306575c891461031e578063097514231461033457600080fd5b8063013cf08b146102cd5780630577ef4b146102f6575b600080fd5b6102e06102db366004614f08565b61074c565b6040516102ed9190614fd2565b60405180910390f35b6103096103043660046152dd565b610899565b005b610309610319366004614f08565b61091f565b610326610bcd565b6040519081526020016102ed565b61035b7f000000000000000000000000f4fbc617a5733eaaf9af08e1ab816b103388d8b681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102ed565b61035b7f0000000000000000000000000116da066517f010e59b32274bf18083af34e10881565b6103267f000000000000000000000000000000000000000000000000000000006559500081565b610309610c0c565b6103096103e4366004615394565b610c2f565b61045a6103f7366004614f08565b6040805180820190915260008082526020820152506000908152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015290565b6040805182516fffffffffffffffffffffffffffffffff90811682526020938401511692810192909252016102ed565b61049d610498366004614f08565b610d31565b6040516102ed9190615489565b6103096104b83660046154a3565b610d90565b6103266104cb3660046154c5565b60056020526000908152604090205481565b6103096104eb3660046154a3565b610f98565b6105036104fe3660046154e2565b61120f565b60405190151581526020016102ed565b610326610521366004614f08565b600c6020526000908152604090205481565b610309611275565b6103266105493660046154c5565b611636565b61030961055c36600461550e565b611778565b61035b7f000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c81565b610309610596366004615549565b611a42565b6105a3611b0c565b6040516102ed979695949392919061561a565b6103096105c43660046156f2565b611b6e565b610309611f69565b6103096105df366004615743565b611f7b565b6103096105f23660046154a3565b61209b565b6103267f03f41c6366d1b8eee338b5696f0b3ce825e8b8eaf9a99b2665c8fb1f68b82aa181565b61030961062c366004614f08565b61231a565b610326612474565b61035b7f0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c481565b61030961066e3660046157a0565b612494565b6103266106813660046154e2565b600760209081526000928352604080842090915290825290205481565b6103096106ac366004615824565b6128c8565b6103266106bf366004614f08565b600a6020526000908152604090205481565b6103096106df3660046154a3565b612c06565b610326612e85565b61035b7f00000000000000000000000021c46173591f39afc1d2b634b74c98f0576a272b81565b6103096107213660046154e2565b612e96565b6103096107343660046152dd565b613102565b610309610747366004614f08565b61317a565b61077660408051608081019091528060008152600060208201819052604082015260609081015290565b600082815260096020526040908190208151608081019092528054829060ff1660058111156107a7576107a7614f21565b60058111156107b8576107b8614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161081090615898565b80601f016020809104026020016040519081016040528092919081815260200182805461083c90615898565b80156108895780601f1061085e57610100808354040283529160200191610889565b820191906000526020600020905b81548152906001019060200180831161086c57829003601f168201915b5050505050815250509050919050565b6000856040516020016108ae91815260200190565b60405160208183030381529060405290506000806108d187878787876004613532565b604080518b815260208101839052929450909250339184917f940f82c67bc94b7c8d3cd1b2880ec0118cb36e350461977bea1330d0cdd8079a91015b60405180910390a35050505050505050565b6040517febd7dc520000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c73ffffffffffffffffffffffffffffffffffffffff169063ebd7dc5290602401602060405180830381865afa1580156109a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109cd91906158eb565b6109fa576109fa7f0622c3290000000000000000000000000000000000000000000000000000000061397d565b6000610a04610bcd565b9050808210610a3657610a367fdb6754140000000000000000000000000000000000000000000000000000000061397d565b6000610a4b610a46600485615937565b613987565b905080421115610a7e57610a7e7f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b6000610a8c61010085615979565b90506000610a9c6101008661598d565b336000908152600d602090815260408083208684529091529020549091506001821b80821615610aef57610aef7f74175e970000000000000000000000000000000000000000000000000000000061397d565b336000908152600d6020908152604080832087845282528083208585179055898352600c825280832054600a835281842054808552600990935292205460ff166002816005811115610b4357610b43614f21565b14610b7157610b717feffa48790000000000000000000000000000000000000000000000000000000061397d565b610b7c600184615937565b92506005831115610bb057610bb07f41d075010000000000000000000000000000000000000000000000000000000061397d565b50506000978852600c602052604090972096909655505050505050565b600062093a80610bfd7f0000000000000000000000000000000000000000000000000000000065595000426159a1565b610c079190615979565b905090565b3360009081526005602052604081208054909190610c29906159b4565b90915550565b600585511115610c6257610c627f1e6a29350000000000000000000000000000000000000000000000000000000061397d565b600a86511115610c9557610c957f7a8ed5d80000000000000000000000000000000000000000000000000000000061397d565b60008686604051602001610caa929190615a3d565b6040516020818303038152906040529050600080610ccd87878787876002613532565b915091503373ffffffffffffffffffffffffffffffffffffffff16827f7d4b61e999c91b6fae43058c3e02c29f8048bba71d9198a4e60e3730420be9d68b8b4286604051610d1e9493929190615a6b565b60405180910390a3505050505050505050565b600080610d3f602084615979565b90506000610d4e60208561598d565b610d59906008615aa4565b6000838152600b602052604090205490915060ff821b908116821c806003811115610d8657610d86614f21565b9695505050505050565b610d98611275565b610da1826139cc565b600082815260096020526040812054610100900467ffffffffffffffff1690819003610df057610df07fd9c78e020000000000000000000000000000000000000000000000000000000061397d565b80421115610e2157610e217f28a723790000000000000000000000000000000000000000000000000000000061397d565b610e2b3383613a9f565b600083815260096020526040812054610e7490610e6f9085906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16615937565b613ba0565b6000858152600960205260408120805468ffffffffffffffffff16690100000000000000000076ffffffffffffffffffffffffffffffffffffffffffffff851602179055909150610ec3610bcd565b6000818152600a6020526040902054909150858114610f585760008181526009602052604090205476ffffffffffffffffffffffffffffffffffffffffffffff690100000000000000000090910481169084161115610f58576000828152600a602052604080822088905551879184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b604051858152339087907fc44b98809ee80ebce271d1746069982ebd2dcca69e7a7040fbab30a796664d4c906020015b60405180910390a3505050505050565b6040517febd7dc520000000000000000000000000000000000000000000000000000000081523360048201527f000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c73ffffffffffffffffffffffffffffffffffffffff169063ebd7dc5290602401602060405180830381865afa158015611022573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061104691906158eb565b611073576110737f0622c3290000000000000000000000000000000000000000000000000000000061397d565b6000828152600a602052604090205481146110b1576110b17fcb4331500000000000000000000000000000000000000000000000000000000061397d565b60006110bb610bcd565b90508083106110ed576110ed7fdb6754140000000000000000000000000000000000000000000000000000000061397d565b60006110fd610a46600486615937565b905080421115611130576111307f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b60008381526009602052604090205460ff16600181600581111561115657611156614f21565b03611184576111847ff3ac1b520000000000000000000000000000000000000000000000000000000061397d565b600281600581111561119857611198614f21565b036111c6576111c67f562ece0a0000000000000000000000000000000000000000000000000000000061397d565b6111d1846003613c06565b604051848152339086907f7ab1a7c147acfa67a40c50647a306a7b98ad5beebb756da4df2841171ffc5aca9060200160405180910390a35050505050565b60008061121e61010084615979565b9050600061122e6101008561598d565b73ffffffffffffffffffffffffffffffffffffffff86166000908152600d602090815260408083209583529490529290922054600190921b90911615159150505b92915050565b600061127f610bcd565b90508060000361128c5750565b600454600191820191015b81811015611632576000818152600a60205260409020546112b781613c6e565b6112c15750611622565b6000818152600960205260408082208151608081019092528054829060ff1660058111156112f1576112f1614f21565b600581111561130257611302614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161135a90615898565b80601f016020809104026020016040519081016040528092919081815260200182805461138690615898565b80156113d35780601f106113a8576101008083540402835291602001916113d3565b820191906000526020600020905b8154815290600101906020018083116113b657829003601f168201915b50505091909252505081516000858152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015292935091905061143d610a46600487615937565b42101561148757841561145a576114556001866159a1565b61147c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5b600455505050505050565b600282600581111561149b5761149b614f21565b03611554576000858152600c6020526040812054906114bb600583615aa4565b6114c690603c6159a1565b90506000836020015184600001516114de9190615abb565b6fffffffffffffffffffffffffffffffff169050806000036115065750505050505050611622565b83516000908290611518906064615aeb565b6fffffffffffffffffffffffffffffffff166115349190615979565b90508281101561154b575050505050505050611622565b5050505061160d565b600582600581111561156857611568614f21565b141580156115885750600382600581111561158557611585614f21565b14155b1561160d57602081015181516000916115a091615abb565b6fffffffffffffffffffffffffffffffff169050806000036115c6575050505050611622565b815160009082906115d8906064615aeb565b6fffffffffffffffffffffffffffffffff166115f49190615979565b9050603c81101561160a57505050505050611622565b50505b61161d8585848660600151613ce6565b505050505b61162b816159b4565b9050611297565b5050565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260086020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff811682527801000000000000000000000000000000000000000000000000900467ffffffffffffffff169181018290529082906116bd90426159a1565b82516040517fab45f3aa00000000000000000000000000000000000000000000000000000000815277ffffffffffffffffffffffffffffffffffffffffffffffff90911660048201526024810182905290915073cf4d7552ca9f07c474d69e89a88943fabb60b1999063ab45f3aa90604401602060405180830381865af415801561174c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117709190615b1f565b949350505050565b6002546000611785614174565b9050808310156117b8576117b87fd1c628250000000000000000000000000000000000000000000000000000000061397d565b6117c23382613a9f565b604080516080810190915280600381526020016117ea6117e56293a80042615937565b61418b565b67ffffffffffffffff16815260200161180283613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526040805173ffffffffffffffffffffffffffffffffffffffff8a1660208281019190915291810189905260608101889052910190608001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156118cb576118cb614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff909116171781556060820151600182019061193c9082615b87565b50905050600061194a610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156119d5576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b6119e0846001615937565b6002556040805173ffffffffffffffffffffffffffffffffffffffff8a1681526020810189905290810187905260608101849052339085907fe12dc78051e06dc7c1212d6dbafcf85f4a97c5dfa2268e206aaa3c22ebbabfd29060800161090d565b6040805173ffffffffffffffffffffffffffffffffffffffff89166020820152908101879052606081018690526000906080016040516020818303038152906040529050600080611a9887878787876003613532565b6040805173ffffffffffffffffffffffffffffffffffffffff8e168152602081018d90529081018b9052606081018290529193509150339083907fe12dc78051e06dc7c1212d6dbafcf85f4a97c5dfa2268e206aaa3c22ebbabfd2906080015b60405180910390a350505050505050505050565b600060608060008060006060611b206141db565b611b28614208565b604080516000808252602082019092527f0f000000000000000000000000000000000000000000000000000000000000009b939a50919850469750309650945092509050565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1603611bca57611bca7f1b05f4bd0000000000000000000000000000000000000000000000000000000061397d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000173ffffffffffffffffffffffffffffffffffffffff851601611c3057611c307fc27cd7710000000000000000000000000000000000000000000000000000000061397d565b7fffffffffffffffffffffffff000000000000000000000000000000000000000173ffffffffffffffffffffffffffffffffffffffff841601611c9657611c967fc27cd7710000000000000000000000000000000000000000000000000000000061397d565b6002546000611ca3614174565b905080831015611cd657611cd67fd1c628250000000000000000000000000000000000000000000000000000000061397d565b611ce03382613a9f565b60408051608081019091528060018152602001611d006293a80042615937565b67ffffffffffffffff168152602001611d1883613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526040805173ffffffffffffffffffffffffffffffffffffffff808b16602083810191909152908a1692820192909252871515606082015242608082015291019060a001604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115611ded57611ded614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190611e5e9082615b87565b509050506000611e6c610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16831115611ef7576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b611f02846001615937565b6002556040805173ffffffffffffffffffffffffffffffffffffffff808b168252891660208201528715159181019190915260608101849052339085907f90ba2ce71a1bfada21ece0a0a16d173169337ac350d41671831d4475336efb419060800161090d565b6000611f73614235565b506003555050565b8573ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff1603611fd757611fd77f1b05f4bd0000000000000000000000000000000000000000000000000000000061397d565b6040805173ffffffffffffffffffffffffffffffffffffffff808a1660208301528816918101919091528515156060820152600090608001604051602081830303815290604052905060008061203287878787876001613532565b6040805173ffffffffffffffffffffffffffffffffffffffff8e811682528d1660208201528b151591810191909152606081018290529193509150339083907f90ba2ce71a1bfada21ece0a0a16d173169337ac350d41671831d4475336efb4190608001611af8565b60025460006120a8614174565b9050808310156120db576120db7fd1c628250000000000000000000000000000000000000000000000000000000061397d565b6120e53382613a9f565b604080516080810190915280600581526020016121086117e56293a80042615937565b67ffffffffffffffff16815260200161212083613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526020018560405160200161215191815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156121c8576121c8614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff90911617178155606082015160018201906122399082615b87565b509050506000612247610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156122d2576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b6122dd846001615937565b6002556040805187815260208101859052339186917f1c2379a7c23a1b01b01df87517e84e0794326effc88ac06031734520651174e09101610f88565b612322611275565b61232b816139cc565b6000612335610bcd565b6000818152600a602090815260408083205486845260099092529091205491925090610100810467ffffffffffffffff16906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16428210156123be576123be7f28a723790000000000000000000000000000000000000000000000000000000061397d565b828514612440576000838152600960205260409020546901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16811115612417576000848152600a60205260409020859055612440565b6124407f9472ad340000000000000000000000000000000000000000000000000000000061397d565b604051859085907f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d0490600090a35050505050565b60008061247f614235565b5090915061248e9050816142af565b91505090565b600061249e610bcd565b6000858152600a60205260408120549192506124b982610d31565b905060038160038111156124cf576124cf614f21565b036124fd576124fd7f205513150000000000000000000000000000000000000000000000000000000061397d565b600281600381111561251157612511614f21565b148061252e5750600181600381111561252c5761252c614f21565b145b1561255c5761255c7f51618d530000000000000000000000000000000000000000000000000000000061397d565b82861061258c5761258c7fb7d0ea710000000000000000000000000000000000000000000000000000000061397d565b61259a610a46600488615937565b4211156125ca576125ca7f30a8b0dc0000000000000000000000000000000000000000000000000000000061397d565b816000036125fb576125fb7fdb391df90000000000000000000000000000000000000000000000000000000061397d565b6040517f08ee0c740000000000000000000000000000000000000000000000000000000081523360048201526000907f000000000000000000000000f4fbc617a5733eaaf9af08e1ab816b103388d8b673ffffffffffffffffffffffffffffffffffffffff16906308ee0c7490602401602060405180830381865afa158015612688573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126ac9190615b1f565b336000908152600760209081526040808320878452909152902054909150816126d58783615937565b1115612704576127047fa00141bd0000000000000000000000000000000000000000000000000000000061397d565b86156127c6576000848152600660205260408120805488929061273a9084906fffffffffffffffffffffffffffffffff16615abb565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16847f93274e0943f2ec27ac6dc1c6971d739e99ef1895382f76a3818b159328e3766d886040516127b991815260200190565b60405180910390a3612895565b6000848152600660205260409020805487919060109061280d90849070010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff16615abb565b92506101000a8154816fffffffffffffffffffffffffffffffff02191690836fffffffffffffffffffffffffffffffff1602179055503373ffffffffffffffffffffffffffffffffffffffff16847f9698f272413c440f69fc0a22e53a7db613af3c038d9f342385253e62de361fb98860405161288c91815260200190565b60405180910390a35b61289f8682615937565b336000908152600760209081526040808320978352969052949094209390935550505050505050565b60058211156128fa576128fa7f1e6a29350000000000000000000000000000000000000000000000000000000061397d565b600a84111561292c5761292c7f7a8ed5d80000000000000000000000000000000000000000000000000000000061397d565b60008585858542604051602001612947959493929190615cec565b604051602081830303815290604052805190602001209050600060025490506000612970614174565b9050808410156129a3576129a37fd1c628250000000000000000000000000000000000000000000000000000000061397d565b8615156129b03383613a9f565b604080516080810190915280600281526020016129d06293a80042615937565b67ffffffffffffffff1681526020016129e884613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff1681526020018583604051602001612a249291909182521515602082015260400190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008581526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115612a9b57612a9b614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190612b0c9082615b87565b509050506000612b1a610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16841115612ba5576000828152600a602052604080822087905551869184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b612bb0856001615937565b600255604051339086907f7d4b61e999c91b6fae43058c3e02c29f8048bba71d9198a4e60e3730420be9d690612bf1908f908f908f908f9042908d90615d26565b60405180910390a35050505050505050505050565b6002546000612c13614174565b905080831015612c4657612c467fd1c628250000000000000000000000000000000000000000000000000000000061397d565b612c503382613a9f565b60408051608081019091528060048152602001612c736117e56293a80042615937565b67ffffffffffffffff168152602001612c8b83613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff16815260200185604051602001612cbc91815260200190565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152915260008481526009602052208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001836005811115612d3357612d33614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff9091161717815560608201516001820190612da49082615b87565b509050506000612db2610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16831115612e3d576000828152600a602052604080822086905551859184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b612e48846001615937565b6002556040805187815260208101859052339186917f940f82c67bc94b7c8d3cd1b2880ec0118cb36e350461977bea1330d0cdd8079a9101610f88565b60006001600254610c0791906159a1565b3373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000021c46173591f39afc1d2b634b74c98f0576a272b1614612efc57612efc7fceaef8650000000000000000000000000000000000000000000000000000000061397d565b73ffffffffffffffffffffffffffffffffffffffff8216600090815260086020908152604080832081518083019092525477ffffffffffffffffffffffffffffffffffffffffffffffff8116808352780100000000000000000000000000000000000000000000000090910467ffffffffffffffff1692820183905290929173cf4d7552ca9f07c474d69e89a88943fabb60b1999163ab45f3aa91612fa190426159a1565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815277ffffffffffffffffffffffffffffffffffffffffffffffff90921660048301526024820152604401602060405180830381865af4158015613013573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130379190615b1f565b9050604051806040016040528061305885846130539190615937565b6142fe565b77ffffffffffffffffffffffffffffffffffffffffffffffff1681526020016130804261418b565b67ffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff90951660009081526008602090815260409091208251929091015190951678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff90911617909355505050565b60008560405160200161311791815260200190565b604051602081830303815290604052905060008061313a87878787876005613532565b604080518b815260208101839052929450909250339184917f1c2379a7c23a1b01b01df87517e84e0794326effc88ac06031734520651174e0910161090d565b6004546001018181146131b0576131b07f6032dc5a0000000000000000000000000000000000000000000000000000000061397d565b6000828152600a60205260409020546131c881613c6e565b6131d3575050600455565b6000818152600960205260408082208151608081019092528054829060ff16600581111561320357613203614f21565b600581111561321457613214614f21565b81528154610100810467ffffffffffffffff1660208301526901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff16604082015260018201805460609092019161326c90615898565b80601f016020809104026020016040519081016040528092919081815260200182805461329890615898565b80156132e55780601f106132ba576101008083540402835291602001916132e5565b820191906000526020600020905b8154815290600101906020018083116132c857829003601f168201915b50505091909252505081516000858152600660209081526040918290208251808401909352546fffffffffffffffffffffffffffffffff8082168452700100000000000000000000000000000000909104169082015292935091905061334f610a46600488615937565b42101561337f5761337f7f3646d7820000000000000000000000000000000000000000000000000000000061397d565b600282600581111561339357613393614f21565b03613454576000868152600c6020526040812054906133b3600583615aa4565b6133be90603c6159a1565b90506000836020015184600001516133d69190615abb565b6fffffffffffffffffffffffffffffffff16905080600003613402575050506004959095555050505050565b83516000908290613414906064615aeb565b6fffffffffffffffffffffffffffffffff166134309190615979565b90508281101561344b57505050600496909655505050505050565b50505050613515565b600582600581111561346857613468614f21565b141580156134885750600382600581111561348557613485614f21565b14155b1561351557602081015181516000916134a091615abb565b6fffffffffffffffffffffffffffffffff169050806000036134ca57505050600493909355505050565b815160009082906134dc906064615aeb565b6fffffffffffffffffffffffffffffffff166134f89190615979565b9050603c8110156135125750505060049490945550505050565b50505b6135258685848660600151613ce6565b5050506004929092555050565b600254600090819081805b8851811015613623576135b8868b838151811061355c5761355c615d63565b60200260200101518d848151811061357657613576615d63565b60200260200101518c858151811061359057613590615d63565b60200260200101518c86815181106135aa576135aa615d63565b60200260200101518c61435c565b6135f48982815181106135cd576135cd615d63565b60200260200101518b83815181106135e7576135e7615d63565b6020026020010151613a9f565b89818151811061360657613606615d63565b6020026020010151826136199190615937565b915060010161353d565b50600061362e614174565b905080821015613661576136617f620bc4960000000000000000000000000000000000000000000000000000000061397d565b600061366b610bcd565b6000818152600a6020908152604080832054808452600990925290912054919250906901000000000000000000900476ffffffffffffffffffffffffffffffffffffffffffffff168311156136f6576000828152600a602052604080822087905551869184917f663e0daedbefabe1bdf9f46ee7e1df6d9c9010b148223f95206ff16cb8215d049190a35b600288600581111561370a5761370a614f21565b0361379e576000808a8060200190518101906137269190615df6565b91509150600082824260405160200161374193929190615e5a565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152828252805160209182012095519083019590955293151581850152835180820385018152606090910190935250909950505b60018860058111156137b2576137b2614f21565b036138225760008060008b8060200190518101906137d09190615e90565b6040805173ffffffffffffffffffffffffffffffffffffffff9485166020820152929093168284015215156060820152426080808301919091528251808303909101815260a09091019091529b505050505b604051806080016040528089600581111561383f5761383f614f21565b81526020016138546117e56293a80042615937565b67ffffffffffffffff16815260200161386c86613ba0565b76ffffffffffffffffffffffffffffffffffffffffffffff16815260209081018b905260008781526009909152604090208151815482907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660018360058111156138d9576138d9614f21565b021790555060208201518154604084015176ffffffffffffffffffffffffffffffffffffffffffffff1669010000000000000000000268ffffffffffffffffff67ffffffffffffffff909316610100029290921660ff909116171781556060820151600182019061394a9082615b87565b5090505084613958906159b4565b6002819055945061396a6001866159a1565b9d939c50929a5050505050505050505050565b8060005260046000fd5b600062093a80613998836001615937565b6139a29190615aa4565b61126f907f0000000000000000000000000000000000000000000000000000000065595000615937565b60006139d782610d31565b905060028160038111156139ed576139ed614f21565b03613a1b57613a1b7f51618d530000000000000000000000000000000000000000000000000000000061397d565b6001816003811115613a2f57613a2f614f21565b03613a5d57613a5d7f51618d530000000000000000000000000000000000000000000000000000000061397d565b6003816003811115613a7157613a71614f21565b03611632576116327f6d3e62930000000000000000000000000000000000000000000000000000000061397d565b6000613aaa83611636565b905081811015613add57613add7f620bc4960000000000000000000000000000000000000000000000000000000061397d565b6040518060400160405280613af7848461305391906159a1565b77ffffffffffffffffffffffffffffffffffffffffffffffff168152602001613b1f4261418b565b67ffffffffffffffff90811690915273ffffffffffffffffffffffffffffffffffffffff90941660009081526008602090815260409091208251929091015190941678010000000000000000000000000000000000000000000000000277ffffffffffffffffffffffffffffffffffffffffffffffff909116179092555050565b600076ffffffffffffffffffffffffffffffffffffffffffffff821115613c02576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260b86004820152602481018390526044015b60405180910390fd5b5090565b6000613c13602084615979565b90506000613c2260208561598d565b613c2d906008615aa4565b905060ff811b600082856003811115613c4857613c48614f21565b6000958652600b6020526040909520805493199390931694901b93909317905550505050565b600080613c7a83610d31565b90506003816003811115613c9057613c90614f21565b03613c9e5750600092915050565b6002816003811115613cb257613cb2614f21565b1480613ccf57506001816003811115613ccd57613ccd614f21565b145b15613cdd5750600092915050565b50600192915050565b60006001836005811115613cfc57613cfc614f21565b03613dec57600080600084806020019051810190613d1a9190615e90565b6040517f20bac31d00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff84811660048301528381166024830152821515604483015293965091945092507f000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c909116906320bac31d906064016020604051808303816000875af1158015613dc2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613de691906158eb565b93505050505b6002836005811115613e0057613e00614f21565b03613ed05760008083806020019051810190613e1c9190615edd565b6040517f296e540700000000000000000000000000000000000000000000000000000000815260048101839052811515602482015291935091507f0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c473ffffffffffffffffffffffffffffffffffffffff169063296e540790604401600060405180830381600087803b158015613eb157600080fd5b505af1158015613ec5573d6000803e3d6000fd5b505050506001925050505b6003836005811115613ee457613ee4614f21565b03613fc75760008083806020019051810190613f009190615f0d565b506040517fcd12099000000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8084166004830152602482018390529294509092507f0000000000000000000000000116da066517f010e59b32274bf18083af34e1089091169063cd120990906044016020604051808303816000875af1158015613f9e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613fc291906158eb565b925050505b6004836005811115613fdb57613fdb614f21565b0361409f57600082806020019051810190613ff69190615b1f565b6040517fb744aaa5000000000000000000000000000000000000000000000000000000008152600481018290529091507f0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c473ffffffffffffffffffffffffffffffffffffffff169063b744aaa590602401600060405180830381600087803b15801561408157600080fd5b505af1158015614095573d6000803e3d6000fd5b5050505060019150505b60058360058111156140b3576140b3614f21565b03614110576000828060200190518101906140ce9190615b1f565b9050847fe25a4d93d90a403cb2ee36abec0c7dbf52b064220b5cb47d26b670b987325d558260405161410291815260200190565b60405180910390a260019150505b801561412657614121846002613c06565b614131565b614131846001613c06565b847fdcb90c5cbc98ab88833cf2ddca2514638b8f7f96c83c1826bdf8f503b21e1e6385858460405161416593929190615f44565b60405180910390a25050505050565b60008061417f61443a565b50905061248e816142af565b600067ffffffffffffffff821115613c0257604080517f6dfcc650000000000000000000000000000000000000000000000000000000008152600481019190915260248101839052604401613bf9565b6060610c077f476c6f7720476f7665726e616e6365000000000000000000000000000000000f600061445f565b6060610c077f3100000000000000000000000000000000000000000000000000000000000001600161445f565b60035460009081818015614249578261424c565b60015b600254909350835b81811015614297576000818152600960205260409020544261010090910467ffffffffffffffff16101561428a5780945061428f565b614297565b600101614254565b506142a284826159a1565b9593945050831415919050565b6000806142e76127106142de6142ce68011999999999999a008761450a565b6801000000000000000090614871565b600f0b906148c9565b90506142f7816305f5e100615aa4565b9392505050565b600077ffffffffffffffffffffffffffffffffffffffffffffffff821115613c02576040517f6dfcc65000000000000000000000000000000000000000000000000000000000815260c0600482015260248101839052604401613bf9565b73ffffffffffffffffffffffffffffffffffffffff8316600090815260056020526040902054428510156143b3576143b37faab28a450000000000000000000000000000000000000000000000000000000061397d565b60006143c2888884898761494e565b90506143cf858286614a4a565b6143fc576143fc7f7caf5a700000000000000000000000000000000000000000000000000000000061397d565b614407826001615937565b73ffffffffffffffffffffffffffffffffffffffff90951660009081526005602052604090209490945550505050505050565b6000806000614447614235565b91945092509050801561445a5760038290555b509091565b606060ff83146144795761447283614abc565b905061126f565b81805461448590615898565b80601f01602080910402602001604051908101604052809291908181526020018280546144b190615898565b80156144fe5780601f106144d3576101008083540402835291602001916144fe565b820191906000526020600020905b8154815290600101906020018083116144e157829003601f168201915b5050505050905061126f565b600080600084600f0b1280156145235750826001166001145b905060008085600f0b12614537578461453c565b846000035b6fffffffffffffffffffffffffffffffff1690507001000000000000000000000000000000006801000000000000000082116145ec57603f82901b91505b84156145e457600185161561458f578102607f1c5b908002607f1c9060028516156145a5578102607f1c5b908002607f1c9060048516156145bb578102607f1c5b908002607f1c9060088516156145d1578102607f1c5b60049490941c93908002607f1c9061457a565b60401c614814565b603f6c0100000000000000000000000083101561462d5760209290921b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015b6e01000000000000000000000000000083101561466e5760109290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0015b6f010000000000000000000000000000008310156146b05760089290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8015b6f100000000000000000000000000000008310156146f25760049290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc015b6f400000000000000000000000000000008310156147345760029290921b917ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe015b6f800000000000000000000000000000008310156147765760019290921b917fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff015b60005b86156147fd576040821061478c57600080fd5b60018716156147bf57918302607f1c9181017001000000000000000000000000000000008311156147bf57600192831c92015b928002607f1c9260019190911b9070010000000000000000000000000000000084106147f157600193841c9391909101905b600187901c9650614779565b6040811061480a57600080fd5b6040039190911c90505b6000836148215781614826565b816000035b90507fffffffffffffffffffffffffffffffff80000000000000000000000000000000811280159061486857506f7fffffffffffffffffffffffffffffff8113155b610d8657600080fd5b6000600f83810b9083900b0260401d7fffffffffffffffffffffffffffffffff8000000000000000000000000000000081128015906148c057506f7fffffffffffffffffffffffffffffff8113155b6142f757600080fd5b6000816000036148db5750600061126f565b600083600f0b12156148ec57600080fd5b600f83900b6fffffffffffffffffffffffffffffffff8316810260401c90608084901c0277ffffffffffffffffffffffffffffffffffffffffffffffff81111561493557600080fd5b60401b811981111561494657600080fd5b019392505050565b6000614958614afb565b7f03f41c6366d1b8eee338b5696f0b3ce825e8b8eaf9a99b2665c8fb1f68b82aa187600581111561498b5761498b614f21565b87878787805190602001206040516020016149d19695949392919095865260ff94909416602086015260408501929092526060840152608083015260a082015260c00190565b60405160208183030381529060405280519060200120604051602001614a299291907f190100000000000000000000000000000000000000000000000000000000000081526002810192909252602282015260420190565b60405160208183030381529060405280519060200120905095945050505050565b6000806000614a598585614c33565b5090925090506000816003811115614a7357614a73614f21565b148015614aab57508573ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff16145b80610d865750610d86868686614c80565b60606000614ac983614dcd565b604080516020808252818301909252919250600091906020820181803683375050509182525060208101929092525090565b60003073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000008d01a258bc1adb728322499e5d84173ea971d66516148015614b6157507f000000000000000000000000000000000000000000000000000000000000000146145b15614b8b57507f1652cf1af2714f030a46cc333690c3b612b5f9b26f510fea5a789de27907397190565b610c07604080517f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60208201527fa43f4b194f1307a5fcab6aacb8aedb2d8bcfa4031f0f8e066cb077293af85450918101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260009060c00160405160208183030381529060405280519060200120905090565b60008060008351604103614c6d5760208401516040850151606086015160001a614c5f88828585614e0e565b955095509550505050614c79565b50508151600091506002905b9250925092565b60008060008573ffffffffffffffffffffffffffffffffffffffff168585604051602401614caf929190615f68565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529181526020820180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f1626ba7e0000000000000000000000000000000000000000000000000000000017905251614d309190615f81565b600060405180830381855afa9150503d8060008114614d6b576040519150601f19603f3d011682016040523d82523d6000602084013e614d70565b606091505b5091509150818015614d8457506020815110155b8015610d86575080517f1626ba7e0000000000000000000000000000000000000000000000000000000090614dc29083016020908101908401615b1f565b149695505050505050565b600060ff8216601f81111561126f576040517fb3512b0c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0841115614e495750600091506003905082614efe565b604080516000808252602082018084528a905260ff891692820192909252606081018790526080810186905260019060a0016020604051602081039080840390855afa158015614e9d573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff8116614ef457506000925060019150829050614efe565b9250600091508190505b9450945094915050565b600060208284031215614f1a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b60068110614f6057614f60614f21565b9052565b60005b83811015614f7f578181015183820152602001614f67565b50506000910152565b60008151808452614fa0816020860160208601614f64565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b60208152614fe4602082018351614f50565b67ffffffffffffffff602083015116604082015276ffffffffffffffffffffffffffffffffffffffffffffff60408301511660608201526000606083015160808084015261177060a0840182614f88565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156150ab576150ab615035565b604052919050565b600067ffffffffffffffff8211156150cd576150cd615035565b5060051b60200190565b600082601f8301126150e857600080fd5b813560206150fd6150f8836150b3565b615064565b82815260059290921b8401810191818101908684111561511c57600080fd5b8286015b848110156151375780358352918301918301615120565b509695505050505050565b73ffffffffffffffffffffffffffffffffffffffff8116811461516457600080fd5b50565b803561517281615142565b919050565b600082601f83011261518857600080fd5b813560206151986150f8836150b3565b82815260059290921b840181019181810190868411156151b757600080fd5b8286015b848110156151375780356151ce81615142565b83529183019183016151bb565b6000601f83818401126151ed57600080fd5b823560206151fd6150f8836150b3565b82815260059290921b8501810191818101908784111561521c57600080fd5b8287015b848110156152d157803567ffffffffffffffff808211156152415760008081fd5b818a0191508a603f8301126152565760008081fd5b8582013560408282111561526c5761526c615035565b61529b887fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08c85011601615064565b92508183528c818386010111156152b25760008081fd5b8181850189850137506000908201870152845250918301918301615220565b50979650505050505050565b600080600080600060a086880312156152f557600080fd5b85359450602086013567ffffffffffffffff8082111561531457600080fd5b61532089838a016150d7565b9550604088013591508082111561533657600080fd5b61534289838a016150d7565b9450606088013591508082111561535857600080fd5b61536489838a01615177565b9350608088013591508082111561537a57600080fd5b50615387888289016151db565b9150509295509295909350565b60008060008060008060c087890312156153ad57600080fd5b863567ffffffffffffffff808211156153c557600080fd5b6153d18a838b01615177565b975060208901359150808211156153e757600080fd5b6153f38a838b01615177565b9650604089013591508082111561540957600080fd5b6154158a838b016150d7565b9550606089013591508082111561542b57600080fd5b6154378a838b016150d7565b9450608089013591508082111561544d57600080fd5b6154598a838b01615177565b935060a089013591508082111561546f57600080fd5b5061547c89828a016151db565b9150509295509295509295565b602081016004831061549d5761549d614f21565b91905290565b600080604083850312156154b657600080fd5b50508035926020909101359150565b6000602082840312156154d757600080fd5b81356142f781615142565b600080604083850312156154f557600080fd5b823561550081615142565b946020939093013593505050565b6000806000806080858703121561552457600080fd5b843561552f81615142565b966020860135965060408601359560600135945092505050565b600080600080600080600060e0888a03121561556457600080fd5b61556d88615167565b96506020880135955060408801359450606088013567ffffffffffffffff8082111561559857600080fd5b6155a48b838c016150d7565b955060808a01359150808211156155ba57600080fd5b6155c68b838c016150d7565b945060a08a01359150808211156155dc57600080fd5b6155e88b838c01615177565b935060c08a01359150808211156155fe57600080fd5b5061560b8a828b016151db565b91505092959891949750929550565b7fff00000000000000000000000000000000000000000000000000000000000000881681526000602060e08184015261565660e084018a614f88565b8381036040850152615668818a614f88565b6060850189905273ffffffffffffffffffffffffffffffffffffffff8816608086015260a0850187905284810360c0860152855180825283870192509083019060005b818110156156c7578351835292840192918401916001016156ab565b50909c9b505050505050505050505050565b801515811461516457600080fd5b8035615172816156d9565b6000806000806080858703121561570857600080fd5b843561571381615142565b9350602085013561572381615142565b92506040850135615733816156d9565b9396929550929360600135925050565b600080600080600080600060e0888a03121561575e57600080fd5b61576788615167565b965061577560208901615167565b9550615783604089016156e7565b9450606088013567ffffffffffffffff8082111561559857600080fd5b6000806000606084860312156157b557600080fd5b8335925060208401356157c7816156d9565b929592945050506040919091013590565b60008083601f8401126157ea57600080fd5b50813567ffffffffffffffff81111561580257600080fd5b6020830191508360208260051b850101111561581d57600080fd5b9250929050565b60008060008060006060868803121561583c57600080fd5b853567ffffffffffffffff8082111561585457600080fd5b61586089838a016157d8565b9097509550602088013591508082111561587957600080fd5b50615886888289016157d8565b96999598509660400135949350505050565b600181811c908216806158ac57607f821691505b6020821081036158e5577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b6000602082840312156158fd57600080fd5b81516142f7816156d9565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561126f5761126f615908565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b6000826159885761598861594a565b500490565b60008261599c5761599c61594a565b500690565b8181038181111561126f5761126f615908565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82036159e5576159e5615908565b5060010190565b600081518084526020808501945080840160005b83811015615a3257815173ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615a00565b509495945050505050565b604081526000615a5060408301856159ec565b8281036020840152615a6281856159ec565b95945050505050565b608081526000615a7e60808301876159ec565b8281036020840152615a9081876159ec565b604084019590955250506060015292915050565b808202811582820484141761126f5761126f615908565b6fffffffffffffffffffffffffffffffff818116838216019080821115615ae457615ae4615908565b5092915050565b6fffffffffffffffffffffffffffffffff818116838216028082169190828114615b1757615b17615908565b505092915050565b600060208284031215615b3157600080fd5b5051919050565b601f821115615b8257600081815260208120601f850160051c81016020861015615b5f5750805b601f850160051c820191505b81811015615b7e57828155600101615b6b565b5050505b505050565b815167ffffffffffffffff811115615ba157615ba1615035565b615bb581615baf8454615898565b84615b38565b602080601f831160018114615c085760008415615bd25750858301515b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600386901b1c1916600185901b178555615b7e565b6000858152602081207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08616915b82811015615c5557888601518255948401946001909101908401615c36565b5085821015615c9157878501517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600388901b60f8161c191681555b5050505050600190811b01905550565b8183526000602080850194508260005b85811015615a32578135615cc481615142565b73ffffffffffffffffffffffffffffffffffffffff1687529582019590820190600101615cb1565b606081526000615d00606083018789615ca1565b8281036020840152615d13818688615ca1565b9150508260408301529695505050505050565b608081526000615d3a60808301888a615ca1565b8281036020840152615d4d818789615ca1565b6040840195909552505060600152949350505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082601f830112615da357600080fd5b81516020615db36150f8836150b3565b82815260059290921b84018101918181019086841115615dd257600080fd5b8286015b84811015615137578051615de981615142565b8352918301918301615dd6565b60008060408385031215615e0957600080fd5b825167ffffffffffffffff80821115615e2157600080fd5b615e2d86838701615d92565b93506020850151915080821115615e4357600080fd5b50615e5085828601615d92565b9150509250929050565b606081526000615e6d60608301866159ec565b8281036020840152615e7f81866159ec565b915050826040830152949350505050565b600080600060608486031215615ea557600080fd5b8351615eb081615142565b6020850151909350615ec181615142565b6040850151909250615ed2816156d9565b809150509250925092565b60008060408385031215615ef057600080fd5b825191506020830151615f02816156d9565b809150509250929050565b600080600060608486031215615f2257600080fd5b8351615f2d81615142565b602085015160409095015190969495509392505050565b83815260608101615f586020830185614f50565b8215156040830152949350505050565b8281526040602082015260006117706040830184614f88565b60008251615f93818460208701614f64565b919091019291505056fea2646970667358221220a4a0ea6d9f5a360187cd380013d49245c410ee614a03c675337a55fa46401dfe64736f6c63430008150033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000021c46173591f39afc1d2b634b74c98f0576a272b0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c4000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c0000000000000000000000000116da066517f010e59b32274bf18083af34e108000000000000000000000000f4fbc617a5733eaaf9af08e1ab816b103388d8b6

-----Decoded View---------------
Arg [0] : gcc (address): 0x21C46173591f39AfC1d2B634b74c98F0576A272B
Arg [1] : gca (address): 0x6Fa8C7a89b22bf3212392b778905B12f3dBAF5C4
Arg [2] : vetoCouncil (address): 0xA3A32d3c9a5A593bc35D69BACbe2dF5Ea2C3cF5C
Arg [3] : grantsTreasury (address): 0x0116DA066517F010E59b32274BF18083aF34e108
Arg [4] : glw (address): 0xf4fbC617A5733EAAF9af08E1Ab816B103388d8B6

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 00000000000000000000000021c46173591f39afc1d2b634b74c98f0576a272b
Arg [1] : 0000000000000000000000006fa8c7a89b22bf3212392b778905b12f3dbaf5c4
Arg [2] : 000000000000000000000000a3a32d3c9a5a593bc35d69bacbe2df5ea2c3cf5c
Arg [3] : 0000000000000000000000000116da066517f010e59b32274bf18083af34e108
Arg [4] : 000000000000000000000000f4fbc617a5733eaaf9af08e1ab816b103388d8b6


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.