Feature Tip: Add private address tag to any address under My Name Tag !
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 22 from a total of 22 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
Create Grants Pr... | 19962989 | 39 days ago | IN | 0 ETH | 0.0039008 | ||||
Sync Proposals | 19912050 | 46 days ago | IN | 0 ETH | 0.001788 | ||||
Ratify Or Reject | 19842875 | 56 days ago | IN | 0 ETH | 0.00042085 | ||||
Create Veto Coun... | 19834686 | 57 days ago | IN | 0 ETH | 0.0008523 | ||||
Sync Proposals | 19804002 | 61 days ago | IN | 0 ETH | 0.00073937 | ||||
Sync Proposals | 19783859 | 64 days ago | IN | 0 ETH | 0.0017405 | ||||
Ratify Or Reject | 19724219 | 72 days ago | IN | 0 ETH | 0.00108158 | ||||
Create GCA Counc... | 19691689 | 77 days ago | IN | 0 ETH | 0.00153857 | ||||
Create GCA Counc... | 19646211 | 83 days ago | IN | 0 ETH | 0.00155104 | ||||
Create Grants Pr... | 19613043 | 88 days ago | IN | 0 ETH | 0.00590081 | ||||
Create Grants Pr... | 19585059 | 92 days ago | IN | 0 ETH | 0.00491256 | ||||
Create Grants Pr... | 19585025 | 92 days ago | IN | 0 ETH | 0.00516979 | ||||
Create Grants Pr... | 19500376 | 104 days ago | IN | 0 ETH | 0.00302699 | ||||
Create Grants Pr... | 19399493 | 118 days ago | IN | 0 ETH | 0.01347738 | ||||
Sync Proposals | 19056418 | 166 days ago | IN | 0 ETH | 0.00195091 | ||||
Sync Proposals | 19013827 | 172 days ago | IN | 0 ETH | 0.00112302 | ||||
Create Grants Pr... | 19013635 | 172 days ago | IN | 0 ETH | 0.00522136 | ||||
Create Grants Pr... | 19013630 | 172 days ago | IN | 0 ETH | 0.00490506 | ||||
Create Grants Pr... | 19013627 | 172 days ago | IN | 0 ETH | 0.00462402 | ||||
Ratify Or Reject | 18928518 | 184 days ago | IN | 0 ETH | 0.00222563 | ||||
Create GCA Counc... | 18830098 | 198 days ago | IN | 0 ETH | 0.00869834 | ||||
0x61022060 | 18809233 | 201 days ago | IN | Create: Governance | 0 ETH | 0.22242505 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
Governance
Compiler Version
v0.8.21+commit.d9974bed
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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) } } }
// 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; }
// 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; } }
// 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); } } } }
// 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); }
// 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); }
// 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); }
// 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); }
// 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); } }
// 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)); } }
// 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) } } }
// 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); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; uint256 constant _BUCKET_DURATION = uint256(7 days); uint256 constant _GENESIS_TIMESTAMP = 1700352000;
// 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); }
// 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) } } }
// 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; } } }
// 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 ); }
// 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); } } }
// 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); }
// 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); } }
// 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; } }
// 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)); } }
// 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 } } }
// 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); }
// 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(); } } }
// 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; } }
// 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); } } }
{ "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
- No Contract Security Audit Submitted- Submit Audit Here
[{"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"}]
Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
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.